From b7b6348ab433519f16c1500e3ea04805428be91e Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 12 Feb 2015 18:09:37 +0100 Subject: [PATCH] s390x/ioinst: Rework memory access in TSCH instruction Change the TSCH handler to use the new logical memory access functions. Since the channel should not be updated in case of a protection or access exception while writing to the guest memory, the css_do_tsch() has to be split up into two parts, one for retrieving the IRB and one for the update. Signed-off-by: Thomas Huth Signed-off-by: Jens Freimann Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- hw/s390x/css.c | 38 +++++++++++++++++++++++--------------- target-s390x/cpu.h | 3 ++- target-s390x/ioinst.c | 33 +++++++++++++++++++-------------- 3 files changed, 44 insertions(+), 30 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 65e6b712a1..f6d0c0a80e 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -801,7 +801,8 @@ out: return ret; } -static void copy_irb_to_guest(IRB *dest, const IRB *src, PMCW *pmcw) +static void copy_irb_to_guest(IRB *dest, const IRB *src, PMCW *pmcw, + int *irb_len) { int i; uint16_t stctl = src->scsw.ctrl & SCSW_CTRL_MASK_STCTL; @@ -815,6 +816,8 @@ static void copy_irb_to_guest(IRB *dest, const IRB *src, PMCW *pmcw) for (i = 0; i < ARRAY_SIZE(dest->ecw); i++) { dest->ecw[i] = cpu_to_be32(src->ecw[i]); } + *irb_len = sizeof(*dest) - sizeof(dest->emw); + /* extended measurements enabled? */ if ((src->scsw.flags & SCSW_FLAGS_MASK_ESWF) || !(pmcw->flags & PMCW_FLAGS_MASK_TF) || @@ -832,26 +835,21 @@ static void copy_irb_to_guest(IRB *dest, const IRB *src, PMCW *pmcw) dest->emw[i] = cpu_to_be32(src->emw[i]); } } + *irb_len = sizeof(*dest); } -int css_do_tsch(SubchDev *sch, IRB *target_irb) +int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len) { SCSW *s = &sch->curr_status.scsw; PMCW *p = &sch->curr_status.pmcw; uint16_t stctl; - uint16_t fctl; - uint16_t actl; IRB irb; - int ret; if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { - ret = 3; - goto out; + return 3; } stctl = s->ctrl & SCSW_CTRL_MASK_STCTL; - fctl = s->ctrl & SCSW_CTRL_MASK_FCTL; - actl = s->ctrl & SCSW_CTRL_MASK_ACTL; /* Prepare the irb for the guest. */ memset(&irb, 0, sizeof(IRB)); @@ -876,7 +874,22 @@ int css_do_tsch(SubchDev *sch, IRB *target_irb) } } /* Store the irb to the guest. */ - copy_irb_to_guest(target_irb, &irb, p); + copy_irb_to_guest(target_irb, &irb, p, irb_len); + + return ((stctl & SCSW_STCTL_STATUS_PEND) == 0); +} + +void css_do_tsch_update_subch(SubchDev *sch) +{ + SCSW *s = &sch->curr_status.scsw; + PMCW *p = &sch->curr_status.pmcw; + uint16_t stctl; + uint16_t fctl; + uint16_t actl; + + stctl = s->ctrl & SCSW_CTRL_MASK_STCTL; + fctl = s->ctrl & SCSW_CTRL_MASK_FCTL; + actl = s->ctrl & SCSW_CTRL_MASK_ACTL; /* Clear conditions on subchannel, if applicable. */ if (stctl & SCSW_STCTL_STATUS_PEND) { @@ -913,11 +926,6 @@ int css_do_tsch(SubchDev *sch, IRB *target_irb) memset(sch->sense_data, 0 , sizeof(sch->sense_data)); } } - - ret = ((stctl & SCSW_STCTL_STATUS_PEND) == 0); - -out: - return ret; } static void copy_crw_to_guest(CRW *dest, const CRW *src) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 7180d68429..7c07ca6304 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -455,7 +455,8 @@ int css_do_xsch(SubchDev *sch); int css_do_csch(SubchDev *sch); int css_do_hsch(SubchDev *sch); int css_do_ssch(SubchDev *sch, ORB *orb); -int css_do_tsch(SubchDev *sch, IRB *irb); +int css_do_tsch_get_irb(SubchDev *sch, IRB *irb, int *irb_len); +void css_do_tsch_update_subch(SubchDev *sch); int css_do_stcrw(CRW *crw); int css_do_tpi(IOIntCode *int_code, int lowcore); int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid, diff --git a/target-s390x/ioinst.c b/target-s390x/ioinst.c index 8052886276..aa55ca8870 100644 --- a/target-s390x/ioinst.c +++ b/target-s390x/ioinst.c @@ -341,10 +341,9 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) CPUS390XState *env = &cpu->env; int cssid, ssid, schid, m; SubchDev *sch; - IRB *irb; + IRB irb; uint64_t addr; - int cc; - hwaddr len = sizeof(*irb); + int cc, irb_len; if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { program_interrupt(env, PGM_OPERAND, 2); @@ -356,23 +355,29 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) program_interrupt(env, PGM_SPECIFICATION, 2); return -EIO; } - irb = s390_cpu_physical_memory_map(env, addr, &len, 1); - if (!irb || len != sizeof(*irb)) { - program_interrupt(env, PGM_ADDRESSING, 2); - cc = -EIO; - goto out; - } + sch = css_find_subch(m, cssid, ssid, schid); if (sch && css_subch_visible(sch)) { - cc = css_do_tsch(sch, irb); - /* 0 - status pending, 1 - not status pending */ + cc = css_do_tsch_get_irb(sch, &irb, &irb_len); } else { cc = 3; } + /* 0 - status pending, 1 - not status pending, 3 - not operational */ + if (cc != 3) { + if (s390_cpu_virt_mem_write(cpu, addr, &irb, irb_len) != 0) { + return -EFAULT; + } + css_do_tsch_update_subch(sch); + } else { + irb_len = sizeof(irb) - sizeof(irb.emw); + /* Access exceptions have a higher priority than cc3 */ + if (s390_cpu_virt_mem_check_write(cpu, addr, irb_len) != 0) { + return -EFAULT; + } + } + setcc(cpu, cc); -out: - s390_cpu_physical_memory_unmap(env, irb, sizeof(*irb), 1); - return cc; + return 0; } typedef struct ChscReq {