summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2023-07-16 00:43:57 +1000
committerDamien Zammit <damien@zamaudio.com>2023-07-20 20:00:37 +1000
commitdb94575b4eebb84852ea9bbad8216250c1f9cd19 (patch)
tree73881ad17e65c28eb9dd0bcf26ffbc00ab980419
parent03d0b467804bf033c2be259be3f091231f74cff9 (diff)
hurd: Make io port access granular and go through pci-arbiterfix-ioperm
-rw-r--r--src/hurd_pci.c95
-rw-r--r--src/pciaccess_private.h3
-rw-r--r--src/x86_pci.c6
-rw-r--r--src/x86_pci.h3
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