:p
atchew
Login
Hi; this is a collection of mostly GIC related patches for rc3. The "Update cached state after LPI state changes" fix is important and fixes what would otherwise be a regression since we enable the ITS by default in the virt board now. The others are not regressions but I think are OK for rc3 as they're fairly self contained (and two of them are fixes to new-in-6.2 functionality). thanks -- PMM The following changes since commit dd4b0de45965538f19bb40c7ddaaba384a8c613a: Fix version for v6.2.0-rc2 release (2021-11-26 11:58:54 +0100) are available in the Git repository at: https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20211129 for you to fetch changes up to 90feffad2aafe856ed2af75313b2c1669ba671e9: hw/intc/arm_gicv3: fix handling of LPIs in list registers (2021-11-29 10:10:21 +0000) ---------------------------------------------------------------- target-arm queue: * virt: Diagnose attempts to enable MTE or virt when using HVF accelerator * GICv3 ITS: Allow clearing of ITS CTLR Enabled bit * GICv3: Update cached state after LPI state changes * GICv3: Fix handling of LPIs in list registers ---------------------------------------------------------------- Alexander Graf (1): hw/arm/virt: Extend nested and mte checks to hvf Peter Maydell (3): hw/intc/arm_gicv3: Update cached state after LPI state changes hw/intc/arm_gicv3: Add new gicv3_intid_is_special() function hw/intc/arm_gicv3: fix handling of LPIs in list registers Shashi Mallela (1): hw/intc: cannot clear GICv3 ITS CTLR[Enabled] bit hw/intc/gicv3_internal.h | 30 ++++++++++++++++++++++++++++++ hw/arm/virt.c | 15 +++++++++------ hw/intc/arm_gicv3.c | 6 ++++-- hw/intc/arm_gicv3_cpuif.c | 9 ++++----- hw/intc/arm_gicv3_its.c | 7 ++++--- hw/intc/arm_gicv3_redist.c | 14 ++++++++++---- 6 files changed, 61 insertions(+), 20 deletions(-)
From: Alexander Graf <agraf@csgraf.de> The virt machine has properties to enable MTE and Nested Virtualization support. However, its check to ensure the backing accel implementation supports it today only looks for KVM and bails out if it finds it. Extend the checks to HVF as well as it does not support either today. This will cause QEMU to print a useful error message rather than silently ignoring the attempt by the user to enable either MTE or the Virtualization extensions. Reported-by: saar amar <saaramar5@gmail.com> Signed-off-by: Alexander Graf <agraf@csgraf.de> Message-id: 20211123122859.22452-1-agraf@csgraf.de Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/virt.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -XXX,XX +XXX,XX @@ #include "sysemu/runstate.h" #include "sysemu/tpm.h" #include "sysemu/kvm.h" +#include "sysemu/hvf.h" #include "hw/loader.h" #include "qapi/error.h" #include "qemu/bitops.h" @@ -XXX,XX +XXX,XX @@ static void machvirt_init(MachineState *machine) exit(1); } - if (vms->virt && kvm_enabled()) { - error_report("mach-virt: KVM does not support providing " - "Virtualization extensions to the guest CPU"); + if (vms->virt && (kvm_enabled() || hvf_enabled())) { + error_report("mach-virt: %s does not support providing " + "Virtualization extensions to the guest CPU", + kvm_enabled() ? "KVM" : "HVF"); exit(1); } - if (vms->mte && kvm_enabled()) { - error_report("mach-virt: KVM does not support providing " - "MTE to the guest CPU"); + if (vms->mte && (kvm_enabled() || hvf_enabled())) { + error_report("mach-virt: %s does not support providing " + "MTE to the guest CPU", + kvm_enabled() ? "KVM" : "HVF"); exit(1); } -- 2.25.1
From: Shashi Mallela <shashi.mallela@linaro.org> When Enabled bit is cleared in GITS_CTLR,ITS feature continues to be enabled.This patch fixes the issue. Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org> Tested-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20211124182246.67691-1-shashi.mallela@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/intc/arm_gicv3_its.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/arm_gicv3_its.c +++ b/hw/intc/arm_gicv3_its.c @@ -XXX,XX +XXX,XX @@ static bool its_writel(GICv3ITSState *s, hwaddr offset, switch (offset) { case GITS_CTLR: - s->ctlr |= (value & ~(s->ctlr)); - - if (s->ctlr & ITS_CTLR_ENABLED) { + if (value & R_GITS_CTLR_ENABLED_MASK) { + s->ctlr |= ITS_CTLR_ENABLED; extract_table_params(s); extract_cmdq_params(s); s->creadr = 0; process_cmdq(s); + } else { + s->ctlr &= ~ITS_CTLR_ENABLED; } break; case GITS_CBASER: -- 2.25.1
The logic of gicv3_redist_update() is as follows: * it must be called in any code path that changes the state of (only) redistributor interrupts * if it finds a redistributor interrupt that is (now) higher priority than the previous highest-priority pending interrupt, then this must be the new highest-priority pending interrupt * if it does *not* find a better redistributor interrupt, then: - if the previous state was "no interrupts pending" then the new state is still "no interrupts pending" - if the previous best interrupt was not a redistributor interrupt then that remains the best interrupt - if the previous best interrupt *was* a redistributor interrupt, then the new best interrupt must be some non-redistributor interrupt, but we don't know which so must do a full scan In commit 17fb5e36aabd4b2c125 we effectively added the LPI interrupts as a kind of "redistributor interrupt" for this purpose, by adding cs->hpplpi to the set of things that gicv3_redist_update() considers before it gives up and decides to do a full scan of distributor interrupts. However we didn't quite get this right: * the condition check for "was the previous best interrupt a redistributor interrupt" must be updated to include LPIs in what it considers to be redistributor interrupts * every code path which updates the LPI state which gicv3_redist_update() checks must also call gicv3_redist_update(): this is cs->hpplpi and the GICR_CTLR ENABLE_LPIS bit This commit fixes this by: * correcting the test on cs->hppi.irq in gicv3_redist_update() * making gicv3_redist_update_lpi() always call gicv3_redist_update() * introducing a new gicv3_redist_update_lpi_only() for the one callsite (the post-load hook) which must not call gicv3_redist_update() * making gicv3_redist_lpi_pending() always call gicv3_redist_update(), either directly or via gicv3_redist_update_lpi() * removing a couple of now-unnecessary calls to gicv3_redist_update() from some callers of those two functions * calling gicv3_redist_update() when the GICR_CTLR ENABLE_LPIS bit is cleared (This means that the not-file-local gicv3_redist_* LPI related functions now all take care of the updates of internally cached GICv3 information, in the same way the older functions gicv3_redist_set_irq() and gicv3_redist_send_sgi() do.) The visible effect of this bug was that when the guest acknowledged an LPI by reading ICC_IAR1_EL1, we marked it as not pending in the LPI data structure but still left it in cs->hppi so we would offer it to the guest again. In particular for setups using an emulated GICv3 and ITS and using devices which use LPIs (ie PCI devices) a Linux guest would complain "irq 54: nobody cared" and then hang. (The hang was intermittent, presumably depending on the timing between different interrupts arriving and being completed.) Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Tested-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20211124202005.989935-1-peter.maydell@linaro.org --- hw/intc/gicv3_internal.h | 17 +++++++++++++++++ hw/intc/arm_gicv3.c | 6 ++++-- hw/intc/arm_gicv3_redist.c | 14 ++++++++++---- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/gicv3_internal.h +++ b/hw/intc/gicv3_internal.h @@ -XXX,XX +XXX,XX @@ void gicv3_dist_set_irq(GICv3State *s, int irq, int level); void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level); void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level); void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level); +/** + * gicv3_redist_update_lpi: + * @cs: GICv3CPUState + * + * Scan the LPI pending table and recalculate the highest priority + * pending LPI and also the overall highest priority pending interrupt. + */ void gicv3_redist_update_lpi(GICv3CPUState *cs); +/** + * gicv3_redist_update_lpi_only: + * @cs: GICv3CPUState + * + * Scan the LPI pending table and recalculate cs->hpplpi only, + * without calling gicv3_redist_update() to recalculate the overall + * highest priority pending interrupt. This should be called after + * an incoming migration has loaded new state. + */ +void gicv3_redist_update_lpi_only(GICv3CPUState *cs); void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns); void gicv3_init_cpuif(GICv3State *s); diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/arm_gicv3.c +++ b/hw/intc/arm_gicv3.c @@ -XXX,XX +XXX,XX @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs) * interrupt has reduced in priority and any other interrupt could * now be the new best one). */ - if (!seenbetter && cs->hppi.prio != 0xff && cs->hppi.irq < GIC_INTERNAL) { + if (!seenbetter && cs->hppi.prio != 0xff && + (cs->hppi.irq < GIC_INTERNAL || + cs->hppi.irq >= GICV3_LPI_INTID_START)) { gicv3_full_update_noirqset(cs->gic); } } @@ -XXX,XX +XXX,XX @@ static void arm_gicv3_post_load(GICv3State *s) * pending interrupt, but don't set IRQ or FIQ lines. */ for (i = 0; i < s->num_cpu; i++) { - gicv3_redist_update_lpi(&s->cpu[i]); + gicv3_redist_update_lpi_only(&s->cpu[i]); } gicv3_full_update_noirqset(s); /* Repopulate the cache of GICv3CPUState pointers for target CPUs */ diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/arm_gicv3_redist.c +++ b/hw/intc/arm_gicv3_redist.c @@ -XXX,XX +XXX,XX @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset, cs->gicr_ctlr |= GICR_CTLR_ENABLE_LPIS; /* Check for any pending interr in pending table */ gicv3_redist_update_lpi(cs); - gicv3_redist_update(cs); } else { cs->gicr_ctlr &= ~GICR_CTLR_ENABLE_LPIS; + /* cs->hppi might have been an LPI; recalculate */ + gicv3_redist_update(cs); } } return MEMTX_OK; @@ -XXX,XX +XXX,XX @@ static void gicv3_redist_check_lpi_priority(GICv3CPUState *cs, int irq) } } -void gicv3_redist_update_lpi(GICv3CPUState *cs) +void gicv3_redist_update_lpi_only(GICv3CPUState *cs) { /* * This function scans the LPI pending table and for each pending @@ -XXX,XX +XXX,XX @@ void gicv3_redist_update_lpi(GICv3CPUState *cs) } } +void gicv3_redist_update_lpi(GICv3CPUState *cs) +{ + gicv3_redist_update_lpi_only(cs); + gicv3_redist_update(cs); +} + void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level) { /* @@ -XXX,XX +XXX,XX @@ void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level) */ if (level) { gicv3_redist_check_lpi_priority(cs, irq); + gicv3_redist_update(cs); } else { if (irq == cs->hpplpi.irq) { gicv3_redist_update_lpi(cs); @@ -XXX,XX +XXX,XX @@ void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level) /* set/clear the pending bit for this irq */ gicv3_redist_lpi_pending(cs, irq, level); - - gicv3_redist_update(cs); } void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level) -- 2.25.1
The GICv3/v4 pseudocode has a function IsSpecial() which returns true if passed a "special" interrupt ID number (anything between 1020 and 1023 inclusive). We open-code this condition in a couple of places, so abstract it out into a new function gicv3_intid_is_special(). Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Marc Zyngier <maz@kernel.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> --- hw/intc/gicv3_internal.h | 13 +++++++++++++ hw/intc/arm_gicv3_cpuif.c | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/gicv3_internal.h +++ b/hw/intc/gicv3_internal.h @@ -XXX,XX +XXX,XX @@ FIELD(MAPC, RDBASE, 16, 32) /* Functions internal to the emulated GICv3 */ +/** + * gicv3_intid_is_special: + * @intid: interrupt ID + * + * Return true if @intid is a special interrupt ID (1020 to + * 1023 inclusive). This corresponds to the GIC spec pseudocode + * IsSpecial() function. + */ +static inline bool gicv3_intid_is_special(int intid) +{ + return intid >= INTID_SECURE && intid <= INTID_SPURIOUS; +} + /** * gicv3_redist_update: * @cs: GICv3CPUState for this redistributor diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -XXX,XX +XXX,XX @@ static uint64_t icc_iar0_read(CPUARMState *env, const ARMCPRegInfo *ri) intid = icc_hppir0_value(cs, env); } - if (!(intid >= INTID_SECURE && intid <= INTID_SPURIOUS)) { + if (!gicv3_intid_is_special(intid)) { icc_activate_irq(cs, intid); } @@ -XXX,XX +XXX,XX @@ static uint64_t icc_iar1_read(CPUARMState *env, const ARMCPRegInfo *ri) intid = icc_hppir1_value(cs, env); } - if (!(intid >= INTID_SECURE && intid <= INTID_SPURIOUS)) { + if (!gicv3_intid_is_special(intid)) { icc_activate_irq(cs, intid); } -- 2.25.1
It is valid for an OS to put virtual interrupt ID values into the list registers ICH_LR<n> which are greater than 1023. This corresponds to (for example) KVM using the in-kernel emulated ITS to give a (nested) guest an ITS. LPIs are delivered by the L1 kernel to the L2 guest via the list registers in the same way as non-LPI interrupts. QEMU's code for handling writes to ICV_IARn (which happen when the L2 guest acknowledges an interrupt) and to ICV_EOIRn (which happen at the end of the interrupt) did not consider LPIs, so it would incorrectly treat interrupt IDs above 1023 as invalid. Fix this by using the correct condition, which is gicv3_intid_is_special(). Note that the condition in icv_dir_write() is correct -- LPIs are not valid there and so we want to ignore both "special" ID values and LPIs. (In the pseudocode this logic is in: - VirtualReadIAR0(), VirtualReadIAR1(), which call IsSpecial() - VirtualWriteEOIR0(), VirtualWriteEOIR1(), which call VirtualIdentifierValid(data, TRUE) meaning "LPIs OK" - VirtualWriteDIR(), which calls VirtualIdentifierValid(data, FALSE) meaning "LPIs not OK") This bug doesn't seem to have any visible effect on Linux L2 guests most of the time, because the two bugs cancel each other out: we neither mark the interrupt active nor deactivate it. However it does mean that the L2 vCPU priority while the LPI handler is running will not be correct, so the interrupt handler could be unexpectedly interrupted by a different interrupt. (NB: this has nothing to do with using QEMU's emulated ITS.) Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Marc Zyngier <maz@kernel.org> --- hw/intc/arm_gicv3_cpuif.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -XXX,XX +XXX,XX @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri) if (thisgrp == grp && icv_hppi_can_preempt(cs, lr)) { intid = ich_lr_vintid(lr); - if (intid < INTID_SECURE) { + if (!gicv3_intid_is_special(intid)) { icv_activate_irq(cs, idx, grp); } else { /* Interrupt goes from Pending to Invalid */ @@ -XXX,XX +XXX,XX @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri, trace_gicv3_icv_eoir_write(ri->crm == 8 ? 0 : 1, gicv3_redist_affid(cs), value); - if (irq >= GICV3_MAXIRQ) { - /* Also catches special interrupt numbers and LPIs */ + if (gicv3_intid_is_special(irq)) { return; } -- 2.25.1
v3->v4: Windows headers define an INT type which clashed with an enum value name in arm_gicv3_its.c... The following changes since commit eae587e8e3694b1aceab23239493fb4c7e1a80f5: Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2021-09-13' into staging (2021-09-13 11:00:30 +0100) are available in the Git repository at: https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210913-3 for you to fetch changes up to 28e987a7e7edaa3ca7feeac65edca26145df8814: hw/arm/mps2.c: Mark internal-only I2C buses as 'full' (2021-09-13 21:01:08 +0100) ---------------------------------------------------------------- target-arm queue: * mark MPS2/MPS3 board-internal i2c buses as 'full' so that command line user-created devices are not plugged into them * Take an exception if PSTATE.IL is set * Support an emulated ITS in the virt board * Add support for kudo-bmc board * Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM * cadence_uart: Fix clock handling issues that prevented u-boot from running ---------------------------------------------------------------- Bin Meng (6): hw/misc: zynq_slcr: Correctly compute output clocks in the reset exit phase hw/char: cadence_uart: Disable transmit when input clock is disabled hw/char: cadence_uart: Move clock/reset check to uart_can_receive() hw/char: cadence_uart: Convert to memop_with_attrs() ops hw/char: cadence_uart: Ignore access when unclocked or in reset for uart_{read, write}() hw/char: cadence_uart: Log a guest error when device is unclocked or in reset Chris Rauer (1): hw/arm: Add support for kudo-bmc board. Marc Zyngier (1): hw/arm/virt: KVM: Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM Peter Maydell (5): target/arm: Take an exception if PSTATE.IL is set qdev: Support marking individual buses as 'full' hw/arm/mps2-tz.c: Add extra data parameter to MakeDevFn hw/arm/mps2-tz.c: Mark internal-only I2C buses as 'full' hw/arm/mps2.c: Mark internal-only I2C buses as 'full' Richard Henderson (1): target/arm: Merge disas_a64_insn into aarch64_tr_translate_insn Shashi Mallela (9): hw/intc: GICv3 ITS initial framework hw/intc: GICv3 ITS register definitions added hw/intc: GICv3 ITS command queue framework hw/intc: GICv3 ITS Command processing hw/intc: GICv3 ITS Feature enablement hw/intc: GICv3 redistributor ITS processing tests/data/acpi/virt: Add IORT files for ITS hw/arm/virt: add ITS support in virt GIC tests/data/acpi/virt: Update IORT files for ITS docs/system/arm/nuvoton.rst | 1 + hw/intc/gicv3_internal.h | 188 ++++- include/hw/arm/virt.h | 2 + include/hw/intc/arm_gicv3_common.h | 13 + include/hw/intc/arm_gicv3_its_common.h | 32 +- include/hw/qdev-core.h | 24 + target/arm/cpu.h | 1 + target/arm/kvm_arm.h | 4 +- target/arm/syndrome.h | 5 + target/arm/translate.h | 2 + hw/arm/mps2-tz.c | 92 ++- hw/arm/mps2.c | 12 +- hw/arm/npcm7xx_boards.c | 34 + hw/arm/virt.c | 29 +- hw/char/cadence_uart.c | 61 +- hw/intc/arm_gicv3.c | 14 + hw/intc/arm_gicv3_common.c | 13 + hw/intc/arm_gicv3_cpuif.c | 7 +- hw/intc/arm_gicv3_dist.c | 5 +- hw/intc/arm_gicv3_its.c | 1322 ++++++++++++++++++++++++++++++++ hw/intc/arm_gicv3_its_common.c | 7 +- hw/intc/arm_gicv3_its_kvm.c | 2 +- hw/intc/arm_gicv3_redist.c | 153 +++- hw/misc/zynq_slcr.c | 31 +- softmmu/qdev-monitor.c | 7 +- target/arm/helper-a64.c | 1 + target/arm/helper.c | 8 + target/arm/kvm.c | 7 +- target/arm/translate-a64.c | 255 +++--- target/arm/translate.c | 21 + hw/intc/meson.build | 1 + tests/data/acpi/virt/IORT | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.memhp | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.numamem | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.pxb | Bin 0 -> 124 bytes 35 files changed, 2144 insertions(+), 210 deletions(-) create mode 100644 hw/intc/arm_gicv3_its.c create mode 100644 tests/data/acpi/virt/IORT create mode 100644 tests/data/acpi/virt/IORT.memhp create mode 100644 tests/data/acpi/virt/IORT.numamem create mode 100644 tests/data/acpi/virt/IORT.pxb