diff options
Diffstat (limited to 'hw/s390x')
-rw-r--r-- | hw/s390x/s390-pci-bus.c | 22 | ||||
-rw-r--r-- | hw/s390x/sclp.c | 18 |
2 files changed, 31 insertions, 9 deletions
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index f87d274..5282089 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -652,7 +652,16 @@ static const PCIIOMMUOps s390_iommu_ops = { .get_address_space = s390_pci_dma_iommu, }; -static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set) +/** + * set_ind_bit_atomic - Atomically set a bit in an indicator + * + * @ind_loc: Address of the indicator + * @to_be_set: Bit to set + * + * Returns true if the bit was set by this function, false if it was + * already set or mapping failed. + */ +static bool set_ind_bit_atomic(uint64_t ind_loc, uint8_t to_be_set) { uint8_t expected, actual; hwaddr len = 1; @@ -662,7 +671,7 @@ static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set) ind_addr = cpu_physical_memory_map(ind_loc, &len, true); if (!ind_addr) { s390_pci_generate_error_event(ERR_EVENT_AIRERR, 0, 0, 0, 0); - return -1; + return false; } actual = *ind_addr; do { @@ -671,7 +680,7 @@ static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set) } while (actual != expected); cpu_physical_memory_unmap((void *)ind_addr, len, 1, len); - return actual; + return (actual & to_be_set) ? false : true; } static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data, @@ -693,10 +702,10 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data, ind_bit = pbdev->routes.adapter.ind_offset; sum_bit = pbdev->routes.adapter.summary_offset; - set_ind_atomic(pbdev->routes.adapter.ind_addr + (ind_bit + vec) / 8, + set_ind_bit_atomic(pbdev->routes.adapter.ind_addr + (ind_bit + vec) / 8, 0x80 >> ((ind_bit + vec) % 8)); - if (!set_ind_atomic(pbdev->routes.adapter.summary_addr + sum_bit / 8, - 0x80 >> (sum_bit % 8))) { + if (set_ind_bit_atomic(pbdev->routes.adapter.summary_addr + sum_bit / 8, + 0x80 >> (sum_bit % 8))) { css_adapter_interrupt(CSS_IO_ADAPTER_PCI, pbdev->isc); } } @@ -891,6 +900,7 @@ static void s390_pcihost_realize(DeviceState *dev, Error **errp) s390_pci_init_default_group(); css_register_io_adapters(CSS_IO_ADAPTER_PCI, true, false, S390_ADAPTER_SUPPRESSIBLE, errp); + s390_pcihost_kvm_realize(); } static void s390_pcihost_unrealize(DeviceState *dev) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 51e88ba..8602a56 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -306,6 +306,7 @@ int sclp_service_call(S390CPU *cpu, uint64_t sccb, uint32_t code) g_autofree SCCB *work_sccb = NULL; AddressSpace *as = CPU(cpu)->as; const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + MemTxResult ret; /* first some basic checks on program checks */ if (env->psw.mask & PSW_MASK_PSTATE) { @@ -320,7 +321,10 @@ int sclp_service_call(S390CPU *cpu, uint64_t sccb, uint32_t code) } /* the header contains the actual length of the sccb */ - address_space_read(as, sccb, attrs, &header, sizeof(SCCBHeader)); + ret = address_space_read(as, sccb, attrs, &header, sizeof(SCCBHeader)); + if (ret != MEMTX_OK) { + return -PGM_ADDRESSING; + } /* Valid sccb sizes */ if (be16_to_cpu(header.length) < sizeof(SCCBHeader)) { @@ -333,7 +337,11 @@ int sclp_service_call(S390CPU *cpu, uint64_t sccb, uint32_t code) * the host has checked the values */ work_sccb = g_malloc0(be16_to_cpu(header.length)); - address_space_read(as, sccb, attrs, work_sccb, be16_to_cpu(header.length)); + ret = address_space_read(as, sccb, attrs, + work_sccb, be16_to_cpu(header.length)); + if (ret != MEMTX_OK) { + return -PGM_ADDRESSING; + } if (!sclp_command_code_valid(code)) { work_sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); @@ -347,7 +355,11 @@ int sclp_service_call(S390CPU *cpu, uint64_t sccb, uint32_t code) sclp_c->execute(sclp, work_sccb, code); out_write: - address_space_write(as, sccb, attrs, work_sccb, be16_to_cpu(header.length)); + ret = address_space_write(as, sccb, attrs, + work_sccb, be16_to_cpu(header.length)); + if (ret != MEMTX_OK) { + return -PGM_PROTECTION; + } sclp_c->service_interrupt(sclp, sccb); |