diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2009-07-26 19:56:46 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2009-07-26 19:56:46 +0000 |
commit | a29d0e216725a6b1807156bd981d51a92267d524 (patch) | |
tree | 224496452ef6c35d31f9df45f03a548c22f60b60 | |
parent | 372d908cdf6cb8b6da3978805b6e704774ccec01 (diff) |
A better implementation of bus_space_subregion() for xbridge, with boundary
checks if option DIAGNOSTIC.
-rw-r--r-- | sys/arch/sgi/xbow/xbridge.c | 135 |
1 files changed, 134 insertions, 1 deletions
diff --git a/sys/arch/sgi/xbow/xbridge.c b/sys/arch/sgi/xbow/xbridge.c index c2e3636d83c..3db0600a906 100644 --- a/sys/arch/sgi/xbow/xbridge.c +++ b/sys/arch/sgi/xbow/xbridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xbridge.c,v 1.42 2009/07/26 18:48:55 miod Exp $ */ +/* $OpenBSD: xbridge.c,v 1.43 2009/07/26 19:56:45 miod Exp $ */ /* * Copyright (c) 2008, 2009 Miodrag Vallat. @@ -176,6 +176,12 @@ int xbridge_space_map_io(bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_handle_t *); int xbridge_space_map_mem(bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_handle_t *); +int xbridge_space_region_devio(bus_space_tag_t, bus_space_handle_t, + bus_size_t, bus_size_t, bus_space_handle_t *); +int xbridge_space_region_io(bus_space_tag_t, bus_space_handle_t, + bus_size_t, bus_size_t, bus_space_handle_t *); +int xbridge_space_region_mem(bus_space_tag_t, bus_space_handle_t, + bus_size_t, bus_size_t, bus_space_handle_t *); int xbridge_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t, struct proc *, int, paddr_t *, int *, int); @@ -309,6 +315,7 @@ xbridge_attach(struct device *parent, struct device *self, void *aux) sizeof(*sc->sc_mem_bus_space)); sc->sc_mem_bus_space->bus_private = sc; sc->sc_mem_bus_space->_space_map = xbridge_space_map_devio; + sc->sc_mem_bus_space->_space_subregion = xbridge_space_region_devio; sc->sc_mem_bus_space->_space_read_1 = xbridge_read_1; sc->sc_mem_bus_space->_space_write_1 = xbridge_write_1; sc->sc_mem_bus_space->_space_read_2 = xbridge_read_2; @@ -324,6 +331,7 @@ xbridge_attach(struct device *parent, struct device *self, void *aux) sizeof(*sc->sc_io_bus_space)); sc->sc_io_bus_space->bus_private = sc; sc->sc_io_bus_space->_space_map = xbridge_space_map_devio; + sc->sc_io_bus_space->_space_subregion = xbridge_space_region_devio; sc->sc_io_bus_space->_space_read_1 = xbridge_read_1; sc->sc_io_bus_space->_space_write_1 = xbridge_write_1; sc->sc_io_bus_space->_space_read_2 = xbridge_read_2; @@ -1052,6 +1060,12 @@ xbridge_space_map_io(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, if ((offs >> 24) == sc->sc_devio_skew) return xbridge_space_map_devio(t, offs, size, flags, bshp); +#ifdef DIAGNOSTIC + /* check that this does not overflow the mapping */ + if (offs < sc->sc_iostart || offs + size - 1 > sc->sc_ioend) + return EINVAL; +#endif + *bshp = (t->bus_base + offs); return 0; } @@ -1072,10 +1086,125 @@ xbridge_space_map_mem(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, (offs >> 24) == sc->sc_devio_skew) return xbridge_space_map_devio(t, offs, size, flags, bshp); +#ifdef DIAGNOSTIC + /* check that this does not overflow the mapping */ + if (offs < sc->sc_memstart || offs + size - 1 > sc->sc_memend) + return EINVAL; +#endif + *bshp = (t->bus_base + offs); return 0; } +int +xbridge_space_region_devio(bus_space_tag_t t , bus_space_handle_t bsh, + bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) +{ + struct xbridge_softc *sc = (struct xbridge_softc *)t->bus_private; +#ifdef DIAGNOSTIC + bus_addr_t bpa; + bus_addr_t start, end; + uint d; +#endif + +#ifdef DIAGNOSTIC + /* + * Note we can not use our own bus_base because it might not point + * to our small window. Instead, use the one used by the xbridge + * driver itself, which _always_ points to the short window. + */ + bpa = (bus_addr_t)bsh - sc->sc_iot->bus_base; + + if ((bpa >> 24) != 0) + return EINVAL; /* not a devio mapping */ + + /* + * Figure out which devio `slot' we are using, and make sure + * we do not overrun it. + */ + for (d = 0; d < BRIDGE_NSLOTS; d++) { + start = BRIDGE_DEVIO_OFFS(d); + end = start + BRIDGE_DEVIO_SIZE(d); + if (bpa >= start && bpa < end) { + if (bpa + offset + size > end) + return EINVAL; + else + break; + } + } + if (d == BRIDGE_NSLOTS) + return EINVAL; +#endif + + *nbshp = bsh + offset; + return 0; +} + +int +xbridge_space_region_io(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) +{ + struct xbridge_softc *sc = (struct xbridge_softc *)t->bus_private; + bus_addr_t bpa; + + /* + * Note we can not use our own bus_base because it might not point + * to our small window. Instead, use the one used by the xbridge + * driver itself, which _always_ points to the short window. + */ + bpa = (bus_addr_t)bsh - sc->sc_iot->bus_base; + + if ((bpa >> 24) == 0) + return xbridge_space_region_devio(t, bsh, offset, size, nbshp); + +#ifdef DIAGNOSTIC + /* check that this does not overflow the mapping */ + bpa = (bus_addr_t)bsh - t->bus_base; + if (bpa + offset + size - 1 > sc->sc_ioend) + return EINVAL; +#endif + + *nbshp = bsh + offset; + return 0; +} + +int +xbridge_space_region_mem(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) +{ + struct xbridge_softc *sc = (struct xbridge_softc *)t->bus_private; + bus_addr_t bpa; + + /* + * Base address is either within the devio area, or our direct + * window. Except on Octane where we never setup devio memory + * mappings, because the large mapping is always available. + */ + if (sys_config.system_type != SGI_OCTANE) { + /* + * Note we can not use our own bus_base because it might not + * point to our small window. Instead, use the one used by + * the xbridge driver itself, which _always_ points to the + * short window. + */ + bpa = (bus_addr_t)bsh - sc->sc_iot->bus_base; + + if ((bpa >> 24) == 0) + return xbridge_space_region_devio(t, bsh, offset, size, + nbshp); + } + +#ifdef DIAGNOSTIC + /* check that this does not overflow the mapping */ + bpa = (bus_addr_t)bsh - t->bus_base; + if (bpa + offset + size - 1 > sc->sc_memend) + return EINVAL; +#endif + + *nbshp = bsh + offset; + return 0; +} + /* ********************* bus_dma helpers */ @@ -2198,6 +2327,8 @@ xbridge_mapping_setup(struct xbridge_softc *sc, int io) sc->sc_io_bus_space->bus_base = base - offs; sc->sc_io_bus_space->_space_map = xbridge_space_map_io; + sc->sc_io_bus_space->_space_subregion = + xbridge_space_region_io; sc->sc_iostart = offs; sc->sc_ioend = offs + len - 1; @@ -2239,6 +2370,8 @@ xbridge_mapping_setup(struct xbridge_softc *sc, int io) sc->sc_mem_bus_space->bus_base = base - offs; sc->sc_mem_bus_space->_space_map = xbridge_space_map_mem; + sc->sc_mem_bus_space->_space_subregion = + xbridge_space_region_mem; sc->sc_memstart = offs; sc->sc_memend = offs + len - 1; |