Skip to content

Commit 3367805

Browse files
Alexandru EliseiMarc Zyngier
authored andcommitted
irqchip/gic-v3: Support pseudo-NMIs when SCR_EL3.FIQ == 0
The GIC's internal view of the priority mask register and the assigned interrupt priorities are based on whether GIC security is enabled and whether firmware routes Group 0 interrupts to EL3. At the moment, we support priority masking when ICC_PMR_EL1 and interrupt priorities are either both modified by the GIC, or both left unchanged. Trusted Firmware-A's default interrupt routing model allows Group 0 interrupts to be delivered to the non-secure world (SCR_EL3.FIQ == 0). Unfortunately, this is precisely the case that the GIC driver doesn't support: ICC_PMR_EL1 remains unchanged, but the GIC's view of interrupt priorities is different from the software programmed values. Support pseudo-NMIs when SCR_EL3.FIQ == 0 by using a different value to mask regular interrupts. All the other values remain the same. Signed-off-by: Alexandru Elisei <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 4e594ad commit 3367805

File tree

4 files changed

+66
-14
lines changed

4 files changed

+66
-14
lines changed

arch/arm64/include/asm/arch_gicv3.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ static inline bool gic_prio_masking_enabled(void)
153153

154154
static inline void gic_pmr_mask_irqs(void)
155155
{
156-
BUILD_BUG_ON(GICD_INT_DEF_PRI < (GIC_PRIO_IRQOFF |
156+
BUILD_BUG_ON(GICD_INT_DEF_PRI < (__GIC_PRIO_IRQOFF |
157157
GIC_PRIO_PSR_I_SET));
158158
BUILD_BUG_ON(GICD_INT_DEF_PRI >= GIC_PRIO_IRQON);
159159
/*
@@ -162,6 +162,12 @@ static inline void gic_pmr_mask_irqs(void)
162162
* are applied to IRQ priorities
163163
*/
164164
BUILD_BUG_ON((0x80 | (GICD_INT_DEF_PRI >> 1)) >= GIC_PRIO_IRQON);
165+
/*
166+
* Same situation as above, but now we make sure that we can mask
167+
* regular interrupts.
168+
*/
169+
BUILD_BUG_ON((0x80 | (GICD_INT_DEF_PRI >> 1)) < (__GIC_PRIO_IRQOFF_NS |
170+
GIC_PRIO_PSR_I_SET));
165171
gic_write_pmr(GIC_PRIO_IRQOFF);
166172
}
167173

arch/arm64/include/asm/ptrace.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,21 @@
3131
* interrupt disabling temporarily does not rely on IRQ priorities.
3232
*/
3333
#define GIC_PRIO_IRQON 0xe0
34-
#define GIC_PRIO_IRQOFF (GIC_PRIO_IRQON & ~0x80)
34+
#define __GIC_PRIO_IRQOFF (GIC_PRIO_IRQON & ~0x80)
35+
#define __GIC_PRIO_IRQOFF_NS 0xa0
3536
#define GIC_PRIO_PSR_I_SET (1 << 4)
3637

38+
#define GIC_PRIO_IRQOFF \
39+
({ \
40+
extern struct static_key_false gic_nonsecure_priorities;\
41+
u8 __prio = __GIC_PRIO_IRQOFF; \
42+
\
43+
if (static_branch_unlikely(&gic_nonsecure_priorities)) \
44+
__prio = __GIC_PRIO_IRQOFF_NS; \
45+
\
46+
__prio; \
47+
})
48+
3749
/* Additional SPSR bits not exposed in the UABI */
3850
#define PSR_MODE_THREAD_BIT (1 << 0)
3951
#define PSR_IL_BIT (1 << 20)

arch/arm64/kernel/image-vars.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ KVM_NVHE_ALIAS(vgic_v3_cpuif_trap);
101101
/* Static key checked in pmr_sync(). */
102102
#ifdef CONFIG_ARM64_PSEUDO_NMI
103103
KVM_NVHE_ALIAS(gic_pmr_sync);
104+
/* Static key checked in GIC_PRIO_IRQOFF. */
105+
KVM_NVHE_ALIAS(gic_nonsecure_priorities);
104106
#endif
105107

106108
/* EL2 exception handling */

drivers/irqchip/irq-gic-v3.c

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,14 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
7575
*
7676
* If SCR_EL3.FIQ == 1, the values writen to/read from PMR and RPR at non-secure
7777
* EL1 are subject to a similar operation thus matching the priorities presented
78-
* from the (re)distributor when security is enabled.
78+
* from the (re)distributor when security is enabled. When SCR_EL3.FIQ == 0,
79+
* these values are unchanched by the GIC.
7980
*
8081
* see GICv3/GICv4 Architecture Specification (IHI0069D):
8182
* - section 4.8.1 Non-secure accesses to register fields for Secure interrupt
8283
* priorities.
8384
* - Figure 4-7 Secure read of the priority field for a Non-secure Group 1
8485
* interrupt.
85-
*
86-
* For now, we only support pseudo-NMIs if we have non-secure view of
87-
* priorities.
8886
*/
8987
static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis);
9088

@@ -97,6 +95,9 @@ static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis);
9795
DEFINE_STATIC_KEY_FALSE(gic_pmr_sync);
9896
EXPORT_SYMBOL(gic_pmr_sync);
9997

98+
DEFINE_STATIC_KEY_FALSE(gic_nonsecure_priorities);
99+
EXPORT_SYMBOL(gic_nonsecure_priorities);
100+
100101
/* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */
101102
static refcount_t *ppi_nmi_refs;
102103

@@ -932,14 +933,20 @@ static void gic_cpu_sys_reg_init(void)
932933
/* Set priority mask register */
933934
if (!gic_prio_masking_enabled()) {
934935
write_gicreg(DEFAULT_PMR_VALUE, ICC_PMR_EL1);
935-
} else {
936+
} else if (gic_supports_nmi()) {
936937
/*
937938
* Mismatch configuration with boot CPU, the system is likely
938939
* to die as interrupt masking will not work properly on all
939940
* CPUs
941+
*
942+
* The boot CPU calls this function before enabling NMI support,
943+
* and as a result we'll never see this warning in the boot path
944+
* for that CPU.
940945
*/
941-
WARN_ON(gic_supports_nmi() && group0 &&
942-
!gic_dist_security_disabled());
946+
if (static_branch_unlikely(&gic_nonsecure_priorities))
947+
WARN_ON(!group0 || gic_dist_security_disabled());
948+
else
949+
WARN_ON(group0 && !gic_dist_security_disabled());
943950
}
944951

945952
/*
@@ -1544,11 +1551,6 @@ static void gic_enable_nmi_support(void)
15441551
if (!gic_prio_masking_enabled())
15451552
return;
15461553

1547-
if (gic_has_group0() && !gic_dist_security_disabled()) {
1548-
pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n");
1549-
return;
1550-
}
1551-
15521554
ppi_nmi_refs = kcalloc(gic_data.ppi_nr, sizeof(*ppi_nmi_refs), GFP_KERNEL);
15531555
if (!ppi_nmi_refs)
15541556
return;
@@ -1567,6 +1569,36 @@ static void gic_enable_nmi_support(void)
15671569
pr_info("Pseudo-NMIs enabled using %s ICC_PMR_EL1 synchronisation\n",
15681570
static_branch_unlikely(&gic_pmr_sync) ? "forced" : "relaxed");
15691571

1572+
/*
1573+
* How priority values are used by the GIC depends on two things:
1574+
* the security state of the GIC (controlled by the GICD_CTRL.DS bit)
1575+
* and if Group 0 interrupts can be delivered to Linux in the non-secure
1576+
* world as FIQs (controlled by the SCR_EL3.FIQ bit). These affect the
1577+
* the ICC_PMR_EL1 register and the priority that software assigns to
1578+
* interrupts:
1579+
*
1580+
* GICD_CTRL.DS | SCR_EL3.FIQ | ICC_PMR_EL1 | Group 1 priority
1581+
* -----------------------------------------------------------
1582+
* 1 | - | unchanged | unchanged
1583+
* -----------------------------------------------------------
1584+
* 0 | 1 | non-secure | non-secure
1585+
* -----------------------------------------------------------
1586+
* 0 | 0 | unchanged | non-secure
1587+
*
1588+
* where non-secure means that the value is right-shifted by one and the
1589+
* MSB bit set, to make it fit in the non-secure priority range.
1590+
*
1591+
* In the first two cases, where ICC_PMR_EL1 and the interrupt priority
1592+
* are both either modified or unchanged, we can use the same set of
1593+
* priorities.
1594+
*
1595+
* In the last case, where only the interrupt priorities are modified to
1596+
* be in the non-secure range, we use a different PMR value to mask IRQs
1597+
* and the rest of the values that we use remain unchanged.
1598+
*/
1599+
if (gic_has_group0() && !gic_dist_security_disabled())
1600+
static_branch_enable(&gic_nonsecure_priorities);
1601+
15701602
static_branch_enable(&supports_pseudo_nmis);
15711603

15721604
if (static_branch_likely(&supports_deactivate_key))

0 commit comments

Comments
 (0)