diff options
author | Damien Zammit <damien@zamaudio.com> | 2023-07-16 00:43:57 +1000 |
---|---|---|
committer | Damien Zammit <damien@zamaudio.com> | 2023-07-20 20:00:37 +1000 |
commit | db94575b4eebb84852ea9bbad8216250c1f9cd19 (patch) | |
tree | 73881ad17e65c28eb9dd0bcf26ffbc00ab980419 | |
parent | 03d0b467804bf033c2be259be3f091231f74cff9 (diff) |
hurd: Make io port access granular and go through pci-arbiterfix-ioperm
-rw-r--r-- | src/hurd_pci.c | 95 | ||||
-rw-r--r-- | src/pciaccess_private.h | 3 | ||||
-rw-r--r-- | src/x86_pci.c | 6 | ||||
-rw-r--r-- | src/x86_pci.h | 3 |
4 files changed, 97 insertions, 10 deletions
diff --git a/src/hurd_pci.c b/src/hurd_pci.c index 8653e1b..09da28b 100644 --- a/src/hurd_pci.c +++ b/src/hurd_pci.c @@ -31,9 +31,11 @@ #include <fcntl.h> #include <dirent.h> #include <sys/mman.h> +#include <sys/io.h> #include <string.h> #include <strings.h> #include <mach.h> +#include <mach/machine/mach_i386.h> #include <hurd.h> #include <hurd/pci.h> #include <hurd/paths.h> @@ -74,6 +76,80 @@ struct pci_system_hurd { mach_port_t root; }; +/* TODO: remove me (io requests need to go through pci-arbiter) */ +static struct pci_io_handle * +pci_device_hurd_open_legacy_io(struct pci_io_handle *handle, + struct pci_device *dev, + pciaddr_t base, pciaddr_t size) +{ + /* Mach will eventually reject access to more than one process overlapping each requested range */ + if (!ioperm (base, base + size - 1, 1)) { + return NULL; + } + + handle->base = base; + handle->size = size; + handle->memory = NULL; + handle->fd = -1; + handle->is_legacy = 1; + handle->ioperm_port = MACH_PORT_NULL; + + return handle; +} + +static struct pci_io_handle * +pci_device_hurd_open_device_io(struct pci_io_handle *handle, + struct pci_device *dev, int bar, + pciaddr_t base, pciaddr_t size) +{ + mach_port_t io_perm; + struct pci_device_private *d; + d = (struct pci_device_private *)dev; + + if (__pci_request_io_ports (d->device_port, bar, &io_perm)) + return NULL; + + if (__i386_io_perm_modify (mach_task_self (), io_perm, 1)) + return NULL; + + handle->base = base; + handle->size = size; + handle->memory = NULL; + handle->fd = -1; + handle->is_legacy = 0; + handle->ioperm_port = io_perm; + + return handle; +} + +static void +pci_device_hurd_close_io(struct pci_device *dev, struct pci_io_handle *handle) +{ + int bar; + + if (handle->is_legacy) { + /* Just release the ports we requested earlier */ + ioperm (handle->base, handle->base + handle->size - 1, 0); + return; + } + + for (bar = 0; bar < 6; bar++) { + struct pci_mem_region *region = &(dev->regions[bar]); + if (!region->is_IO) + continue; + + if ((handle->base < region->base_addr) || (handle->base > (region->base_addr + region->size))) + continue; + + if ((handle->base + handle->size) > (region->base_addr + region->size)) + continue; + + __i386_io_perm_modify (mach_task_self (), handle->ioperm_port, 0); + + mach_port_deallocate (mach_task_self (), handle->ioperm_port); + } +} + static int pci_device_hurd_probe(struct pci_device *dev) { @@ -158,7 +234,6 @@ pci_system_hurd_destroy(void) { struct pci_system_hurd *pci_sys_hurd = (struct pci_system_hurd *)pci_sys; - x86_disable_io(); mach_port_deallocate(mach_task_self(), pci_sys_hurd->root); } @@ -200,6 +275,8 @@ pci_device_hurd_map_range(struct pci_device *dev, snprintf(server, NAME_MAX, "%04x/%02x/%02x/%01u/%s%01u", dev->domain, dev->bus, dev->dev, dev->func, FILE_REGION_NAME, map->region); + if (region->is_IO) + return EINVAL; } else { region = &rom_region; snprintf(server, NAME_MAX, "%04x/%02x/%02x/%01u/%s", @@ -640,8 +717,9 @@ static const struct pci_system_methods hurd_pci_methods = { .read = pci_device_hurd_read, .write = pci_device_hurd_write, .fill_capabilities = pci_fill_capabilities_generic, - .open_legacy_io = pci_device_x86_open_legacy_io, - .close_io = pci_device_x86_close_io, + .open_legacy_io = pci_device_hurd_open_legacy_io, + .open_device_io = pci_device_hurd_open_device_io, + .close_io = pci_device_hurd_close_io, .read32 = pci_device_x86_read32, .read16 = pci_device_x86_read16, .read8 = pci_device_x86_read8, @@ -673,16 +751,17 @@ pci_system_hurd_create(void) return 0; } - /* - * From this point on, we are either a client or a nested arbiter. - * Both will connect to a master arbiter. - */ - pci_sys_hurd = calloc(1, sizeof(struct pci_system_hurd)); if (pci_sys_hurd == NULL) { x86_disable_io(); return ENOMEM; } + + /* + * From this point on, we are either a client or a nested arbiter. + * Both will connect to a master arbiter. + */ + pci_sys = &pci_sys_hurd->system; pci_sys->methods = &hurd_pci_methods; diff --git a/src/pciaccess_private.h b/src/pciaccess_private.h index 078b7be..16b4571 100644 --- a/src/pciaccess_private.h +++ b/src/pciaccess_private.h @@ -114,6 +114,9 @@ struct pci_io_handle { void *memory; int fd; int is_legacy; +#ifdef __GNU__ + unsigned long ioperm_port; +#endif }; struct pci_device_private { diff --git a/src/x86_pci.c b/src/x86_pci.c index dfe3fa3..0207e2f 100644 --- a/src/x86_pci.c +++ b/src/x86_pci.c @@ -45,7 +45,9 @@ int x86_enable_io(void) { - if (!ioperm(0, 0xffff, 1)) + /* The first process to claim this gets to be the pci-arbiter + * and mach will eventually reject all subsequent requests to any overlapping ranges */ + if (!ioperm(PCI_CFG1_BASE, PCI_CFG1_BASE + PCI_CFG1_SIZE - 1, 1)) return 0; return errno; } @@ -53,7 +55,7 @@ x86_enable_io(void) int x86_disable_io(void) { - if (!ioperm(0, 0xffff, 0)) + if (!ioperm(PCI_CFG1_BASE, PCI_CFG1_BASE + PCI_CFG1_SIZE - 1, 0)) return 0; return errno; } diff --git a/src/x86_pci.h b/src/x86_pci.h index b550e3d..2ef8e71 100644 --- a/src/x86_pci.h +++ b/src/x86_pci.h @@ -28,6 +28,9 @@ #include "pciaccess.h" #include "pciaccess_private.h" +#define PCI_CFG1_BASE 0xcf8 +#define PCI_CFG1_SIZE 8 + #define PCI_VENDOR(reg) ((reg) & 0xFFFF) #define PCI_VENDOR_INVALID 0xFFFF |