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
This commit is contained in:
parent
629734783d
commit
7d2dd08d01
@ -221,7 +221,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. */
|
||||
@ -246,6 +249,8 @@ struct gicv3_its_softc {
|
||||
cpuset_t sc_cpus;
|
||||
struct domainset *sc_ds;
|
||||
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 */
|
||||
@ -476,7 +481,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;
|
||||
|
||||
@ -505,6 +511,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++) {
|
||||
@ -515,7 +522,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);
|
||||
@ -527,8 +534,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:
|
||||
@ -550,7 +562,8 @@ gicv3_its_table_init(device_t dev, struct gicv3_its_softc *sc)
|
||||
(1ul << 48) - 1, 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);
|
||||
|
||||
@ -874,6 +887,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;
|
||||
@ -1200,6 +1214,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)
|
||||
{
|
||||
@ -1225,6 +1256,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);
|
||||
|
Loading…
Reference in New Issue
Block a user