From 8827bb6d8900b92090ba79b2db13b88f7500c276 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sat, 11 Jul 2020 23:05:22 +0200 Subject: [PATCH] freebsd_network: Apply empty size and type check to IO ports. Factor out the conversion to BAR index and hand the pci_info to both memory and IO port allocation functions. Then apply the same checks in the IO port case as are done for memory. This aligns with what is done on FreeBSD. Change-Id: Ib4bd28fd861959a467ba676de22efb1f97e5a27c Reviewed-on: https://review.haiku-os.org/c/haiku/+/3025 Reviewed-by: waddlesplash --- src/libs/compat/freebsd_network/bus.cpp | 69 +++++++++++++++++-------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/src/libs/compat/freebsd_network/bus.cpp b/src/libs/compat/freebsd_network/bus.cpp index fd696b4b9c..506f8937ac 100644 --- a/src/libs/compat/freebsd_network/bus.cpp +++ b/src/libs/compat/freebsd_network/bus.cpp @@ -110,29 +110,19 @@ bus_alloc_irq_resource(device_t dev, struct resource *res) static int -bus_alloc_mem_resource(device_t dev, struct resource *res, int regid) +bus_alloc_mem_resource(device_t dev, struct resource *res, pci_info *info, + int bar_index) { - pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info; - - // check the offset really is of a BAR - if (regid < PCI_base_registers || (regid % sizeof(uint32) != 0) - || (regid >= PCI_base_registers + 6 * (int)sizeof(uint32))) - return -1; - - // turn offset into array index - regid -= PCI_base_registers; - regid /= sizeof(uint32); - - uint32 addr = info->u.h0.base_registers[regid]; - uint32 size = info->u.h0.base_register_sizes[regid]; - uchar flags = info->u.h0.base_register_flags[regid]; + uint32 addr = info->u.h0.base_registers[bar_index]; + uint32 size = info->u.h0.base_register_sizes[bar_index]; + uchar flags = info->u.h0.base_register_flags[bar_index]; // reject empty regions if (size == 0) return -1; // reject I/O space - if (flags & PCI_address_space) + if ((flags & PCI_address_space) != 0) return -1; // TODO: check flags & PCI_address_prefetchable ? @@ -155,18 +145,46 @@ bus_alloc_mem_resource(device_t dev, struct resource *res, int regid) static int -bus_alloc_ioport_resource(device_t dev, struct resource *res, int regid) +bus_alloc_ioport_resource(device_t dev, struct resource *res, pci_info *info, + int bar_index) { + uint32 size = info->u.h0.base_register_sizes[bar_index]; + uchar flags = info->u.h0.base_register_flags[bar_index]; + + // reject empty regions + if (size == 0) + return -1; + + // reject memory space + if ((flags & PCI_address_space) == 0) + return -1; + // enable this I/O resource if (pci_enable_io(dev, SYS_RES_IOPORT) != 0) return -1; res->r_bustag = X86_BUS_SPACE_IO; - res->r_bushandle = pci_read_config(dev, regid, 4) & PCI_address_io_mask; + res->r_bushandle = info->u.h0.base_registers[bar_index]; return 0; } +static int +bus_register_to_bar_index(pci_info *info, int regid) +{ + // check the offset really is of a BAR + if (regid < PCI_base_registers || (regid % sizeof(uint32) != 0) + || (regid >= PCI_base_registers + 6 * (int)sizeof(uint32))) { + return -1; + } + + // turn offset into array index + regid -= PCI_base_registers; + regid /= sizeof(uint32); + return regid; +} + + struct resource * bus_alloc_resource(device_t dev, int type, int *rid, unsigned long start, unsigned long end, unsigned long count, uint32 flags) @@ -198,10 +216,17 @@ bus_alloc_resource(device_t dev, int type, int *rid, unsigned long start, res->r_bushandle = info->u.h0.interrupt_line + *rid - 1; result = 0; } - } else if (type == SYS_RES_MEMORY) - result = bus_alloc_mem_resource(dev, res, *rid); - else if (type == SYS_RES_IOPORT) - result = bus_alloc_ioport_resource(dev, res, *rid); + } else if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { + pci_info *info + = &((struct root_device_softc *)dev->root->softc)->pci_info; + int bar_index = bus_register_to_bar_index(info, *rid); + if (bar_index >= 0) { + if (type == SYS_RES_MEMORY) + result = bus_alloc_mem_resource(dev, res, info, bar_index); + else + result = bus_alloc_ioport_resource(dev, res, info, bar_index); + } + } if (result < 0) { free(res);