aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Turner <andrew@FreeBSD.org>2023-08-22 14:37:19 +0000
committerAndrew Turner <andrew@FreeBSD.org>2023-09-25 10:50:56 +0000
commit107bb46b6cc238cc6257f80e58f8fa3c94df45e1 (patch)
tree1ac07c8a5f505f4be22832264dc6b57eeeda1cce
parentb549c8f9e6e093fbbddd1a160ef61351d0fe5110 (diff)
downloadsrc-107bb46b6cc238cc6257f80e58f8fa3c94df45e1.tar.gz
src-107bb46b6cc238cc6257f80e58f8fa3c94df45e1.zip
gicv3: Add checks for the device ID
Add checks that the device ID is supported by the hardware and is within the range allocated when the driver attaches. Reviewed by: gallatin, imp Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D41554 (cherry picked from commit 7d2dd08d013d79dc3f2a22747b079628a571cea2)
-rw-r--r--sys/arm64/arm64/gicv3_its.c48
1 files changed, 42 insertions, 6 deletions
diff --git a/sys/arm64/arm64/gicv3_its.c b/sys/arm64/arm64/gicv3_its.c
index 74f2894d0a2c..852db0054aa7 100644
--- a/sys/arm64/arm64/gicv3_its.c
+++ b/sys/arm64/arm64/gicv3_its.c
@@ -220,7 +220,10 @@ struct its_cmd {
/* An ITS private table */
struct its_ptable {
vm_offset_t ptab_vaddr;
- unsigned long ptab_size;
+ /* Size of the L1 table */
+ size_t ptab_l1_size;
+ /* Number of L1 entries */
+ int ptab_l1_nidents;
};
/* ITS collection description. */
@@ -244,6 +247,8 @@ struct gicv3_its_softc {
cpuset_t sc_cpus;
u_int gic_irq_cpu;
+ int sc_devbits;
+ int sc_dev_table_idx;
struct its_ptable sc_its_ptab[GITS_BASER_NUM];
struct its_col *sc_its_cols[MAXCPU]; /* Per-CPU collections */
@@ -473,7 +478,8 @@ gicv3_its_table_init(device_t dev, struct gicv3_its_softc *sc)
vm_offset_t table;
vm_paddr_t paddr;
uint64_t cache, reg, share, tmp, type;
- size_t esize, its_tbl_size, nidents, nitspages, npages;
+ size_t its_tbl_size, nitspages, npages;
+ size_t l1_esize, l1_nidents;
int i, page_size;
int devbits;
@@ -502,6 +508,7 @@ gicv3_its_table_init(device_t dev, struct gicv3_its_softc *sc)
devbits = GITS_TYPER_DEVB(gic_its_read_8(sc, GITS_TYPER));
cache = GITS_BASER_CACHE_WAWB;
}
+ sc->sc_devbits = devbits;
share = GITS_BASER_SHARE_IS;
for (i = 0; i < GITS_BASER_NUM; i++) {
@@ -512,7 +519,7 @@ gicv3_its_table_init(device_t dev, struct gicv3_its_softc *sc)
continue;
/* The table entry size */
- esize = GITS_BASER_ESIZE(reg);
+ l1_esize = GITS_BASER_ESIZE(reg);
/* Find the tables page size */
page_size = gicv3_its_table_page_size(sc, i);
@@ -524,8 +531,13 @@ gicv3_its_table_init(device_t dev, struct gicv3_its_softc *sc)
switch(type) {
case GITS_BASER_TYPE_DEV:
- nidents = (1 << devbits);
- its_tbl_size = esize * nidents;
+ if (sc->sc_dev_table_idx != -1)
+ device_printf(dev,
+ "Warning: Multiple device tables found\n");
+
+ sc->sc_dev_table_idx = i;
+ l1_nidents = (1 << devbits);
+ its_tbl_size = l1_esize * l1_nidents;
its_tbl_size = roundup2(its_tbl_size, page_size);
break;
case GITS_BASER_TYPE_VP:
@@ -547,7 +559,8 @@ gicv3_its_table_init(device_t dev, struct gicv3_its_softc *sc)
PAGE_SIZE_64K, 0);
sc->sc_its_ptab[i].ptab_vaddr = table;
- sc->sc_its_ptab[i].ptab_size = npages * PAGE_SIZE;
+ sc->sc_its_ptab[i].ptab_l1_size = its_tbl_size;
+ sc->sc_its_ptab[i].ptab_l1_nidents = l1_nidents;
paddr = vtophys(table);
@@ -870,6 +883,7 @@ gicv3_its_attach(device_t dev)
sc = device_get_softc(dev);
+ sc->sc_dev_table_idx = -1;
sc->sc_irq_length = gicv3_get_nirqs(dev);
sc->sc_irq_base = GIC_FIRST_LPI;
sc->sc_irq_base += device_get_unit(dev) * sc->sc_irq_length;
@@ -1188,6 +1202,23 @@ its_device_find(device_t dev, device_t child)
return (its_dev);
}
+static bool
+its_device_alloc(struct gicv3_its_softc *sc, int devid)
+{
+ struct its_ptable *ptable;
+
+ /* No device table */
+ if (sc->sc_dev_table_idx < 0) {
+ if (devid < (1 << sc->sc_devbits))
+ return (true);
+ return (false);
+ }
+
+ ptable = &sc->sc_its_ptab[sc->sc_dev_table_idx];
+ /* Check the devid is within the table limit */
+ return (devid < ptable->ptab_l1_nidents);
+}
+
static struct its_dev *
its_device_get(device_t dev, device_t child, u_int nvecs)
{
@@ -1213,6 +1244,11 @@ its_device_get(device_t dev, device_t child, u_int nvecs)
its_dev->lpis.lpi_num = nvecs;
its_dev->lpis.lpi_free = nvecs;
+ if (!its_device_alloc(sc, its_dev->devid)) {
+ free(its_dev, M_GICV3_ITS);
+ return (NULL);
+ }
+
if (vmem_alloc(sc->sc_irq_alloc, nvecs, M_FIRSTFIT | M_NOWAIT,
&irq_base) != 0) {
free(its_dev, M_GICV3_ITS);