Skip to content

Commit 6eb486b

Browse files
Shanker DonthineniMarc Zyngier
authored andcommitted
irqchip/gic-v3: Ensure GICR_CTLR.EnableLPI=0 is observed before enabling
Booting with GICR_CTLR.EnableLPI=1 is usually a bad idea, and may result in subtle memory corruption. Detecting this is thus pretty important. On detecting that LPIs are still enabled, we taint the kernel (because we're not sure of anything anymore), and try to disable LPIs. This can fail, as implementations are allowed to implement GICR_CTLR.EnableLPI as a one-way enable, meaning the redistributors cannot be reprogrammed with new tables. Should this happen, we fail probing the redistributor and warn the user that things are pretty dire. Signed-off-by: Shanker Donthineni <[email protected]> [maz: reworded changelog, minor comment and message changes] Signed-off-by: Marc Zyngier <[email protected]>
1 parent 19d9916 commit 6eb486b

File tree

2 files changed

+61
-14
lines changed

2 files changed

+61
-14
lines changed

drivers/irqchip/irq-gic-v3-its.c

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,16 +1879,6 @@ static void its_cpu_init_lpis(void)
18791879
gic_data_rdist()->pend_page = pend_page;
18801880
}
18811881

1882-
/* Disable LPIs */
1883-
val = readl_relaxed(rbase + GICR_CTLR);
1884-
val &= ~GICR_CTLR_ENABLE_LPIS;
1885-
writel_relaxed(val, rbase + GICR_CTLR);
1886-
1887-
/*
1888-
* Make sure any change to the table is observable by the GIC.
1889-
*/
1890-
dsb(sy);
1891-
18921882
/* set PROPBASE */
18931883
val = (page_to_phys(gic_rdists->prop_page) |
18941884
GICR_PROPBASER_InnerShareable |
@@ -3403,13 +3393,69 @@ static bool gic_rdists_supports_plpis(void)
34033393
return !!(gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER) & GICR_TYPER_PLPIS);
34043394
}
34053395

3396+
static int redist_disable_lpis(void)
3397+
{
3398+
void __iomem *rbase = gic_data_rdist_rd_base();
3399+
u64 timeout = USEC_PER_SEC;
3400+
u64 val;
3401+
3402+
if (!gic_rdists_supports_plpis()) {
3403+
pr_info("CPU%d: LPIs not supported\n", smp_processor_id());
3404+
return -ENXIO;
3405+
}
3406+
3407+
val = readl_relaxed(rbase + GICR_CTLR);
3408+
if (!(val & GICR_CTLR_ENABLE_LPIS))
3409+
return 0;
3410+
3411+
pr_warn("CPU%d: Booted with LPIs enabled, memory probably corrupted\n",
3412+
smp_processor_id());
3413+
add_taint(TAINT_CRAP, LOCKDEP_STILL_OK);
3414+
3415+
/* Disable LPIs */
3416+
val &= ~GICR_CTLR_ENABLE_LPIS;
3417+
writel_relaxed(val, rbase + GICR_CTLR);
3418+
3419+
/* Make sure any change to GICR_CTLR is observable by the GIC */
3420+
dsb(sy);
3421+
3422+
/*
3423+
* Software must observe RWP==0 after clearing GICR_CTLR.EnableLPIs
3424+
* from 1 to 0 before programming GICR_PEND{PROP}BASER registers.
3425+
* Error out if we time out waiting for RWP to clear.
3426+
*/
3427+
while (readl_relaxed(rbase + GICR_CTLR) & GICR_CTLR_RWP) {
3428+
if (!timeout) {
3429+
pr_err("CPU%d: Timeout while disabling LPIs\n",
3430+
smp_processor_id());
3431+
return -ETIMEDOUT;
3432+
}
3433+
udelay(1);
3434+
timeout--;
3435+
}
3436+
3437+
/*
3438+
* After it has been written to 1, it is IMPLEMENTATION
3439+
* DEFINED whether GICR_CTLR.EnableLPI becomes RES1 or can be
3440+
* cleared to 0. Error out if clearing the bit failed.
3441+
*/
3442+
if (readl_relaxed(rbase + GICR_CTLR) & GICR_CTLR_ENABLE_LPIS) {
3443+
pr_err("CPU%d: Failed to disable LPIs\n", smp_processor_id());
3444+
return -EBUSY;
3445+
}
3446+
3447+
return 0;
3448+
}
3449+
34063450
int its_cpu_init(void)
34073451
{
34083452
if (!list_empty(&its_nodes)) {
3409-
if (!gic_rdists_supports_plpis()) {
3410-
pr_info("CPU%d: LPIs not supported\n", smp_processor_id());
3411-
return -ENXIO;
3412-
}
3453+
int ret;
3454+
3455+
ret = redist_disable_lpis();
3456+
if (ret)
3457+
return ret;
3458+
34133459
its_cpu_init_lpis();
34143460
its_cpu_init_collections();
34153461
}

include/linux/irqchip/arm-gic-v3.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
#define GICR_PIDR2 GICD_PIDR2
107107

108108
#define GICR_CTLR_ENABLE_LPIS (1UL << 0)
109+
#define GICR_CTLR_RWP (1UL << 3)
109110

110111
#define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff)
111112

0 commit comments

Comments
 (0)