bug-hurd
[Top][All Lists]
Advanced

[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 *) &regions;
+      size = sizeof (regions);
+
+      err = pci_get_dev_regions (device_port, &buf, &size);
+      if (err)
+       return err;
+
+      if ((char *) &regions != buf)
+       {
+         /* Sanity check for bogus server.  */
+         if (size > sizeof (regions))
+           {
+             vm_deallocate (mach_task_self (), (vm_address_t) buf, size);
+             return EGRATUITOUS;
+           }
+
+         memcpy (&regions, 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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]