From 7abf97975088595682f52c7cfb030b45ea38d8c3 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 15 Jul 2020 10:42:28 +1000 Subject: ppc/spapr: Fix 32 bit logical memory block size assumptions When testing large LMB sizes (eg 4GB), I found a couple of places that assume they are 32bit in size. Signed-off-by: Anton Blanchard Message-Id: <20200715004228.1262681-1-anton@ozlabs.org> Signed-off-by: David Gibson --- hw/ppc/spapr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 0ae293e..a5bb073 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -558,7 +558,8 @@ static int spapr_dt_dynamic_reconfiguration_memory(SpaprMachineState *spapr, int nb_numa_nodes = machine->numa_state->num_nodes; int ret, i, offset; uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE; - uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)}; + uint32_t prop_lmb_size[] = {cpu_to_be32(lmb_size >> 32), + cpu_to_be32(lmb_size & 0xffffffff)}; uint32_t *int_buf, *cur_index, buf_len; int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1; MemoryDeviceInfoList *dimms = NULL; @@ -905,7 +906,8 @@ static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt) uint32_t lrdr_capacity[] = { cpu_to_be32(max_device_addr >> 32), cpu_to_be32(max_device_addr & 0xffffffff), - 0, cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE), + cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE >> 32), + cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE & 0xffffffff), cpu_to_be32(ms->smp.max_cpus / ms->smp.threads), }; uint32_t maxdomain = cpu_to_be32(spapr->gpu_numa_id > 1 ? 1 : 0); -- cgit v1.1 From d9c5b5fa86ce37125dcc64c6274a1bc48cf11903 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 28 Jul 2020 15:29:34 +0200 Subject: spapr: Use error_append_hint() in spapr_caps.c We have a dedicated error API for hints. Use it instead of embedding the hint in the error message, as recommanded in the "qapi/error.h" header file. While here, have cap_fwnmi_apply(), which already uses error_append_hint(), to call ERRP_GUARD() as well. Signed-off-by: Greg Kurz Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Laurent Vivier Message-Id: <159594297421.8262.14314530897345809924.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/ppc/spapr_caps.c | 89 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 39 deletions(-) (limited to 'hw') diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 3225fc5..275f5bd 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -180,24 +180,24 @@ static void spapr_cap_set_pagesize(Object *obj, Visitor *v, const char *name, static void cap_htm_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { + ERRP_GUARD(); if (!val) { /* TODO: We don't support disabling htm yet */ return; } if (tcg_enabled()) { - error_setg(errp, - "No Transactional Memory support in TCG," - " try appending -machine cap-htm=off"); + error_setg(errp, "No Transactional Memory support in TCG"); + error_append_hint(errp, "Try appending -machine cap-htm=off\n"); } else if (kvm_enabled() && !kvmppc_has_cap_htm()) { error_setg(errp, -"KVM implementation does not support Transactional Memory," - " try appending -machine cap-htm=off" - ); + "KVM implementation does not support Transactional Memory"); + error_append_hint(errp, "Try appending -machine cap-htm=off\n"); } } static void cap_vsx_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { + ERRP_GUARD(); PowerPCCPU *cpu = POWERPC_CPU(first_cpu); CPUPPCState *env = &cpu->env; @@ -209,13 +209,14 @@ static void cap_vsx_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) * rid of anything that doesn't do VMX */ g_assert(env->insns_flags & PPC_ALTIVEC); if (!(env->insns_flags2 & PPC2_VSX)) { - error_setg(errp, "VSX support not available," - " try appending -machine cap-vsx=off"); + error_setg(errp, "VSX support not available"); + error_append_hint(errp, "Try appending -machine cap-vsx=off\n"); } } static void cap_dfp_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { + ERRP_GUARD(); PowerPCCPU *cpu = POWERPC_CPU(first_cpu); CPUPPCState *env = &cpu->env; @@ -224,8 +225,8 @@ static void cap_dfp_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) return; } if (!(env->insns_flags2 & PPC2_DFP)) { - error_setg(errp, "DFP support not available," - " try appending -machine cap-dfp=off"); + error_setg(errp, "DFP support not available"); + error_append_hint(errp, "Try appending -machine cap-dfp=off\n"); } } @@ -239,6 +240,7 @@ SpaprCapPossible cap_cfpc_possible = { static void cap_safe_cache_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { + ERRP_GUARD(); uint8_t kvm_val = kvmppc_get_cap_safe_cache(); if (tcg_enabled() && val) { @@ -247,9 +249,9 @@ static void cap_safe_cache_apply(SpaprMachineState *spapr, uint8_t val, cap_cfpc_possible.vals[val]); } else if (kvm_enabled() && (val > kvm_val)) { error_setg(errp, - "Requested safe cache capability level not supported by kvm," - " try appending -machine cap-cfpc=%s", - cap_cfpc_possible.vals[kvm_val]); + "Requested safe cache capability level not supported by KVM"); + error_append_hint(errp, "Try appending -machine cap-cfpc=%s\n", + cap_cfpc_possible.vals[kvm_val]); } } @@ -263,6 +265,7 @@ SpaprCapPossible cap_sbbc_possible = { static void cap_safe_bounds_check_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { + ERRP_GUARD(); uint8_t kvm_val = kvmppc_get_cap_safe_bounds_check(); if (tcg_enabled() && val) { @@ -271,9 +274,9 @@ static void cap_safe_bounds_check_apply(SpaprMachineState *spapr, uint8_t val, cap_sbbc_possible.vals[val]); } else if (kvm_enabled() && (val > kvm_val)) { error_setg(errp, -"Requested safe bounds check capability level not supported by kvm," - " try appending -machine cap-sbbc=%s", - cap_sbbc_possible.vals[kvm_val]); +"Requested safe bounds check capability level not supported by KVM"); + error_append_hint(errp, "Try appending -machine cap-sbbc=%s\n", + cap_sbbc_possible.vals[kvm_val]); } } @@ -290,6 +293,7 @@ SpaprCapPossible cap_ibs_possible = { static void cap_safe_indirect_branch_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { + ERRP_GUARD(); uint8_t kvm_val = kvmppc_get_cap_safe_indirect_branch(); if (tcg_enabled() && val) { @@ -298,9 +302,9 @@ static void cap_safe_indirect_branch_apply(SpaprMachineState *spapr, cap_ibs_possible.vals[val]); } else if (kvm_enabled() && (val > kvm_val)) { error_setg(errp, -"Requested safe indirect branch capability level not supported by kvm," - " try appending -machine cap-ibs=%s", - cap_ibs_possible.vals[kvm_val]); +"Requested safe indirect branch capability level not supported by KVM"); + error_append_hint(errp, "Try appending -machine cap-ibs=%s\n", + cap_ibs_possible.vals[kvm_val]); } } @@ -377,23 +381,25 @@ static void cap_hpt_maxpagesize_cpu_apply(SpaprMachineState *spapr, static void cap_nested_kvm_hv_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { + ERRP_GUARD(); if (!val) { /* capability disabled by default */ return; } if (tcg_enabled()) { - error_setg(errp, - "No Nested KVM-HV support in tcg," - " try appending -machine cap-nested-hv=off"); + error_setg(errp, "No Nested KVM-HV support in TCG"); + error_append_hint(errp, "Try appending -machine cap-nested-hv=off\n"); } else if (kvm_enabled()) { if (!kvmppc_has_cap_nested_kvm_hv()) { error_setg(errp, -"KVM implementation does not support Nested KVM-HV," - " try appending -machine cap-nested-hv=off"); + "KVM implementation does not support Nested KVM-HV"); + error_append_hint(errp, + "Try appending -machine cap-nested-hv=off\n"); } else if (kvmppc_set_cap_nested_kvm_hv(val) < 0) { - error_setg(errp, -"Error enabling cap-nested-hv with KVM, try cap-nested-hv=off"); + error_setg(errp, "Error enabling cap-nested-hv with KVM"); + error_append_hint(errp, + "Try appending -machine cap-nested-hv=off\n"); } } } @@ -401,6 +407,7 @@ static void cap_nested_kvm_hv_apply(SpaprMachineState *spapr, static void cap_large_decr_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { + ERRP_GUARD(); PowerPCCPU *cpu = POWERPC_CPU(first_cpu); PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); @@ -411,22 +418,23 @@ static void cap_large_decr_apply(SpaprMachineState *spapr, if (tcg_enabled()) { if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, spapr->max_compat_pvr)) { - error_setg(errp, - "Large decrementer only supported on POWER9, try -cpu POWER9"); + error_setg(errp, "Large decrementer only supported on POWER9"); + error_append_hint(errp, "Try -cpu POWER9\n"); return; } } else if (kvm_enabled()) { int kvm_nr_bits = kvmppc_get_cap_large_decr(); if (!kvm_nr_bits) { - error_setg(errp, - "No large decrementer support," - " try appending -machine cap-large-decr=off"); + error_setg(errp, "No large decrementer support"); + error_append_hint(errp, + "Try appending -machine cap-large-decr=off\n"); } else if (pcc->lrg_decr_bits != kvm_nr_bits) { error_setg(errp, -"KVM large decrementer size (%d) differs to model (%d)," - " try appending -machine cap-large-decr=off", - kvm_nr_bits, pcc->lrg_decr_bits); + "KVM large decrementer size (%d) differs to model (%d)", + kvm_nr_bits, pcc->lrg_decr_bits); + error_append_hint(errp, + "Try appending -machine cap-large-decr=off\n"); } } } @@ -435,14 +443,15 @@ static void cap_large_decr_cpu_apply(SpaprMachineState *spapr, PowerPCCPU *cpu, uint8_t val, Error **errp) { + ERRP_GUARD(); CPUPPCState *env = &cpu->env; target_ulong lpcr = env->spr[SPR_LPCR]; if (kvm_enabled()) { if (kvmppc_enable_cap_large_decr(cpu, val)) { - error_setg(errp, - "No large decrementer support," - " try appending -machine cap-large-decr=off"); + error_setg(errp, "No large decrementer support"); + error_append_hint(errp, + "Try appending -machine cap-large-decr=off\n"); } } @@ -457,6 +466,7 @@ static void cap_large_decr_cpu_apply(SpaprMachineState *spapr, static void cap_ccf_assist_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { + ERRP_GUARD(); uint8_t kvm_val = kvmppc_get_cap_count_cache_flush_assist(); if (tcg_enabled() && val) { @@ -479,14 +489,15 @@ static void cap_ccf_assist_apply(SpaprMachineState *spapr, uint8_t val, return; } error_setg(errp, -"Requested count cache flush assist capability level not supported by kvm," - " try appending -machine cap-ccf-assist=off"); + "Requested count cache flush assist capability level not supported by KVM"); + error_append_hint(errp, "Try appending -machine cap-ccf-assist=off\n"); } } static void cap_fwnmi_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { + ERRP_GUARD(); if (!val) { return; /* Disabled by default */ } -- cgit v1.1 From 19d55e2031f2473a65ffc11aff5b1059e7c4173b Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 16 Jul 2020 19:11:21 +0200 Subject: spapr: Forbid nested KVM-HV in pre-power9 compat mode Nested KVM HV only works if the kernel is using the radix MMU mode, ie. the CPU is POWER9 and it is not running in some pre-power9 compat mode. Otherwise, the KVM HV module fails to load in the guest with -ENODEV. It might be painful for a user to discover this late that nested cannot work with their setup. Erroring out at machine init instead seems to be the best we can do. Signed-off-by: Greg Kurz Reviewed-by: Laurent Vivier Message-Id: <159491948127.188975.9621435875869177751.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/ppc/spapr_caps.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'hw') diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 275f5bd..10a80a8 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -382,6 +382,8 @@ static void cap_nested_kvm_hv_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { ERRP_GUARD(); + PowerPCCPU *cpu = POWERPC_CPU(first_cpu); + if (!val) { /* capability disabled by default */ return; @@ -391,6 +393,14 @@ static void cap_nested_kvm_hv_apply(SpaprMachineState *spapr, error_setg(errp, "No Nested KVM-HV support in TCG"); error_append_hint(errp, "Try appending -machine cap-nested-hv=off\n"); } else if (kvm_enabled()) { + if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, + spapr->max_compat_pvr)) { + error_setg(errp, "Nested KVM-HV only supported on POWER9"); + error_append_hint(errp, + "Try appending -machine max-cpu-compat=power9\n"); + return; + } + if (!kvmppc_has_cap_nested_kvm_hv()) { error_setg(errp, "KVM implementation does not support Nested KVM-HV"); -- cgit v1.1 From 4b160fad4f6179fa7f8385f87f124cfce1f809d3 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Wed, 22 Jul 2020 19:43:54 -0400 Subject: ppc/xive: Fix some typos in comments Fix some typos in comments about code modeling coalescing points in the XIVE routing engine (IVRE). Signed-off-by: Gustavo Romero Message-Id: <1595461434-27725-1-git-send-email-gromero@linux.ibm.com> Signed-off-by: David Gibson --- hw/intc/xive.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 9a16243..9b55e03 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -1502,7 +1502,7 @@ static bool xive_presenter_notify(XiveFabric *xfb, uint8_t format, /* * Notification using the END ESe/ESn bit (Event State Buffer for - * escalation and notification). Profide futher coalescing in the + * escalation and notification). Provide further coalescing in the * Router. */ static bool xive_router_end_es_notify(XiveRouter *xrtr, uint8_t end_blk, @@ -1581,7 +1581,7 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk, /* * Check the END ESn (Event State Buffer for notification) for - * even futher coalescing in the Router + * even further coalescing in the Router */ if (!xive_end_is_notify(&end)) { /* ESn[Q]=1 : end of notification */ @@ -1660,7 +1660,7 @@ do_escalation: /* * Check the END ESe (Event State Buffer for escalation) for even - * futher coalescing in the Router + * further coalescing in the Router */ if (!xive_end_is_uncond_escalation(&end)) { /* ESe[Q]=1 : end of notification */ -- cgit v1.1 From c55bcb1f47071a134a4b96b4137cccca831ac5cf Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 5 Aug 2020 17:47:16 +0200 Subject: spapr: Clarify error and documentation for broken KVM XICS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When starting an L2 KVM guest with `ic-mode=dual,kernel-irqchip=on`, QEMU fails with: KVM is too old to support ic-mode=dual,kernel-irqchip=on This error message was introduced to detect older KVM versions that didn't allow destruction and re-creation of the XICS KVM device that we do at reboot. But it is actually the same issue that we get with nested guests : when running under pseries, KVM currently provides a genuine XICS device (not the XICS-on-XIVE device that we get under powernv) which doesn't support destruction/re-creation. This will eventually be fixed in KVM but in the meantime, update the error message and documentation to mention the nested case. While here, mention that in "No XIVE support in KVM" section that this can also happen with "guest OSes supporting XIVE" since we check this at init time before starting the guest. Reported-by: Satheesh Rajendran Buglink: https://bugs.launchpad.net/qemu/+bug/1890290 Signed-off-by: Greg Kurz Message-Id: <159664243614.622889.18307368735989783528.stgit@bahia.lan> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/spapr_irq.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 2f8f7d6..72bb938 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -139,6 +139,7 @@ SpaprIrq spapr_irq_dual = { static int spapr_irq_check(SpaprMachineState *spapr, Error **errp) { + ERRP_GUARD(); MachineState *machine = MACHINE(spapr); /* @@ -179,14 +180,19 @@ static int spapr_irq_check(SpaprMachineState *spapr, Error **errp) /* * On a POWER9 host, some older KVM XICS devices cannot be destroyed and - * re-created. Detect that early to avoid QEMU to exit later when the - * guest reboots. + * re-created. Same happens with KVM nested guests. Detect that early to + * avoid QEMU to exit later when the guest reboots. */ if (kvm_enabled() && spapr->irq == &spapr_irq_dual && kvm_kernel_irqchip_required() && xics_kvm_has_broken_disconnect(spapr)) { - error_setg(errp, "KVM is too old to support ic-mode=dual,kernel-irqchip=on"); + error_setg(errp, + "KVM is incompatible with ic-mode=dual,kernel-irqchip=on"); + error_append_hint(errp, + "This can happen with an old KVM or in a KVM nested guest.\n"); + error_append_hint(errp, + "Try without kernel-irqchip or with kernel-irqchip=off.\n"); return -1; } -- cgit v1.1 From 82f086b5e7ec0adff5a3972f74c446325b4fef9a Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 6 Aug 2020 18:56:05 +0200 Subject: spapr/xive: Fix xive->fd if kvm_create_device() fails If the creation of the KVM XIVE device fails for some reasons, the negative errno ends up in xive->fd, but the rest of the code assumes that xive->fd either contains an open fd, ie. positive value, or -1. This doesn't cause any misbehavior except kvmppc_xive_disconnect() that will try to close(xive->fd) during rollback and likely be rewarded with an EBADF. Only set xive->fd with a open fd. Signed-off-by: Greg Kurz Message-Id: <159673296585.766512.15404407281299745442.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index edb7ee0..d55ea46 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -745,6 +745,7 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers, size_t esb_len = (1ull << xsrc->esb_shift) * xsrc->nr_irqs; size_t tima_len = 4ull << TM_SHIFT; CPUState *cs; + int fd; /* * The KVM XIVE device already in use. This is the case when @@ -760,11 +761,12 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers, } /* First, create the KVM XIVE device */ - xive->fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_XIVE, false); - if (xive->fd < 0) { - error_setg_errno(errp, -xive->fd, "XIVE: error creating KVM device"); + fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_XIVE, false); + if (fd < 0) { + error_setg_errno(errp, -fd, "XIVE: error creating KVM device"); return -1; } + xive->fd = fd; /* Tell KVM about the # of VCPUs we may have */ if (kvm_device_check_attr(xive->fd, KVM_DEV_XIVE_GRP_CTRL, -- cgit v1.1 From e781139539f3d73ac00f2aea17f5a154b10e4302 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 6 Aug 2020 18:56:13 +0200 Subject: spapr/xive: Simplify kvmppc_xive_disconnect() Since this function begins with: /* The KVM XIVE device is not in use */ if (!xive || xive->fd == -1) { return; } we obviously don't need to check xive->fd again. Signed-off-by: Greg Kurz Message-Id: <159673297296.766512.14780055521619233656.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index d55ea46..893a1ee 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -873,10 +873,8 @@ void kvmppc_xive_disconnect(SpaprInterruptController *intc) * and removed from the list of devices of the VM. The VCPU * presenters are also detached from the device. */ - if (xive->fd != -1) { - close(xive->fd); - xive->fd = -1; - } + close(xive->fd); + xive->fd = -1; kvm_kernel_irqchip = false; kvm_msi_via_irqfd_allowed = false; -- cgit v1.1 From cf36e5b3760df0a1fdd38970294cf7b0968fcc5c Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 7 Aug 2020 13:32:06 +0200 Subject: ppc/xive: Rework setup of XiveSource::esb_mmio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Depending on whether XIVE is emultated or backed with a KVM XIVE device, the ESB MMIOs of a XIVE source point to an I/O memory region or a mapped memory region. This is currently handled by checking kvm_irqchip_in_kernel() returns false in xive_source_realize(). This is a bit awkward as we usually need to do extra things when we're using the in-kernel backend, not less. But most important, we can do better: turn the existing "xive.esb" memory region into a plain container, introduce an "xive.esb-emulated" I/O subregion and rename the existing "xive.esb" subregion in the KVM code to "xive.esb-kvm". Since "xive.esb-kvm" is added with overlap and a higher priority, it prevails over "xive.esb-emulated" (ie. a guest using KVM XIVE will interact with "xive.esb-kvm" instead of the default "xive.esb-emulated" region. While here, consolidate the computation of the MMIO region size in a common helper. Suggested-by: Cédric Le Goater Signed-off-by: Greg Kurz Message-Id: <159679992680.876294.7520540158586170894.stgit@bahia.lan> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 4 ++-- hw/intc/xive.c | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index 893a1ee..6130882 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -742,7 +742,7 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers, SpaprXive *xive = SPAPR_XIVE(intc); XiveSource *xsrc = &xive->source; Error *local_err = NULL; - size_t esb_len = (1ull << xsrc->esb_shift) * xsrc->nr_irqs; + size_t esb_len = xive_source_esb_len(xsrc); size_t tima_len = 4ull << TM_SHIFT; CPUState *cs; int fd; @@ -788,7 +788,7 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers, } memory_region_init_ram_device_ptr(&xsrc->esb_mmio_kvm, OBJECT(xsrc), - "xive.esb", esb_len, xsrc->esb_mmap); + "xive.esb-kvm", esb_len, xsrc->esb_mmap); memory_region_add_subregion_overlap(&xsrc->esb_mmio, 0, &xsrc->esb_mmio_kvm, 1); diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 9b55e03..561d746 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -1128,6 +1128,7 @@ static void xive_source_reset(void *dev) static void xive_source_realize(DeviceState *dev, Error **errp) { XiveSource *xsrc = XIVE_SOURCE(dev); + size_t esb_len = xive_source_esb_len(xsrc); assert(xsrc->xive); @@ -1147,11 +1148,11 @@ static void xive_source_realize(DeviceState *dev, Error **errp) xsrc->status = g_malloc0(xsrc->nr_irqs); xsrc->lsi_map = bitmap_new(xsrc->nr_irqs); - if (!kvm_irqchip_in_kernel()) { - memory_region_init_io(&xsrc->esb_mmio, OBJECT(xsrc), - &xive_source_esb_ops, xsrc, "xive.esb", - (1ull << xsrc->esb_shift) * xsrc->nr_irqs); - } + memory_region_init(&xsrc->esb_mmio, OBJECT(xsrc), "xive.esb", esb_len); + memory_region_init_io(&xsrc->esb_mmio_emulated, OBJECT(xsrc), + &xive_source_esb_ops, xsrc, "xive.esb-emulated", + esb_len); + memory_region_add_subregion(&xsrc->esb_mmio, 0, &xsrc->esb_mmio_emulated); qemu_register_reset(xive_source_reset, dev); } -- cgit v1.1 From e519cdd9bc02990bddd395656bdaec821c94c8fe Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 7 Aug 2020 13:32:14 +0200 Subject: ppc/xive: Introduce dedicated kvm_irqchip_in_kernel() wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calls to the KVM XIVE device are guarded by kvm_irqchip_in_kernel(). This ensures that QEMU won't try to use the device if KVM is disabled or if an in-kernel irqchip isn't required. When using ic-mode=dual with the pseries machine, we have two possible interrupt controllers: XIVE and XICS. The kvm_irqchip_in_kernel() helper will return true as soon as any of the KVM device is created. It might lure QEMU to think that the other one is also around, while it is not. This is exactly what happens with ic-mode=dual at machine init when claiming IRQ numbers, which must be done on all possible IRQ backends, eg. RTAS event sources or the PHB0 LSI table : only the KVM XICS device is active but we end up calling kvmppc_xive_source_reset_one() anyway, which fails. This doesn't cause any trouble because of another bug : kvmppc_xive_source_reset_one() lacks an error_setg() and callers don't see the failure. Most of the other kvmppc_xive_* functions have similar xive->fd checks to filter out the case when KVM XIVE isn't active. It might look safer to have idempotent functions but it doesn't really help to understand what's going on when debugging. Since we already have all the kvm_irqchip_in_kernel() in place, also have the callers to check xive->fd as well before calling KVM XIVE specific code. This is straight-forward for the spapr specific XIVE code. Some more care is needed for the platform agnostic XIVE code since it cannot access xive->fd directly. Introduce new in_kernel() methods in some base XIVE classes for this purpose and implement them only in spapr. In all cases, we still need to call kvm_irqchip_in_kernel() so that compilers can optimize the kvmppc_xive_* calls away when CONFIG_KVM isn't defined, thus avoiding the need for stubs. Signed-off-by: Greg Kurz Message-Id: <159679993438.876294.7285654331498605426.stgit@bahia.lan> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/intc/spapr_xive.c | 45 +++++++++++++++++++++++++++++++-------------- hw/intc/xive.c | 25 +++++++++++++++++++------ 2 files changed, 50 insertions(+), 20 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 89c8cd9..3c84f64 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -148,12 +148,19 @@ static void spapr_xive_end_pic_print_info(SpaprXive *xive, XiveEND *end, xive_end_queue_pic_print_info(end, 6, mon); } +/* + * kvm_irqchip_in_kernel() will cause the compiler to turn this + * info a nop if CONFIG_KVM isn't defined. + */ +#define spapr_xive_in_kernel(xive) \ + (kvm_irqchip_in_kernel() && (xive)->fd != -1) + void spapr_xive_pic_print_info(SpaprXive *xive, Monitor *mon) { XiveSource *xsrc = &xive->source; int i; - if (kvm_irqchip_in_kernel()) { + if (spapr_xive_in_kernel(xive)) { Error *local_err = NULL; kvmppc_xive_synchronize_state(xive, &local_err); @@ -507,8 +514,10 @@ static const VMStateDescription vmstate_spapr_xive_eas = { static int vmstate_spapr_xive_pre_save(void *opaque) { - if (kvm_irqchip_in_kernel()) { - return kvmppc_xive_pre_save(SPAPR_XIVE(opaque)); + SpaprXive *xive = SPAPR_XIVE(opaque); + + if (spapr_xive_in_kernel(xive)) { + return kvmppc_xive_pre_save(xive); } return 0; @@ -520,8 +529,10 @@ static int vmstate_spapr_xive_pre_save(void *opaque) */ static int spapr_xive_post_load(SpaprInterruptController *intc, int version_id) { - if (kvm_irqchip_in_kernel()) { - return kvmppc_xive_post_load(SPAPR_XIVE(intc), version_id); + SpaprXive *xive = SPAPR_XIVE(intc); + + if (spapr_xive_in_kernel(xive)) { + return kvmppc_xive_post_load(xive, version_id); } return 0; @@ -564,7 +575,7 @@ static int spapr_xive_claim_irq(SpaprInterruptController *intc, int lisn, xive_source_irq_set_lsi(xsrc, lisn); } - if (kvm_irqchip_in_kernel()) { + if (spapr_xive_in_kernel(xive)) { return kvmppc_xive_source_reset_one(xsrc, lisn, errp); } @@ -641,7 +652,7 @@ static void spapr_xive_set_irq(SpaprInterruptController *intc, int irq, int val) { SpaprXive *xive = SPAPR_XIVE(intc); - if (kvm_irqchip_in_kernel()) { + if (spapr_xive_in_kernel(xive)) { kvmppc_xive_source_set_irq(&xive->source, irq, val); } else { xive_source_set_irq(&xive->source, irq, val); @@ -749,11 +760,16 @@ static void spapr_xive_deactivate(SpaprInterruptController *intc) spapr_xive_mmio_set_enabled(xive, false); - if (kvm_irqchip_in_kernel()) { + if (spapr_xive_in_kernel(xive)) { kvmppc_xive_disconnect(intc); } } +static bool spapr_xive_in_kernel_xptr(const XivePresenter *xptr) +{ + return spapr_xive_in_kernel(SPAPR_XIVE(xptr)); +} + static void spapr_xive_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -788,6 +804,7 @@ static void spapr_xive_class_init(ObjectClass *klass, void *data) sicc->post_load = spapr_xive_post_load; xpc->match_nvt = spapr_xive_match_nvt; + xpc->in_kernel = spapr_xive_in_kernel_xptr; } static const TypeInfo spapr_xive_info = { @@ -1058,7 +1075,7 @@ static target_ulong h_int_set_source_config(PowerPCCPU *cpu, new_eas.w = xive_set_field64(EAS_END_DATA, new_eas.w, eisn); } - if (kvm_irqchip_in_kernel()) { + if (spapr_xive_in_kernel(xive)) { Error *local_err = NULL; kvmppc_xive_set_source_config(xive, lisn, &new_eas, &local_err); @@ -1379,7 +1396,7 @@ static target_ulong h_int_set_queue_config(PowerPCCPU *cpu, */ out: - if (kvm_irqchip_in_kernel()) { + if (spapr_xive_in_kernel(xive)) { Error *local_err = NULL; kvmppc_xive_set_queue_config(xive, end_blk, end_idx, &end, &local_err); @@ -1480,7 +1497,7 @@ static target_ulong h_int_get_queue_config(PowerPCCPU *cpu, args[2] = 0; } - if (kvm_irqchip_in_kernel()) { + if (spapr_xive_in_kernel(xive)) { Error *local_err = NULL; kvmppc_xive_get_queue_config(xive, end_blk, end_idx, end, &local_err); @@ -1642,7 +1659,7 @@ static target_ulong h_int_esb(PowerPCCPU *cpu, return H_P3; } - if (kvm_irqchip_in_kernel()) { + if (spapr_xive_in_kernel(xive)) { args[0] = kvmppc_xive_esb_rw(xsrc, lisn, offset, data, flags & SPAPR_XIVE_ESB_STORE); } else { @@ -1717,7 +1734,7 @@ static target_ulong h_int_sync(PowerPCCPU *cpu, * under KVM */ - if (kvm_irqchip_in_kernel()) { + if (spapr_xive_in_kernel(xive)) { Error *local_err = NULL; kvmppc_xive_sync_source(xive, lisn, &local_err); @@ -1761,7 +1778,7 @@ static target_ulong h_int_reset(PowerPCCPU *cpu, device_legacy_reset(DEVICE(xive)); - if (kvm_irqchip_in_kernel()) { + if (spapr_xive_in_kernel(xive)) { Error *local_err = NULL; kvmppc_xive_reset(xive, &local_err); diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 561d746..a453e8f 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -592,6 +592,17 @@ static const char * const xive_tctx_ring_names[] = { "USER", "OS", "POOL", "PHYS", }; +/* + * kvm_irqchip_in_kernel() will cause the compiler to turn this + * info a nop if CONFIG_KVM isn't defined. + */ +#define xive_in_kernel(xptr) \ + (kvm_irqchip_in_kernel() && \ + ({ \ + XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr); \ + xpc->in_kernel ? xpc->in_kernel(xptr) : false; \ + })) + void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon) { int cpu_index; @@ -606,7 +617,7 @@ void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon) cpu_index = tctx->cs ? tctx->cs->cpu_index : -1; - if (kvm_irqchip_in_kernel()) { + if (xive_in_kernel(tctx->xptr)) { Error *local_err = NULL; kvmppc_xive_cpu_synchronize_state(tctx, &local_err); @@ -671,7 +682,7 @@ static void xive_tctx_realize(DeviceState *dev, Error **errp) } /* Connect the presenter to the VCPU (required for CPU hotplug) */ - if (kvm_irqchip_in_kernel()) { + if (xive_in_kernel(tctx->xptr)) { kvmppc_xive_cpu_connect(tctx, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -682,10 +693,11 @@ static void xive_tctx_realize(DeviceState *dev, Error **errp) static int vmstate_xive_tctx_pre_save(void *opaque) { + XiveTCTX *tctx = XIVE_TCTX(opaque); Error *local_err = NULL; - if (kvm_irqchip_in_kernel()) { - kvmppc_xive_cpu_get_state(XIVE_TCTX(opaque), &local_err); + if (xive_in_kernel(tctx->xptr)) { + kvmppc_xive_cpu_get_state(tctx, &local_err); if (local_err) { error_report_err(local_err); return -1; @@ -697,14 +709,15 @@ static int vmstate_xive_tctx_pre_save(void *opaque) static int vmstate_xive_tctx_post_load(void *opaque, int version_id) { + XiveTCTX *tctx = XIVE_TCTX(opaque); Error *local_err = NULL; - if (kvm_irqchip_in_kernel()) { + if (xive_in_kernel(tctx->xptr)) { /* * Required for hotplugged CPU, for which the state comes * after all states of the machine. */ - kvmppc_xive_cpu_set_state(XIVE_TCTX(opaque), &local_err); + kvmppc_xive_cpu_set_state(tctx, &local_err); if (local_err) { error_report_err(local_err); return -1; -- cgit v1.1 From a4907119348d928e8b72e2d3b7566e50f272fa09 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 7 Aug 2020 13:32:21 +0200 Subject: spapr/xive: Convert KVM device fd checks to assert() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All callers guard these functions with an xive_in_kernel() helper. Make it clear that they are only to be called when the KVM XIVE device exists. Note that the check on xive is dropped in kvmppc_xive_disconnect(). It really cannot be NULL since it comes from set_active_intc() which only passes pointers to allocated objects. Signed-off-by: Greg Kurz Reviewed-by: David Gibson Message-Id: <159679994169.876294.11026653581505077112.stgit@bahia.lan> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index 6130882..82a6f99 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -79,10 +79,7 @@ void kvmppc_xive_cpu_set_state(XiveTCTX *tctx, Error **errp) uint64_t state[2]; int ret; - /* The KVM XIVE device is not in use yet */ - if (xive->fd == -1) { - return; - } + assert(xive->fd != -1); /* word0 and word1 of the OS ring. */ state[0] = *((uint64_t *) &tctx->regs[TM_QW1_OS]); @@ -101,10 +98,7 @@ void kvmppc_xive_cpu_get_state(XiveTCTX *tctx, Error **errp) uint64_t state[2] = { 0 }; int ret; - /* The KVM XIVE device is not in use */ - if (xive->fd == -1) { - return; - } + assert(xive->fd != -1); ret = kvm_get_one_reg(tctx->cs, KVM_REG_PPC_VP_STATE, state); if (ret != 0) { @@ -156,10 +150,7 @@ void kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp) unsigned long vcpu_id; int ret; - /* The KVM XIVE device is not in use */ - if (xive->fd == -1) { - return; - } + assert(xive->fd != -1); /* Check if CPU was hot unplugged and replugged. */ if (kvm_cpu_is_enabled(tctx->cs)) { @@ -245,10 +236,7 @@ int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp) SpaprXive *xive = SPAPR_XIVE(xsrc->xive); uint64_t state = 0; - /* The KVM XIVE device is not in use */ - if (xive->fd == -1) { - return -ENODEV; - } + assert(xive->fd != -1); if (xive_source_irq_is_lsi(xsrc, srcno)) { state |= KVM_XIVE_LEVEL_SENSITIVE; @@ -592,10 +580,7 @@ static void kvmppc_xive_change_state_handler(void *opaque, int running, void kvmppc_xive_synchronize_state(SpaprXive *xive, Error **errp) { - /* The KVM XIVE device is not in use */ - if (xive->fd == -1) { - return; - } + assert(xive->fd != -1); /* * When the VM is stopped, the sources are masked and the previous @@ -622,10 +607,7 @@ int kvmppc_xive_pre_save(SpaprXive *xive) { Error *local_err = NULL; - /* The KVM XIVE device is not in use */ - if (xive->fd == -1) { - return 0; - } + assert(xive->fd != -1); /* EAT: there is no extra state to query from KVM */ @@ -845,10 +827,7 @@ void kvmppc_xive_disconnect(SpaprInterruptController *intc) XiveSource *xsrc; size_t esb_len; - /* The KVM XIVE device is not in use */ - if (!xive || xive->fd == -1) { - return; - } + assert(xive->fd != -1); /* Clear the KVM mapping */ xsrc = &xive->source; -- cgit v1.1 From 4a6891b838e4914d25ab97a2a03f946e3c085a8f Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 10 Aug 2020 18:53:58 +0200 Subject: spapr: Simplify error handling in spapr_phb_realize() The spapr_phb_realize() function has a local_err variable which is used to: 1) check failures of spapr_irq_findone() and spapr_irq_claim() 2) prepend extra information to the error message Recent work from Markus Armbruster highlighted we get better code when testing the return value of a function, rather than setting up all the local_err boiler plate. For similar reasons, it is now preferred to use ERRP_GUARD() and error_prepend() rather than error_propagate_prepend(). Since spapr_irq_findone() and spapr_irq_claim() return negative values in case of failure, do both changes. This is just cleanup, no functional impact. Signed-off-by: Greg Kurz Reviewed-by: Markus Armbruster Reviewed-by: David Gibson Message-Id: <159707843851.1489912.6108405733810934642.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/ppc/spapr_pci.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'hw') diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 363cdb3..0a418f1 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1796,6 +1796,7 @@ static void spapr_phb_destroy_msi(gpointer opaque) static void spapr_phb_realize(DeviceState *dev, Error **errp) { + ERRP_GUARD(); /* We don't use SPAPR_MACHINE() in order to exit gracefully if the user * tries to add a sPAPR PHB to a non-pseries machine. */ @@ -1813,7 +1814,6 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) uint64_t msi_window_size = 4096; SpaprTceTable *tcet; const unsigned windows_supported = spapr_phb_windows_supported(sphb); - Error *local_err = NULL; if (!spapr) { error_setg(errp, TYPE_SPAPR_PCI_HOST_BRIDGE " needs a pseries machine"); @@ -1964,13 +1964,12 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) /* Initialize the LSI table */ for (i = 0; i < PCI_NUM_PINS; i++) { - uint32_t irq = SPAPR_IRQ_PCI_LSI + sphb->index * PCI_NUM_PINS + i; + int irq = SPAPR_IRQ_PCI_LSI + sphb->index * PCI_NUM_PINS + i; if (smc->legacy_irq_allocation) { - irq = spapr_irq_findone(spapr, &local_err); - if (local_err) { - error_propagate_prepend(errp, local_err, - "can't allocate LSIs: "); + irq = spapr_irq_findone(spapr, errp); + if (irq < 0) { + error_prepend(errp, "can't allocate LSIs: "); /* * Older machines will never support PHB hotplug, ie, this is an * init only path and QEMU will terminate. No need to rollback. @@ -1979,9 +1978,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) } } - spapr_irq_claim(spapr, irq, true, &local_err); - if (local_err) { - error_propagate_prepend(errp, local_err, "can't allocate LSIs: "); + if (spapr_irq_claim(spapr, irq, true, errp) < 0) { + error_prepend(errp, "can't allocate LSIs: "); goto unrealize; } -- cgit v1.1 From 3885ca66881f1d2568e169dcbf793fd493146d14 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 10 Aug 2020 18:54:05 +0200 Subject: spapr/xive: Rework error handling of kvmppc_xive_cpu_connect() Use error_setg_errno() instead of error_setg(strerror()). While here, use -ret instead of errno since kvm_vcpu_enable_cap() returns a negative errno on failure. Use ERRP_GUARD() to ensure that errp can be passed to error_append_hint(), and get rid of the local_err boilerplate. Propagate the return value so that callers may use it as well to check failures. Signed-off-by: Greg Kurz Message-Id: <159707844549.1489912.4862921680328017645.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index 82a6f99..aa1a2f9 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -144,8 +144,9 @@ void kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp) } } -void kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp) +int kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp) { + ERRP_GUARD(); SpaprXive *xive = SPAPR_XIVE(tctx->xptr); unsigned long vcpu_id; int ret; @@ -154,7 +155,7 @@ void kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp) /* Check if CPU was hot unplugged and replugged. */ if (kvm_cpu_is_enabled(tctx->cs)) { - return; + return 0; } vcpu_id = kvm_arch_vcpu_id(tctx->cs); @@ -162,20 +163,18 @@ void kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp) ret = kvm_vcpu_enable_cap(tctx->cs, KVM_CAP_PPC_IRQ_XIVE, 0, xive->fd, vcpu_id, 0); if (ret < 0) { - Error *local_err = NULL; - - error_setg(&local_err, - "XIVE: unable to connect CPU%ld to KVM device: %s", - vcpu_id, strerror(errno)); - if (errno == ENOSPC) { - error_append_hint(&local_err, "Try -smp maxcpus=N with N < %u\n", + error_setg_errno(errp, -ret, + "XIVE: unable to connect CPU%ld to KVM device", + vcpu_id); + if (ret == -ENOSPC) { + error_append_hint(errp, "Try -smp maxcpus=N with N < %u\n", MACHINE(qdev_get_machine())->smp.max_cpus); } - error_propagate(errp, local_err); - return; + return ret; } kvm_cpu_enable(tctx->cs); + return 0; } /* -- cgit v1.1 From 46407a2531da4ff206c1aefe8c3f6d8ad53f2de4 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 10 Aug 2020 18:54:12 +0200 Subject: spapr/xive: Rework error handling of kvmppc_xive_source_reset() Since kvmppc_xive_source_reset_one() has a return value, convert kvmppc_xive_source_reset() to use it for error checking. This allows to get rid of the local_err boiler plate. Propagate the return value so that callers may use it as well to check failures. Signed-off-by: Greg Kurz Message-Id: <159707845245.1489912.9151822670764690034.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index aa1a2f9..d801bf5 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -248,24 +248,25 @@ int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp) true, errp); } -static void kvmppc_xive_source_reset(XiveSource *xsrc, Error **errp) +static int kvmppc_xive_source_reset(XiveSource *xsrc, Error **errp) { SpaprXive *xive = SPAPR_XIVE(xsrc->xive); int i; for (i = 0; i < xsrc->nr_irqs; i++) { - Error *local_err = NULL; + int ret; if (!xive_eas_is_valid(&xive->eat[i])) { continue; } - kvmppc_xive_source_reset_one(xsrc, i, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + ret = kvmppc_xive_source_reset_one(xsrc, i, errp); + if (ret < 0) { + return ret; } } + + return 0; } /* -- cgit v1.1 From b14adb4a27c80a255fb35451d7cb2bc70743e7f4 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 10 Aug 2020 18:54:19 +0200 Subject: spapr/xive: Rework error handling of kvmppc_xive_mmap() Callers currently check failures of kvmppc_xive_mmap() through the @errp argument, which isn't a recommanded practice. It is preferred to use a return value when possible. Since NULL isn't an invalid address in theory, it seems better to return MAP_FAILED and to teach callers to handle it. Signed-off-by: Greg Kurz Message-Id: <159707845972.1489912.719896767746375765.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index d801bf5..b2a36fd 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -698,6 +698,7 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id) return 0; } +/* Returns MAP_FAILED on error and sets errno */ static void *kvmppc_xive_mmap(SpaprXive *xive, int pgoff, size_t len, Error **errp) { @@ -708,7 +709,6 @@ static void *kvmppc_xive_mmap(SpaprXive *xive, int pgoff, size_t len, pgoff << page_shift); if (addr == MAP_FAILED) { error_setg_errno(errp, errno, "XIVE: unable to set memory mapping"); - return NULL; } return addr; @@ -728,6 +728,7 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers, size_t tima_len = 4ull << TM_SHIFT; CPUState *cs; int fd; + void *addr; /* * The KVM XIVE device already in use. This is the case when @@ -763,11 +764,12 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers, /* * 1. Source ESB pages - KVM mapping */ - xsrc->esb_mmap = kvmppc_xive_mmap(xive, KVM_XIVE_ESB_PAGE_OFFSET, esb_len, - &local_err); - if (local_err) { + addr = kvmppc_xive_mmap(xive, KVM_XIVE_ESB_PAGE_OFFSET, esb_len, + &local_err); + if (addr == MAP_FAILED) { goto fail; } + xsrc->esb_mmap = addr; memory_region_init_ram_device_ptr(&xsrc->esb_mmio_kvm, OBJECT(xsrc), "xive.esb-kvm", esb_len, xsrc->esb_mmap); @@ -781,11 +783,13 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers, /* * 3. TIMA pages - KVM mapping */ - xive->tm_mmap = kvmppc_xive_mmap(xive, KVM_XIVE_TIMA_PAGE_OFFSET, tima_len, - &local_err); - if (local_err) { + addr = kvmppc_xive_mmap(xive, KVM_XIVE_TIMA_PAGE_OFFSET, tima_len, + &local_err); + if (addr == MAP_FAILED) { goto fail; } + xive->tm_mmap = addr; + memory_region_init_ram_device_ptr(&xive->tm_mmio_kvm, OBJECT(xive), "xive.tima", tima_len, xive->tm_mmap); memory_region_add_subregion_overlap(&xive->tm_mmio, 0, -- cgit v1.1 From 5fa36b7ffbcb2056249929a7b1ee4e30c07dc67c Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 10 Aug 2020 18:54:26 +0200 Subject: spapr/xive: Rework error handling of kvmppc_xive_cpu_[gs]et_state() kvm_set_one_reg() returns a negative errno on failure, use that instead of errno. Also propagate it to callers so they can use it to check for failures and hopefully get rid of their local_err boilerplate. Signed-off-by: Greg Kurz Message-Id: <159707846665.1489912.14267225652103441921.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index b2a36fd..5e088cc 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -73,7 +73,7 @@ static void kvm_cpu_disable_all(void) * XIVE Thread Interrupt Management context (KVM) */ -void kvmppc_xive_cpu_set_state(XiveTCTX *tctx, Error **errp) +int kvmppc_xive_cpu_set_state(XiveTCTX *tctx, Error **errp) { SpaprXive *xive = SPAPR_XIVE(tctx->xptr); uint64_t state[2]; @@ -86,13 +86,16 @@ void kvmppc_xive_cpu_set_state(XiveTCTX *tctx, Error **errp) ret = kvm_set_one_reg(tctx->cs, KVM_REG_PPC_VP_STATE, state); if (ret != 0) { - error_setg_errno(errp, errno, + error_setg_errno(errp, -ret, "XIVE: could not restore KVM state of CPU %ld", kvm_arch_vcpu_id(tctx->cs)); + return ret; } + + return 0; } -void kvmppc_xive_cpu_get_state(XiveTCTX *tctx, Error **errp) +int kvmppc_xive_cpu_get_state(XiveTCTX *tctx, Error **errp) { SpaprXive *xive = SPAPR_XIVE(tctx->xptr); uint64_t state[2] = { 0 }; @@ -102,14 +105,16 @@ void kvmppc_xive_cpu_get_state(XiveTCTX *tctx, Error **errp) ret = kvm_get_one_reg(tctx->cs, KVM_REG_PPC_VP_STATE, state); if (ret != 0) { - error_setg_errno(errp, errno, + error_setg_errno(errp, -ret, "XIVE: could not capture KVM state of CPU %ld", kvm_arch_vcpu_id(tctx->cs)); - return; + return ret; } /* word0 and word1 of the OS ring. */ *((uint64_t *) &tctx->regs[TM_QW1_OS]) = state[0]; + + return 0; } typedef struct { -- cgit v1.1 From f9a548edf2a54f59c37032dee3763f532e968fee Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 10 Aug 2020 18:54:33 +0200 Subject: spapr/xive: Rework error handling of kvmppc_xive_[gs]et_queue_config() Since kvm_device_access() returns a negative errno on failure, convert kvmppc_xive_get_queue_config() and kvmppc_xive_set_queue_config() to use it for error checking. This allows to get rid of the local_err boilerplate. Propagate the return value so that callers may use it as well to check failures. Signed-off-by: Greg Kurz Message-Id: <159707847357.1489912.2032291280645236480.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index 5e088cc..696623f 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -374,15 +374,15 @@ void kvmppc_xive_source_set_irq(void *opaque, int srcno, int val) /* * sPAPR XIVE interrupt controller (KVM) */ -void kvmppc_xive_get_queue_config(SpaprXive *xive, uint8_t end_blk, - uint32_t end_idx, XiveEND *end, - Error **errp) +int kvmppc_xive_get_queue_config(SpaprXive *xive, uint8_t end_blk, + uint32_t end_idx, XiveEND *end, + Error **errp) { struct kvm_ppc_xive_eq kvm_eq = { 0 }; uint64_t kvm_eq_idx; uint8_t priority; uint32_t server; - Error *local_err = NULL; + int ret; assert(xive_end_is_valid(end)); @@ -394,11 +394,10 @@ void kvmppc_xive_get_queue_config(SpaprXive *xive, uint8_t end_blk, kvm_eq_idx |= server << KVM_XIVE_EQ_SERVER_SHIFT & KVM_XIVE_EQ_SERVER_MASK; - kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_EQ_CONFIG, kvm_eq_idx, - &kvm_eq, false, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + ret = kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_EQ_CONFIG, kvm_eq_idx, + &kvm_eq, false, errp); + if (ret < 0) { + return ret; } /* @@ -408,17 +407,18 @@ void kvmppc_xive_get_queue_config(SpaprXive *xive, uint8_t end_blk, */ end->w1 = xive_set_field32(END_W1_GENERATION, 0ul, kvm_eq.qtoggle) | xive_set_field32(END_W1_PAGE_OFF, 0ul, kvm_eq.qindex); + + return 0; } -void kvmppc_xive_set_queue_config(SpaprXive *xive, uint8_t end_blk, - uint32_t end_idx, XiveEND *end, - Error **errp) +int kvmppc_xive_set_queue_config(SpaprXive *xive, uint8_t end_blk, + uint32_t end_idx, XiveEND *end, + Error **errp) { struct kvm_ppc_xive_eq kvm_eq = { 0 }; uint64_t kvm_eq_idx; uint8_t priority; uint32_t server; - Error *local_err = NULL; /* * Build the KVM state from the local END structure. @@ -456,12 +456,9 @@ void kvmppc_xive_set_queue_config(SpaprXive *xive, uint8_t end_blk, kvm_eq_idx |= server << KVM_XIVE_EQ_SERVER_SHIFT & KVM_XIVE_EQ_SERVER_MASK; - kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_EQ_CONFIG, kvm_eq_idx, - &kvm_eq, true, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + return + kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_EQ_CONFIG, kvm_eq_idx, + &kvm_eq, true, errp); } void kvmppc_xive_reset(SpaprXive *xive, Error **errp) -- cgit v1.1 From d53482a73bba983f521d6b9652e6f68e856ab794 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 10 Aug 2020 18:54:40 +0200 Subject: spapr/xive: Rework error handling in kvmppc_xive_get_queues() Since kvmppc_xive_get_queue_config() has a return value, convert kvmppc_xive_get_queues() to use it for error checking. This allows to get rid of the local_err boiler plate. Propagate the return value so that callers may use it as well to check failures. Signed-off-by: Greg Kurz Message-Id: <159707848069.1489912.14879208798696134531.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index 696623f..4142aaf 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -467,23 +467,24 @@ void kvmppc_xive_reset(SpaprXive *xive, Error **errp) NULL, true, errp); } -static void kvmppc_xive_get_queues(SpaprXive *xive, Error **errp) +static int kvmppc_xive_get_queues(SpaprXive *xive, Error **errp) { - Error *local_err = NULL; int i; + int ret; for (i = 0; i < xive->nr_ends; i++) { if (!xive_end_is_valid(&xive->endt[i])) { continue; } - kvmppc_xive_get_queue_config(xive, SPAPR_XIVE_BLOCK_ID, i, - &xive->endt[i], &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + ret = kvmppc_xive_get_queue_config(xive, SPAPR_XIVE_BLOCK_ID, i, + &xive->endt[i], errp); + if (ret < 0) { + return ret; } } + + return 0; } /* -- cgit v1.1 From d55daadcb801f309556fdbab00b2653d20e26603 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 10 Aug 2020 18:54:47 +0200 Subject: spapr/xive: Rework error handling of kvmppc_xive_set_source_config() Since kvm_device_access() returns a negative errno on failure, convert kvmppc_xive_set_source_config() to use it for error checking. This allows to get rid of the local_err boilerplate. Propagate the return value so that callers may use it as well to check failures. Signed-off-by: Greg Kurz Message-Id: <159707848764.1489912.17078842252160674523.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index 4142aaf..f2dda69 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -186,8 +186,8 @@ int kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp) * XIVE Interrupt Source (KVM) */ -void kvmppc_xive_set_source_config(SpaprXive *xive, uint32_t lisn, XiveEAS *eas, - Error **errp) +int kvmppc_xive_set_source_config(SpaprXive *xive, uint32_t lisn, XiveEAS *eas, + Error **errp) { uint32_t end_idx; uint32_t end_blk; @@ -196,7 +196,6 @@ void kvmppc_xive_set_source_config(SpaprXive *xive, uint32_t lisn, XiveEAS *eas, bool masked; uint32_t eisn; uint64_t kvm_src; - Error *local_err = NULL; assert(xive_eas_is_valid(eas)); @@ -216,12 +215,8 @@ void kvmppc_xive_set_source_config(SpaprXive *xive, uint32_t lisn, XiveEAS *eas, kvm_src |= ((uint64_t)eisn << KVM_XIVE_SOURCE_EISN_SHIFT) & KVM_XIVE_SOURCE_EISN_MASK; - kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SOURCE_CONFIG, lisn, - &kvm_src, true, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + return kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SOURCE_CONFIG, lisn, + &kvm_src, true, errp); } void kvmppc_xive_sync_source(SpaprXive *xive, uint32_t lisn, Error **errp) -- cgit v1.1 From 42a92d925d03ec49dfdefb43c15b46c3ca55f9e4 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 10 Aug 2020 18:54:54 +0200 Subject: spapr/kvm: Fix error handling in kvmppc_xive_pre_save() Now that kvmppc_xive_get_queues() returns a negative errno on failure, check with that because it is preferred to local_err. And most of all, propagate it because vmstate expects negative errnos. Signed-off-by: Greg Kurz Message-Id: <159707849455.1489912.6034461176847728064.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index f2dda69..1686b03 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -604,16 +604,17 @@ void kvmppc_xive_synchronize_state(SpaprXive *xive, Error **errp) int kvmppc_xive_pre_save(SpaprXive *xive) { Error *local_err = NULL; + int ret; assert(xive->fd != -1); /* EAT: there is no extra state to query from KVM */ /* ENDT */ - kvmppc_xive_get_queues(xive, &local_err); - if (local_err) { + ret = kvmppc_xive_get_queues(xive, &local_err); + if (ret < 0) { error_report_err(local_err); - return -1; + return ret; } return 0; -- cgit v1.1 From a845a54cbe0f197b833921b2af13fee88bb8240d Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 10 Aug 2020 18:55:01 +0200 Subject: spapr/xive: Fix error handling in kvmppc_xive_post_load() Now that all these functions return a negative errno on failure, check that because it is preferred to local_err. And most of all, propagate it because vmstate expects negative errnos. Signed-off-by: Greg Kurz Message-Id: <159707850148.1489912.18355118622296682631.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index 1686b03..005729e 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -631,6 +631,7 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id) Error *local_err = NULL; CPUState *cs; int i; + int ret; /* The KVM XIVE device should be in use */ assert(xive->fd != -1); @@ -641,11 +642,10 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id) continue; } - kvmppc_xive_set_queue_config(xive, SPAPR_XIVE_BLOCK_ID, i, - &xive->endt[i], &local_err); - if (local_err) { - error_report_err(local_err); - return -1; + ret = kvmppc_xive_set_queue_config(xive, SPAPR_XIVE_BLOCK_ID, i, + &xive->endt[i], &local_err); + if (ret < 0) { + goto fail; } } @@ -660,16 +660,14 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id) * previously set in KVM. Since we don't do that for all interrupts * at reset time anymore, let's do it now. */ - kvmppc_xive_source_reset_one(&xive->source, i, &local_err); - if (local_err) { - error_report_err(local_err); - return -1; + ret = kvmppc_xive_source_reset_one(&xive->source, i, &local_err); + if (ret < 0) { + goto fail; } - kvmppc_xive_set_source_config(xive, i, &xive->eat[i], &local_err); - if (local_err) { - error_report_err(local_err); - return -1; + ret = kvmppc_xive_set_source_config(xive, i, &xive->eat[i], &local_err); + if (ret < 0) { + goto fail; } } @@ -686,15 +684,18 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id) CPU_FOREACH(cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); - kvmppc_xive_cpu_set_state(spapr_cpu_state(cpu)->tctx, &local_err); - if (local_err) { - error_report_err(local_err); - return -1; + ret = kvmppc_xive_cpu_set_state(spapr_cpu_state(cpu)->tctx, &local_err); + if (ret < 0) { + goto fail; } } /* The source states will be restored when the machine starts running */ return 0; + +fail: + error_report_err(local_err); + return ret; } /* Returns MAP_FAILED on error and sets errno */ -- cgit v1.1 From 2a8100cb61959e7a934049f2bd3a49a0f84a066b Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 10 Aug 2020 18:55:08 +0200 Subject: ppc/xive: Fix error handling in vmstate_xive_tctx_*() callbacks Now that kvmppc_xive_cpu_get_state() and kvmppc_xive_cpu_set_state() return negative errnos on failures, use that instead local_err because it is the recommended practice. Also return that instead of -1 since vmstate expects negative errnos. Signed-off-by: Greg Kurz Message-Id: <159707850840.1489912.14912810818646455474.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/xive.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/intc/xive.c b/hw/intc/xive.c index a453e8f..17ca5a1 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -695,12 +695,13 @@ static int vmstate_xive_tctx_pre_save(void *opaque) { XiveTCTX *tctx = XIVE_TCTX(opaque); Error *local_err = NULL; + int ret; if (xive_in_kernel(tctx->xptr)) { - kvmppc_xive_cpu_get_state(tctx, &local_err); - if (local_err) { + ret = kvmppc_xive_cpu_get_state(tctx, &local_err); + if (ret < 0) { error_report_err(local_err); - return -1; + return ret; } } @@ -711,16 +712,17 @@ static int vmstate_xive_tctx_post_load(void *opaque, int version_id) { XiveTCTX *tctx = XIVE_TCTX(opaque); Error *local_err = NULL; + int ret; if (xive_in_kernel(tctx->xptr)) { /* * Required for hotplugged CPU, for which the state comes * after all states of the machine. */ - kvmppc_xive_cpu_set_state(tctx, &local_err); - if (local_err) { + ret = kvmppc_xive_cpu_set_state(tctx, &local_err); + if (ret < 0) { error_report_err(local_err); - return -1; + return ret; } } -- cgit v1.1 From 6cdc0e20631faf781047b515215208660393c9a9 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 10 Aug 2020 18:55:15 +0200 Subject: spapr/xive: Simplify error handling in kvmppc_xive_connect() Now that all these functions return a negative errno on failure, check that and get rid of the local_err boilerplate. Signed-off-by: Greg Kurz Message-Id: <159707851537.1489912.1030839306195472651.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index 005729e..e9a3611 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -723,12 +723,12 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers, { SpaprXive *xive = SPAPR_XIVE(intc); XiveSource *xsrc = &xive->source; - Error *local_err = NULL; size_t esb_len = xive_source_esb_len(xsrc); size_t tima_len = 4ull << TM_SHIFT; CPUState *cs; int fd; void *addr; + int ret; /* * The KVM XIVE device already in use. This is the case when @@ -754,9 +754,10 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers, /* Tell KVM about the # of VCPUs we may have */ if (kvm_device_check_attr(xive->fd, KVM_DEV_XIVE_GRP_CTRL, KVM_DEV_XIVE_NR_SERVERS)) { - if (kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_CTRL, - KVM_DEV_XIVE_NR_SERVERS, &nr_servers, true, - &local_err)) { + ret = kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_CTRL, + KVM_DEV_XIVE_NR_SERVERS, &nr_servers, true, + errp); + if (ret < 0) { goto fail; } } @@ -764,8 +765,7 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers, /* * 1. Source ESB pages - KVM mapping */ - addr = kvmppc_xive_mmap(xive, KVM_XIVE_ESB_PAGE_OFFSET, esb_len, - &local_err); + addr = kvmppc_xive_mmap(xive, KVM_XIVE_ESB_PAGE_OFFSET, esb_len, errp); if (addr == MAP_FAILED) { goto fail; } @@ -783,8 +783,7 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers, /* * 3. TIMA pages - KVM mapping */ - addr = kvmppc_xive_mmap(xive, KVM_XIVE_TIMA_PAGE_OFFSET, tima_len, - &local_err); + addr = kvmppc_xive_mmap(xive, KVM_XIVE_TIMA_PAGE_OFFSET, tima_len, errp); if (addr == MAP_FAILED) { goto fail; } @@ -802,15 +801,15 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers, CPU_FOREACH(cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); - kvmppc_xive_cpu_connect(spapr_cpu_state(cpu)->tctx, &local_err); - if (local_err) { + ret = kvmppc_xive_cpu_connect(spapr_cpu_state(cpu)->tctx, errp); + if (ret < 0) { goto fail; } } /* Update the KVM sources */ - kvmppc_xive_source_reset(xsrc, &local_err); - if (local_err) { + ret = kvmppc_xive_source_reset(xsrc, errp); + if (ret < 0) { goto fail; } @@ -820,7 +819,6 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers, return 0; fail: - error_propagate(errp, local_err); kvmppc_xive_disconnect(intc); return -1; } -- cgit v1.1 From 61203f2b356f8aa7b6cfd3f792cd1f0cc7bdf99b Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 10 Aug 2020 18:55:22 +0200 Subject: ppc/xive: Simplify error handling in xive_tctx_realize() Now that kvmppc_xive_cpu_connect() returns a negative errno on failure, use that and get rid of the local_err boilerplate. Signed-off-by: Greg Kurz Message-Id: <159707852234.1489912.16410314514265848075.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/xive.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 17ca5a1..489e625 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -662,7 +662,6 @@ static void xive_tctx_realize(DeviceState *dev, Error **errp) XiveTCTX *tctx = XIVE_TCTX(dev); PowerPCCPU *cpu; CPUPPCState *env; - Error *local_err = NULL; assert(tctx->cs); assert(tctx->xptr); @@ -683,9 +682,7 @@ static void xive_tctx_realize(DeviceState *dev, Error **errp) /* Connect the presenter to the VCPU (required for CPU hotplug) */ if (xive_in_kernel(tctx->xptr)) { - kvmppc_xive_cpu_connect(tctx, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (kvmppc_xive_cpu_connect(tctx, errp) < 0) { return; } } -- cgit v1.1 From 1118b6b72719ff83f2be1efc11d7248cf225074c Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 10 Aug 2020 18:55:29 +0200 Subject: spapr/xive: Simplify error handling of kvmppc_xive_cpu_synchronize_state() Now that kvmppc_xive_cpu_get_state() returns negative on error, use that and get rid of the temporary Error object and error_propagate(). Signed-off-by: Greg Kurz Message-Id: <159707852916.1489912.8376334685349668124.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index e9a3611..d871bb1 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -119,7 +119,8 @@ int kvmppc_xive_cpu_get_state(XiveTCTX *tctx, Error **errp) typedef struct { XiveTCTX *tctx; - Error *err; + Error **errp; + int ret; } XiveCpuGetState; static void kvmppc_xive_cpu_do_synchronize_state(CPUState *cpu, @@ -127,14 +128,14 @@ static void kvmppc_xive_cpu_do_synchronize_state(CPUState *cpu, { XiveCpuGetState *s = arg.host_ptr; - kvmppc_xive_cpu_get_state(s->tctx, &s->err); + s->ret = kvmppc_xive_cpu_get_state(s->tctx, s->errp); } -void kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp) +int kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp) { XiveCpuGetState s = { .tctx = tctx, - .err = NULL, + .errp = errp, }; /* @@ -143,10 +144,7 @@ void kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp) run_on_cpu(tctx->cs, kvmppc_xive_cpu_do_synchronize_state, RUN_ON_CPU_HOST_PTR(&s)); - if (s.err) { - error_propagate(errp, s.err); - return; - } + return s.ret; } int kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp) -- cgit v1.1 From 37035df51eaabb8d26b71da75b88a1c6727de8fa Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 14 Aug 2020 01:12:19 +0200 Subject: nvram: Exit QEMU if NVRAM cannot contain all -prom-env data Since commit 61f20b9dc5b7 ("spapr_nvram: Pre-initialize the NVRAM to support the -prom-env parameter"), pseries machines can pre-initialize the "system" partition in the NVRAM with the data passed to all -prom-env parameters on the QEMU command line. In this case it is assumed that all the data fits in 64 KiB, but the user can easily pass more and crash QEMU: $ qemu-system-ppc64 -M pseries $(for ((x=0;x<128;x++)); do \ echo -n " -prom-env " ; printf "%0.sx" {1..1024}; \ done) # this requires ~128 Kib malloc(): corrupted top size Aborted (core dumped) This happens because we don't check if all the prom-env data fits in the NVRAM and chrp_nvram_set_var() happily memcpy() it passed the buffer. This crash affects basically all ppc/ppc64 machine types that use -prom-env: - pseries (all versions) - g3beige - mac99 and also sparc/sparc64 machine types: - LX - SPARCClassic - SPARCbook - SS-10 - SS-20 - SS-4 - SS-5 - SS-600MP - Voyager - sun4u - sun4v Add a max_len argument to chrp_nvram_create_system_partition() so that it can check the available size before writing to memory. Since NVRAM is populated at machine init, it seems reasonable to consider this error as fatal. So, instead of reporting an error when we detect that the NVRAM is too small and adapt all machine types to handle it, we simply exit QEMU in all cases. This is still better than crashing. If someone wants another behavior, I guess this can be reworked later. Tested with: $ yes q | \ (for arch in ppc ppc64 sparc sparc64; do \ echo == $arch ==; \ qemu=${arch}-softmmu/qemu-system-$arch; \ for mach in $($qemu -M help | awk '! /^Supported/ { print $1 }'); do \ echo $mach; \ $qemu -M $mach -monitor stdio -nodefaults -nographic \ $(for ((x=0;x<128;x++)); do \ echo -n " -prom-env " ; printf "%0.sx" {1..1024}; \ done) >/dev/null; \ done; echo; \ done) Without the patch, affected machine types cause QEMU to report some memory corruption and crash: malloc(): corrupted top size free(): invalid size *** stack smashing detected ***: terminated With the patch, QEMU prints the following message and exits: NVRAM is too small. Try to pass less data to -prom-env It seems that the conditions for the crash have always existed, but it affects pseries, the machine type I care for, since commit 61f20b9dc5b7 only. Fixes: 61f20b9dc5b7 ("spapr_nvram: Pre-initialize the NVRAM to support the -prom-env parameter") RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1867739 Reported-by: John Snow Reviewed-by: Laurent Vivier Signed-off-by: Greg Kurz Message-Id: <159736033937.350502.12402444542194031035.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/nvram/chrp_nvram.c | 24 +++++++++++++++++++++--- hw/nvram/mac_nvram.c | 2 +- hw/nvram/spapr_nvram.c | 3 ++- hw/sparc/sun4m.c | 2 +- hw/sparc64/sun4u.c | 2 +- 5 files changed, 26 insertions(+), 7 deletions(-) (limited to 'hw') diff --git a/hw/nvram/chrp_nvram.c b/hw/nvram/chrp_nvram.c index d969f26..d4d10a7 100644 --- a/hw/nvram/chrp_nvram.c +++ b/hw/nvram/chrp_nvram.c @@ -21,14 +21,21 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" +#include "qemu/error-report.h" #include "hw/nvram/chrp_nvram.h" #include "sysemu/sysemu.h" -static int chrp_nvram_set_var(uint8_t *nvram, int addr, const char *str) +static int chrp_nvram_set_var(uint8_t *nvram, int addr, const char *str, + int max_len) { int len; len = strlen(str) + 1; + + if (max_len < len) { + return -1; + } + memcpy(&nvram[addr], str, len); return addr + len; @@ -38,19 +45,26 @@ static int chrp_nvram_set_var(uint8_t *nvram, int addr, const char *str) * Create a "system partition", used for the Open Firmware * environment variables. */ -int chrp_nvram_create_system_partition(uint8_t *data, int min_len) +int chrp_nvram_create_system_partition(uint8_t *data, int min_len, int max_len) { ChrpNvramPartHdr *part_header; unsigned int i; int end; + if (max_len < sizeof(*part_header)) { + goto fail; + } + part_header = (ChrpNvramPartHdr *)data; part_header->signature = CHRP_NVPART_SYSTEM; pstrcpy(part_header->name, sizeof(part_header->name), "system"); end = sizeof(ChrpNvramPartHdr); for (i = 0; i < nb_prom_envs; i++) { - end = chrp_nvram_set_var(data, end, prom_envs[i]); + end = chrp_nvram_set_var(data, end, prom_envs[i], max_len - end); + if (end == -1) { + goto fail; + } } /* End marker */ @@ -65,6 +79,10 @@ int chrp_nvram_create_system_partition(uint8_t *data, int min_len) chrp_nvram_finish_partition(part_header, end); return end; + +fail: + error_report("NVRAM is too small. Try to pass less data to -prom-env"); + exit(EXIT_FAILURE); } /** diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c index beec1c4..11f2d31 100644 --- a/hw/nvram/mac_nvram.c +++ b/hw/nvram/mac_nvram.c @@ -141,7 +141,7 @@ static void pmac_format_nvram_partition_of(MacIONVRAMState *nvr, int off, /* OpenBIOS nvram variables partition */ sysp_end = chrp_nvram_create_system_partition(&nvr->data[off], - DEF_SYSTEM_SIZE) + off; + DEF_SYSTEM_SIZE, len) + off; /* Free space partition */ chrp_nvram_create_free_partition(&nvr->data[sysp_end], len - sysp_end); diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c index 15d0828..3865134 100644 --- a/hw/nvram/spapr_nvram.c +++ b/hw/nvram/spapr_nvram.c @@ -188,7 +188,8 @@ static void spapr_nvram_realize(SpaprVioDevice *dev, Error **errp) } } else if (nb_prom_envs > 0) { /* Create a system partition to pass the -prom-env variables */ - chrp_nvram_create_system_partition(nvram->buf, MIN_NVRAM_SIZE / 4); + chrp_nvram_create_system_partition(nvram->buf, MIN_NVRAM_SIZE / 4, + nvram->size); chrp_nvram_create_free_partition(&nvram->buf[MIN_NVRAM_SIZE / 4], nvram->size - MIN_NVRAM_SIZE / 4); } diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 9be9304..cf7dfa4 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -143,7 +143,7 @@ static void nvram_init(Nvram *nvram, uint8_t *macaddr, memset(image, '\0', sizeof(image)); /* OpenBIOS nvram variables partition */ - sysp_end = chrp_nvram_create_system_partition(image, 0); + sysp_end = chrp_nvram_create_system_partition(image, 0, 0x1fd0); /* Free space partition */ chrp_nvram_create_free_partition(&image[sysp_end], 0x1fd0 - sysp_end); diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 9e30203..37310b7 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -136,7 +136,7 @@ static int sun4u_NVRAM_set_params(Nvram *nvram, uint16_t NVRAM_size, memset(image, '\0', sizeof(image)); /* OpenBIOS nvram variables partition */ - sysp_end = chrp_nvram_create_system_partition(image, 0); + sysp_end = chrp_nvram_create_system_partition(image, 0, 0x1fd0); /* Free space partition */ chrp_nvram_create_free_partition(&image[sysp_end], 0x1fd0 - sysp_end); -- cgit v1.1 From 3110f0ee19ccdb50adff3dfa1321039f69efddcd Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 13 Aug 2020 19:28:10 +0200 Subject: spapr/xive: Use xive_source_esb_len() static inline size_t xive_source_esb_len(XiveSource *xsrc) { return (1ull << xsrc->esb_shift) * xsrc->nr_irqs; } Signed-off-by: Greg Kurz Message-Id: <159733969034.320580.6571451425779179477.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/intc/spapr_xive.c | 2 +- hw/intc/spapr_xive_kvm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 3c84f64..4bd0d60 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -336,7 +336,7 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(xive), &end_xsrc->esb_mmio); /* Set the mapping address of the END ESB pages after the source ESBs */ - xive->end_base = xive->vc_base + (1ull << xsrc->esb_shift) * xsrc->nr_irqs; + xive->end_base = xive->vc_base + xive_source_esb_len(xsrc); /* * Allocate the routing tables diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index d871bb1..e8667ce 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -831,7 +831,7 @@ void kvmppc_xive_disconnect(SpaprInterruptController *intc) /* Clear the KVM mapping */ xsrc = &xive->source; - esb_len = (1ull << xsrc->esb_shift) * xsrc->nr_irqs; + esb_len = xive_source_esb_len(xsrc); if (xsrc->esb_mmap) { memory_region_del_subregion(&xsrc->esb_mmio, &xsrc->esb_mmio_kvm); -- cgit v1.1