[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] New module for the Hurd.
From: |
Joan Lledó |
Subject: |
[PATCH] New module for the Hurd. |
Date: |
Tue, 24 Oct 2017 13:21:36 +0200 |
This new module uses Hurd's RPCs for accessing the PCI configuration space.
Direct access as in {read_write}_{8,16,32} functions is done by the old x86
module.
Some x86 function prototypes are now declared in a new header for the Hurd
module to use them, in order to duplicate as little code as possible.
---
src/Makefile.am | 4 +-
src/common_init.c | 4 +-
src/hurd_pci.c | 299 ++++++++++++++++++++++++++++++++++++++++++++++++
src/pciaccess_private.h | 6 +
src/x86_pci.c | 58 +++-------
src/x86_pci.h | 77 +++++++++++++
6 files changed, 406 insertions(+), 42 deletions(-)
create mode 100644 src/hurd_pci.c
create mode 100644 src/x86_pci.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 3a46a85..f222aa5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -52,12 +52,12 @@ VGA_ARBITER = common_vgaarb_stub.c
endif
if GNU
-OS_SUPPORT = x86_pci.c
+OS_SUPPORT = hurd_pci.c x86_pci.c x86_pci.h
VGA_ARBITER = common_vgaarb_stub.c
endif
if CYGWIN
-OS_SUPPORT = x86_pci.c
+OS_SUPPORT = x86_pci.c x86_pci.h
VGA_ARBITER = common_vgaarb_stub.c
endif
diff --git a/src/common_init.c b/src/common_init.c
index b1c0c3e..21572ee 100644
--- a/src/common_init.c
+++ b/src/common_init.c
@@ -62,7 +62,9 @@ pci_system_init( void )
err = pci_system_openbsd_create();
#elif defined(__sun)
err = pci_system_solx_devfs_create();
-#elif defined(__GNU__) || defined(__CYGWIN__)
+#elif defined(__GNU__)
+ err = pci_system_hurd_create();
+#elif defined(__CYGWIN__)
err = pci_system_x86_create();
#else
# error "Unsupported OS"
diff --git a/src/hurd_pci.c b/src/hurd_pci.c
new file mode 100644
index 0000000..cf0b1d6
--- /dev/null
+++ b/src/hurd_pci.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2017, Joan Lledó
+ * Copyright (c) 2009, 2012 Samuel Thibault
+ * Heavily inspired from the freebsd, netbsd, and openbsd backends
+ * (C) Copyright Eric Anholt 2006
+ * (C) Copyright IBM Corporation 2006
+ * Copyright (c) 2008 Juan Romero Pardines
+ * Copyright (c) 2008 Mark Kettenis
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <strings.h>
+#include <hurd.h>
+#include <hurd/pci_conf.h>
+#include <hurd/paths.h>
+
+#include "x86_pci.h"
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+struct pci_system_hurd {
+ struct pci_system system;
+};
+
+/* Server port */
+mach_port_t pci_server_port = MACH_PORT_NULL;
+
+/* Get the server port */
+static int
+init_client(void)
+{
+ int ret = 0;
+ pci_server_port = file_name_lookup(_SERVERS_PCI_CONF, 0, 0);
+
+ if (pci_server_port == MACH_PORT_NULL)
+ ret = errno;
+
+ return ret;
+}
+
+/*
+ * Read 'size' bytes from B/D/F + reg and store them in 'data'.
+ *
+ * It's assumed that 'size' bytes are allocated in 'data'
+ */
+static int
+pciclient_cfg_read(int bus, int dev, int func, int reg, char *buf,
+ size_t * nbytes)
+{
+ error_t err;
+ size_t nread;
+ char *data;
+
+ data = buf;
+ nread = *nbytes;
+ err = pci_conf_read(pci_server_port, bus, dev, func, reg, &data, &nread,
+ *nbytes);
+ if (err)
+ return err;
+
+ if (data != buf) {
+ if (nread > *nbytes) /* Sanity check for bogus server. */ {
+ vm_deallocate(mach_task_self(), (vm_address_t) data, nread);
+ return EGRATUITOUS;
+ }
+
+ memcpy(buf, data, nread);
+ vm_deallocate(mach_task_self(), (vm_address_t)data, nread);
+ }
+
+ *nbytes = nread;
+
+ return 0;
+}
+
+/* Write 'size' bytes from 'data' to B/D/F + reg */
+static int
+pciclient_cfg_write(int bus, int dev, int func, int reg, char *buf,
+ size_t * nbytes)
+{
+ error_t err;
+ size_t nwrote;
+
+ err = pci_conf_write(pci_server_port, bus, dev, func, reg, buf, *nbytes,
+ &nwrote);
+
+ if (!err)
+ *nbytes = nwrote;
+
+ return err;
+}
+
+static int
+pci_nfuncs(struct pci_system_hurd *pci_sys_hurd, int bus, int dev)
+{
+ uint8_t hdr;
+ size_t size;
+ int err;
+
+ size = sizeof(hdr);
+ err = pciclient_cfg_read(bus, dev, 0, PCI_HDRTYPE, (char*)&hdr, &size);
+
+ if (err)
+ return err;
+
+ if(size != sizeof(hdr))
+ return EIO;
+
+ return hdr & 0x80 ? 8 : 1;
+}
+
+static int
+pci_device_hurd_read(struct pci_device *dev, void *data,
+ pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
+{
+ int err;
+
+ *bytes_read = 0;
+ while (size > 0) {
+ size_t toread = 1 << (ffs(0x4 + (offset & 0x03)) - 1);
+ if (toread > size)
+ toread = size;
+
+ err = pciclient_cfg_read(dev->bus, dev->dev, dev->func, offset,
+ (char*)data, &toread);
+ if (err)
+ return err;
+
+ offset += toread;
+ data = (char*)data + toread;
+ size -= toread;
+ *bytes_read += toread;
+ }
+ return 0;
+}
+
+static int
+pci_device_hurd_write(struct pci_device *dev, const void *data,
+ pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
+{
+ int err;
+
+ *bytes_written = 0;
+ while (size > 0) {
+ size_t towrite = 4;
+ if (towrite > size)
+ towrite = size;
+ if (towrite > 4 - (offset & 0x3))
+ towrite = 4 - (offset & 0x3);
+
+ err = pciclient_cfg_write(dev->bus, dev->dev, dev->func, offset,
+ (char*)data, &towrite);
+ if (err)
+ return err;
+
+ offset += towrite;
+ data = (const char*)data + towrite;
+ size -= towrite;
+ *bytes_written += towrite;
+ }
+ return 0;
+}
+
+static const struct pci_system_methods hurd_pci_methods = {
+ .destroy = pci_system_x86_destroy,
+ .read_rom = pci_device_x86_read_rom,
+ .probe = pci_device_x86_probe,
+ .map_range = pci_device_x86_map_range,
+ .unmap_range = pci_device_x86_unmap_range,
+ .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,
+ .read32 = pci_device_x86_read32,
+ .read16 = pci_device_x86_read16,
+ .read8 = pci_device_x86_read8,
+ .write32 = pci_device_x86_write32,
+ .write16 = pci_device_x86_write16,
+ .write8 = pci_device_x86_write8,
+ .map_legacy = pci_device_x86_map_legacy,
+ .unmap_legacy = pci_device_x86_unmap_legacy,
+};
+
+_pci_hidden int
+pci_system_hurd_create(void)
+{
+ struct pci_device_private *device;
+ int ret, bus, dev, ndevs, func, nfuncs;
+ struct pci_system_hurd *pci_sys_hurd;
+ uint32_t reg;
+ size_t toread;
+
+ ret = x86_enable_io();
+ if (ret)
+ return ret;
+
+ ret = init_client();
+ if (ret)
+ return ret;
+
+ pci_sys_hurd = calloc(1, sizeof(struct pci_system_hurd));
+ if (pci_sys_hurd == NULL) {
+ x86_disable_io();
+ return ENOMEM;
+ }
+ pci_sys = &pci_sys_hurd->system;
+
+ pci_sys->methods = &hurd_pci_methods;
+
+ ndevs = 0;
+ for (bus = 0; bus < 256; bus++) {
+ for (dev = 0; dev < 32; dev++) {
+ nfuncs = pci_nfuncs(pci_sys_hurd, bus, dev);
+ for (func = 0; func < nfuncs; func++) {
+ toread = sizeof(reg);
+ if (pciclient_cfg_read(bus, dev, func, PCI_VENDOR_ID,
+ (char*)®, &toread) != 0)
+ continue;
+ if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
+ PCI_VENDOR(reg) == 0 ||
+ toread != sizeof(reg))
+ continue;
+ ndevs++;
+ }
+ }
+ }
+
+ pci_sys->num_devices = ndevs;
+ pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
+ if (pci_sys->devices == NULL) {
+ x86_disable_io();
+ free(pci_sys_hurd);
+ pci_sys = NULL;
+ return ENOMEM;
+ }
+
+ device = pci_sys->devices;
+ for (bus = 0; bus < 256; bus++) {
+ for (dev = 0; dev < 32; dev++) {
+ nfuncs = pci_nfuncs(pci_sys_hurd, bus, dev);
+ for (func = 0; func < nfuncs; func++) {
+ toread = sizeof(reg);
+ if (pciclient_cfg_read(bus, dev, func, PCI_VENDOR_ID,
+ (char*)®, &toread) != 0)
+ continue;
+ if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
+ PCI_VENDOR(reg) == 0 ||
+ toread != sizeof(reg))
+ continue;
+ device->base.domain = 0;
+ device->base.bus = bus;
+ device->base.dev = dev;
+ device->base.func = func;
+ device->base.vendor_id = PCI_VENDOR(reg);
+ device->base.device_id = PCI_DEVICE(reg);
+
+ toread = sizeof(reg);
+ if (pciclient_cfg_read(bus, dev, func, PCI_CLASS,
+ (char*)®,&toread) != 0)
+ continue;
+ device->base.device_class = reg >> 8;
+ device->base.revision = reg & 0xFF;
+
+ toread = sizeof(reg);
+ if (pciclient_cfg_read(bus, dev, func, PCI_SUB_VENDOR_ID,
+ (char*)®, &toread) != 0)
+ continue;
+ if (toread != sizeof(reg))
+ continue;
+ device->base.subvendor_id = PCI_VENDOR(reg);
+ device->base.subdevice_id = PCI_DEVICE(reg);
+
+ device++;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/pciaccess_private.h b/src/pciaccess_private.h
index 2f05b29..329e2fd 100644
--- a/src/pciaccess_private.h
+++ b/src/pciaccess_private.h
@@ -29,6 +29,9 @@
* \author Ian Romanick <idr@us.ibm.com>
*/
+#ifndef PCIACCESS_PRIVATE_H
+#define PCIACCESS_PRIVATE_H
+
#if defined(__GNUC__) && (__GNUC__ >= 4)
# define _pci_hidden __attribute__((visibility("hidden")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
@@ -189,5 +192,8 @@ extern int pci_system_netbsd_create( void );
extern int pci_system_openbsd_create( void );
extern void pci_system_openbsd_init_dev_mem( int );
extern int pci_system_solx_devfs_create( void );
+extern int pci_system_hurd_create( void );
extern int pci_system_x86_create( void );
extern void pci_io_cleanup( void );
+
+#endif /* PCIACCESS_PRIVATE_H */
diff --git a/src/x86_pci.c b/src/x86_pci.c
index 49c1cab..9fccc5d 100644
--- a/src/x86_pci.c
+++ b/src/x86_pci.c
@@ -20,6 +20,8 @@
*/
#define _GNU_SOURCE
+#include "x86_pci.h"
+
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -36,7 +38,7 @@
#include <sys/io.h>
-static int
+int
x86_enable_io(void)
{
if (!ioperm(0, 0xffff, 1))
@@ -44,7 +46,7 @@ x86_enable_io(void)
return errno;
}
-static int
+int
x86_disable_io(void)
{
if (!ioperm(0, 0xffff, 0))
@@ -205,28 +207,6 @@ outl(uint32_t value, uint16_t port)
#endif
-#define PCI_VENDOR(reg) ((reg) & 0xFFFF)
-#define PCI_VENDOR_INVALID 0xFFFF
-
-#define PCI_VENDOR_ID 0x00
-#define PCI_SUB_VENDOR_ID 0x2c
-#define PCI_VENDOR_ID_COMPAQ 0x0e11
-#define PCI_VENDOR_ID_INTEL 0x8086
-
-#define PCI_DEVICE(reg) (((reg) >> 16) & 0xFFFF)
-#define PCI_DEVICE_INVALID 0xFFFF
-
-#define PCI_CLASS 0x08
-#define PCI_CLASS_DEVICE 0x0a
-#define PCI_CLASS_DISPLAY_VGA 0x0300
-#define PCI_CLASS_BRIDGE_HOST 0x0600
-
-#define PCIC_DISPLAY 0x03
-#define PCIS_DISPLAY_VGA 0x00
-
-#define PCI_HDRTYPE 0x0E
-#define PCI_IRQ 0x3C
-
struct pci_system_x86 {
struct pci_system system;
int (*read)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void
*data, unsigned size);
@@ -446,7 +426,7 @@ pci_nfuncs(struct pci_system_x86 *pci_sys_x86, int bus, int
dev)
/**
* Read a VGA rom using the 0xc0000 mapping.
*/
-static int
+int
pci_device_x86_read_rom(struct pci_device *dev, void *buffer)
{
void *bios;
@@ -524,7 +504,7 @@ get_test_val_size( uint32_t testval )
return size;
}
-static int
+int
pci_device_x86_probe(struct pci_device *dev)
{
uint8_t irq, hdrtype;
@@ -633,7 +613,7 @@ pci_device_x86_unmap_range(struct pci_device *dev,
#else
-static int
+int
pci_device_x86_map_range(struct pci_device *dev,
struct pci_device_mapping *map)
{
@@ -654,7 +634,7 @@ pci_device_x86_map_range(struct pci_device *dev,
return 0;
}
-static int
+int
pci_device_x86_unmap_range(struct pci_device *dev,
struct pci_device_mapping *map)
{
@@ -715,13 +695,13 @@ pci_device_x86_write(struct pci_device *dev, const void
*data,
return 0;
}
-static void
+void
pci_system_x86_destroy(void)
{
x86_disable_io();
}
-static struct pci_io_handle *
+struct pci_io_handle *
pci_device_x86_open_legacy_io(struct pci_io_handle *ret,
struct pci_device *dev, pciaddr_t base, pciaddr_t size)
{
@@ -734,7 +714,7 @@ pci_device_x86_open_legacy_io(struct pci_io_handle *ret,
return ret;
}
-static void
+void
pci_device_x86_close_io(struct pci_device *dev, struct pci_io_handle *handle)
{
/* Like in the Linux case, do not disable I/O, as it may be opened several
@@ -742,46 +722,46 @@ pci_device_x86_close_io(struct pci_device *dev, struct
pci_io_handle *handle)
/* x86_disable_io(); */
}
-static uint32_t
+uint32_t
pci_device_x86_read32(struct pci_io_handle *handle, uint32_t reg)
{
return inl(reg + handle->base);
}
-static uint16_t
+uint16_t
pci_device_x86_read16(struct pci_io_handle *handle, uint32_t reg)
{
return inw(reg + handle->base);
}
-static uint8_t
+uint8_t
pci_device_x86_read8(struct pci_io_handle *handle, uint32_t reg)
{
return inb(reg + handle->base);
}
-static void
+void
pci_device_x86_write32(struct pci_io_handle *handle, uint32_t reg,
uint32_t data)
{
outl(data, reg + handle->base);
}
-static void
+void
pci_device_x86_write16(struct pci_io_handle *handle, uint32_t reg,
uint16_t data)
{
outw(data, reg + handle->base);
}
-static void
+void
pci_device_x86_write8(struct pci_io_handle *handle, uint32_t reg,
uint8_t data)
{
outb(data, reg + handle->base);
}
-static int
+int
pci_device_x86_map_legacy(struct pci_device *dev, pciaddr_t base,
pciaddr_t size, unsigned map_flags, void **addr)
{
@@ -797,7 +777,7 @@ pci_device_x86_map_legacy(struct pci_device *dev, pciaddr_t
base,
return err;
}
-static int
+int
pci_device_x86_unmap_legacy(struct pci_device *dev, void *addr,
pciaddr_t size)
{
diff --git a/src/x86_pci.h b/src/x86_pci.h
new file mode 100644
index 0000000..2f796f4
--- /dev/null
+++ b/src/x86_pci.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2009, 2012 Samuel Thibault
+ * Heavily inspired from the freebsd, netbsd, and openbsd backends
+ * (C) Copyright Eric Anholt 2006
+ * (C) Copyright IBM Corporation 2006
+ * Copyright (c) 2008 Juan Romero Pardines
+ * Copyright (c) 2008 Mark Kettenis
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef X86_PCI_H
+#define X86_PCI_H
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+#define PCI_VENDOR(reg) ((reg) & 0xFFFF)
+#define PCI_VENDOR_INVALID 0xFFFF
+
+#define PCI_VENDOR_ID 0x00
+#define PCI_SUB_VENDOR_ID 0x2c
+#define PCI_VENDOR_ID_COMPAQ 0x0e11
+#define PCI_VENDOR_ID_INTEL 0x8086
+
+#define PCI_DEVICE(reg) (((reg) >> 16) & 0xFFFF)
+#define PCI_DEVICE_INVALID 0xFFFF
+
+#define PCI_CLASS 0x08
+#define PCI_CLASS_DEVICE 0x0a
+#define PCI_CLASS_DISPLAY_VGA 0x0300
+#define PCI_CLASS_BRIDGE_HOST 0x0600
+
+#define PCIC_DISPLAY 0x03
+#define PCIS_DISPLAY_VGA 0x00
+
+#define PCI_HDRTYPE 0x0E
+#define PCI_IRQ 0x3C
+
+int x86_enable_io(void);
+int x86_disable_io(void);
+void pci_system_x86_destroy(void);
+int pci_device_x86_read_rom(struct pci_device *dev, void *buffer);
+int pci_device_x86_probe(struct pci_device *dev);
+int pci_device_x86_map_range(struct pci_device *dev,
+ struct pci_device_mapping *map);
+int pci_device_x86_unmap_range(struct pci_device *dev,
+ struct pci_device_mapping *map);
+struct pci_io_handle *pci_device_x86_open_legacy_io(struct pci_io_handle *ret,
+ struct pci_device *dev, pciaddr_t base, pciaddr_t size);
+void pci_device_x86_close_io(struct pci_device *dev,
+ struct pci_io_handle *handle);
+uint32_t pci_device_x86_read32(struct pci_io_handle *handle, uint32_t reg);
+uint16_t pci_device_x86_read16(struct pci_io_handle *handle, uint32_t reg);
+uint8_t pci_device_x86_read8(struct pci_io_handle *handle, uint32_t reg);
+void pci_device_x86_write32(struct pci_io_handle *handle, uint32_t reg,
+ uint32_t data);
+void pci_device_x86_write16(struct pci_io_handle *handle, uint32_t reg,
+ uint16_t data);
+void pci_device_x86_write8(struct pci_io_handle *handle, uint32_t reg,
+ uint8_t data);
+int pci_device_x86_map_legacy(struct pci_device *dev, pciaddr_t base,
+ pciaddr_t size, unsigned map_flags, void **addr);
+int pci_device_x86_unmap_legacy(struct pci_device *dev, void *addr,
+ pciaddr_t size);
+
+#endif /* X86_PCI_H */
--
2.14.0
- PCI Arbiter, Joan Lledó, 2017/10/20
- [PATCH] PCI Arbiter, Joan Lledó, 2017/10/20
- Re: [PATCH] PCI Arbiter, Justus Winter, 2017/10/20
- Re: [PATCH] PCI Arbiter, Joan Lledó, 2017/10/21
- Re: [PATCH] PCI Arbiter, Justus Winter, 2017/10/22
- Re: [PATCH] PCI Arbiter, Samuel Thibault, 2017/10/22
- PCI Arbiter, Joan Lledó, 2017/10/24
- [PATCH] New module for the Hurd.,
Joan Lledó <=
- [PATCH] PCI Arbiter, Joan Lledó, 2017/10/24
- Re: [PATCH] PCI Arbiter, Joan Lledó, 2017/10/26
- Re: [PATCH] PCI Arbiter, Justus Winter, 2017/10/26