diff options
Diffstat (limited to 'src/hurd_pci.c')
-rw-r--r-- | src/hurd_pci.c | 95 |
1 files changed, 87 insertions, 8 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; |