From 3ac85fb66626ea91641f5fb9ad9069aab94754f5 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 29 Jul 2013 15:49:16 +0200 Subject: [PATCH 01/17] s390/kvm: Add check for priviledged SCLP handler The SCLP instruction is priviledged, so we should make sure that we generate an exception when it is called from the problem state. Signed-off-by: Thomas Huth Signed-off-by: Christian Borntraeger --- target-s390x/kvm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 4923e0a717..0bc317e928 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -439,6 +439,10 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run, int r = 0; cpu_synchronize_state(CPU(cpu)); + if (env->psw.mask & PSW_MASK_PSTATE) { + enter_pgmcheck(cpu, PGM_PRIVILEGED); + return 0; + } sccb = env->regs[ipbh0 & 0xf]; code = env->regs[(ipbh0 & 0xf0) >> 4]; From abd137a1bc72614e1e6ca1cd9502426e4b4f7e6a Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 29 Aug 2013 12:40:25 +0200 Subject: [PATCH 02/17] s390/dump: zero out padding bytes in notes sections The prstatus of an s390x dump contains several padding areas. Zero out these bytes to make reading the notes section easier with a hexdump. Signed-off-by: Christian Borntraeger --- target-s390x/arch_dump.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-s390x/arch_dump.c b/target-s390x/arch_dump.c index 9d36116242..5cbb53ca2e 100644 --- a/target-s390x/arch_dump.c +++ b/target-s390x/arch_dump.c @@ -151,6 +151,7 @@ static int s390x_write_all_elf64_notes(const char *note_name, int ret = -1; for (nf = note_func; nf->note_contents_func; nf++) { + memset(¬e, 0, sizeof(note)); note.hdr.n_namesz = cpu_to_be32(sizeof(note.name)); note.hdr.n_descsz = cpu_to_be32(nf->contents_size); strncpy(note.name, note_name, sizeof(note.name)); From 441ea695f9e9d64399f69904c2dd12e59963f1a4 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 29 Aug 2013 17:52:43 +0200 Subject: [PATCH 03/17] s390/ipl: Fix waiting for virtio processing The guest side must not manipulate the index for the used buffers. Instead, remember the state of the used buffer locally and wait until it has moved. Signed-off-by: Cornelia Huck Acked-by: Alexander Graf Signed-off-by: Christian Borntraeger --- pc-bios/s390-ccw/virtio.c | 7 ++++--- pc-bios/s390-ccw/virtio.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c index 49f2d291fc..4d6e48fcbe 100644 --- a/pc-bios/s390-ccw/virtio.c +++ b/pc-bios/s390-ccw/virtio.c @@ -123,6 +123,7 @@ static void vring_init(struct vring *vr, unsigned int num, void *p, /* We're running with interrupts off anyways, so don't bother */ vr->used->flags = VRING_USED_F_NO_NOTIFY; vr->used->idx = 0; + vr->used_idx = 0; debug_print_addr("init vr", vr); } @@ -150,8 +151,6 @@ static void vring_send_buf(struct vring *vr, void *p, int len, int flags) if (!(flags & VRING_DESC_F_NEXT)) { vr->avail->idx++; } - - vr->used->idx = vr->next_idx; } static u64 get_clock(void) @@ -180,7 +179,8 @@ static int vring_wait_reply(struct vring *vr, int timeout) struct subchannel_id schid = vr->schid; int r = 0; - while (vr->used->idx == vr->next_idx) { + /* Wait until the used index has moved. */ + while (vr->used->idx == vr->used_idx) { vring_notify(schid); if (timeout && (get_second() >= target_second)) { r = 1; @@ -189,6 +189,7 @@ static int vring_wait_reply(struct vring *vr, int timeout) yield(); } + vr->used_idx = vr->used->idx; vr->next_idx = 0; vr->desc[0].len = 0; vr->desc[0].flags = 0; diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h index 86fdd579b4..772a63f152 100644 --- a/pc-bios/s390-ccw/virtio.h +++ b/pc-bios/s390-ccw/virtio.h @@ -115,6 +115,7 @@ struct vring_used { struct vring { unsigned int num; int next_idx; + int used_idx; struct vring_desc *desc; struct vring_avail *avail; struct vring_used *used; From 1902269c19a2c8ba852f90f04d6dfde1d1145d6f Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Mon, 2 Sep 2013 11:05:43 +0200 Subject: [PATCH 04/17] s390/ipl: Update the s390-ccw.img rom Rebuild of the virtio-ccw rom containing these patches: 1. s390/ipl: Fix waiting for virtio processing Signed-off-by: Christian Borntraeger --- pc-bios/s390-ccw.img | Bin 9432 -> 9336 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img index 05fc7c2fae97caf222d9ccce88631d8a20ccd565..6727f0ca39d6bf6d114974d1535cb7ad9e56355f 100644 GIT binary patch literal 9336 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 U<32@#56aKxd7D2r=jhYF0b?J4UH||9 literal 9432 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 BZma+R From 3d0a615fe92501684d8d2dc54326f0241b666bd2 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 2 Jul 2013 13:43:38 +0200 Subject: [PATCH 05/17] s390/cpu: Make setcc() function available to other files Moved the setcc() function to cpu.h so that it can be used by other files, too. It now also does not modify the kvm state anymore since this gets updated during kvm_arch_put_registers() anyway. Signed-off-by: Thomas Huth Signed-off-by: Christian Borntraeger --- target-s390x/cpu.h | 11 +++++++++-- target-s390x/kvm.c | 12 ------------ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 8be5648806..a2c077bdcd 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -148,6 +148,7 @@ typedef struct CPUS390XState { } CPUS390XState; #include "cpu-qom.h" +#include /* distinguish between 24 bit and 31 bit addressing */ #define HIGH_ORDER_BIT 0x80000000 @@ -692,6 +693,14 @@ static inline const char *cc_name(int cc_op) return cc_names[cc_op]; } +static inline void setcc(S390CPU *cpu, uint64_t cc) +{ + CPUS390XState *env = &cpu->env; + + env->psw.mask &= ~(3ull << 44); + env->psw.mask |= (cc & 3) << 44; +} + typedef struct LowCore { /* prefix area: defined by architecture */ @@ -1058,8 +1067,6 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, uintptr_t retaddr); -#include - #ifdef CONFIG_KVM void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, uint16_t subchannel_nr, uint32_t io_int_parm, diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 0bc317e928..a5d5584fc3 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -418,18 +418,6 @@ static void enter_pgmcheck(S390CPU *cpu, uint16_t code) kvm_s390_interrupt(cpu, KVM_S390_PROGRAM_INT, code); } -static inline void setcc(S390CPU *cpu, uint64_t cc) -{ - CPUS390XState *env = &cpu->env; - CPUState *cs = CPU(cpu); - - cs->kvm_run->psw_mask &= ~(3ull << 44); - cs->kvm_run->psw_mask |= (cc & 3) << 44; - - env->psw.mask &= ~(3ul << 44); - env->psw.mask |= (cc & 3) << 44; -} - static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run, uint16_t ipbh0) { From 5d9bf1c07c1369ab3506fc82cc65a10f4415d867 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 1 Jul 2013 15:44:18 +0200 Subject: [PATCH 06/17] s390/ioinst: Moved the CC setting to the IO instruction handlers The IO instruction handlers now take care of setting the CC value on their own, so that the confusing return code magic in kvm_handle_css_inst() is not needed anymore. Signed-off-by: Thomas Huth Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- target-s390x/ioinst.c | 110 +++++++++++++++++++----------------------- target-s390x/ioinst.h | 26 +++++----- target-s390x/kvm.c | 38 ++++++--------- 3 files changed, 77 insertions(+), 97 deletions(-) diff --git a/target-s390x/ioinst.c b/target-s390x/ioinst.c index 85fd285736..8d6363df4e 100644 --- a/target-s390x/ioinst.c +++ b/target-s390x/ioinst.c @@ -36,7 +36,7 @@ int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid, return 0; } -int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1) +void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1) { int cssid, ssid, schid, m; SubchDev *sch; @@ -44,8 +44,8 @@ int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1) int cc; if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { - program_interrupt(env, PGM_OPERAND, 2); - return -EIO; + program_interrupt(&cpu->env, PGM_OPERAND, 2); + return; } trace_ioinst_sch_id("xsch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); @@ -66,11 +66,10 @@ int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1) cc = 1; break; } - - return cc; + setcc(cpu, cc); } -int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1) +void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1) { int cssid, ssid, schid, m; SubchDev *sch; @@ -78,8 +77,8 @@ int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1) int cc; if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { - program_interrupt(env, PGM_OPERAND, 2); - return -EIO; + program_interrupt(&cpu->env, PGM_OPERAND, 2); + return; } trace_ioinst_sch_id("csch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); @@ -91,10 +90,10 @@ int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1) } else { cc = 0; } - return cc; + setcc(cpu, cc); } -int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1) +void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1) { int cssid, ssid, schid, m; SubchDev *sch; @@ -102,8 +101,8 @@ int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1) int cc; if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { - program_interrupt(env, PGM_OPERAND, 2); - return -EIO; + program_interrupt(&cpu->env, PGM_OPERAND, 2); + return; } trace_ioinst_sch_id("hsch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); @@ -124,8 +123,7 @@ int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1) cc = 1; break; } - - return cc; + setcc(cpu, cc); } static int ioinst_schib_valid(SCHIB *schib) @@ -141,7 +139,7 @@ static int ioinst_schib_valid(SCHIB *schib) return 1; } -int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) +void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) { int cssid, ssid, schid, m; SubchDev *sch; @@ -150,22 +148,21 @@ int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) int ret = -ENODEV; int cc; hwaddr len = sizeof(*schib); + CPUS390XState *env = &cpu->env; addr = decode_basedisp_s(env, ipb); if (addr & 3) { program_interrupt(env, PGM_SPECIFICATION, 2); - return -EIO; + return; } schib = s390_cpu_physical_memory_map(env, addr, &len, 0); if (!schib || len != sizeof(*schib)) { program_interrupt(env, PGM_ADDRESSING, 2); - cc = -EIO; goto out; } if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) || !ioinst_schib_valid(schib)) { program_interrupt(env, PGM_OPERAND, 2); - cc = -EIO; goto out; } trace_ioinst_sch_id("msch", cssid, ssid, schid); @@ -187,9 +184,10 @@ int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) cc = 1; break; } + setcc(cpu, cc); + out: s390_cpu_physical_memory_unmap(env, schib, len, 0); - return cc; } static void copy_orb_from_guest(ORB *dest, const ORB *src) @@ -213,7 +211,7 @@ static int ioinst_orb_valid(ORB *orb) return 1; } -int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) +void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) { int cssid, ssid, schid, m; SubchDev *sch; @@ -222,23 +220,22 @@ int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) int ret = -ENODEV; int cc; hwaddr len = sizeof(*orig_orb); + CPUS390XState *env = &cpu->env; addr = decode_basedisp_s(env, ipb); if (addr & 3) { program_interrupt(env, PGM_SPECIFICATION, 2); - return -EIO; + return; } orig_orb = s390_cpu_physical_memory_map(env, addr, &len, 0); if (!orig_orb || len != sizeof(*orig_orb)) { program_interrupt(env, PGM_ADDRESSING, 2); - cc = -EIO; goto out; } copy_orb_from_guest(&orb, orig_orb); if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) || !ioinst_orb_valid(&orb)) { program_interrupt(env, PGM_OPERAND, 2); - cc = -EIO; goto out; } trace_ioinst_sch_id("ssch", cssid, ssid, schid); @@ -260,38 +257,39 @@ int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) cc = 1; break; } + setcc(cpu, cc); out: s390_cpu_physical_memory_unmap(env, orig_orb, len, 0); - return cc; } -int ioinst_handle_stcrw(CPUS390XState *env, uint32_t ipb) +void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb) { CRW *crw; uint64_t addr; int cc; hwaddr len = sizeof(*crw); + CPUS390XState *env = &cpu->env; addr = decode_basedisp_s(env, ipb); if (addr & 3) { program_interrupt(env, PGM_SPECIFICATION, 2); - return -EIO; + return; } crw = s390_cpu_physical_memory_map(env, addr, &len, 1); if (!crw || len != sizeof(*crw)) { program_interrupt(env, PGM_ADDRESSING, 2); - cc = -EIO; goto out; } cc = css_do_stcrw(crw); /* 0 - crw stored, 1 - zeroes stored */ + setcc(cpu, cc); + out: s390_cpu_physical_memory_unmap(env, crw, len, 1); - return cc; } -int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) +void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) { int cssid, ssid, schid, m; SubchDev *sch; @@ -299,22 +297,21 @@ int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) int cc; SCHIB *schib; hwaddr len = sizeof(*schib); + CPUS390XState *env = &cpu->env; addr = decode_basedisp_s(env, ipb); if (addr & 3) { program_interrupt(env, PGM_SPECIFICATION, 2); - return -EIO; + return; } schib = s390_cpu_physical_memory_map(env, addr, &len, 1); if (!schib || len != sizeof(*schib)) { program_interrupt(env, PGM_ADDRESSING, 2); - cc = -EIO; goto out; } if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { program_interrupt(env, PGM_OPERAND, 2); - cc = -EIO; goto out; } trace_ioinst_sch_id("stsch", cssid, ssid, schid); @@ -336,9 +333,10 @@ int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) cc = 0; } } + setcc(cpu, cc); + out: s390_cpu_physical_memory_unmap(env, schib, len, 1); - return cc; } int ioinst_handle_tsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) @@ -575,7 +573,7 @@ static void ioinst_handle_chsc_unimplemented(ChscResp *res) res->param = 0; } -int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb) +void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb) { ChscReq *req; ChscResp *res; @@ -584,7 +582,7 @@ int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb) uint16_t len; uint16_t command; hwaddr map_size = TARGET_PAGE_SIZE; - int ret = 0; + CPUS390XState *env = &cpu->env; trace_ioinst("chsc"); reg = (ipb >> 20) & 0x00f; @@ -592,19 +590,17 @@ int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb) /* Page boundary? */ if (addr & 0xfff) { program_interrupt(env, PGM_SPECIFICATION, 2); - return -EIO; + return; } req = s390_cpu_physical_memory_map(env, addr, &map_size, 1); if (!req || map_size != TARGET_PAGE_SIZE) { program_interrupt(env, PGM_ADDRESSING, 2); - ret = -EIO; goto out; } len = be16_to_cpu(req->len); /* Length field valid? */ if ((len < 16) || (len > 4088) || (len & 7)) { program_interrupt(env, PGM_OPERAND, 2); - ret = -EIO; goto out; } memset((char *)req + len, 0, TARGET_PAGE_SIZE - len); @@ -628,7 +624,6 @@ int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb) out: s390_cpu_physical_memory_unmap(env, req, map_size, 1); - return ret; } int ioinst_handle_tpi(CPUS390XState *env, uint32_t ipb) @@ -666,18 +661,19 @@ out: #define SCHM_REG1_UPD(_reg) ((_reg & 0x0000000000000002) >> 1) #define SCHM_REG1_DCT(_reg) (_reg & 0x0000000000000001) -int ioinst_handle_schm(CPUS390XState *env, uint64_t reg1, uint64_t reg2, - uint32_t ipb) +void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2, + uint32_t ipb) { uint8_t mbk; int update; int dct; + CPUS390XState *env = &cpu->env; trace_ioinst("schm"); if (SCHM_REG1_RES(reg1)) { program_interrupt(env, PGM_OPERAND, 2); - return -EIO; + return; } mbk = SCHM_REG1_MBK(reg1); @@ -686,15 +682,13 @@ int ioinst_handle_schm(CPUS390XState *env, uint64_t reg1, uint64_t reg2, if (update && (reg2 & 0x000000000000001f)) { program_interrupt(env, PGM_OPERAND, 2); - return -EIO; + return; } css_do_schm(mbk, update, dct, update ? reg2 : 0); - - return 0; } -int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1) +void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1) { int cssid, ssid, schid, m; SubchDev *sch; @@ -702,8 +696,8 @@ int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1) int cc; if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { - program_interrupt(env, PGM_OPERAND, 2); - return -EIO; + program_interrupt(&cpu->env, PGM_OPERAND, 2); + return; } trace_ioinst_sch_id("rsch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); @@ -724,24 +718,23 @@ int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1) cc = 1; break; } - - return cc; - + setcc(cpu, cc); } #define RCHP_REG1_RES(_reg) (_reg & 0x00000000ff00ff00) #define RCHP_REG1_CSSID(_reg) ((_reg & 0x0000000000ff0000) >> 16) #define RCHP_REG1_CHPID(_reg) (_reg & 0x00000000000000ff) -int ioinst_handle_rchp(CPUS390XState *env, uint64_t reg1) +void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1) { int cc; uint8_t cssid; uint8_t chpid; int ret; + CPUS390XState *env = &cpu->env; if (RCHP_REG1_RES(reg1)) { program_interrupt(env, PGM_OPERAND, 2); - return -EIO; + return; } cssid = RCHP_REG1_CSSID(reg1); @@ -764,19 +757,16 @@ int ioinst_handle_rchp(CPUS390XState *env, uint64_t reg1) default: /* Invalid channel subsystem. */ program_interrupt(env, PGM_OPERAND, 2); - return -EIO; + return; } - - return cc; + setcc(cpu, cc); } #define SAL_REG1_INVALID(_reg) (_reg & 0x0000000080000000) -int ioinst_handle_sal(CPUS390XState *env, uint64_t reg1) +void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1) { /* We do not provide address limit checking, so let's suppress it. */ if (SAL_REG1_INVALID(reg1) || reg1 & 0x000000000000ffff) { - program_interrupt(env, PGM_OPERAND, 2); - return -EIO; + program_interrupt(&cpu->env, PGM_OPERAND, 2); } - return 0; } diff --git a/target-s390x/ioinst.h b/target-s390x/ioinst.h index 7bed2910dc..613da49b3b 100644 --- a/target-s390x/ioinst.h +++ b/target-s390x/ioinst.h @@ -214,20 +214,20 @@ typedef struct IOIntCode { int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid, int *schid); -int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1); -int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1); -int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1); -int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb); -int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb); -int ioinst_handle_stcrw(CPUS390XState *env, uint32_t ipb); -int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb); +void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1); +void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1); +void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1); +void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); +void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); +void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb); +void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); int ioinst_handle_tsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb); -int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb); +void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb); int ioinst_handle_tpi(CPUS390XState *env, uint32_t ipb); -int ioinst_handle_schm(CPUS390XState *env, uint64_t reg1, uint64_t reg2, - uint32_t ipb); -int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1); -int ioinst_handle_rchp(CPUS390XState *env, uint64_t reg1); -int ioinst_handle_sal(CPUS390XState *env, uint64_t reg1); +void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2, + uint32_t ipb); +void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1); +void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1); +void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1); #endif diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index a5d5584fc3..a444f6999b 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -446,8 +446,6 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run, static int kvm_handle_css_inst(S390CPU *cpu, struct kvm_run *run, uint8_t ipa0, uint8_t ipa1, uint8_t ipb) { - int r = 0; - int no_cc = 0; CPUS390XState *env = &cpu->env; CPUState *cs = CPU(cpu); @@ -461,69 +459,61 @@ static int kvm_handle_css_inst(S390CPU *cpu, struct kvm_run *run, switch (ipa1) { case PRIV_XSCH: - r = ioinst_handle_xsch(env, env->regs[1]); + ioinst_handle_xsch(cpu, env->regs[1]); break; case PRIV_CSCH: - r = ioinst_handle_csch(env, env->regs[1]); + ioinst_handle_csch(cpu, env->regs[1]); break; case PRIV_HSCH: - r = ioinst_handle_hsch(env, env->regs[1]); + ioinst_handle_hsch(cpu, env->regs[1]); break; case PRIV_MSCH: - r = ioinst_handle_msch(env, env->regs[1], run->s390_sieic.ipb); + ioinst_handle_msch(cpu, env->regs[1], run->s390_sieic.ipb); break; case PRIV_SSCH: - r = ioinst_handle_ssch(env, env->regs[1], run->s390_sieic.ipb); + ioinst_handle_ssch(cpu, env->regs[1], run->s390_sieic.ipb); break; case PRIV_STCRW: - r = ioinst_handle_stcrw(env, run->s390_sieic.ipb); + ioinst_handle_stcrw(cpu, run->s390_sieic.ipb); break; case PRIV_STSCH: - r = ioinst_handle_stsch(env, env->regs[1], run->s390_sieic.ipb); + ioinst_handle_stsch(cpu, env->regs[1], run->s390_sieic.ipb); break; case PRIV_TSCH: /* We should only get tsch via KVM_EXIT_S390_TSCH. */ fprintf(stderr, "Spurious tsch intercept\n"); break; case PRIV_CHSC: - r = ioinst_handle_chsc(env, run->s390_sieic.ipb); + ioinst_handle_chsc(cpu, run->s390_sieic.ipb); break; case PRIV_TPI: /* This should have been handled by kvm already. */ fprintf(stderr, "Spurious tpi intercept\n"); break; case PRIV_SCHM: - no_cc = 1; - r = ioinst_handle_schm(env, env->regs[1], env->regs[2], - run->s390_sieic.ipb); + ioinst_handle_schm(cpu, env->regs[1], env->regs[2], + run->s390_sieic.ipb); break; case PRIV_RSCH: - r = ioinst_handle_rsch(env, env->regs[1]); + ioinst_handle_rsch(cpu, env->regs[1]); break; case PRIV_RCHP: - r = ioinst_handle_rchp(env, env->regs[1]); + ioinst_handle_rchp(cpu, env->regs[1]); break; case PRIV_STCPS: /* We do not provide this instruction, it is suppressed. */ - no_cc = 1; - r = 0; break; case PRIV_SAL: - no_cc = 1; - r = ioinst_handle_sal(env, env->regs[1]); + ioinst_handle_sal(cpu, env->regs[1]); break; case PRIV_SIGA: /* Not provided, set CC = 3 for subchannel not operational */ - r = 3; + setcc(cpu, 3); break; default: return -1; } - if (r >= 0 && !no_cc) { - setcc(cpu, r); - } - return 0; } From d8b30c830243c5b7180befd9e1921383c9626bf0 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 19 Sep 2013 09:32:03 +0200 Subject: [PATCH 07/17] s390/kexec: Implement diag308 subcode 0 This patch implements subcode 0 of diag 308. This is necessary for kexec (without kdump). The main difference to subcode 1 is that all CPUs get a full reset, instead of the architectured CPU reset (which leaves all registers untouched). Signed-off-by: Christian Borntraeger --- target-s390x/misc_helper.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 1690907169..37ea60d20b 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -192,6 +192,29 @@ static void cpu_reset_all(void) } } +static void cpu_full_reset_all(void) +{ + CPUState *cpu; + + CPU_FOREACH(cpu) { + cpu_reset(cpu); + } +} + +static int modified_clear_reset(S390CPU *cpu) +{ + S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); + + pause_all_vcpus(); + cpu_synchronize_all_states(); + cpu_full_reset_all(); + io_subsystem_reset(); + scc->load_normal(CPU(cpu)); + cpu_synchronize_all_post_reset(); + resume_all_vcpus(); + return 0; +} + static int load_normal_reset(S390CPU *cpu) { S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); @@ -225,6 +248,9 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3) } switch (subcode) { + case 0: + modified_clear_reset(s390_env_get_cpu(env)); + break; case 1: load_normal_reset(s390_env_get_cpu(env)); break; From ea9ad3e945526c56935c245a268731878c74e570 Mon Sep 17 00:00:00 2001 From: Heinz Graalfs Date: Wed, 28 Aug 2013 16:30:28 +0200 Subject: [PATCH 08/17] s390/sclpconsole: modify definition of input buffer To use VMState for migration, we need to adapt some sclp code: - allocate console buffer as part of the console - change semantic of sclpconsole offset fields Signed-off-by: Heinz Graalfs Reviewed-by: Alexander Graf Signed-off-by: Christian Borntraeger --- hw/char/sclpconsole.c | 54 +++++++++++++------------------------------ 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c index eb3988c2e4..fd270be64c 100644 --- a/hw/char/sclpconsole.c +++ b/hw/char/sclpconsole.c @@ -31,12 +31,11 @@ typedef struct ASCIIConsoleData { typedef struct SCLPConsole { SCLPEvent event; CharDriverState *chr; - /* io vector */ - uint8_t *iov; /* iov buffer pointer */ - uint8_t *iov_sclp; /* pointer to SCLP read offset */ - uint8_t *iov_bs; /* pointer byte stream read offset */ - uint32_t iov_data_len; /* length of byte stream in buffer */ - uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */ + uint8_t iov[SIZE_BUFFER_VT220]; + uint32_t iov_sclp; /* offset in buf for SCLP read operation */ + uint32_t iov_bs; /* offset in buf for char layer read operation */ + uint32_t iov_data_len; /* length of byte stream in buffer */ + uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */ qemu_irq irq_read_vt220; } SCLPConsole; @@ -47,7 +46,7 @@ static int chr_can_read(void *opaque) { SCLPConsole *scon = opaque; - return scon->iov ? SIZE_BUFFER_VT220 - scon->iov_data_len : 0; + return SIZE_BUFFER_VT220 - scon->iov_data_len; } /* Receive n bytes from character layer, save in iov buffer, @@ -55,13 +54,11 @@ static int chr_can_read(void *opaque) static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf, int size) { - assert(scon->iov); - /* read data must fit into current buffer */ assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len); /* put byte-stream from character layer into buffer */ - memcpy(scon->iov_bs, buf, size); + memcpy(&scon->iov[scon->iov_bs], buf, size); scon->iov_data_len += size; scon->iov_sclp_rest += size; scon->iov_bs += size; @@ -80,29 +77,6 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) qemu_irq_raise(scon->irq_read_vt220); } -static void chr_event(void *opaque, int event) -{ - SCLPConsole *scon = opaque; - - switch (event) { - case CHR_EVENT_OPENED: - if (!scon->iov) { - scon->iov = g_malloc0(SIZE_BUFFER_VT220); - scon->iov_sclp = scon->iov; - scon->iov_bs = scon->iov; - scon->iov_data_len = 0; - scon->iov_sclp_rest = 0; - } - break; - case CHR_EVENT_CLOSED: - if (scon->iov) { - g_free(scon->iov); - scon->iov = NULL; - } - break; - } -} - /* functions to be called by event facility */ static int event_type(void) @@ -134,17 +108,17 @@ static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size, /* if all data fit into provided SCLP buffer */ if (avail >= cons->iov_sclp_rest) { /* copy character byte-stream to SCLP buffer */ - memcpy(buf, cons->iov_sclp, cons->iov_sclp_rest); + memcpy(buf, &cons->iov[cons->iov_sclp], cons->iov_sclp_rest); *size = cons->iov_sclp_rest + 1; - cons->iov_sclp = cons->iov; - cons->iov_bs = cons->iov; + cons->iov_sclp = 0; + cons->iov_bs = 0; cons->iov_data_len = 0; cons->iov_sclp_rest = 0; event->event_pending = false; /* data provided and no more data pending */ } else { /* if provided buffer is too small, just copy part */ - memcpy(buf, cons->iov_sclp, avail); + memcpy(buf, &cons->iov[cons->iov_sclp], avail); *size = avail + 1; cons->iov_sclp_rest -= avail; cons->iov_sclp += avail; @@ -237,10 +211,14 @@ static int console_init(SCLPEvent *event) return -1; } console_available = true; + scon->iov_sclp = 0; + scon->iov_bs = 0; + scon->iov_data_len = 0; + scon->iov_sclp_rest = 0; event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA; if (scon->chr) { qemu_chr_add_handlers(scon->chr, chr_can_read, - chr_read, chr_event, scon); + chr_read, NULL, scon); } scon->irq_read_vt220 = *qemu_allocate_irqs(trigger_ascii_console_data, NULL, 1); From cb335bebe1f5eadd0188215a9703c3fd90cfe84e Mon Sep 17 00:00:00 2001 From: Heinz Graalfs Date: Tue, 11 Sep 2012 13:41:26 +0200 Subject: [PATCH 09/17] s390/sclpconsole: Add code to support live migration for sclpconsole This patch adds the necessary life migration pieces to the sclp code by using vmstate_register. Signed-off-by: Heinz Graalfs Reviewed-by: Alexander Graf Signed-off-by: Christian Borntraeger --- hw/char/sclpconsole.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c index fd270be64c..776f2840ed 100644 --- a/hw/char/sclpconsole.c +++ b/hw/char/sclpconsole.c @@ -197,9 +197,26 @@ static void trigger_ascii_console_data(void *opaque, int n, int level) sclp_service_interrupt(0); } +static const VMStateDescription vmstate_sclpconsole = { + .name = "sclpconsole", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_BOOL(event.event_pending, SCLPConsole), + VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220), + VMSTATE_UINT32(iov_sclp, SCLPConsole), + VMSTATE_UINT32(iov_bs, SCLPConsole), + VMSTATE_UINT32(iov_data_len, SCLPConsole), + VMSTATE_UINT32(iov_sclp_rest, SCLPConsole), + VMSTATE_END_OF_LIST() + } +}; + /* qemu object creation and initialization functions */ /* tell character layer our call-back functions */ + static int console_init(SCLPEvent *event) { static bool console_available; @@ -242,6 +259,7 @@ static void console_class_init(ObjectClass *klass, void *data) SCLPEventClass *ec = SCLP_EVENT_CLASS(klass); dc->props = console_properties; + dc->vmsd = &vmstate_sclpconsole; ec->init = console_init; ec->exit = console_exit; ec->get_send_mask = send_mask; From 7e36b7a3561d685b8fb071b25ab887e890973a4d Mon Sep 17 00:00:00 2001 From: Heinz Graalfs Date: Tue, 11 Sep 2012 13:41:26 +0200 Subject: [PATCH 10/17] s390/sclpquiesce: Add code to support live migration This patch adds the necessary life migration pieces to sclpquiesce by using the vmstate_register. Signed-off-by: Heinz Graalfs Reviewed-by: Alexander Graf Signed-off-by: Christian Borntraeger --- hw/s390x/sclpquiesce.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index 5fadc86d42..d335251c00 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -65,6 +65,17 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, return 1; } +static const VMStateDescription vmstate_sclpquiesce = { + .name = "sclpquiesce", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_BOOL(event_pending, SCLPEvent), + VMSTATE_END_OF_LIST() + } +}; + typedef struct QuiesceNotifier QuiesceNotifier; static struct QuiesceNotifier { @@ -96,8 +107,10 @@ static int quiesce_init(SCLPEvent *event) static void quiesce_class_init(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); SCLPEventClass *k = SCLP_EVENT_CLASS(klass); + dc->vmsd = &vmstate_sclpquiesce; k->init = quiesce_init; k->get_send_mask = send_mask; From 3af6de321f39eda37d60a26559c63029c0d5b4c9 Mon Sep 17 00:00:00 2001 From: Heinz Graalfs Date: Wed, 4 Sep 2013 12:55:45 +0200 Subject: [PATCH 11/17] s390/sclp: add reset() functions Add reset() functions for event-facility, sclpconsole, and sclpquiesce. The reset() functions perform variable initialization at IPL and e.g. when monitor system_reset is called. Signed-off-by: Heinz Graalfs Reviewed-by: Thomas Huth Reviewed-by: Alexander Graf Signed-off-by: Christian Borntraeger --- hw/char/sclpconsole.c | 17 +++++++++++++---- hw/s390x/event-facility.c | 9 +++++++++ hw/s390x/sclpquiesce.c | 8 ++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c index 776f2840ed..12488afca6 100644 --- a/hw/char/sclpconsole.c +++ b/hw/char/sclpconsole.c @@ -228,10 +228,6 @@ static int console_init(SCLPEvent *event) return -1; } console_available = true; - scon->iov_sclp = 0; - scon->iov_bs = 0; - scon->iov_data_len = 0; - scon->iov_sclp_rest = 0; event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA; if (scon->chr) { qemu_chr_add_handlers(scon->chr, chr_can_read, @@ -243,6 +239,18 @@ static int console_init(SCLPEvent *event) return 0; } +static void console_reset(DeviceState *dev) +{ + SCLPEvent *event = SCLP_EVENT(dev); + SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event); + + event->event_pending = false; + scon->iov_sclp = 0; + scon->iov_bs = 0; + scon->iov_data_len = 0; + scon->iov_sclp_rest = 0; +} + static int console_exit(SCLPEvent *event) { return 0; @@ -259,6 +267,7 @@ static void console_class_init(ObjectClass *klass, void *data) SCLPEventClass *ec = SCLP_EVENT_CLASS(klass); dc->props = console_properties; + dc->reset = console_reset; dc->vmsd = &vmstate_sclpconsole; ec->init = console_init; ec->exit = console_exit; diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index a3aceef8f5..d45968fa42 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -338,10 +338,19 @@ static int init_event_facility(S390SCLPDevice *sdev) return 0; } +static void reset_event_facility(DeviceState *dev) +{ + S390SCLPDevice *sdev = SCLP_S390_DEVICE(dev); + + sdev->ef->receive_mask = 0; +} + static void init_event_facility_class(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); S390SCLPDeviceClass *k = SCLP_S390_DEVICE_CLASS(klass); + dc->reset = reset_event_facility; k->init = init_event_facility; } diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index d335251c00..73a18ea3bb 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -105,11 +105,19 @@ static int quiesce_init(SCLPEvent *event) return 0; } +static void quiesce_reset(DeviceState *dev) +{ + SCLPEvent *event = SCLP_EVENT(dev); + + event->event_pending = false; +} + static void quiesce_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SCLPEventClass *k = SCLP_EVENT_CLASS(klass); + dc->reset = quiesce_reset; dc->vmsd = &vmstate_sclpquiesce; k->init = quiesce_init; From a0c8699b23ea065f8435d3bd04bd23f1783aa454 Mon Sep 17 00:00:00 2001 From: Ralf Hoppe Date: Mon, 19 Aug 2013 09:41:24 +0200 Subject: [PATCH 12/17] s390/eventfacility: fix multiple Read Event Data sources Make the handler for SCLP Read Event Data deal with notifications for multiple sources correctly. Signed-off-by: Ralf Hoppe Reviewed-by: Thomas Huth Signed-off-by: Christian Borntraeger [split bigger patch into smaller independent chunks] Reviewed-by: Alexander Graf --- hw/s390x/event-facility.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index d45968fa42..d2fd22776b 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -183,7 +183,7 @@ static uint16_t handle_sccb_read_events(SCLPEventFacility *ef, SCCB *sccb, { uint16_t rc; int slen; - unsigned elen = 0; + unsigned elen; BusChild *kid; SCLPEvent *event; SCLPEventClass *ec; @@ -203,11 +203,11 @@ static uint16_t handle_sccb_read_events(SCLPEventFacility *ef, SCCB *sccb, if (mask & ec->get_send_mask()) { if (ec->read_event_data(event, event_buf, &slen)) { + elen = be16_to_cpu(event_buf->length); + event_buf = (EventBufferHeader *) ((char *)event_buf + elen); rc = SCLP_RC_NORMAL_COMPLETION; } } - elen = be16_to_cpu(event_buf->length); - event_buf = (void *) event_buf + elen; } if (sccb->h.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE) { From 788be8e9d669c314ad7aef1a71bce31367cfe462 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 17 Sep 2013 10:32:54 +0200 Subject: [PATCH 13/17] s390/eventfacility: Fix receive/send masks Currently we announce interchanged receive/send masks. This did not trigger a bug, since the sclp console has the same masks for send/receive and the Linux guest does not check the sclp mask for simple events like quiesce. With other event users like the sclp line mode console, we will have different send/receive bits. Fix it. Signed-off-by: Christian Borntraeger Reviewed-by: Alexander Graf --- include/hw/s390x/event-facility.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h index 791ab2a6de..727ef4fdf8 100644 --- a/include/hw/s390x/event-facility.h +++ b/include/hw/s390x/event-facility.h @@ -43,8 +43,8 @@ typedef struct WriteEventMask { uint16_t mask_length; uint32_t cp_receive_mask; uint32_t cp_send_mask; - uint32_t send_mask; uint32_t receive_mask; + uint32_t send_mask; } QEMU_PACKED WriteEventMask; typedef struct EventBufferHeader { From 8b8b1138df5e512dc8a89896c44b67d192dd3d7d Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 17 Sep 2013 13:01:31 +0200 Subject: [PATCH 14/17] s390/eventfacility: remove unused event_type variable The event_type variable is never used. Get rid of it. Signed-off-by: Christian Borntraeger Reviewed-by: Alexander Graf --- hw/char/sclpconsole.c | 1 - hw/s390x/sclpquiesce.c | 2 -- include/hw/s390x/event-facility.h | 1 - 3 files changed, 4 deletions(-) diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c index 12488afca6..8cb0e41fa0 100644 --- a/hw/char/sclpconsole.c +++ b/hw/char/sclpconsole.c @@ -228,7 +228,6 @@ static int console_init(SCLPEvent *event) return -1; } console_available = true; - event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA; if (scon->chr) { qemu_chr_add_handlers(scon->chr, chr_can_read, chr_read, NULL, scon); diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index 73a18ea3bb..616267883c 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -95,8 +95,6 @@ static void quiesce_powerdown_req(Notifier *n, void *opaque) static int quiesce_init(SCLPEvent *event) { - event->event_type = SCLP_EVENT_SIGNAL_QUIESCE; - qn.notifier.notify = quiesce_powerdown_req; qn.event = event; diff --git a/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h index 727ef4fdf8..ff0f625860 100644 --- a/include/hw/s390x/event-facility.h +++ b/include/hw/s390x/event-facility.h @@ -68,7 +68,6 @@ typedef struct ReadEventData { typedef struct SCLPEvent { DeviceState qdev; bool event_pending; - uint32_t event_type; char *name; } SCLPEvent; From c3d9f24a392979cbd6a40d102c71eab018117f3e Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 17 Sep 2013 13:07:30 +0200 Subject: [PATCH 15/17] s390/eventfacility: allow childs to handle more than 1 event type Currently all handlers (quiesce, console) only handle one event type. Some drivers will handle multiple (compatible) event types. Rework the code accordingly. Signed-off-by: Christian Borntraeger Reviewed-by: Alexander Graf --- hw/char/sclpconsole.c | 6 +++--- hw/s390x/event-facility.c | 2 +- hw/s390x/sclpquiesce.c | 6 +++--- include/hw/s390x/event-facility.h | 5 ++--- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c index 8cb0e41fa0..16d77c5e27 100644 --- a/hw/char/sclpconsole.c +++ b/hw/char/sclpconsole.c @@ -79,9 +79,9 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) /* functions to be called by event facility */ -static int event_type(void) +static bool can_handle_event(uint8_t type) { - return SCLP_EVENT_ASCII_CONSOLE_DATA; + return type == SCLP_EVENT_ASCII_CONSOLE_DATA; } static unsigned int send_mask(void) @@ -272,7 +272,7 @@ static void console_class_init(ObjectClass *klass, void *data) ec->exit = console_exit; ec->get_send_mask = send_mask; ec->get_receive_mask = receive_mask; - ec->event_type = event_type; + ec->can_handle_event = can_handle_event; ec->read_event_data = read_event_data; ec->write_event_data = write_event_data; } diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index d2fd22776b..25951a020a 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -120,7 +120,7 @@ static uint16_t handle_write_event_buf(SCLPEventFacility *ef, ec = SCLP_EVENT_GET_CLASS(event); if (ec->write_event_data && - ec->event_type() == event_buf->type) { + ec->can_handle_event(event_buf->type)) { rc = ec->write_event_data(event, event_buf); break; } diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index 616267883c..a3c4bd6272 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -22,9 +22,9 @@ typedef struct SignalQuiesce { uint8_t unit; } QEMU_PACKED SignalQuiesce; -static int event_type(void) +static bool can_handle_event(uint8_t type) { - return SCLP_EVENT_SIGNAL_QUIESCE; + return type == SCLP_EVENT_SIGNAL_QUIESCE; } static unsigned int send_mask(void) @@ -121,7 +121,7 @@ static void quiesce_class_init(ObjectClass *klass, void *data) k->get_send_mask = send_mask; k->get_receive_mask = receive_mask; - k->event_type = event_type; + k->can_handle_event = can_handle_event; k->read_event_data = read_event_data; k->write_event_data = NULL; } diff --git a/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h index ff0f625860..c0f5d196f5 100644 --- a/include/hw/s390x/event-facility.h +++ b/include/hw/s390x/event-facility.h @@ -87,9 +87,8 @@ typedef struct SCLPEventClass { int (*write_event_data)(SCLPEvent *event, EventBufferHeader *evt_buf_hdr); - /* returns the supported event type */ - int (*event_type)(void); - + /* can we handle this event type? */ + bool (*can_handle_event)(uint8_t type); } SCLPEventClass; #endif From 40fa5264f68e04fdeb1fe0367955a98925349efd Mon Sep 17 00:00:00 2001 From: Heinz Graalfs Date: Tue, 21 May 2013 17:04:58 +0200 Subject: [PATCH 16/17] s390/ebcdic: Move conversion tables to header file Move conversion tables to header file. - In SCLP line mode processing EBCDIC/ASCII conversion is needed. - An additional EBCDIC to ASCII conversion function is added. Signed-off-by: Heinz Graalfs Reviewed-by: Alexander Graf Signed-off-by: Christian Borntraeger --- include/hw/s390x/ebcdic.h | 104 +++++++++++++++++++++++++++++++++++++ target-s390x/misc_helper.c | 81 +---------------------------- 2 files changed, 105 insertions(+), 80 deletions(-) create mode 100644 include/hw/s390x/ebcdic.h diff --git a/include/hw/s390x/ebcdic.h b/include/hw/s390x/ebcdic.h new file mode 100644 index 0000000000..1d6fde9c12 --- /dev/null +++ b/include/hw/s390x/ebcdic.h @@ -0,0 +1,104 @@ +/* + * EBCDIC/ASCII conversion Support + * + * Copyright (c) 2011 Alexander Graf + * Copyright IBM, Corp. 2013 + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at your + * option) any later version. See the COPYING file in the top-level directory. + * + */ + +#ifndef EBCDIC_H_ +#define EBCDIC_H_ + +/* EBCDIC handling */ +static const uint8_t ebcdic2ascii[] = { + 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, + 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, + 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, + 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, + 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, + 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, + 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21, + 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, + 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E, + 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, + 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, + 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, + 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, + 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, + 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07, + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, + 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07, +}; + +static const uint8_t ascii2ebcdic[] = { + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, + 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, + 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF +}; + +static inline void ebcdic_put(uint8_t *p, const char *ascii, int len) +{ + int i; + + for (i = 0; i < len; i++) { + p[i] = ascii2ebcdic[(uint8_t)ascii[i]]; + } +} + +static inline void ascii_put(uint8_t *p, const char *ebcdic, int len) +{ + int i; + + for (i = 0; i < len; i++) { + p[i] = ebcdic2ascii[(uint8_t)ebcdic[i]]; + } +} + +#endif /* EBCDIC_H_ */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 37ea60d20b..10d04252d5 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -33,6 +33,7 @@ #include "exec/softmmu_exec.h" #include "sysemu/cpus.h" #include "sysemu/sysemu.h" +#include "hw/s390x/ebcdic.h" #endif /* #define DEBUG_HELPER */ @@ -72,86 +73,6 @@ void HELPER(exception)(CPUS390XState *env, uint32_t excp) #ifndef CONFIG_USER_ONLY -/* EBCDIC handling */ -static const uint8_t ebcdic2ascii[] = { - 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, - 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, - 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, - 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, - 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, - 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, - 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21, - 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, - 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E, - 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, - 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, - 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, - 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, - 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, - 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, - 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, - 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, - 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07, - 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, - 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, - 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, - 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07, -}; - -static const uint8_t ascii2ebcdic[] = { - 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, - 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, - 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, - 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, - 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, - 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, - 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, - 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, - 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF -}; - -static inline void ebcdic_put(uint8_t *p, const char *ascii, int len) -{ - int i; - - for (i = 0; i < len; i++) { - p[i] = ascii2ebcdic[(uint8_t)ascii[i]]; - } -} - void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) { qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", From 6a444f8507514b3707c8807ed11c176d3fbc5860 Mon Sep 17 00:00:00 2001 From: Heinz Graalfs Date: Wed, 22 May 2013 14:11:36 +0200 Subject: [PATCH 17/17] s390/sclplmconsole: Add support for SCLP line-mode console Add simple support for SCLP line-mode also known as operating system messages. This can be added in addition to or instead of the SCLP full screen console with -device sclplmconsole. Signed-off-by: Heinz Graalfs Reviewed-by: Alexander Graf Signed-off-by: Christian Borntraeger --- hw/char/Makefile.objs | 2 +- hw/char/sclpconsole-lm.c | 398 ++++++++++++++++++++++++++++++ include/hw/s390x/event-facility.h | 80 ++++++ 3 files changed, 479 insertions(+), 1 deletion(-) create mode 100644 hw/char/sclpconsole-lm.c diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs index f8f3dbca3e..cbd6a006f4 100644 --- a/hw/char/Makefile.objs +++ b/hw/char/Makefile.objs @@ -22,6 +22,6 @@ common-obj-$(CONFIG_IMX) += imx_serial.o common-obj-$(CONFIG_LM32) += lm32_juart.o common-obj-$(CONFIG_LM32) += lm32_uart.o common-obj-$(CONFIG_MILKYMIST) += milkymist-uart.o -common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o +common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o sclpconsole-lm.o obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c new file mode 100644 index 0000000000..93390675d6 --- /dev/null +++ b/hw/char/sclpconsole-lm.c @@ -0,0 +1,398 @@ +/* + * SCLP event types + * Operations Command - Line Mode input + * Message - Line Mode output + * + * Copyright IBM, Corp. 2013 + * + * Authors: + * Heinz Graalfs + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at your + * option) any later version. See the COPYING file in the top-level directory. + * + */ + +#include "hw/qdev.h" +#include "qemu/thread.h" +#include "qemu/error-report.h" +#include "sysemu/char.h" + +#include "hw/s390x/sclp.h" +#include "hw/s390x/event-facility.h" +#include "hw/s390x/ebcdic.h" + +#define SIZE_BUFFER 4096 +#define NEWLINE "\n" + +typedef struct OprtnsCommand { + EventBufferHeader header; + MDMSU message_unit; + char data[0]; +} QEMU_PACKED OprtnsCommand; + +/* max size for line-mode data in 4K SCCB page */ +#define SIZE_CONSOLE_BUFFER (SCCB_DATA_LEN - sizeof(OprtnsCommand)) + +typedef struct SCLPConsoleLM { + SCLPEvent event; + CharDriverState *chr; + bool echo; /* immediate echo of input if true */ + uint32_t write_errors; /* errors writing to char layer */ + uint32_t length; /* length of byte stream in buffer */ + uint8_t buf[SIZE_CONSOLE_BUFFER]; + qemu_irq irq_console_read; +} SCLPConsoleLM; + +/* +* Character layer call-back functions + * + * Allow 1 character at a time + * + * Accumulate bytes from character layer in console buffer, + * event_pending is set when a newline character is encountered + * + * The maximum command line length is limited by the maximum + * space available in an SCCB + */ + +static int chr_can_read(void *opaque) +{ + SCLPConsoleLM *scon = opaque; + + if (scon->event.event_pending) { + return 0; + } else if (SIZE_CONSOLE_BUFFER - scon->length) { + return 1; + } + return 0; +} + +static void receive_from_chr_layer(SCLPConsoleLM *scon, const uint8_t *buf, + int size) +{ + assert(size == 1); + + if (*buf == '\r' || *buf == '\n') { + scon->event.event_pending = true; + return; + } + scon->buf[scon->length] = *buf; + scon->length += 1; + if (scon->echo) { + qemu_chr_fe_write(scon->chr, buf, size); + } +} + +/* + * Send data from a char device over to the guest + */ +static void chr_read(void *opaque, const uint8_t *buf, int size) +{ + SCLPConsoleLM *scon = opaque; + + receive_from_chr_layer(scon, buf, size); + if (scon->event.event_pending) { + /* trigger SCLP read operation */ + qemu_irq_raise(scon->irq_console_read); + } +} + +/* functions to be called by event facility */ + +static bool can_handle_event(uint8_t type) +{ + return type == SCLP_EVENT_MESSAGE || type == SCLP_EVENT_PMSGCMD; +} + +static unsigned int send_mask(void) +{ + return SCLP_EVENT_MASK_OP_CMD | SCLP_EVENT_MASK_PMSGCMD; +} + +static unsigned int receive_mask(void) +{ + return SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_PMSGCMD; +} + +/* + * Triggered by SCLP's read_event_data + * - convert ASCII byte stream to EBCDIC and + * - copy converted data into provided (SCLP) buffer + */ +static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size, + int avail) +{ + int len; + + SCLPConsoleLM *cons = DO_UPCAST(SCLPConsoleLM, event, event); + + len = cons->length; + /* data need to fit into provided SCLP buffer */ + if (len > avail) { + return 1; + } + + ebcdic_put(buf, (char *)&cons->buf, len); + *size = len; + cons->length = 0; + /* data provided and no more data pending */ + event->event_pending = false; + return 0; +} + +static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, + int *slen) +{ + int avail, rc; + size_t src_len; + uint8_t *to; + OprtnsCommand *oc = (OprtnsCommand *) evt_buf_hdr; + + if (!event->event_pending) { + /* no data pending */ + return 0; + } + + to = (uint8_t *)&oc->data; + avail = *slen - sizeof(OprtnsCommand); + rc = get_console_data(event, to, &src_len, avail); + if (rc) { + /* data didn't fit, try next SCCB */ + return 1; + } + + oc->message_unit.mdmsu.gds_id = GDS_ID_MDSMU; + oc->message_unit.mdmsu.length = cpu_to_be16(sizeof(struct MDMSU)); + + oc->message_unit.cpmsu.gds_id = GDS_ID_CPMSU; + oc->message_unit.cpmsu.length = + cpu_to_be16(sizeof(struct MDMSU) - sizeof(GdsVector)); + + oc->message_unit.text_command.gds_id = GDS_ID_TEXTCMD; + oc->message_unit.text_command.length = + cpu_to_be16(sizeof(struct MDMSU) - (2 * sizeof(GdsVector))); + + oc->message_unit.self_def_text_message.key = GDS_KEY_SELFDEFTEXTMSG; + oc->message_unit.self_def_text_message.length = + cpu_to_be16(sizeof(struct MDMSU) - (3 * sizeof(GdsVector))); + + oc->message_unit.text_message.key = GDS_KEY_TEXTMSG; + oc->message_unit.text_message.length = + cpu_to_be16(sizeof(GdsSubvector) + src_len); + + oc->header.length = cpu_to_be16(sizeof(OprtnsCommand) + src_len); + oc->header.type = SCLP_EVENT_OPRTNS_COMMAND; + *slen = avail - src_len; + + return 1; +} + +/* + * Triggered by SCLP's write_event_data + * - write console data to character layer + * returns < 0 if an error occurred + */ +static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len) +{ + int ret = 0; + const uint8_t *buf_offset; + + SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); + + if (!scon->chr) { + /* If there's no backend, we can just say we consumed all data. */ + return len; + } + + buf_offset = buf; + while (len > 0) { + ret = qemu_chr_fe_write(scon->chr, buf, len); + if (ret == 0) { + /* a pty doesn't seem to be connected - no error */ + len = 0; + } else if (ret == -EAGAIN || (ret > 0 && ret < len)) { + len -= ret; + buf_offset += ret; + } else { + len = 0; + } + } + + return ret; +} + +static int process_mdb(SCLPEvent *event, MDBO *mdbo) +{ + int rc; + int len; + uint8_t buffer[SIZE_BUFFER]; + + len = be16_to_cpu(mdbo->length); + len -= sizeof(mdbo->length) + sizeof(mdbo->type) + + sizeof(mdbo->mto.line_type_flags) + + sizeof(mdbo->mto.alarm_control) + + sizeof(mdbo->mto._reserved); + + assert(len <= SIZE_BUFFER); + + /* convert EBCDIC SCLP contents to ASCII console message */ + ascii_put(buffer, mdbo->mto.message, len); + rc = write_console_data(event, (uint8_t *)NEWLINE, 1); + if (rc < 0) { + return rc; + } + return write_console_data(event, buffer, len); +} + +static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh) +{ + int len; + int written; + int errors = 0; + MDBO *mdbo; + SclpMsg *data = (SclpMsg *) ebh; + SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); + + len = be16_to_cpu(data->mdb.header.length); + if (len < sizeof(data->mdb.header)) { + return SCLP_RC_INCONSISTENT_LENGTHS; + } + len -= sizeof(data->mdb.header); + + /* first check message buffers */ + mdbo = data->mdb.mdbo; + while (len > 0) { + if (be16_to_cpu(mdbo->length) > len + || be16_to_cpu(mdbo->length) == 0) { + return SCLP_RC_INCONSISTENT_LENGTHS; + } + len -= be16_to_cpu(mdbo->length); + mdbo = (void *) mdbo + be16_to_cpu(mdbo->length); + } + + /* then execute */ + len = be16_to_cpu(data->mdb.header.length) - sizeof(data->mdb.header); + mdbo = data->mdb.mdbo; + while (len > 0) { + switch (be16_to_cpu(mdbo->type)) { + case MESSAGE_TEXT: + /* message text object */ + written = process_mdb(event, mdbo); + if (written < 0) { + /* character layer error */ + errors++; + } + break; + default: /* ignore */ + break; + } + len -= be16_to_cpu(mdbo->length); + mdbo = (void *) mdbo + be16_to_cpu(mdbo->length); + } + if (errors) { + scon->write_errors += errors; + } + data->header.flags = SCLP_EVENT_BUFFER_ACCEPTED; + + return SCLP_RC_NORMAL_COMPLETION; +} + +static void trigger_console_data(void *opaque, int n, int level) +{ + sclp_service_interrupt(0); +} + +/* functions for live migration */ + +static const VMStateDescription vmstate_sclplmconsole = { + .name = "sclplmconsole", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_BOOL(event.event_pending, SCLPConsoleLM), + VMSTATE_UINT32(write_errors, SCLPConsoleLM), + VMSTATE_UINT32(length, SCLPConsoleLM), + VMSTATE_UINT8_ARRAY(buf, SCLPConsoleLM, SIZE_CONSOLE_BUFFER), + VMSTATE_END_OF_LIST() + } +}; + +/* qemu object creation and initialization functions */ + +/* tell character layer our call-back functions */ + +static int console_init(SCLPEvent *event) +{ + static bool console_available; + + SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); + + if (console_available) { + error_report("Multiple line-mode operator consoles are not supported"); + return -1; + } + console_available = true; + + if (scon->chr) { + qemu_chr_add_handlers(scon->chr, chr_can_read, chr_read, NULL, scon); + } + scon->irq_console_read = *qemu_allocate_irqs(trigger_console_data, NULL, 1); + + return 0; +} + +static int console_exit(SCLPEvent *event) +{ + return 0; +} + +static void console_reset(DeviceState *dev) +{ + SCLPEvent *event = SCLP_EVENT(dev); + SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); + + event->event_pending = false; + scon->length = 0; + scon->write_errors = 0; +} + +static Property console_properties[] = { + DEFINE_PROP_CHR("chardev", SCLPConsoleLM, chr), + DEFINE_PROP_UINT32("write_errors", SCLPConsoleLM, write_errors, 0), + DEFINE_PROP_BOOL("echo", SCLPConsoleLM, echo, true), + DEFINE_PROP_END_OF_LIST(), +}; + +static void console_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SCLPEventClass *ec = SCLP_EVENT_CLASS(klass); + + dc->props = console_properties; + dc->reset = console_reset; + dc->vmsd = &vmstate_sclplmconsole; + ec->init = console_init; + ec->exit = console_exit; + ec->get_send_mask = send_mask; + ec->get_receive_mask = receive_mask; + ec->can_handle_event = can_handle_event; + ec->read_event_data = read_event_data; + ec->write_event_data = write_event_data; +} + +static const TypeInfo sclp_console_info = { + .name = "sclplmconsole", + .parent = TYPE_SCLP_EVENT, + .instance_size = sizeof(SCLPConsoleLM), + .class_init = console_class_init, + .class_size = sizeof(SCLPEventClass), +}; + +static void register_types(void) +{ + type_register_static(&sclp_console_info); +} + +type_init(register_types) diff --git a/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h index c0f5d196f5..7ce7079f9f 100644 --- a/include/hw/s390x/event-facility.h +++ b/include/hw/s390x/event-facility.h @@ -19,12 +19,18 @@ #include "qemu/thread.h" /* SCLP event types */ +#define SCLP_EVENT_OPRTNS_COMMAND 0x01 +#define SCLP_EVENT_MESSAGE 0x02 +#define SCLP_EVENT_PMSGCMD 0x09 #define SCLP_EVENT_ASCII_CONSOLE_DATA 0x1a #define SCLP_EVENT_SIGNAL_QUIESCE 0x1d /* SCLP event masks */ #define SCLP_EVENT_MASK_SIGNAL_QUIESCE 0x00000008 #define SCLP_EVENT_MASK_MSG_ASCII 0x00000040 +#define SCLP_EVENT_MASK_OP_CMD 0x80000000 +#define SCLP_EVENT_MASK_MSG 0x40000000 +#define SCLP_EVENT_MASK_PMSGCMD 0x00800000 #define SCLP_UNCONDITIONAL_READ 0x00 #define SCLP_SELECTIVE_READ 0x01 @@ -54,6 +60,80 @@ typedef struct EventBufferHeader { uint16_t _reserved; } QEMU_PACKED EventBufferHeader; +typedef struct MdbHeader { + uint16_t length; + uint16_t type; + uint32_t tag; + uint32_t revision_code; +} QEMU_PACKED MdbHeader; + +typedef struct MTO { + uint16_t line_type_flags; + uint8_t alarm_control; + uint8_t _reserved[3]; + char message[]; +} QEMU_PACKED MTO; + +typedef struct GO { + uint32_t domid; + uint8_t hhmmss_time[8]; + uint8_t th_time[3]; + uint8_t _reserved_0; + uint8_t dddyyyy_date[7]; + uint8_t _reserved_1; + uint16_t general_msg_flags; + uint8_t _reserved_2[10]; + uint8_t originating_system_name[8]; + uint8_t job_guest_name[8]; +} QEMU_PACKED GO; + +#define MESSAGE_TEXT 0x0004 + +typedef struct MDBO { + uint16_t length; + uint16_t type; + union { + GO go; + MTO mto; + }; +} QEMU_PACKED MDBO; + +typedef struct MDB { + MdbHeader header; + MDBO mdbo[0]; +} QEMU_PACKED MDB; + +typedef struct SclpMsg { + EventBufferHeader header; + MDB mdb; +} QEMU_PACKED SclpMsg; + +#define GDS_ID_MDSMU 0x1310 +#define GDS_ID_CPMSU 0x1212 +#define GDS_ID_TEXTCMD 0x1320 + +typedef struct GdsVector { + uint16_t length; + uint16_t gds_id; +} QEMU_PACKED GdsVector; + +#define GDS_KEY_SELFDEFTEXTMSG 0x31 +#define GDS_KEY_TEXTMSG 0x30 + +typedef struct GdsSubvector { + uint8_t length; + uint8_t key; +} QEMU_PACKED GdsSubvector; + +/* MDS Message Unit */ +typedef struct MDMSU { + GdsVector mdmsu; + GdsVector cpmsu; + GdsVector text_command; + GdsSubvector self_def_text_message; + GdsSubvector text_message; +} QEMU_PACKED MDMSU; + typedef struct WriteEventData { SCCBHeader h; EventBufferHeader ebh;