[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] New access method: Hurd via RPCs
From: |
Joan Lledó |
Subject: |
[PATCH] New access method: Hurd via RPCs |
Date: |
Sun, 3 Dec 2017 11:21:55 +0100 |
A new module for the Hurd that accesses PCI bus using available RPCs.
All references to the Hurd in the i386 access method have been removed.
---
lib/Makefile | 7 +-
lib/configure | 6 +-
lib/hurd.c | 366 +++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/i386-io-hurd.h | 27 ----
lib/i386-ports.c | 4 -
lib/init.c | 5 +
lib/internal.h | 2 +-
lib/pci.h | 1 +
8 files changed, 382 insertions(+), 36 deletions(-)
create mode 100644 lib/hurd.c
delete mode 100644 lib/i386-io-hurd.h
diff --git a/lib/Makefile b/lib/Makefile
index f119b72..3e824dd 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -46,6 +46,10 @@ ifdef PCI_HAVE_PM_DARWIN_DEVICE
OBJS += darwin
endif
+ifdef PCI_HAVE_PM_HURD_CONF
+OBJS += hurd
+endif
+
all: $(PCILIB) $(PCILIBPC)
ifeq ($(SHARED),no)
@@ -74,7 +78,7 @@ $(PCILIBPC): libpci.pc.in
init.o: init.c $(INCL)
access.o: access.c $(INCL)
params.o: params.c $(INCL)
-i386-ports.o: i386-ports.c $(INCL) i386-io-hurd.h i386-io-linux.h
i386-io-sunos.h i386-io-windows.h i386-io-cygwin.h
+i386-ports.o: i386-ports.c $(INCL) i386-io-linux.h i386-io-sunos.h
i386-io-windows.h i386-io-cygwin.h
proc.o: proc.c $(INCL) pread.h
sysfs.o: sysfs.c $(INCL) pread.h
generic.o: generic.c $(INCL)
@@ -91,3 +95,4 @@ names-parse.o: names-parse.c $(INCL) names.h
names-hwdb.o: names-hwdb.c $(INCL) names.h
filter.o: filter.c $(INCL)
nbsd-libpci.o: nbsd-libpci.c $(INCL)
+hurd.o: hurd.c $(INCL)
diff --git a/lib/configure b/lib/configure
index 7d4cec8..1a6b171 100755
--- a/lib/configure
+++ b/lib/configure
@@ -125,9 +125,9 @@ case $sys in
echo >>$m 'WITH_LIBS+=-lpci'
LIBRESOLV=
;;
- gnu)
- echo_n " i386-ports"
- echo >>$c '#define PCI_HAVE_PM_INTEL_CONF'
+ gnu)
+ echo_n " hurd"
+ echo >>$c '#define PCI_HAVE_PM_HURD_CONF'
;;
cygwin)
echo_n " i386-ports"
diff --git a/lib/hurd.c b/lib/hurd.c
new file mode 100644
index 0000000..40aa067
--- /dev/null
+++ b/lib/hurd.c
@@ -0,0 +1,366 @@
+/*
+ * The PCI Library -- Hurd access via RPCs
+ *
+ * Copyright (c) 2017 Joan Lledó <jlledom@member.fsf.org>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#define _GNU_SOURCE
+
+#include "internal.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <string.h>
+#include <assert.h>
+#include <hurd.h>
+#include <hurd/pci.h>
+#include <hurd/paths.h>
+
+/* Server path */
+#define _SERVERS_PCI_CONF _SERVERS_BUS "/pci"
+
+/* File names */
+#define FILE_CONFIG_NAME "config"
+#define FILE_ROM_NAME "rom"
+
+/* Level in the fs tree */
+typedef enum
+{
+ LEVEL_NONE,
+ LEVEL_DOMAIN,
+ LEVEL_BUS,
+ LEVEL_DEV,
+ LEVEL_FUNC
+} tree_level;
+
+/* Check whether there's a pci server */
+static int
+hurd_detect (struct pci_access *a)
+{
+ int err;
+ struct stat st;
+
+ err = lstat (_SERVERS_PCI_CONF, &st);
+ if (err)
+ {
+ a->error ("Could not open file `%s'", _SERVERS_PCI_CONF);
+ return 0;
+ }
+
+ /* The node must be a directory and a translator */
+ return S_ISDIR (st.st_mode) && ((st.st_mode & S_ITRANS) == S_IROOT);
+}
+
+/* Empty callbacks, we don't need any special init or cleanup */
+static void
+hurd_init (struct pci_access *a UNUSED)
+{
+}
+
+static void
+hurd_cleanup (struct pci_access *a UNUSED)
+{
+}
+
+/* Each device has its own server path. Allocate space for the port. */
+static void
+hurd_init_dev (struct pci_dev *d)
+{
+ d->aux = calloc (1, sizeof (mach_port_t));
+ assert (d->aux);
+}
+
+/* Deallocate the port and free its space */
+static void
+hurd_cleanup_dev (struct pci_dev *d)
+{
+ mach_port_t device_port;
+
+ device_port = *((mach_port_t *) d->aux);
+ mach_port_deallocate (mach_task_self (), device_port);
+
+ free (d->aux);
+}
+
+/* Walk through the FS tree to see what is allowed for us */
+static int
+enum_devices (const char *parent, struct pci_access *a, int domain, int bus,
+ int dev, int func, tree_level lev)
+{
+ int err, ret;
+ DIR *dir;
+ struct dirent *entry;
+ char path[NAME_MAX];
+ char server[NAME_MAX];
+ uint32_t vd;
+ uint8_t ht;
+ mach_port_t device_port;
+ struct pci_dev *d;
+
+ dir = opendir (parent);
+ if (!dir)
+ return errno;
+
+ while ((entry = readdir (dir)) != 0)
+ {
+ snprintf (path, NAME_MAX, "%s/%s", parent, entry->d_name);
+ if (entry->d_type == DT_DIR)
+ {
+ if (!strncmp (entry->d_name, ".", NAME_MAX)
+ || !strncmp (entry->d_name, "..", NAME_MAX))
+ continue;
+
+ errno = 0;
+ ret = strtol (entry->d_name, 0, 16);
+ if (errno)
+ return errno;
+
+ /*
+ * We found a valid directory.
+ * Update the address and switch to the next level.
+ */
+ switch (lev)
+ {
+ case LEVEL_DOMAIN:
+ domain = ret;
+ break;
+ case LEVEL_BUS:
+ bus = ret;
+ break;
+ case LEVEL_DEV:
+ dev = ret;
+ break;
+ case LEVEL_FUNC:
+ func = ret;
+ break;
+ default:
+ return -1;
+ }
+
+ err = enum_devices (path, a, domain, bus, dev, func, lev + 1);
+ if (err == EPERM)
+ continue;
+ }
+ else
+ {
+ if (strncmp (entry->d_name, FILE_CONFIG_NAME, NAME_MAX))
+ /* We are looking for the config file */
+ continue;
+
+ /* We found an available virtual device, add it to our list */
+ snprintf (server, NAME_MAX, "%s/%04x/%02x/%02x/%01u/%s",
+ _SERVERS_PCI_CONF, domain, bus, dev, func, entry->d_name);
+ device_port = file_name_lookup (server, 0, 0);
+ if (device_port == MACH_PORT_NULL)
+ return errno;
+
+ d = pci_alloc_dev (a);
+ *((mach_port_t *) d->aux) = device_port;
+ d->bus = bus;
+ d->dev = dev;
+ d->func = func;
+ pci_link_dev (a, d);
+
+ vd = pci_read_long (d, PCI_VENDOR_ID);
+ ht = pci_read_byte (d, PCI_HEADER_TYPE);
+
+ d->vendor_id = vd & 0xffff;
+ d->device_id = vd >> 16U;
+ d->known_fields = PCI_FILL_IDENT;
+ d->hdrtype = ht;
+ }
+ }
+
+ return 0;
+}
+
+/* Enumerate devices */
+static void
+hurd_scan (struct pci_access *a)
+{
+ int err;
+
+ err = enum_devices (_SERVERS_PCI_CONF, a, -1, -1, -1, -1, LEVEL_DOMAIN);
+ assert (err == 0);
+}
+
+/*
+ * Read `len' bytes to `buf'.
+ *
+ * Returns error when the number of read bytes does not match `len'.
+ */
+static int
+hurd_read (struct pci_dev *d, int pos, byte * buf, int len)
+{
+ int err;
+ size_t nread;
+ char *data;
+ mach_port_t device_port;
+
+ nread = len;
+ device_port = *((mach_port_t *) d->aux);
+ if (len > 4)
+ err = !pci_generic_block_read (d, pos, buf, nread);
+ else
+ {
+ data = (char *) buf;
+ err = pci_conf_read (device_port, pos, &data, &nread, len);
+
+ if (data != (char *) buf)
+ {
+ if (nread > (size_t) len) /* Sanity check for bogus server. */
+ {
+ vm_deallocate (mach_task_self (), (vm_address_t) data, nread);
+ return 0;
+ }
+
+ memcpy (buf, data, nread);
+ vm_deallocate (mach_task_self (), (vm_address_t) data, nread);
+ }
+ }
+ if (err)
+ return 0;
+
+ return nread == (size_t) len;
+}
+
+/*
+ * Write `len' bytes from `buf'.
+ *
+ * Returns error when the number of written bytes does not match `len'.
+ */
+static int
+hurd_write (struct pci_dev *d, int pos, byte * buf, int len)
+{
+ int err;
+ size_t nwrote;
+ mach_port_t device_port;
+
+ nwrote = len;
+ device_port = *((mach_port_t *) d->aux);
+ if (len > 4)
+ err = !pci_generic_block_write (d, pos, buf, len);
+ else
+ err = pci_conf_write (device_port, pos, (char *) buf, len, &nwrote);
+ if (err)
+ return 0;
+
+ return nwrote == (size_t) len;
+}
+
+/* Get requested info from the server */
+static int
+hurd_fill_info (struct pci_dev *d, int flags)
+{
+ int err, i;
+ struct pci_bar regions[6];
+ struct pci_xrom_bar rom;
+ size_t size;
+ char *buf;
+ mach_port_t device_port;
+
+ device_port = *((mach_port_t *) d->aux);
+
+ if (flags & PCI_FILL_IDENT)
+ {
+ d->vendor_id = pci_read_word (d, PCI_VENDOR_ID);
+ d->device_id = pci_read_word (d, PCI_DEVICE_ID);
+ }
+
+ if (flags & PCI_FILL_CLASS)
+ d->device_class = pci_read_word (d, PCI_CLASS_DEVICE);
+
+ if (flags & PCI_FILL_IRQ)
+ d->irq = pci_read_byte (d, PCI_INTERRUPT_LINE);
+
+ if (flags & PCI_FILL_BASES)
+ {
+ buf = (char *) ®ions;
+ size = sizeof (regions);
+
+ err = pci_get_dev_regions (device_port, &buf, &size);
+ if (err)
+ return err;
+
+ if ((char *) ®ions != buf)
+ {
+ /* Sanity check for bogus server. */
+ if (size > sizeof (regions))
+ {
+ vm_deallocate (mach_task_self (), (vm_address_t) buf, size);
+ return EGRATUITOUS;
+ }
+
+ memcpy (®ions, buf, size);
+ vm_deallocate (mach_task_self (), (vm_address_t) buf, size);
+ }
+
+ for (i = 0; i < 6; i++)
+ {
+ if (regions[i].size == 0)
+ continue;
+
+ d->base_addr[i] = regions[i].base_addr;
+ d->base_addr[i] |= regions[i].is_IO;
+ d->base_addr[i] |= regions[i].is_64 << 2;
+ d->base_addr[i] |= regions[i].is_prefetchable << 3;
+
+ if (flags & PCI_FILL_SIZES)
+ d->size[i] = regions[i].size;
+ }
+ }
+
+ if (flags & PCI_FILL_ROM_BASE)
+ {
+ /* Get rom info */
+ buf = (char *) &rom;
+ size = sizeof (rom);
+ err = pci_get_dev_rom (device_port, &buf, &size);
+ if (err)
+ return err;
+
+ if ((char *) &rom != buf)
+ {
+ /* Sanity check for bogus server. */
+ if (size > sizeof (rom))
+ {
+ vm_deallocate (mach_task_self (), (vm_address_t) buf, size);
+ return EGRATUITOUS;
+ }
+
+ memcpy (&rom, buf, size);
+ vm_deallocate (mach_task_self (), (vm_address_t) buf, size);
+ }
+
+ d->rom_base_addr = rom.base_addr;
+ d->rom_size = rom.size;
+ }
+
+ if (flags & (PCI_FILL_CAPS | PCI_FILL_EXT_CAPS))
+ flags |= pci_scan_caps (d, flags);
+
+ return flags;
+}
+
+struct pci_methods pm_hurd = {
+ "hurd",
+ "Hurd access using RPCs",
+ NULL, /* config */
+ hurd_detect,
+ hurd_init,
+ hurd_cleanup,
+ hurd_scan,
+ hurd_fill_info,
+ hurd_read,
+ hurd_write,
+ NULL, /* read_vpd */
+ hurd_init_dev,
+ hurd_cleanup_dev
+};
diff --git a/lib/i386-io-hurd.h b/lib/i386-io-hurd.h
deleted file mode 100644
index b61d656..0000000
--- a/lib/i386-io-hurd.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * The PCI Library -- Access to i386 I/O ports on GNU Hurd
- *
- * Copyright (c) 2003 Marco Gerards <metgerards@student.han.nl>
- * Copyright (c) 2003 Martin Mares <mj@ucw.cz>
- * Copyright (c) 2006 Samuel Thibault <samuel.thibault@ens-lyon.org> and
- * Thomas Schwinge <tschwinge@gnu.org>
- * Copyright (c) 2007 Thomas Schwinge <tschwinge@gnu.org>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#include <sys/io.h>
-
-static inline int
-intel_setup_io(struct pci_access *a UNUSED)
-{
- return (ioperm (0, 65535, 1) == -1) ? 0 : 1;
-}
-
-static inline int
-intel_cleanup_io(struct pci_access *a UNUSED)
-{
- ioperm (0, 65535, 0);
-
- return -1;
-}
diff --git a/lib/i386-ports.c b/lib/i386-ports.c
index 421bbfd..e191c2d 100644
--- a/lib/i386-ports.c
+++ b/lib/i386-ports.c
@@ -6,16 +6,12 @@
* Can be freely distributed and used under the terms of the GNU GPL.
*/
-#define _GNU_SOURCE
-
#include "internal.h"
#include <unistd.h>
#if defined(PCI_OS_LINUX)
#include "i386-io-linux.h"
-#elif defined(PCI_OS_GNU)
-#include "i386-io-hurd.h"
#elif defined(PCI_OS_SUNOS)
#include "i386-io-sunos.h"
#elif defined(PCI_OS_WINDOWS)
diff --git a/lib/init.c b/lib/init.c
index c7800e0..008ce40 100644
--- a/lib/init.c
+++ b/lib/init.c
@@ -62,6 +62,11 @@ static struct pci_methods *pci_methods[PCI_ACCESS_MAX] = {
#else
NULL,
#endif
+#ifdef PCI_HAVE_PM_HURD_CONF
+ &pm_hurd,
+#else
+ NULL,
+#endif
};
void *
diff --git a/lib/internal.h b/lib/internal.h
index cbac2a7..6c8b19b 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -86,4 +86,4 @@ void pci_free_caps(struct pci_dev *);
extern struct pci_methods pm_intel_conf1, pm_intel_conf2, pm_linux_proc,
pm_fbsd_device, pm_aix_device, pm_nbsd_libpci, pm_obsd_device,
- pm_dump, pm_linux_sysfs, pm_darwin;
+ pm_dump, pm_linux_sysfs, pm_darwin, pm_hurd;
diff --git a/lib/pci.h b/lib/pci.h
index 794b487..99511ca 100644
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -41,6 +41,7 @@ enum pci_access_type {
PCI_ACCESS_OBSD_DEVICE, /* OpenBSD /dev/pci */
PCI_ACCESS_DUMP, /* Dump file */
PCI_ACCESS_DARWIN, /* Darwin */
+ PCI_ACCESS_GNU, /* GNU/Hurd */
PCI_ACCESS_MAX
};
--
2.14.0