git: ae16cbfdd2a1 - main - gicv3: Use an offset to find the redist registers
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 31 May 2023 14:20:14 UTC
The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=ae16cbfdd2a1821f69d166c4fc4cdbb4b8d5ef62 commit ae16cbfdd2a1821f69d166c4fc4cdbb4b8d5ef62 Author: Andrew Turner <andrew@FreeBSD.org> AuthorDate: 2023-05-25 08:22:03 +0000 Commit: Andrew Turner <andrew@FreeBSD.org> CommitDate: 2023-05-31 14:10:41 +0000 gicv3: Use an offset to find the redist registers To find the redistributor registers use the resource we have already found and add an offset. This removed the need to create a per-redistributor resource as it can now be a pointer to the resource found in attach. While here check the offset is within the bounds of the resource. Some ACPI tables list each redistributor as a separate memory range, even if they are physically contiguous. In this case we may not have each resource virtually contiguous with neighbouring resources. This can lead to a data abort when reading past the resource range. Reviewed by: kevans Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D40263 --- sys/arm64/arm64/gic_v3.c | 41 ++++++++++++++++++++++++----------------- sys/arm64/arm64/gic_v3_var.h | 12 +++++++----- sys/arm64/arm64/gicv3_its.c | 3 ++- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/sys/arm64/arm64/gic_v3.c b/sys/arm64/arm64/gic_v3.c index e9754797d095..d108cabfe4d9 100644 --- a/sys/arm64/arm64/gic_v3.c +++ b/sys/arm64/arm64/gic_v3.c @@ -226,7 +226,8 @@ gic_r_read_4(device_t dev, bus_size_t offset) struct resource *rdist; sc = device_get_softc(dev); - rdist = &sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res; + rdist = sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res; + offset += sc->gic_redists.pcpu[PCPU_GET(cpuid)]->offset; return (bus_read_4(rdist, offset)); } @@ -237,7 +238,8 @@ gic_r_read_8(device_t dev, bus_size_t offset) struct resource *rdist; sc = device_get_softc(dev); - rdist = &sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res; + rdist = sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res; + offset += sc->gic_redists.pcpu[PCPU_GET(cpuid)]->offset; return (bus_read_8(rdist, offset)); } @@ -248,7 +250,8 @@ gic_r_write_4(device_t dev, bus_size_t offset, uint32_t val) struct resource *rdist; sc = device_get_softc(dev); - rdist = &sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res; + rdist = sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res; + offset += sc->gic_redists.pcpu[PCPU_GET(cpuid)]->offset; bus_write_4(rdist, offset, val); } @@ -259,7 +262,8 @@ gic_r_write_8(device_t dev, bus_size_t offset, uint64_t val) struct resource *rdist; sc = device_get_softc(dev); - rdist = &sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res; + rdist = sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res; + offset += sc->gic_redists.pcpu[PCPU_GET(cpuid)]->offset; bus_write_8(rdist, offset, val); } @@ -1215,6 +1219,7 @@ static void gic_v3_wait_for_rwp(struct gic_v3_softc *sc, enum gic_v3_xdist xdist) { struct resource *res; + bus_size_t offset; u_int cpuid; size_t us_left = 1000000; @@ -1223,16 +1228,18 @@ gic_v3_wait_for_rwp(struct gic_v3_softc *sc, enum gic_v3_xdist xdist) switch (xdist) { case DIST: res = sc->gic_dist; + offset = 0; break; case REDIST: - res = &sc->gic_redists.pcpu[cpuid]->res; + res = sc->gic_redists.pcpu[cpuid]->res; + offset = sc->gic_redists.pcpu[PCPU_GET(cpuid)]->offset; break; default: KASSERT(0, ("%s: Attempt to wait for unknown RWP", __func__)); return; } - while ((bus_read_4(res, GICD_CTLR) & GICD_CTLR_RWP) != 0) { + while ((bus_read_4(res, offset + GICD_CTLR) & GICD_CTLR_RWP) != 0) { DELAY(1); if (us_left-- == 0) panic("GICD Register write pending for too long"); @@ -1377,8 +1384,8 @@ gic_v3_redist_alloc(struct gic_v3_softc *sc) static int gic_v3_redist_find(struct gic_v3_softc *sc) { - struct resource r_res; - bus_space_handle_t r_bsh; + struct resource *r_res; + bus_size_t offset; uint64_t aff; uint64_t typer; uint32_t pidr2; @@ -1399,10 +1406,9 @@ gic_v3_redist_find(struct gic_v3_softc *sc) /* Iterate through Re-Distributor regions */ for (i = 0; i < sc->gic_redists.nregions; i++) { /* Take a copy of the region's resource */ - r_res = *sc->gic_redists.regions[i]; - r_bsh = rman_get_bushandle(&r_res); + r_res = sc->gic_redists.regions[i]; - pidr2 = bus_read_4(&r_res, GICR_PIDR2); + pidr2 = bus_read_4(r_res, GICR_PIDR2); switch (GICR_PIDR2_ARCH(pidr2)) { case GICR_PIDR2_ARCH_GICv3: /* fall through */ case GICR_PIDR2_ARCH_GICv4: @@ -1413,13 +1419,15 @@ gic_v3_redist_find(struct gic_v3_softc *sc) return (ENODEV); } + offset = 0; do { - typer = bus_read_8(&r_res, GICR_TYPER); + typer = bus_read_8(r_res, offset + GICR_TYPER); if ((typer >> GICR_TYPER_AFF_SHIFT) == aff) { KASSERT(sc->gic_redists.pcpu[cpuid] != NULL, ("Invalid pointer to per-CPU redistributor")); /* Copy res contents to its final destination */ sc->gic_redists.pcpu[cpuid]->res = r_res; + sc->gic_redists.pcpu[cpuid]->offset = offset; sc->gic_redists.pcpu[cpuid]->lpi_enabled = false; if (bootverbose) { device_printf(sc->dev, @@ -1429,14 +1437,13 @@ gic_v3_redist_find(struct gic_v3_softc *sc) return (0); } - r_bsh += (GICR_RD_BASE_SIZE + GICR_SGI_BASE_SIZE); + offset += (GICR_RD_BASE_SIZE + GICR_SGI_BASE_SIZE); if ((typer & GICR_TYPER_VLPIS) != 0) { - r_bsh += + offset += (GICR_VLPI_BASE_SIZE + GICR_RESERVED_SIZE); } - - rman_set_bushandle(&r_res, r_bsh); - } while ((typer & GICR_TYPER_LAST) == 0); + } while (offset < rman_get_size(r_res) && + (typer & GICR_TYPER_LAST) == 0); } device_printf(sc->dev, "No Re-Distributor found for CPU%u\n", cpuid); diff --git a/sys/arm64/arm64/gic_v3_var.h b/sys/arm64/arm64/gic_v3_var.h index 9fa8b82e16bc..47e73c1ab3b7 100644 --- a/sys/arm64/arm64/gic_v3_var.h +++ b/sys/arm64/arm64/gic_v3_var.h @@ -40,8 +40,9 @@ DECLARE_CLASS(gic_v3_driver); struct gic_v3_irqsrc; struct redist_pcpu { - struct resource res; /* mem resource for redist */ + struct resource *res; /* mem resource for redist */ vm_offset_t pend_base; + bus_size_t offset; bool lpi_enabled; /* redist LPI configured? */ }; @@ -137,8 +138,8 @@ void gic_r_write_8(device_t, bus_size_t, uint64_t var); u_int cpu = PCPU_GET(cpuid); \ \ bus_read_##len( \ - &(sc)->gic_redists.pcpu[cpu]->res, \ - (reg)); \ + (sc)->gic_redists.pcpu[cpu]->res, \ + (sc)->gic_redists.pcpu[cpu]->offset + (reg)); \ }) #define gic_r_write(sc, len, reg, val) \ @@ -146,8 +147,9 @@ void gic_r_write_8(device_t, bus_size_t, uint64_t var); u_int cpu = PCPU_GET(cpuid); \ \ bus_write_##len( \ - &(sc)->gic_redists.pcpu[cpu]->res, \ - (reg), (val)); \ + (sc)->gic_redists.pcpu[cpu]->res, \ + (sc)->gic_redists.pcpu[cpu]->offset + (reg), \ + (val)); \ }) #endif /* _GIC_V3_VAR_H_ */ diff --git a/sys/arm64/arm64/gicv3_its.c b/sys/arm64/arm64/gicv3_its.c index 9c8f87e74f31..57351a7e76aa 100644 --- a/sys/arm64/arm64/gicv3_its.c +++ b/sys/arm64/arm64/gicv3_its.c @@ -723,7 +723,8 @@ its_init_cpu(device_t dev, struct gicv3_its_softc *sc) if ((gic_its_read_8(sc, GITS_TYPER) & GITS_TYPER_PTA) != 0) { /* This ITS wants the redistributor physical address */ - target = vtophys(rman_get_virtual(&rpcpu->res)); + target = vtophys((vm_offset_t)rman_get_virtual(rpcpu->res) + + rpcpu->offset); } else { /* This ITS wants the unique processor number */ target = GICR_TYPER_CPUNUM(gic_r_read_8(gicv3, GICR_TYPER)) <<