diff options
Diffstat (limited to 'target-s390x/ioinst.c')
-rw-r--r-- | target-s390x/ioinst.c | 36 |
1 files changed, 22 insertions, 14 deletions
diff --git a/target-s390x/ioinst.c b/target-s390x/ioinst.c index 0ef7a93a9f..23c2fafb65 100644 --- a/target-s390x/ioinst.c +++ b/target-s390x/ioinst.c @@ -284,8 +284,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) SubchDev *sch; uint64_t addr; int cc; - SCHIB *schib; - hwaddr len = sizeof(*schib); + SCHIB schib; CPUS390XState *env = &cpu->env; addr = decode_basedisp_s(env, ipb); @@ -293,21 +292,23 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) program_interrupt(env, PGM_SPECIFICATION, 2); return; } - schib = s390_cpu_physical_memory_map(env, addr, &len, 1); - if (!schib || len != sizeof(*schib)) { - program_interrupt(env, PGM_ADDRESSING, 2); - goto out; - } if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { - program_interrupt(env, PGM_OPERAND, 2); - goto out; + /* + * As operand exceptions have a lower priority than access exceptions, + * we check whether the memory area is writeable (injecting the + * access execption if it is not) first. + */ + if (!s390_cpu_virt_mem_check_write(cpu, addr, sizeof(schib))) { + program_interrupt(env, PGM_OPERAND, 2); + } + return; } trace_ioinst_sch_id("stsch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); if (sch) { if (css_subch_visible(sch)) { - css_do_stsch(sch, schib); + css_do_stsch(sch, &schib); cc = 0; } else { /* Indicate no more subchannels in this css/ss */ @@ -318,14 +319,21 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) cc = 3; /* No more subchannels in this css/ss */ } else { /* Store an empty schib. */ - memset(schib, 0, sizeof(*schib)); + memset(&schib, 0, sizeof(schib)); cc = 0; } } + if (cc != 3) { + if (s390_cpu_virt_mem_write(cpu, addr, &schib, sizeof(schib)) != 0) { + return; + } + } else { + /* Access exceptions have a higher priority than cc3 */ + if (s390_cpu_virt_mem_check_write(cpu, addr, sizeof(schib)) != 0) { + return; + } + } setcc(cpu, cc); - -out: - s390_cpu_physical_memory_unmap(env, schib, len, 1); } int ioinst_handle_tsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) |