1 | Hi; this is a collection of mostly GIC related patches for rc3. | 1 | The following changes since commit e3debd5e7d0ce031356024878a0a18b9d109354a: |
---|---|---|---|
2 | The "Update cached state after LPI state changes" fix is important | ||
3 | and fixes what would otherwise be a regression since we enable the | ||
4 | ITS by default in the virt board now. The others are not regressions | ||
5 | but I think are OK for rc3 as they're fairly self contained (and two | ||
6 | of them are fixes to new-in-6.2 functionality). | ||
7 | 2 | ||
8 | thanks | 3 | Merge tag 'pull-request-2023-03-24' of https://gitlab.com/thuth/qemu into staging (2023-03-24 16:08:46 +0000) |
9 | -- PMM | ||
10 | |||
11 | The following changes since commit dd4b0de45965538f19bb40c7ddaaba384a8c613a: | ||
12 | |||
13 | Fix version for v6.2.0-rc2 release (2021-11-26 11:58:54 +0100) | ||
14 | 4 | ||
15 | are available in the Git repository at: | 5 | are available in the Git repository at: |
16 | 6 | ||
17 | https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20211129 | 7 | https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20230328 |
18 | 8 | ||
19 | for you to fetch changes up to 90feffad2aafe856ed2af75313b2c1669ba671e9: | 9 | for you to fetch changes up to 46e3b237c52e0c48bfd81bce020b51fbe300b23a: |
20 | 10 | ||
21 | hw/intc/arm_gicv3: fix handling of LPIs in list registers (2021-11-29 10:10:21 +0000) | 11 | target/arm/gdbstub: Only advertise M-profile features if TCG available (2023-03-28 10:53:40 +0100) |
22 | 12 | ||
23 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
24 | target-arm queue: | 14 | target-arm queue: |
25 | * virt: Diagnose attempts to enable MTE or virt when using HVF accelerator | 15 | * fix part of the "TCG-disabled builds are broken" issue |
26 | * GICv3 ITS: Allow clearing of ITS CTLR Enabled bit | ||
27 | * GICv3: Update cached state after LPI state changes | ||
28 | * GICv3: Fix handling of LPIs in list registers | ||
29 | 16 | ||
30 | ---------------------------------------------------------------- | 17 | ---------------------------------------------------------------- |
31 | Alexander Graf (1): | 18 | Philippe Mathieu-Daudé (1): |
32 | hw/arm/virt: Extend nested and mte checks to hvf | 19 | target/arm/gdbstub: Only advertise M-profile features if TCG available |
33 | 20 | ||
34 | Peter Maydell (3): | 21 | target/arm/gdbstub.c | 5 +++-- |
35 | hw/intc/arm_gicv3: Update cached state after LPI state changes | 22 | 1 file changed, 3 insertions(+), 2 deletions(-) |
36 | hw/intc/arm_gicv3: Add new gicv3_intid_is_special() function | ||
37 | hw/intc/arm_gicv3: fix handling of LPIs in list registers | ||
38 | 23 | ||
39 | Shashi Mallela (1): | ||
40 | hw/intc: cannot clear GICv3 ITS CTLR[Enabled] bit | ||
41 | |||
42 | hw/intc/gicv3_internal.h | 30 ++++++++++++++++++++++++++++++ | ||
43 | hw/arm/virt.c | 15 +++++++++------ | ||
44 | hw/intc/arm_gicv3.c | 6 ++++-- | ||
45 | hw/intc/arm_gicv3_cpuif.c | 9 ++++----- | ||
46 | hw/intc/arm_gicv3_its.c | 7 ++++--- | ||
47 | hw/intc/arm_gicv3_redist.c | 14 ++++++++++---- | ||
48 | 6 files changed, 61 insertions(+), 20 deletions(-) | ||
49 | diff view generated by jsdifflib |
1 | From: Alexander Graf <agraf@csgraf.de> | 1 | From: Philippe Mathieu-Daudé <philmd@linaro.org> |
---|---|---|---|
2 | 2 | ||
3 | The virt machine has properties to enable MTE and Nested Virtualization | 3 | Cortex-M profile is only emulable from TCG accelerator. Restrict |
4 | support. However, its check to ensure the backing accel implementation | 4 | the GDBstub features to its availability in order to avoid a link |
5 | supports it today only looks for KVM and bails out if it finds it. | 5 | error when TCG is not enabled: |
6 | 6 | ||
7 | Extend the checks to HVF as well as it does not support either today. | 7 | Undefined symbols for architecture arm64: |
8 | This will cause QEMU to print a useful error message rather than | 8 | "_arm_v7m_get_sp_ptr", referenced from: |
9 | silently ignoring the attempt by the user to enable either MTE or | 9 | _m_sysreg_get in target_arm_gdbstub.c.o |
10 | the Virtualization extensions. | 10 | "_arm_v7m_mrs_control", referenced from: |
11 | _arm_gdb_get_m_systemreg in target_arm_gdbstub.c.o | ||
12 | ld: symbol(s) not found for architecture arm64 | ||
13 | clang: error: linker command failed with exit code 1 (use -v to see invocation) | ||
11 | 14 | ||
12 | Reported-by: saar amar <saaramar5@gmail.com> | 15 | Fixes: 7d8b28b8b5 ("target/arm: Implement gdbstub m-profile systemreg and secext") |
13 | Signed-off-by: Alexander Graf <agraf@csgraf.de> | 16 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> |
14 | Message-id: 20211123122859.22452-1-agraf@csgraf.de | 17 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
15 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 18 | Reviewed-by: Alex Bennée <alex.bennee@linaro.org> |
19 | Message-id: 20230322142902.69511-3-philmd@linaro.org | ||
20 | [PMM: add #include since I cherry-picked this patch from the series] | ||
16 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 21 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
17 | --- | 22 | --- |
18 | hw/arm/virt.c | 15 +++++++++------ | 23 | target/arm/gdbstub.c | 5 +++-- |
19 | 1 file changed, 9 insertions(+), 6 deletions(-) | 24 | 1 file changed, 3 insertions(+), 2 deletions(-) |
20 | 25 | ||
21 | diff --git a/hw/arm/virt.c b/hw/arm/virt.c | 26 | diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c |
22 | index XXXXXXX..XXXXXXX 100644 | 27 | index XXXXXXX..XXXXXXX 100644 |
23 | --- a/hw/arm/virt.c | 28 | --- a/target/arm/gdbstub.c |
24 | +++ b/hw/arm/virt.c | 29 | +++ b/target/arm/gdbstub.c |
25 | @@ -XXX,XX +XXX,XX @@ | 30 | @@ -XXX,XX +XXX,XX @@ |
26 | #include "sysemu/runstate.h" | 31 | #include "cpu.h" |
27 | #include "sysemu/tpm.h" | 32 | #include "exec/gdbstub.h" |
28 | #include "sysemu/kvm.h" | 33 | #include "gdbstub/helpers.h" |
29 | +#include "sysemu/hvf.h" | 34 | +#include "sysemu/tcg.h" |
30 | #include "hw/loader.h" | 35 | #include "internals.h" |
31 | #include "qapi/error.h" | 36 | #include "cpregs.h" |
32 | #include "qemu/bitops.h" | 37 | |
33 | @@ -XXX,XX +XXX,XX @@ static void machvirt_init(MachineState *machine) | 38 | @@ -XXX,XX +XXX,XX @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu) |
34 | exit(1); | 39 | 2, "arm-vfp-sysregs.xml", 0); |
40 | } | ||
35 | } | 41 | } |
36 | 42 | - if (cpu_isar_feature(aa32_mve, cpu)) { | |
37 | - if (vms->virt && kvm_enabled()) { | 43 | + if (cpu_isar_feature(aa32_mve, cpu) && tcg_enabled()) { |
38 | - error_report("mach-virt: KVM does not support providing " | 44 | gdb_register_coprocessor(cs, mve_gdb_get_reg, mve_gdb_set_reg, |
39 | - "Virtualization extensions to the guest CPU"); | 45 | 1, "arm-m-profile-mve.xml", 0); |
40 | + if (vms->virt && (kvm_enabled() || hvf_enabled())) { | ||
41 | + error_report("mach-virt: %s does not support providing " | ||
42 | + "Virtualization extensions to the guest CPU", | ||
43 | + kvm_enabled() ? "KVM" : "HVF"); | ||
44 | exit(1); | ||
45 | } | 46 | } |
46 | 47 | @@ -XXX,XX +XXX,XX @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu) | |
47 | - if (vms->mte && kvm_enabled()) { | 48 | arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs), |
48 | - error_report("mach-virt: KVM does not support providing " | 49 | "system-registers.xml", 0); |
49 | - "MTE to the guest CPU"); | 50 | |
50 | + if (vms->mte && (kvm_enabled() || hvf_enabled())) { | 51 | - if (arm_feature(env, ARM_FEATURE_M)) { |
51 | + error_report("mach-virt: %s does not support providing " | 52 | + if (arm_feature(env, ARM_FEATURE_M) && tcg_enabled()) { |
52 | + "MTE to the guest CPU", | 53 | gdb_register_coprocessor(cs, |
53 | + kvm_enabled() ? "KVM" : "HVF"); | 54 | arm_gdb_get_m_systemreg, arm_gdb_set_m_systemreg, |
54 | exit(1); | 55 | arm_gen_dynamic_m_systemreg_xml(cs, cs->gdb_num_regs), |
55 | } | ||
56 | |||
57 | -- | 56 | -- |
58 | 2.25.1 | 57 | 2.34.1 |
59 | 58 | ||
60 | 59 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Shashi Mallela <shashi.mallela@linaro.org> | ||
2 | 1 | ||
3 | When Enabled bit is cleared in GITS_CTLR,ITS feature continues | ||
4 | to be enabled.This patch fixes the issue. | ||
5 | |||
6 | Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org> | ||
7 | Tested-by: Alex Bennée <alex.bennee@linaro.org> | ||
8 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
9 | Message-id: 20211124182246.67691-1-shashi.mallela@linaro.org | ||
10 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
11 | --- | ||
12 | hw/intc/arm_gicv3_its.c | 7 ++++--- | ||
13 | 1 file changed, 4 insertions(+), 3 deletions(-) | ||
14 | |||
15 | diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/hw/intc/arm_gicv3_its.c | ||
18 | +++ b/hw/intc/arm_gicv3_its.c | ||
19 | @@ -XXX,XX +XXX,XX @@ static bool its_writel(GICv3ITSState *s, hwaddr offset, | ||
20 | |||
21 | switch (offset) { | ||
22 | case GITS_CTLR: | ||
23 | - s->ctlr |= (value & ~(s->ctlr)); | ||
24 | - | ||
25 | - if (s->ctlr & ITS_CTLR_ENABLED) { | ||
26 | + if (value & R_GITS_CTLR_ENABLED_MASK) { | ||
27 | + s->ctlr |= ITS_CTLR_ENABLED; | ||
28 | extract_table_params(s); | ||
29 | extract_cmdq_params(s); | ||
30 | s->creadr = 0; | ||
31 | process_cmdq(s); | ||
32 | + } else { | ||
33 | + s->ctlr &= ~ITS_CTLR_ENABLED; | ||
34 | } | ||
35 | break; | ||
36 | case GITS_CBASER: | ||
37 | -- | ||
38 | 2.25.1 | ||
39 | |||
40 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | The logic of gicv3_redist_update() is as follows: | ||
2 | * it must be called in any code path that changes the state of | ||
3 | (only) redistributor interrupts | ||
4 | * if it finds a redistributor interrupt that is (now) higher | ||
5 | priority than the previous highest-priority pending interrupt, | ||
6 | then this must be the new highest-priority pending interrupt | ||
7 | * if it does *not* find a better redistributor interrupt, then: | ||
8 | - if the previous state was "no interrupts pending" then | ||
9 | the new state is still "no interrupts pending" | ||
10 | - if the previous best interrupt was not a redistributor | ||
11 | interrupt then that remains the best interrupt | ||
12 | - if the previous best interrupt *was* a redistributor interrupt, | ||
13 | then the new best interrupt must be some non-redistributor | ||
14 | interrupt, but we don't know which so must do a full scan | ||
15 | 1 | ||
16 | In commit 17fb5e36aabd4b2c125 we effectively added the LPI interrupts | ||
17 | as a kind of "redistributor interrupt" for this purpose, by adding | ||
18 | cs->hpplpi to the set of things that gicv3_redist_update() considers | ||
19 | before it gives up and decides to do a full scan of distributor | ||
20 | interrupts. However we didn't quite get this right: | ||
21 | * the condition check for "was the previous best interrupt a | ||
22 | redistributor interrupt" must be updated to include LPIs | ||
23 | in what it considers to be redistributor interrupts | ||
24 | * every code path which updates the LPI state which | ||
25 | gicv3_redist_update() checks must also call gicv3_redist_update(): | ||
26 | this is cs->hpplpi and the GICR_CTLR ENABLE_LPIS bit | ||
27 | |||
28 | This commit fixes this by: | ||
29 | * correcting the test on cs->hppi.irq in gicv3_redist_update() | ||
30 | * making gicv3_redist_update_lpi() always call gicv3_redist_update() | ||
31 | * introducing a new gicv3_redist_update_lpi_only() for the one | ||
32 | callsite (the post-load hook) which must not call | ||
33 | gicv3_redist_update() | ||
34 | * making gicv3_redist_lpi_pending() always call gicv3_redist_update(), | ||
35 | either directly or via gicv3_redist_update_lpi() | ||
36 | * removing a couple of now-unnecessary calls to gicv3_redist_update() | ||
37 | from some callers of those two functions | ||
38 | * calling gicv3_redist_update() when the GICR_CTLR ENABLE_LPIS | ||
39 | bit is cleared | ||
40 | |||
41 | (This means that the not-file-local gicv3_redist_* LPI related | ||
42 | functions now all take care of the updates of internally cached | ||
43 | GICv3 information, in the same way the older functions | ||
44 | gicv3_redist_set_irq() and gicv3_redist_send_sgi() do.) | ||
45 | |||
46 | The visible effect of this bug was that when the guest acknowledged | ||
47 | an LPI by reading ICC_IAR1_EL1, we marked it as not pending in the | ||
48 | LPI data structure but still left it in cs->hppi so we would offer it | ||
49 | to the guest again. In particular for setups using an emulated GICv3 | ||
50 | and ITS and using devices which use LPIs (ie PCI devices) a Linux | ||
51 | guest would complain "irq 54: nobody cared" and then hang. (The hang | ||
52 | was intermittent, presumably depending on the timing between | ||
53 | different interrupts arriving and being completed.) | ||
54 | |||
55 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
56 | Tested-by: Alex Bennée <alex.bennee@linaro.org> | ||
57 | Reviewed-by: Alex Bennée <alex.bennee@linaro.org> | ||
58 | Message-id: 20211124202005.989935-1-peter.maydell@linaro.org | ||
59 | --- | ||
60 | hw/intc/gicv3_internal.h | 17 +++++++++++++++++ | ||
61 | hw/intc/arm_gicv3.c | 6 ++++-- | ||
62 | hw/intc/arm_gicv3_redist.c | 14 ++++++++++---- | ||
63 | 3 files changed, 31 insertions(+), 6 deletions(-) | ||
64 | |||
65 | diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h | ||
66 | index XXXXXXX..XXXXXXX 100644 | ||
67 | --- a/hw/intc/gicv3_internal.h | ||
68 | +++ b/hw/intc/gicv3_internal.h | ||
69 | @@ -XXX,XX +XXX,XX @@ void gicv3_dist_set_irq(GICv3State *s, int irq, int level); | ||
70 | void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level); | ||
71 | void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level); | ||
72 | void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level); | ||
73 | +/** | ||
74 | + * gicv3_redist_update_lpi: | ||
75 | + * @cs: GICv3CPUState | ||
76 | + * | ||
77 | + * Scan the LPI pending table and recalculate the highest priority | ||
78 | + * pending LPI and also the overall highest priority pending interrupt. | ||
79 | + */ | ||
80 | void gicv3_redist_update_lpi(GICv3CPUState *cs); | ||
81 | +/** | ||
82 | + * gicv3_redist_update_lpi_only: | ||
83 | + * @cs: GICv3CPUState | ||
84 | + * | ||
85 | + * Scan the LPI pending table and recalculate cs->hpplpi only, | ||
86 | + * without calling gicv3_redist_update() to recalculate the overall | ||
87 | + * highest priority pending interrupt. This should be called after | ||
88 | + * an incoming migration has loaded new state. | ||
89 | + */ | ||
90 | +void gicv3_redist_update_lpi_only(GICv3CPUState *cs); | ||
91 | void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns); | ||
92 | void gicv3_init_cpuif(GICv3State *s); | ||
93 | |||
94 | diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c | ||
95 | index XXXXXXX..XXXXXXX 100644 | ||
96 | --- a/hw/intc/arm_gicv3.c | ||
97 | +++ b/hw/intc/arm_gicv3.c | ||
98 | @@ -XXX,XX +XXX,XX @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs) | ||
99 | * interrupt has reduced in priority and any other interrupt could | ||
100 | * now be the new best one). | ||
101 | */ | ||
102 | - if (!seenbetter && cs->hppi.prio != 0xff && cs->hppi.irq < GIC_INTERNAL) { | ||
103 | + if (!seenbetter && cs->hppi.prio != 0xff && | ||
104 | + (cs->hppi.irq < GIC_INTERNAL || | ||
105 | + cs->hppi.irq >= GICV3_LPI_INTID_START)) { | ||
106 | gicv3_full_update_noirqset(cs->gic); | ||
107 | } | ||
108 | } | ||
109 | @@ -XXX,XX +XXX,XX @@ static void arm_gicv3_post_load(GICv3State *s) | ||
110 | * pending interrupt, but don't set IRQ or FIQ lines. | ||
111 | */ | ||
112 | for (i = 0; i < s->num_cpu; i++) { | ||
113 | - gicv3_redist_update_lpi(&s->cpu[i]); | ||
114 | + gicv3_redist_update_lpi_only(&s->cpu[i]); | ||
115 | } | ||
116 | gicv3_full_update_noirqset(s); | ||
117 | /* Repopulate the cache of GICv3CPUState pointers for target CPUs */ | ||
118 | diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c | ||
119 | index XXXXXXX..XXXXXXX 100644 | ||
120 | --- a/hw/intc/arm_gicv3_redist.c | ||
121 | +++ b/hw/intc/arm_gicv3_redist.c | ||
122 | @@ -XXX,XX +XXX,XX @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset, | ||
123 | cs->gicr_ctlr |= GICR_CTLR_ENABLE_LPIS; | ||
124 | /* Check for any pending interr in pending table */ | ||
125 | gicv3_redist_update_lpi(cs); | ||
126 | - gicv3_redist_update(cs); | ||
127 | } else { | ||
128 | cs->gicr_ctlr &= ~GICR_CTLR_ENABLE_LPIS; | ||
129 | + /* cs->hppi might have been an LPI; recalculate */ | ||
130 | + gicv3_redist_update(cs); | ||
131 | } | ||
132 | } | ||
133 | return MEMTX_OK; | ||
134 | @@ -XXX,XX +XXX,XX @@ static void gicv3_redist_check_lpi_priority(GICv3CPUState *cs, int irq) | ||
135 | } | ||
136 | } | ||
137 | |||
138 | -void gicv3_redist_update_lpi(GICv3CPUState *cs) | ||
139 | +void gicv3_redist_update_lpi_only(GICv3CPUState *cs) | ||
140 | { | ||
141 | /* | ||
142 | * This function scans the LPI pending table and for each pending | ||
143 | @@ -XXX,XX +XXX,XX @@ void gicv3_redist_update_lpi(GICv3CPUState *cs) | ||
144 | } | ||
145 | } | ||
146 | |||
147 | +void gicv3_redist_update_lpi(GICv3CPUState *cs) | ||
148 | +{ | ||
149 | + gicv3_redist_update_lpi_only(cs); | ||
150 | + gicv3_redist_update(cs); | ||
151 | +} | ||
152 | + | ||
153 | void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level) | ||
154 | { | ||
155 | /* | ||
156 | @@ -XXX,XX +XXX,XX @@ void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level) | ||
157 | */ | ||
158 | if (level) { | ||
159 | gicv3_redist_check_lpi_priority(cs, irq); | ||
160 | + gicv3_redist_update(cs); | ||
161 | } else { | ||
162 | if (irq == cs->hpplpi.irq) { | ||
163 | gicv3_redist_update_lpi(cs); | ||
164 | @@ -XXX,XX +XXX,XX @@ void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level) | ||
165 | |||
166 | /* set/clear the pending bit for this irq */ | ||
167 | gicv3_redist_lpi_pending(cs, irq, level); | ||
168 | - | ||
169 | - gicv3_redist_update(cs); | ||
170 | } | ||
171 | |||
172 | void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level) | ||
173 | -- | ||
174 | 2.25.1 | ||
175 | |||
176 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | The GICv3/v4 pseudocode has a function IsSpecial() which returns true | ||
2 | if passed a "special" interrupt ID number (anything between 1020 and | ||
3 | 1023 inclusive). We open-code this condition in a couple of places, | ||
4 | so abstract it out into a new function gicv3_intid_is_special(). | ||
5 | 1 | ||
6 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
7 | Reviewed-by: Marc Zyngier <maz@kernel.org> | ||
8 | Reviewed-by: Alex Bennée <alex.bennee@linaro.org> | ||
9 | --- | ||
10 | hw/intc/gicv3_internal.h | 13 +++++++++++++ | ||
11 | hw/intc/arm_gicv3_cpuif.c | 4 ++-- | ||
12 | 2 files changed, 15 insertions(+), 2 deletions(-) | ||
13 | |||
14 | diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/hw/intc/gicv3_internal.h | ||
17 | +++ b/hw/intc/gicv3_internal.h | ||
18 | @@ -XXX,XX +XXX,XX @@ FIELD(MAPC, RDBASE, 16, 32) | ||
19 | |||
20 | /* Functions internal to the emulated GICv3 */ | ||
21 | |||
22 | +/** | ||
23 | + * gicv3_intid_is_special: | ||
24 | + * @intid: interrupt ID | ||
25 | + * | ||
26 | + * Return true if @intid is a special interrupt ID (1020 to | ||
27 | + * 1023 inclusive). This corresponds to the GIC spec pseudocode | ||
28 | + * IsSpecial() function. | ||
29 | + */ | ||
30 | +static inline bool gicv3_intid_is_special(int intid) | ||
31 | +{ | ||
32 | + return intid >= INTID_SECURE && intid <= INTID_SPURIOUS; | ||
33 | +} | ||
34 | + | ||
35 | /** | ||
36 | * gicv3_redist_update: | ||
37 | * @cs: GICv3CPUState for this redistributor | ||
38 | diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c | ||
39 | index XXXXXXX..XXXXXXX 100644 | ||
40 | --- a/hw/intc/arm_gicv3_cpuif.c | ||
41 | +++ b/hw/intc/arm_gicv3_cpuif.c | ||
42 | @@ -XXX,XX +XXX,XX @@ static uint64_t icc_iar0_read(CPUARMState *env, const ARMCPRegInfo *ri) | ||
43 | intid = icc_hppir0_value(cs, env); | ||
44 | } | ||
45 | |||
46 | - if (!(intid >= INTID_SECURE && intid <= INTID_SPURIOUS)) { | ||
47 | + if (!gicv3_intid_is_special(intid)) { | ||
48 | icc_activate_irq(cs, intid); | ||
49 | } | ||
50 | |||
51 | @@ -XXX,XX +XXX,XX @@ static uint64_t icc_iar1_read(CPUARMState *env, const ARMCPRegInfo *ri) | ||
52 | intid = icc_hppir1_value(cs, env); | ||
53 | } | ||
54 | |||
55 | - if (!(intid >= INTID_SECURE && intid <= INTID_SPURIOUS)) { | ||
56 | + if (!gicv3_intid_is_special(intid)) { | ||
57 | icc_activate_irq(cs, intid); | ||
58 | } | ||
59 | |||
60 | -- | ||
61 | 2.25.1 | ||
62 | |||
63 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | It is valid for an OS to put virtual interrupt ID values into the | ||
2 | list registers ICH_LR<n> which are greater than 1023. This | ||
3 | corresponds to (for example) KVM using the in-kernel emulated ITS to | ||
4 | give a (nested) guest an ITS. LPIs are delivered by the L1 kernel to | ||
5 | the L2 guest via the list registers in the same way as non-LPI | ||
6 | interrupts. | ||
7 | 1 | ||
8 | QEMU's code for handling writes to ICV_IARn (which happen when the L2 | ||
9 | guest acknowledges an interrupt) and to ICV_EOIRn (which happen at | ||
10 | the end of the interrupt) did not consider LPIs, so it would | ||
11 | incorrectly treat interrupt IDs above 1023 as invalid. Fix this by | ||
12 | using the correct condition, which is gicv3_intid_is_special(). | ||
13 | |||
14 | Note that the condition in icv_dir_write() is correct -- LPIs | ||
15 | are not valid there and so we want to ignore both "special" ID | ||
16 | values and LPIs. | ||
17 | |||
18 | (In the pseudocode this logic is in: | ||
19 | - VirtualReadIAR0(), VirtualReadIAR1(), which call IsSpecial() | ||
20 | - VirtualWriteEOIR0(), VirtualWriteEOIR1(), which call | ||
21 | VirtualIdentifierValid(data, TRUE) meaning "LPIs OK" | ||
22 | - VirtualWriteDIR(), which calls VirtualIdentifierValid(data, FALSE) | ||
23 | meaning "LPIs not OK") | ||
24 | |||
25 | This bug doesn't seem to have any visible effect on Linux L2 guests | ||
26 | most of the time, because the two bugs cancel each other out: we | ||
27 | neither mark the interrupt active nor deactivate it. However it does | ||
28 | mean that the L2 vCPU priority while the LPI handler is running will | ||
29 | not be correct, so the interrupt handler could be unexpectedly | ||
30 | interrupted by a different interrupt. | ||
31 | |||
32 | (NB: this has nothing to do with using QEMU's emulated ITS.) | ||
33 | |||
34 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
35 | Reviewed-by: Marc Zyngier <maz@kernel.org> | ||
36 | --- | ||
37 | hw/intc/arm_gicv3_cpuif.c | 5 ++--- | ||
38 | 1 file changed, 2 insertions(+), 3 deletions(-) | ||
39 | |||
40 | diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c | ||
41 | index XXXXXXX..XXXXXXX 100644 | ||
42 | --- a/hw/intc/arm_gicv3_cpuif.c | ||
43 | +++ b/hw/intc/arm_gicv3_cpuif.c | ||
44 | @@ -XXX,XX +XXX,XX @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri) | ||
45 | |||
46 | if (thisgrp == grp && icv_hppi_can_preempt(cs, lr)) { | ||
47 | intid = ich_lr_vintid(lr); | ||
48 | - if (intid < INTID_SECURE) { | ||
49 | + if (!gicv3_intid_is_special(intid)) { | ||
50 | icv_activate_irq(cs, idx, grp); | ||
51 | } else { | ||
52 | /* Interrupt goes from Pending to Invalid */ | ||
53 | @@ -XXX,XX +XXX,XX @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri, | ||
54 | trace_gicv3_icv_eoir_write(ri->crm == 8 ? 0 : 1, | ||
55 | gicv3_redist_affid(cs), value); | ||
56 | |||
57 | - if (irq >= GICV3_MAXIRQ) { | ||
58 | - /* Also catches special interrupt numbers and LPIs */ | ||
59 | + if (gicv3_intid_is_special(irq)) { | ||
60 | return; | ||
61 | } | ||
62 | |||
63 | -- | ||
64 | 2.25.1 | ||
65 | |||
66 | diff view generated by jsdifflib |