aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>2024-02-28 14:08:24 +0000
committerWarner Losh <imp@FreeBSD.org>2024-04-16 21:27:35 +0000
commit5313024117409f58cbe6af04382768df1572d33b (patch)
tree8c0f7684308c7a1c964c057c595c03490cbea771
parent02eaed648f401f2aceaa1cea3fb2ca2e949b47e4 (diff)
gicv3: Panic if the gicv3 already running
Due to undefined behavior, it's impossible to re-program a gicv3 ITS table once it's programmed once. Memory corruption happens otherwise. Panic if we detect the LPI is already enabled. Sponsored by: Netflix Reviewed by: andrew Differential Revision: https://reviews.freebsd.org/D44033 (cherry picked from commit 51c57ca92ed3d0caf8f3e8c61345ac670d494901)
-rw-r--r--sys/arm64/arm64/gicv3_its.c23
1 files changed, 16 insertions, 7 deletions
diff --git a/sys/arm64/arm64/gicv3_its.c b/sys/arm64/arm64/gicv3_its.c
index 16ea48f49b7f..c9eff1e9f474 100644
--- a/sys/arm64/arm64/gicv3_its.c
+++ b/sys/arm64/arm64/gicv3_its.c
@@ -681,6 +681,8 @@ gicv3_its_conftable_init(struct gicv3_its_softc *sc)
{
/* note: we assume the ITS children are serialized by the parent */
static void *conf_table;
+ device_t gicv3;
+ uint32_t ctlr;
/*
* The PROPBASER is a singleton in our parent. We only set it up the
@@ -692,13 +694,20 @@ gicv3_its_conftable_init(struct gicv3_its_softc *sc)
return;
}
- /*
- * Just allocate contiguous pages. We'll configure the PROPBASER
- * register later in its_init_cpu_lpi().
- */
- conf_table = contigmalloc(LPI_CONFTAB_SIZE,
- M_GICV3_ITS, M_WAITOK, 0, LPI_CONFTAB_MAX_ADDR,
- LPI_CONFTAB_ALIGN, 0);
+ gicv3 = device_get_parent(sc->dev);
+ ctlr = gic_r_read_4(gicv3, GICR_CTLR);
+ if ((ctlr & GICR_CTLR_LPI_ENABLE) != 0) {
+ panic("gicv3 already enabled, can't reprogram.");
+ } else {
+
+ /*
+ * Otherwise just allocate contiguous pages. We'll configure the
+ * PROPBASER register later in its_init_cpu_lpi().
+ */
+ conf_table = contigmalloc(LPI_CONFTAB_SIZE,
+ M_GICV3_ITS, M_WAITOK, 0, LPI_CONFTAB_MAX_ADDR,
+ LPI_CONFTAB_ALIGN, 0);
+ }
sc->sc_conf_base = conf_table;
/* Set the default configuration */