From 67ee0cefb09672247f502c0f208f2a0e3c566173 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 24 Nov 2017 16:26:51 +0100 Subject: s390x: introduce 2.12 compat machine Acked-by: Christian Borntraeger Reviewed-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'hw/s390x') diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 6a57f94197..a23b8aec9f 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -639,6 +639,9 @@ bool css_migration_enabled(void) } \ type_init(ccw_machine_register_##suffix) +#define CCW_COMPAT_2_11 \ + HW_COMPAT_2_11 + #define CCW_COMPAT_2_10 \ HW_COMPAT_2_10 @@ -716,14 +719,26 @@ bool css_migration_enabled(void) .value = "0",\ }, +static void ccw_machine_2_12_instance_options(MachineState *machine) +{ +} + +static void ccw_machine_2_12_class_options(MachineClass *mc) +{ +} +DEFINE_CCW_MACHINE(2_12, "2.12", true); + static void ccw_machine_2_11_instance_options(MachineState *machine) { + ccw_machine_2_12_instance_options(machine); } static void ccw_machine_2_11_class_options(MachineClass *mc) { + ccw_machine_2_12_class_options(mc); + SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_11); } -DEFINE_CCW_MACHINE(2_11, "2.11", true); +DEFINE_CCW_MACHINE(2_11, "2.11", false); static void ccw_machine_2_10_instance_options(MachineState *machine) { -- cgit v1.2.3 From fc21eb6bd9f340e8d2083064e86cf09868e69872 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:31 +0100 Subject: s390x/tcg: rip out dead tpi code It is broken and not even wired up. We'll add a new handler soon, but that will live somewhere else. Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-4-david@redhat.com> Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'hw/s390x') diff --git a/hw/s390x/css.c b/hw/s390x/css.c index f6b5c807cd..6bd0fedc78 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -1723,12 +1723,6 @@ void css_undo_stcrw(CRW *crw) QTAILQ_INSERT_HEAD(&channel_subsys.pending_crws, crw_cont, sibling); } -int css_do_tpi(IOIntCode *int_code, int lowcore) -{ - /* No pending interrupts for !KVM. */ - return 0; - } - int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid, int rfmt, void *buf) { -- cgit v1.2.3 From 468a93898a97639d8ba412d6a3cf9252f1927276 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:33 +0100 Subject: s390x/pci: pass the retaddr to all PCI instructions Once we wire up TCG, we will need the retaddr to correctly inject program interrupts. As we want to get rid of the function program_interrupt(), convert PCI code too. For KVM, we can simply use RA_IGNORED. Convert program_interrupt() to s390_program_interrupt() directly, making use of the passed address. Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-6-david@redhat.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 83 +++++++++++++++++++++++++----------------------- hw/s390x/s390-pci-inst.h | 16 ++++++---- 2 files changed, 52 insertions(+), 47 deletions(-) (limited to 'hw/s390x') diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 8e088f3dc9..8123705dfd 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -142,7 +142,7 @@ out: return rc; } -int clp_service_call(S390CPU *cpu, uint8_t r2) +int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) { ClpReqHdr *reqh; ClpRspHdr *resh; @@ -158,7 +158,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2) cpu_synchronize_state(CPU(cpu)); if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 4); + s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra); return 0; } @@ -168,7 +168,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2) reqh = (ClpReqHdr *)buffer; req_len = lduw_p(&reqh->len); if (req_len < 16 || req_len > 8184 || (req_len % 8 != 0)) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } @@ -179,11 +179,11 @@ int clp_service_call(S390CPU *cpu, uint8_t r2) resh = (ClpRspHdr *)(buffer + req_len); res_len = lduw_p(&resh->len); if (res_len < 8 || res_len > 8176 || (res_len % 8 != 0)) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } if ((req_len + res_len) > 8192) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } @@ -314,7 +314,7 @@ out: return 0; } -int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) +int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) { CPUS390XState *env = &cpu->env; S390PCIBusDevice *pbdev; @@ -329,12 +329,12 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) cpu_synchronize_state(CPU(cpu)); if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 4); + s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra); return 0; } if (r2 & 0x1) { - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return 0; } @@ -367,19 +367,19 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) if (pcias < 6) { if ((8 - (offset & 0x7)) < len) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } mr = pbdev->pdev->io_regions[pcias].memory; result = memory_region_dispatch_read(mr, offset, &data, len, MEMTXATTRS_UNSPECIFIED); if (result != MEMTX_OK) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } } else if (pcias == 15) { if ((4 - (offset & 0x3)) < len) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } data = pci_host_config_read_common( @@ -398,7 +398,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) data = bswap64(data); break; default: - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } } else { @@ -425,7 +425,7 @@ static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias) } } -int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) +int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) { CPUS390XState *env = &cpu->env; uint64_t offset, data; @@ -439,12 +439,12 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) cpu_synchronize_state(CPU(cpu)); if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 4); + s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra); return 0; } if (r2 & 0x1) { - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return 0; } @@ -478,7 +478,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) data = env->regs[r1]; if (pcias < 6) { if ((8 - (offset & 0x7)) < len) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } @@ -492,12 +492,12 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) result = memory_region_dispatch_write(mr, offset, data, len, MEMTXATTRS_UNSPECIFIED); if (result != MEMTX_OK) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } } else if (pcias == 15) { if ((4 - (offset & 0x3)) < len) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } switch (len) { @@ -513,7 +513,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) data = bswap64(data); break; default: - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } @@ -531,7 +531,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) return 0; } -int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) +int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) { CPUS390XState *env = &cpu->env; uint32_t fh; @@ -545,12 +545,12 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) cpu_synchronize_state(CPU(cpu)); if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 4); + s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra); goto out; } if (r2 & 0x1) { - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); goto out; } @@ -624,7 +624,7 @@ out: } int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, - uint8_t ar) + uint8_t ar, uintptr_t ra) { CPUS390XState *env = &cpu->env; S390PCIBusDevice *pbdev; @@ -637,7 +637,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, uint8_t buffer[128]; if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 6); + s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra); return 0; } @@ -659,7 +659,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, case 128: break; default: - program_interrupt(env, PGM_SPECIFICATION, 6); + s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); return 0; } @@ -687,7 +687,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, mr = pbdev->pdev->io_regions[pcias].memory; if (!memory_region_access_valid(mr, env->regs[r3], len, true)) { - program_interrupt(env, PGM_OPERAND, 6); + s390_program_interrupt(env, PGM_OPERAND, 6, ra); return 0; } @@ -700,7 +700,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, ldq_p(buffer + i * 8), 8, MEMTXATTRS_UNSPECIFIED); if (result != MEMTX_OK) { - program_interrupt(env, PGM_OPERAND, 6); + s390_program_interrupt(env, PGM_OPERAND, 6, ra); return 0; } } @@ -767,7 +767,8 @@ int pci_dereg_irqs(S390PCIBusDevice *pbdev) return 0; } -static int reg_ioat(CPUS390XState *env, S390PCIIOMMU *iommu, ZpciFib fib) +static int reg_ioat(CPUS390XState *env, S390PCIIOMMU *iommu, ZpciFib fib, + uintptr_t ra) { uint64_t pba = ldq_p(&fib.pba); uint64_t pal = ldq_p(&fib.pal); @@ -776,14 +777,14 @@ static int reg_ioat(CPUS390XState *env, S390PCIIOMMU *iommu, ZpciFib fib) uint8_t t = (g_iota >> 11) & 0x1; if (pba > pal || pba < ZPCI_SDMA_ADDR || pal > ZPCI_EDMA_ADDR) { - program_interrupt(env, PGM_OPERAND, 6); + s390_program_interrupt(env, PGM_OPERAND, 6, ra); return -EINVAL; } /* currently we only support designation type 1 with translation */ if (!(dt == ZPCI_IOTA_RTTO && t)) { error_report("unsupported ioat dt %d t %d", dt, t); - program_interrupt(env, PGM_OPERAND, 6); + s390_program_interrupt(env, PGM_OPERAND, 6, ra); return -EINVAL; } @@ -804,7 +805,8 @@ void pci_dereg_ioat(S390PCIIOMMU *iommu) iommu->g_iota = 0; } -int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) +int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, + uintptr_t ra) { CPUS390XState *env = &cpu->env; uint8_t oc, dmaas; @@ -814,7 +816,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) uint64_t cc = ZPCI_PCI_LS_OK; if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 6); + s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra); return 0; } @@ -823,7 +825,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) fh = env->regs[r1] >> 32; if (fiba & 0x7) { - program_interrupt(env, PGM_SPECIFICATION, 6); + s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); return 0; } @@ -850,7 +852,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) } if (fib.fmt != 0) { - program_interrupt(env, PGM_OPERAND, 6); + s390_program_interrupt(env, PGM_OPERAND, 6, ra); return 0; } @@ -879,7 +881,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) } else if (pbdev->iommu->enabled) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); - } else if (reg_ioat(env, pbdev->iommu, fib)) { + } else if (reg_ioat(env, pbdev->iommu, fib, ra)) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES); } @@ -904,7 +906,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } else { pci_dereg_ioat(pbdev->iommu); - if (reg_ioat(env, pbdev->iommu, fib)) { + if (reg_ioat(env, pbdev->iommu, fib, ra)) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES); } @@ -935,7 +937,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) pbdev->fmb_addr = ldq_p(&fib.fmb_addr); break; default: - program_interrupt(&cpu->env, PGM_OPERAND, 6); + s390_program_interrupt(&cpu->env, PGM_OPERAND, 6, ra); cc = ZPCI_PCI_LS_ERR; } @@ -943,7 +945,8 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) return 0; } -int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) +int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, + uintptr_t ra) { CPUS390XState *env = &cpu->env; uint8_t dmaas; @@ -954,7 +957,7 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) uint64_t cc = ZPCI_PCI_LS_OK; if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 6); + s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra); return 0; } @@ -968,7 +971,7 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) } if (fiba & 0x7) { - program_interrupt(env, PGM_SPECIFICATION, 6); + s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); return 0; } diff --git a/hw/s390x/s390-pci-inst.h b/hw/s390x/s390-pci-inst.h index 94a959f91c..93ef290101 100644 --- a/hw/s390x/s390-pci-inst.h +++ b/hw/s390x/s390-pci-inst.h @@ -293,13 +293,15 @@ typedef struct ZpciFib { int pci_dereg_irqs(S390PCIBusDevice *pbdev); void pci_dereg_ioat(S390PCIIOMMU *iommu); -int clp_service_call(S390CPU *cpu, uint8_t r2); -int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2); -int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2); -int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2); +int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra); +int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra); +int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra); +int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra); int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, - uint8_t ar); -int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar); -int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar); + uint8_t ar, uintptr_t ra); +int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, + uintptr_t ra); +int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, + uintptr_t ra); #endif -- cgit v1.2.3 From 98ee9bedc734e18287902f39e3a3a8adb399386a Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:35 +0100 Subject: s390x: handle exceptions during s390_cpu_virt_mem_rw() correctly (TCG) s390_cpu_virt_mem_rw() must always return, so callers can react on an exception (e.g. see ioinst_handle_stcrw()). However, for TCG we always have to exit the cpu loop (and restore the cpu state before that) if we injected a program interrupt. So let's introduce and use s390_cpu_virt_mem_handle_exc() in code that is not purely KVM. Directly pass the retaddr we already have available in these functions. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-8-david@redhat.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'hw/s390x') diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 8123705dfd..6f41083244 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -163,6 +163,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) } if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer, sizeof(*reqh))) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } reqh = (ClpReqHdr *)buffer; @@ -174,6 +175,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer, req_len + sizeof(*resh))) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } resh = (ClpRspHdr *)(buffer + req_len); @@ -189,6 +191,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer, req_len + res_len)) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } @@ -308,6 +311,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) out: if (s390_cpu_virt_mem_write(cpu, env->regs[r2], r2, buffer, req_len + res_len)) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } setcc(cpu, cc); @@ -692,6 +696,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, } if (s390_cpu_virt_mem_read(cpu, gaddr, ar, buffer, len)) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } @@ -848,6 +853,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, } if (s390_cpu_virt_mem_read(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } @@ -1029,6 +1035,7 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, out: if (s390_cpu_virt_mem_write(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } -- cgit v1.2.3 From c748814b20f1f1b43eed1fd32c84579c60f4cc58 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 30 Nov 2017 13:55:24 +0100 Subject: s390x/pci: factor out endianess conversion There are two places where the same endianness conversion is done. Let's factor this out into a static function. Note that the conversion must always be done for data in a register: The S390 BE guest converted date to le before issuing the instruction. After interception in a BE host: ZPCI VFIO using pwrite must make the conversion back for the BE kernel. Kernel will do BE to le translation when loading the register for the real instruction. After interception in a le host: TCG stores a BE register in le, swapping bytes. But since the data in the register was already le it is now BE ZPCI VFIO must convert it to le before writing to the PCI memory. In both cases ZPCI VFIO must swap the bytes from the register. Signed-off-by: Pierre Morel Reviewed-by: Yi Min Zhao Message-Id: <1512046530-17773-2-git-send-email-pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 58 ++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 26 deletions(-) (limited to 'hw/s390x') diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 6f41083244..cb84d209e0 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -318,6 +318,36 @@ out: return 0; } +/** + * Swap data contained in s390x big endian registers to little endian + * PCI bars. + * + * @ptr: a pointer to a uint64_t data field + * @len: the length of the valid data, must be 1,2,4 or 8 + */ +static int zpci_endian_swap(uint64_t *ptr, uint8_t len) +{ + uint64_t data = *ptr; + + switch (len) { + case 1: + break; + case 2: + data = bswap16(data); + break; + case 4: + data = bswap32(data); + break; + case 8: + data = bswap64(data); + break; + default: + return -EINVAL; + } + *ptr = data; + return 0; +} + int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) { CPUS390XState *env = &cpu->env; @@ -389,19 +419,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) data = pci_host_config_read_common( pbdev->pdev, offset, pci_config_size(pbdev->pdev), len); - switch (len) { - case 1: - break; - case 2: - data = bswap16(data); - break; - case 4: - data = bswap32(data); - break; - case 8: - data = bswap64(data); - break; - default: + if (zpci_endian_swap(&data, len)) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } @@ -504,19 +522,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } - switch (len) { - case 1: - break; - case 2: - data = bswap16(data); - break; - case 4: - data = bswap32(data); - break; - case 8: - data = bswap64(data); - break; - default: + if (zpci_endian_swap(&data, len)) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } -- cgit v1.2.3 From 7645b9a794741be6d007d8074c73c4510d269ad4 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 30 Nov 2017 13:55:25 +0100 Subject: s390x/pci: rework PCI STORE Enhance the fault detection, correction of the fault reporting. Signed-off-by: Pierre Morel Reviewed-by: Yi Min Zhao Message-Id: <1512046530-17773-3-git-send-email-pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 41 +++++++++++++++++++++++++---------------- hw/s390x/s390-pci-inst.h | 4 ++++ 2 files changed, 29 insertions(+), 16 deletions(-) (limited to 'hw/s390x') diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index cb84d209e0..66d191f57f 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -474,6 +474,12 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) pcias = (env->regs[r2] >> 16) & 0xf; len = env->regs[r2] & 0xf; offset = env->regs[r2 + 1]; + data = env->regs[r1]; + + if (!(fh & FH_MASK_ENABLE)) { + setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); + return 0; + } pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh); if (!pbdev) { @@ -483,12 +489,10 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) } switch (pbdev->state) { - case ZPCI_FS_RESERVED: - case ZPCI_FS_STANDBY: - case ZPCI_FS_DISABLED: + /* ZPCI_FS_RESERVED, ZPCI_FS_STANDBY and ZPCI_FS_DISABLED + * are already covered by the FH_MASK_ENABLE check above + */ case ZPCI_FS_PERMANENT_ERROR: - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; case ZPCI_FS_ERROR: setcc(cpu, ZPCI_PCI_LS_ERR); s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED); @@ -497,9 +501,13 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) break; } - data = env->regs[r1]; - if (pcias < 6) { - if ((8 - (offset & 0x7)) < len) { + switch (pcias) { + /* A ZPCI PCI card may use any BAR from BAR 0 to BAR 5 */ + case ZPCI_IO_BAR_MIN...ZPCI_IO_BAR_MAX: + /* Check length: + * A length of 0 is invalid and length should not cross a double word + */ + if (!len || (len > (8 - (offset & 0x7)))) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } @@ -517,20 +525,21 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } - } else if (pcias == 15) { - if ((4 - (offset & 0x3)) < len) { - s390_program_interrupt(env, PGM_OPERAND, 4, ra); - return 0; - } - if (zpci_endian_swap(&data, len)) { + break; + case ZPCI_CONFIG_BAR: + /* ZPCI uses the pseudo BAR number 15 as configuration space */ + /* possible access lengths are 1,2,4 and must not cross a word */ + if (!len || (len > (4 - (offset & 0x3))) || len == 3) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } - + /* len = 1,2,4 so we do not need to test */ + zpci_endian_swap(&data, len); pci_host_config_write_common(pbdev->pdev, offset, pci_config_size(pbdev->pdev), data, len); - } else { + break; + default: DPRINTF("pcistg invalid space\n"); setcc(cpu, ZPCI_PCI_LS_ERR); s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS); diff --git a/hw/s390x/s390-pci-inst.h b/hw/s390x/s390-pci-inst.h index 93ef290101..a396364635 100644 --- a/hw/s390x/s390-pci-inst.h +++ b/hw/s390x/s390-pci-inst.h @@ -304,4 +304,8 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, uintptr_t ra); +#define ZPCI_IO_BAR_MIN 0 +#define ZPCI_IO_BAR_MAX 5 +#define ZPCI_CONFIG_BAR 15 + #endif -- cgit v1.2.3 From 8cbd6aab9579a1ce0601049ea4bce5ea37a668ce Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 30 Nov 2017 13:55:26 +0100 Subject: s390x/pci: rework PCI LOAD Enhance the fault detection, correction of the fault reporting. Signed-off-by: Pierre Morel Reviewed-by: Yi Min Zhao Message-Id: <1512046530-17773-4-git-send-email-pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'hw/s390x') diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 66d191f57f..48ccf2289e 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -377,6 +377,11 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) len = env->regs[r2] & 0xf; offset = env->regs[r2 + 1]; + if (!(fh & FH_MASK_ENABLE)) { + setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); + return 0; + } + pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh); if (!pbdev) { DPRINTF("pcilg no pci dev\n"); @@ -385,12 +390,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) } switch (pbdev->state) { - case ZPCI_FS_RESERVED: - case ZPCI_FS_STANDBY: - case ZPCI_FS_DISABLED: case ZPCI_FS_PERMANENT_ERROR: - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; case ZPCI_FS_ERROR: setcc(cpu, ZPCI_PCI_LS_ERR); s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED); @@ -399,8 +399,9 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) break; } - if (pcias < 6) { - if ((8 - (offset & 0x7)) < len) { + switch (pcias) { + case ZPCI_IO_BAR_MIN...ZPCI_IO_BAR_MAX: + if (!len || (len > (8 - (offset & 0x7)))) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } @@ -411,8 +412,9 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } - } else if (pcias == 15) { - if ((4 - (offset & 0x3)) < len) { + break; + case ZPCI_CONFIG_BAR: + if (!len || (len > (4 - (offset & 0x3))) || len == 3) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } @@ -423,8 +425,9 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } - } else { - DPRINTF("invalid space\n"); + break; + default: + DPRINTF("pcilg invalid space\n"); setcc(cpu, ZPCI_PCI_LS_ERR); s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS); return 0; -- cgit v1.2.3 From 0e7c259adff7e97f829a08a5f146e7ee03b5ae47 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 30 Nov 2017 13:55:27 +0100 Subject: s390x/pci: rework PCI STORE BLOCK Enhance the fault detection. Fixup the precedence to check the destination path existance before checking for the source accessibility. Add the maxstbl entry to both the Query PCI Function Group response and the PCIBusDevice structure. Initialize the maxstbl to 128 per default until we get the actual data from the hardware. Signed-off-by: Pierre Morel Reviewed-by: Yi Min Zhao Message-Id: <1512046530-17773-5-git-send-email-pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-bus.h | 1 + hw/s390x/s390-pci-inst.c | 63 ++++++++++++++++++++++++++++++------------------ hw/s390x/s390-pci-inst.h | 2 +- 3 files changed, 41 insertions(+), 25 deletions(-) (limited to 'hw/s390x') diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h index 560bd82a0f..2993f0ddef 100644 --- a/hw/s390x/s390-pci-bus.h +++ b/hw/s390x/s390-pci-bus.h @@ -284,6 +284,7 @@ struct S390PCIBusDevice { uint64_t fmb_addr; uint8_t isc; uint16_t noi; + uint16_t maxstbl; uint8_t sum; S390MsixInfo msix; AdapterRoutes routes; diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 48ccf2289e..e70cd04eb4 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -297,6 +297,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) stq_p(&resgrp->msia, ZPCI_MSI_ADDR); stw_p(&resgrp->mui, 0); stw_p(&resgrp->i, 128); + stw_p(&resgrp->maxstbl, 128); resgrp->version = 0; stw_p(&resgrp->hdr.rsp, CLP_RC_OK); @@ -652,6 +653,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, S390PCIBusDevice *pbdev; MemoryRegion *mr; MemTxResult result; + uint64_t offset; int i; uint32_t fh; uint8_t pcias; @@ -666,22 +668,10 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, fh = env->regs[r1] >> 32; pcias = (env->regs[r1] >> 16) & 0xf; len = env->regs[r1] & 0xff; + offset = env->regs[r3]; - if (pcias > 5) { - DPRINTF("pcistb invalid space\n"); - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r1, ZPCI_PCI_ST_INVAL_AS); - return 0; - } - - switch (len) { - case 16: - case 32: - case 64: - case 128: - break; - default: - s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); + if (!(fh & FH_MASK_ENABLE)) { + setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); return 0; } @@ -693,12 +683,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, } switch (pbdev->state) { - case ZPCI_FS_RESERVED: - case ZPCI_FS_STANDBY: - case ZPCI_FS_DISABLED: case ZPCI_FS_PERMANENT_ERROR: - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; case ZPCI_FS_ERROR: setcc(cpu, ZPCI_PCI_LS_ERR); s390_set_status_code(env, r1, ZPCI_PCI_ST_BLOCKED); @@ -707,8 +692,34 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, break; } + if (pcias > ZPCI_IO_BAR_MAX) { + DPRINTF("pcistb invalid space\n"); + setcc(cpu, ZPCI_PCI_LS_ERR); + s390_set_status_code(env, r1, ZPCI_PCI_ST_INVAL_AS); + return 0; + } + + /* Verify the address, offset and length */ + /* offset must be a multiple of 8 */ + if (offset % 8) { + goto specification_error; + } + /* Length must be greater than 8, a multiple of 8 */ + /* and not greater than maxstbl */ + if ((len <= 8) || (len % 8) || (len > pbdev->maxstbl)) { + goto specification_error; + } + /* Do not cross a 4K-byte boundary */ + if (((offset & 0xfff) + len) > 0x1000) { + goto specification_error; + } + /* Guest address must be double word aligned */ + if (gaddr & 0x07UL) { + goto specification_error; + } + mr = pbdev->pdev->io_regions[pcias].memory; - if (!memory_region_access_valid(mr, env->regs[r3], len, true)) { + if (!memory_region_access_valid(mr, offset, len, true)) { s390_program_interrupt(env, PGM_OPERAND, 6, ra); return 0; } @@ -719,9 +730,9 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, } for (i = 0; i < len / 8; i++) { - result = memory_region_dispatch_write(mr, env->regs[r3] + i * 8, - ldq_p(buffer + i * 8), 8, - MEMTXATTRS_UNSPECIFIED); + result = memory_region_dispatch_write(mr, offset + i * 8, + ldq_p(buffer + i * 8), 8, + MEMTXATTRS_UNSPECIFIED); if (result != MEMTX_OK) { s390_program_interrupt(env, PGM_OPERAND, 6, ra); return 0; @@ -730,6 +741,10 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, setcc(cpu, ZPCI_PCI_LS_OK); return 0; + +specification_error: + s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); + return 0; } static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib) diff --git a/hw/s390x/s390-pci-inst.h b/hw/s390x/s390-pci-inst.h index a396364635..91c3d61f2a 100644 --- a/hw/s390x/s390-pci-inst.h +++ b/hw/s390x/s390-pci-inst.h @@ -162,7 +162,7 @@ typedef struct ClpRspQueryPciGrp { #define CLP_RSP_QPCIG_MASK_FRAME 0x2 #define CLP_RSP_QPCIG_MASK_REFRESH 0x1 uint8_t fr; - uint16_t reserved2; + uint16_t maxstbl; uint16_t mui; uint64_t reserved3; uint64_t dasm; /* dma address space mask */ -- cgit v1.2.3 From ab0380cab330c986ac6db91df1679c035d19ae77 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 30 Nov 2017 13:55:28 +0100 Subject: s390x/pci: move the memory region read from pcilg Let's move the memory region read from pcilg into a dedicated function. This allows us to prepare a later patch. Signed-off-by: Pierre Morel Reviewed-by: Yi Min Zhao Reviewed-by: Thomas Huth Message-Id: <1512046530-17773-6-git-send-email-pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'hw/s390x') diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index e70cd04eb4..f0247e0ba7 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -349,13 +349,22 @@ static int zpci_endian_swap(uint64_t *ptr, uint8_t len) return 0; } +static MemTxResult zpci_read_bar(S390PCIBusDevice *pbdev, uint8_t pcias, + uint64_t offset, uint64_t *data, uint8_t len) +{ + MemoryRegion *mr; + + mr = pbdev->pdev->io_regions[pcias].memory; + return memory_region_dispatch_read(mr, offset, data, len, + MEMTXATTRS_UNSPECIFIED); +} + int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) { CPUS390XState *env = &cpu->env; S390PCIBusDevice *pbdev; uint64_t offset; uint64_t data; - MemoryRegion *mr; MemTxResult result; uint8_t len; uint32_t fh; @@ -406,9 +415,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } - mr = pbdev->pdev->io_regions[pcias].memory; - result = memory_region_dispatch_read(mr, offset, &data, len, - MEMTXATTRS_UNSPECIFIED); + result = zpci_read_bar(pbdev, pcias, offset, &data, len); if (result != MEMTX_OK) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; -- cgit v1.2.3 From 8af27a9eab16f92990ce9b562719bdb485ffaf1b Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 30 Nov 2017 13:55:29 +0100 Subject: s390x/pci: move the memory region write from pcistg Let's move the memory region write from pcistg into a dedicated function. This allows us to prepare a later patch searching for subregions inside of the memory region. Signed-off-by: Pierre Morel Reviewed-by: Yi Min Zhao Reviewed-by: Thomas Huth Message-Id: <1512046530-17773-7-git-send-email-pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'hw/s390x') diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index f0247e0ba7..4b3be7af83 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -458,12 +458,27 @@ static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias) } } +static MemTxResult zpci_write_bar(S390PCIBusDevice *pbdev, uint8_t pcias, + uint64_t offset, uint64_t data, uint8_t len) +{ + MemoryRegion *mr; + + if (trap_msix(pbdev, offset, pcias)) { + offset = offset - pbdev->msix.table_offset; + mr = &pbdev->pdev->msix_table_mmio; + } else { + mr = pbdev->pdev->io_regions[pcias].memory; + } + + return memory_region_dispatch_write(mr, offset, data, len, + MEMTXATTRS_UNSPECIFIED); +} + int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) { CPUS390XState *env = &cpu->env; uint64_t offset, data; S390PCIBusDevice *pbdev; - MemoryRegion *mr; MemTxResult result; uint8_t len; uint32_t fh; @@ -523,15 +538,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) return 0; } - if (trap_msix(pbdev, offset, pcias)) { - offset = offset - pbdev->msix.table_offset; - mr = &pbdev->pdev->msix_table_mmio; - } else { - mr = pbdev->pdev->io_regions[pcias].memory; - } - - result = memory_region_dispatch_write(mr, offset, data, len, - MEMTXATTRS_UNSPECIFIED); + result = zpci_write_bar(pbdev, pcias, offset, data, len); if (result != MEMTX_OK) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; -- cgit v1.2.3 From 4f6482bfe3da1e6b51ad4722a0c22f22f0d54a3b Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 30 Nov 2017 13:55:30 +0100 Subject: s390x/pci: search for subregion inside the BARs When dispatching memory access to PCI BAR region, we must look for possible subregions, used by the PCI device to map different memory areas inside the same PCI BAR. Since the data offset we received is calculated starting at the region start address we need to adjust the offset for the subregion. The data offset inside the subregion is calculated by substracting the subregion's starting address from the data offset in the region. The access to the MSIX region is now handled in a generic way, we do not need the specific trap_msix() function anymore. Signed-off-by: Pierre Morel Reviewed-by: Yi Min Zhao Message-Id: <1512046530-17773-8-git-send-email-pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'hw/s390x') diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 4b3be7af83..be449210d9 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -349,12 +349,31 @@ static int zpci_endian_swap(uint64_t *ptr, uint8_t len) return 0; } +static MemoryRegion *s390_get_subregion(MemoryRegion *mr, uint64_t offset, + uint8_t len) +{ + MemoryRegion *subregion; + uint64_t subregion_size; + + QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) { + subregion_size = int128_get64(subregion->size); + if ((offset >= subregion->addr) && + (offset + len) <= (subregion->addr + subregion_size)) { + mr = subregion; + break; + } + } + return mr; +} + static MemTxResult zpci_read_bar(S390PCIBusDevice *pbdev, uint8_t pcias, uint64_t offset, uint64_t *data, uint8_t len) { MemoryRegion *mr; mr = pbdev->pdev->io_regions[pcias].memory; + mr = s390_get_subregion(mr, offset, len); + offset -= mr->addr; return memory_region_dispatch_read(mr, offset, data, len, MEMTXATTRS_UNSPECIFIED); } @@ -446,30 +465,14 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) return 0; } -static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias) -{ - if (pbdev->msix.available && pbdev->msix.table_bar == pcias && - offset >= pbdev->msix.table_offset && - offset < (pbdev->msix.table_offset + - pbdev->msix.entries * PCI_MSIX_ENTRY_SIZE)) { - return 1; - } else { - return 0; - } -} - static MemTxResult zpci_write_bar(S390PCIBusDevice *pbdev, uint8_t pcias, uint64_t offset, uint64_t data, uint8_t len) { MemoryRegion *mr; - if (trap_msix(pbdev, offset, pcias)) { - offset = offset - pbdev->msix.table_offset; - mr = &pbdev->pdev->msix_table_mmio; - } else { - mr = pbdev->pdev->io_regions[pcias].memory; - } - + mr = pbdev->pdev->io_regions[pcias].memory; + mr = s390_get_subregion(mr, offset, len); + offset -= mr->addr; return memory_region_dispatch_write(mr, offset, data, len, MEMTXATTRS_UNSPECIFIED); } @@ -733,6 +736,9 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, } mr = pbdev->pdev->io_regions[pcias].memory; + mr = s390_get_subregion(mr, offset, len); + offset -= mr->addr; + if (!memory_region_access_valid(mr, offset, len, true)) { s390_program_interrupt(env, PGM_OPERAND, 6, ra); return 0; -- cgit v1.2.3 From 99577c492fb2916165ed9bc215f058877f0a4106 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Wed, 6 Dec 2017 15:44:37 +0100 Subject: s390x/css: unrestrict cssids The default css 0xfe is currently restricted to virtual subchannel devices. The hope when the decision was made was, that non-virtual subchannel devices will come around when guest can exploit multiple channel subsystems. Since the guests generally don't do, the pain of the partitioned (cssid) namespace outweighs the gain. Let us remove the corresponding restrictions (virtual devices can be put only in 0xfe and non-virtual devices in any css except the 0xfe -- while s390-squash-mcss then remaps everything to cssid 0). At the same time, change our schema for generating css bus ids to put both virtual and non-virtual devices into the default css (spilling over into other css images, if needed). The intention is to deprecate s390-squash-mcss. With this change devices without a specified devno won't end up hidden to guests not supporting multiple channel subsystems, unless this can not be avoided (default css full). Let us also advertise the changes to the management software (so it can tell are cssids unrestricted or restricted). The adverse effect of getting rid of the restriction on migration should not be too severe. Vfio-ccw devices are not live-migratable yet, and for virtual devices using the extra freedom would only make sense with the aforementioned guest support in place. The auto-generated bus ids are affected by both changes. We hope to not encounter any auto-generated bus ids in production as Libvirt is always explicit about the bus id. Since 8ed179c937 ("s390x/css: catch section mismatch on load", 2017-05-18) the worst that can happen because the same device ended up having a different bus id is a cleanly failed migration. I find it hard to reason about the impact of changed auto-generated bus ids on migration for command line users as I don't know which rules is such an user supposed to follow. Another pain-point is down- or upgrade of QEMU for command line users. The old way and the new way of doing vfio-ccw are mutually incompatible. Libvirt is only going to support the new way, so for libvirt users, the possible problems at QEMU downgrade are the following. If a domain contains virtual devices placed into a css different than 0xfe the domain will refuse to start with a QEMU not having this patch. Putting devices into a css different that 0xfe however won't make much sense in the near future (guest support). Libvirt will refuse to do vfio-ccw with a QEMU not having this patch. This is business as usual. Signed-off-by: Halil Pasic Acked-by: Christian Borntraeger Reviewed-by: Dong Jia Shi Message-Id: <20171206144438.28908-2-pasic@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/3270-ccw.c | 2 +- hw/s390x/css-bridge.c | 11 +++++++++++ hw/s390x/css.c | 28 ++++------------------------ hw/s390x/s390-ccw.c | 2 +- hw/s390x/s390-virtio-ccw.c | 1 - hw/s390x/virtio-ccw.c | 2 +- 6 files changed, 18 insertions(+), 28 deletions(-) (limited to 'hw/s390x') diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c index 081e3ef6f4..3af13ea027 100644 --- a/hw/s390x/3270-ccw.c +++ b/hw/s390x/3270-ccw.c @@ -104,7 +104,7 @@ static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp) SubchDev *sch; Error *err = NULL; - sch = css_create_sch(cdev->devno, true, cbus->squash_mcss, errp); + sch = css_create_sch(cdev->devno, cbus->squash_mcss, errp); if (!sch) { return; } diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index c4a9735d71..a91a237f37 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -123,6 +123,11 @@ static Property virtual_css_bridge_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static bool prop_get_true(Object *obj, Error **errp) +{ + return true; +} + static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) { HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); @@ -131,6 +136,12 @@ static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) hc->unplug = ccw_device_unplug; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->props = virtual_css_bridge_properties; + object_class_property_add_bool(klass, "cssid-unrestricted", + prop_get_true, NULL, NULL); + object_class_property_set_description(klass, "cssid-unrestricted", + "A css device can use any cssid, regardless whether virtual" + " or not (read only, always true)", + NULL); } static const TypeInfo virtual_css_bridge_info = { diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 6bd0fedc78..f071e1394b 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -2364,21 +2364,11 @@ const PropertyInfo css_devid_ro_propinfo = { .get = get_css_devid, }; -SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss, - Error **errp) +SubchDev *css_create_sch(CssDevId bus_id, bool squash_mcss, Error **errp) { uint16_t schid = 0; SubchDev *sch; - if (bus_id.valid) { - if (is_virtual != (bus_id.cssid == VIRTUAL_CSSID)) { - error_setg(errp, "cssid %hhx not valid for %s devices", - bus_id.cssid, - (is_virtual ? "virtual" : "non-virtual")); - return NULL; - } - } - if (bus_id.valid) { if (squash_mcss) { bus_id.cssid = channel_subsys.default_cssid; @@ -2390,19 +2380,8 @@ SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss, bus_id.devid, &schid, errp)) { return NULL; } - } else if (squash_mcss || is_virtual) { - bus_id.cssid = channel_subsys.default_cssid; - - if (!css_find_free_subch_and_devno(bus_id.cssid, &bus_id.ssid, - &bus_id.devid, &schid, errp)) { - return NULL; - } } else { - for (bus_id.cssid = 0; bus_id.cssid < MAX_CSSID; ++bus_id.cssid) { - if (bus_id.cssid == VIRTUAL_CSSID) { - continue; - } - + for (bus_id.cssid = channel_subsys.default_cssid;;) { if (!channel_subsys.css[bus_id.cssid]) { css_create_css_image(bus_id.cssid, false); } @@ -2412,7 +2391,8 @@ SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss, NULL)) { break; } - if (bus_id.cssid == MAX_CSSID) { + bus_id.cssid = (bus_id.cssid + 1) % MAX_CSSID; + if (bus_id.cssid == channel_subsys.default_cssid) { error_setg(errp, "Virtual channel subsystem is full!"); return NULL; } diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c index 0ef232ec27..4a9d4d2534 100644 --- a/hw/s390x/s390-ccw.c +++ b/hw/s390x/s390-ccw.c @@ -77,7 +77,7 @@ static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp) goto out_err_propagate; } - sch = css_create_sch(ccw_dev->devno, false, cbus->squash_mcss, &err); + sch = css_create_sch(ccw_dev->devno, cbus->squash_mcss, &err); if (!sch) { goto out_mdevid_free; } diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index a23b8aec9f..5d4aaaf158 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -302,7 +302,6 @@ static void ccw_init(MachineState *machine) /* * Non mcss-e enabled guests only see the devices from the default * css, which is determined by the value of the squash_mcss property. - * Note: we must not squash non virtual devices to css 0xFE. */ if (css_bus->squash_mcss) { ret = css_create_css_image(0, true); diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 184515ce94..3dd902a664 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -701,7 +701,7 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp) SubchDev *sch; Error *err = NULL; - sch = css_create_sch(ccw_dev->devno, true, cbus->squash_mcss, errp); + sch = css_create_sch(ccw_dev->devno, cbus->squash_mcss, errp); if (!sch) { return; } -- cgit v1.2.3 From d69969e55f2187188c3d2a0ea9c6be29631358fb Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Wed, 6 Dec 2017 15:44:38 +0100 Subject: s390x: deprecate s390-squash-mcss machine prop With the cssids unrestricted (commit "s390x/css: unrestrict cssids") the s390-squash-mcss machine property should not be used. Actually Libvirt never supported this, so the expectation is that removing it should be pretty painless. But let's play nice and deprecate it first. Signed-off-by: Halil Pasic Message-Id: <20171206144438.28908-3-pasic@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'hw/s390x') diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 5d4aaaf158..fe3f3b2ad6 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -308,6 +308,11 @@ static void ccw_init(MachineState *machine) } else { ret = css_create_css_image(VIRTUAL_CSSID, true); } + if (qemu_opt_get(qemu_get_machine_opts(), "s390-squash-mcss")) { + warn_report("The machine property 's390-squash-mcss' is deprecated" + " (obsoleted by lifting the cssid restrictions)."); + } + assert(ret == 0); if (css_migration_enabled()) { css_register_vmstate(); @@ -582,7 +587,7 @@ static inline void s390_machine_initfn(Object *obj) object_property_add_bool(obj, "s390-squash-mcss", machine_get_squash_mcss, machine_set_squash_mcss, NULL); - object_property_set_description(obj, "s390-squash-mcss", + object_property_set_description(obj, "s390-squash-mcss", "(deprecated) " "enable/disable squashing subchannels into the default css", NULL); object_property_set_bool(obj, false, "s390-squash-mcss", NULL); -- cgit v1.2.3 From 864c2512576ab4e0d84bda0481b15dd1820d43de Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 28 Nov 2017 14:08:14 +0100 Subject: s390x/css: attach css bridge Logically, the css bridge should be attached to the machine. Reviewed-by: Christian Borntraeger Reviewed-by: David Hildenbrand Tested-by: Bjoern Walk Signed-off-by: Cornelia Huck --- hw/s390x/css-bridge.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'hw/s390x') diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index a91a237f37..a02d708239 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -99,6 +99,8 @@ VirtualCssBus *virtual_css_bus_init(void) /* Create bridge device */ dev = qdev_create(NULL, TYPE_VIRTUAL_CSS_BRIDGE); + object_property_add_child(qdev_get_machine(), TYPE_VIRTUAL_CSS_BRIDGE, + OBJECT(dev), NULL); qdev_init_nofail(dev); /* Create bus on bridge device */ -- cgit v1.2.3 From 35b4df6417fc3cd9d0150590f770fdd404dfbee7 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:55:29 +0100 Subject: s390x: change the QEMU cpu model to a stripped down z12 We are good enough to boot upstream Linux kernels / Fedora 26/27. That should be sufficient for now. As the QEMU CPU model is migration safe, let's add compatibility code. Generate the feature list to reduce the chance of messing things up in the future. Signed-off-by: David Hildenbrand Message-Id: <20171208165529.14124-1-david@redhat.com> [CH: squashed 's390x/cpumodel: make qemu cpu model play with "none" machine' (20171213132407.5227-1-david@redhat.com) and 's390x/tcg: don't include z13 features in the qemu model' (20171213171512.17601-1-david@redhat.com) into patch] Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'hw/s390x') diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index fe3f3b2ad6..466e45343c 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -734,7 +734,11 @@ DEFINE_CCW_MACHINE(2_12, "2.12", true); static void ccw_machine_2_11_instance_options(MachineState *machine) { + static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V2_11 }; ccw_machine_2_12_instance_options(machine); + + /* before 2.12 we emulated the very first z900 */ + s390_set_qemu_cpu_model(0x2064, 7, 1, qemu_cpu_feat); } static void ccw_machine_2_11_class_options(MachineClass *mc) -- cgit v1.2.3 From bb223055b9b327ec66e1f6d2fbaebaee0b8f3dbe Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Mon, 11 Dec 2017 13:21:46 +0100 Subject: s390-ccw-virtio: allow for systems larger that 7.999TB KVM does not allow memory regions > KVM_MEM_MAX_NR_PAGES, basically limiting the memory per slot to 8TB-4k. As memory slots on s390/kvm must be a multiple of 1MB we need start a new memory region if we cross 8TB-1M. With that (and optimistic overcommitment in the kernel) I was able to start a 24TB guest on a 1TB system. Signed-off-by: Christian Borntraeger Message-Id: <20171211122146.162430-1-borntraeger@de.ibm.com> Reviewed-by: David Hildenbrand [CH: 1UL -> 1ULL in KVM_MEM_MAX_NR_PAGES; build fix on 32 bit hosts] Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'hw/s390x') diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 466e45343c..35df7e19c5 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -152,14 +152,38 @@ static void virtio_ccw_register_hcalls(void) virtio_ccw_hcall_early_printk); } +/* + * KVM does only support memory slots up to KVM_MEM_MAX_NR_PAGES pages + * as the dirty bitmap must be managed by bitops that take an int as + * position indicator. If we have a guest beyond that we will split off + * new subregions. The split must happen on a segment boundary (1MB). + */ +#define KVM_MEM_MAX_NR_PAGES ((1ULL << 31) - 1) +#define SEG_MSK (~0xfffffULL) +#define KVM_SLOT_MAX_BYTES ((KVM_MEM_MAX_NR_PAGES * TARGET_PAGE_SIZE) & SEG_MSK) static void s390_memory_init(ram_addr_t mem_size) { MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); + ram_addr_t chunk, offset = 0; + unsigned int number = 0; + gchar *name; /* allocate RAM for core */ - memory_region_allocate_system_memory(ram, NULL, "s390.ram", mem_size); - memory_region_add_subregion(sysmem, 0, ram); + name = g_strdup_printf("s390.ram"); + while (mem_size) { + MemoryRegion *ram = g_new(MemoryRegion, 1); + uint64_t size = mem_size; + + /* KVM does not allow memslots >= 8 TB */ + chunk = MIN(size, KVM_SLOT_MAX_BYTES); + memory_region_allocate_system_memory(ram, NULL, name, chunk); + memory_region_add_subregion(sysmem, offset, ram); + mem_size -= chunk; + offset += chunk; + g_free(name); + name = g_strdup_printf("s390.ram.%u", ++number); + } + g_free(name); /* Initialize storage key device */ s390_skeys_init(); -- cgit v1.2.3 From 3c254ab8d76e49d2bda818ec5885d110f2e1e67e Mon Sep 17 00:00:00 2001 From: Ladi Prosek Date: Tue, 17 Oct 2017 16:40:51 +0200 Subject: Remove empty statements Thanks to Laszlo Ersek for spotting the double semicolon in target/i386/kvm.c I have trivially grepped the tree for ';;' in C files. Suggested-by: Laszlo Ersek Signed-off-by: Ladi Prosek Reviewed-by: Laszlo Ersek Reviewed-by: Cornelia Huck Reviewed-by: Laurent Vivier Signed-off-by: Michael Tokarev --- hw/s390x/virtio-ccw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/s390x') diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 3dd902a664..38f6a8afc9 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -486,7 +486,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) } else { address_space_stb(&address_space_memory, ccw.cda, vdev->status, MEMTXATTRS_UNSPECIFIED, NULL); - sch->curr_status.scsw.count = ccw.count - sizeof(vdev->status);; + sch->curr_status.scsw.count = ccw.count - sizeof(vdev->status); ret = 0; } break; -- cgit v1.2.3 From ff676046fb7018a1e62961cc306e466b0a167540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:57 -0300 Subject: misc: remove duplicated includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit exec: housekeeping (funny since 02d0e095031) applied using ./scripts/clean-includes Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Acked-by: Cornelia Huck Reviewed-by: Anthony PERARD Signed-off-by: Michael Tokarev --- hw/s390x/css.c | 1 - 1 file changed, 1 deletion(-) (limited to 'hw/s390x') diff --git a/hw/s390x/css.c b/hw/s390x/css.c index f071e1394b..1c526fd7e2 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -13,7 +13,6 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "hw/qdev.h" -#include "qemu/error-report.h" #include "qemu/bitops.h" #include "qemu/error-report.h" #include "exec/address-spaces.h" -- cgit v1.2.3