>From 72f96ca9e17e838443cbbf64331d6acdd242ec29 Mon Sep 17 00:00:00 2001 From: Damien Zammit Date: Sun, 4 Nov 2018 21:33:50 -0500 Subject: [PATCH] pci-arbiter: Remove embedded pciaccess code This patch removes all embedded pciaccess code from the arbiter and instead uses the external pciaccess library. There is another patch for pciaccess to add region and rom support, as well as the hurdish access method, but the arbiter will still work with this patch until the others are upstreamed. --- pci-arbiter/Makefile | 14 +- pci-arbiter/TODO | 7 - pci-arbiter/config.h | 4 + pci-arbiter/func_files.c | 34 +- pci-arbiter/func_files.h | 4 + pci-arbiter/main.c | 6 +- pci-arbiter/netfs_impl.c | 22 +- pci-arbiter/pci-ops.c | 12 +- pci-arbiter/pci_access.c | 51 --- pci-arbiter/pci_access.h | 187 --------- pci-arbiter/pcifs.c | 24 +- pci-arbiter/pcifs.h | 11 +- pci-arbiter/x86_pci.c | 843 --------------------------------------- pci-arbiter/x86_pci.h | 34 -- 14 files changed, 76 insertions(+), 1177 deletions(-) create mode 100644 pci-arbiter/config.h delete mode 100644 pci-arbiter/pci_access.c delete mode 100644 pci-arbiter/pci_access.h delete mode 100644 pci-arbiter/x86_pci.c delete mode 100644 pci-arbiter/x86_pci.h diff --git a/pci-arbiter/Makefile b/pci-arbiter/Makefile index 3fc3010b..4e2b8a76 100644 --- a/pci-arbiter/Makefile +++ b/pci-arbiter/Makefile @@ -20,14 +20,14 @@ makemode = server PORTDIR = $(srcdir)/port -SRCS = main.c pci-ops.c pci_access.c x86_pci.c netfs_impl.c \ - pcifs.c ncache.c options.c func_files.c startup.c \ - startup-ops.c -MIGSRCS = pciServer.c startup_notifyServer.c -OBJS = $(patsubst %.S,%.o,$(patsubst %.c,%.o, $(SRCS) $(MIGSRCS))) +SRCS = main.c pci-ops.c netfs_impl.c \ + pcifs.c ncache.c options.c func_files.c startup.c \ + startup-ops.c +MIGSRCS = pciServer.c startup_notifyServer.c +OBJS = $(patsubst %.S,%.o,$(patsubst %.c,%.o, $(SRCS) $(MIGSRCS))) HURDLIBS= fshelp ports shouldbeinlibc netfs -LDLIBS = -lpthread +LDLIBS = -lpthread -lpciaccess target = pci-arbiter @@ -35,6 +35,8 @@ include ../Makeconf CFLAGS += -I$(PORTDIR)/include +CPPFLAGS += -imacros $(srcdir)/config.h + pci-MIGSFLAGS = -imacros $(srcdir)/mig-mutate.h # cpp doesn't automatically make dependencies for -imacros dependencies. argh. diff --git a/pci-arbiter/TODO b/pci-arbiter/TODO index 22ae72a8..972a36e4 100644 --- a/pci-arbiter/TODO +++ b/pci-arbiter/TODO @@ -5,11 +5,4 @@ - pci_get_ndevs should be deprecated, applications shouldn't be relying on this -- we shouldn't duplicate pci_access.[ch] x86_pci.[ch] from libpciaccess, we - should get libpciaccess to expose pci_system_x86_create() to keep the - maintenance of x86 port knocking there. - - At least one difference with libpciaccess is the refresh operation. Perhaps - we'd need to extend libpciaccess to fix that. - BTW we could also support libpci. diff --git a/pci-arbiter/config.h b/pci-arbiter/config.h new file mode 100644 index 00000000..8eb20cd1 --- /dev/null +++ b/pci-arbiter/config.h @@ -0,0 +1,4 @@ +#define __KERNEL__ 1 +#undef __SMP__ + +#define _HURD_ 1 diff --git a/pci-arbiter/func_files.c b/pci-arbiter/func_files.c index 7df94d2f..3e97a732 100644 --- a/pci-arbiter/func_files.c +++ b/pci-arbiter/func_files.c @@ -35,10 +35,11 @@ config_block_op (struct pci_device *dev, off_t offset, size_t * len, { error_t err; size_t pendent = *len; + pciaddr_t actual = 0; while (pendent >= 4) { - err = op (dev->bus, dev->dev, dev->func, offset, data, 4); + err = op (dev, data, offset, 4, &actual); if (err) return err; @@ -49,7 +50,7 @@ config_block_op (struct pci_device *dev, off_t offset, size_t * len, if (pendent >= 2) { - err = op (dev->bus, dev->dev, dev->func, offset, data, 2); + err = op (dev, data, offset, 2, &actual); if (err) return err; @@ -60,7 +61,7 @@ config_block_op (struct pci_device *dev, off_t offset, size_t * len, if (pendent) { - err = op (dev->bus, dev->dev, dev->func, offset, data, 1); + err = op (dev, data, offset, 1, &actual); if (err) return err; @@ -85,10 +86,10 @@ io_config_file (struct pci_device * dev, off_t offset, size_t * len, assert_backtrace (dev != 0); /* Don't exceed the config space size */ - if (offset > dev->config_size) + if (offset > PCI_CONFIG_SIZE) return EINVAL; - if ((offset + *len) > dev->config_size) - *len = dev->config_size - offset; + if ((offset + *len) > PCI_CONFIG_SIZE) + *len = PCI_CONFIG_SIZE - offset; pthread_mutex_lock (&fs->pci_conf_lock); err = config_block_op (dev, offset, len, data, op); @@ -102,24 +103,25 @@ error_t read_rom_file (struct pci_device * dev, off_t offset, size_t * len, void *data) { - error_t err; + void *fullrom; /* This should never happen */ assert_backtrace (dev != 0); - /* Refresh the ROM */ - err = pci_sys->device_refresh (dev, -1, 1); - if (err) - return err; - /* Don't exceed the ROM size */ if (offset > dev->rom_size) return EINVAL; if ((offset + *len) > dev->rom_size) *len = dev->rom_size - offset; - memcpy (data, dev->rom_memory + offset, *len); + /* Grab the full rom first */ + fullrom = calloc(1, dev->rom_size); + pci_device_read_rom(dev, fullrom); + /* Return the requested amount */ + memcpy (data, fullrom + offset, *len); + + free(fullrom); return 0; } @@ -177,7 +179,6 @@ error_t io_region_file (struct pcifs_dirent * e, off_t offset, size_t * len, void *data, int read) { - error_t err; size_t reg_num; struct pci_mem_region *region; @@ -188,11 +189,6 @@ io_region_file (struct pcifs_dirent * e, off_t offset, size_t * len, reg_num = strtol (&e->name[strlen (e->name) - 1], 0, 16); region = &e->device->regions[reg_num]; - /* Refresh the region */ - err = pci_sys->device_refresh (e->device, reg_num, -1); - if (err) - return err; - /* Don't exceed the region size */ if (offset > region->size) return EINVAL; diff --git a/pci-arbiter/func_files.h b/pci-arbiter/func_files.h index b65d2c57..03cafee1 100644 --- a/pci-arbiter/func_files.h +++ b/pci-arbiter/func_files.h @@ -23,6 +23,10 @@ #define FUNC_FILES_H #include "pcifs.h" +#include + +typedef int (*pci_io_op_t) (struct pci_device *dev, void *data, + pciaddr_t reg, pciaddr_t width, pciaddr_t *bytes); /* Config */ #define FILE_CONFIG_NAME "config" diff --git a/pci-arbiter/main.c b/pci-arbiter/main.c index bc085274..112cd98b 100644 --- a/pci-arbiter/main.c +++ b/pci-arbiter/main.c @@ -34,7 +34,7 @@ #include "libnetfs/fsys_S.h" #include "libports/interrupt_S.h" #include "libnetfs/ifsock_S.h" -#include "pci_access.h" +#include #include "pcifs.h" #include "startup.h" @@ -85,7 +85,7 @@ main (int argc, char **argv) if (err) error (1, err, "mapping time"); - /* Start the PCI system */ + /* Start the PCI system: NB: pciaccess will choose x86 first and take lock */ err = pci_system_init (); if (err) error (1, err, "Starting the PCI system"); @@ -96,7 +96,7 @@ main (int argc, char **argv) error (1, err, "Creating the PCI filesystem"); /* Create the filesystem tree */ - err = create_fs_tree (fs, pci_sys); + err = create_fs_tree (fs); if (err) error (1, err, "Creating the PCI filesystem tree"); diff --git a/pci-arbiter/netfs_impl.c b/pci-arbiter/netfs_impl.c index b96c7d8d..0be8c370 100644 --- a/pci-arbiter/netfs_impl.c +++ b/pci-arbiter/netfs_impl.c @@ -32,7 +32,7 @@ #include "pcifs.h" #include "ncache.h" -#include "pci_access.h" +#include #include "func_files.h" #define DIRENTS_CHUNK_SIZE (8*1024) @@ -499,11 +499,11 @@ netfs_attempt_read (struct iouser * cred, struct node * node, if (!strncmp (node->nn->ln->name, FILE_CONFIG_NAME, NAME_SIZE)) { err = - io_config_file (node->nn->ln->device, offset, len, data, - pci_sys->read); + io_config_file (node->nn->ln->device, offset, len, data, + pci_device_cfg_read); if (!err) - /* Update atime */ - UPDATE_TIMES (node->nn->ln, TOUCH_ATIME); + /* Update atime */ + UPDATE_TIMES (node->nn->ln, TOUCH_ATIME); } else if (!strncmp (node->nn->ln->name, FILE_ROM_NAME, NAME_SIZE)) { @@ -538,13 +538,13 @@ netfs_attempt_write (struct iouser * cred, struct node * node, if (!strncmp (node->nn->ln->name, FILE_CONFIG_NAME, NAME_SIZE)) { err = - io_config_file (node->nn->ln->device, offset, len, data, - pci_sys->write); + io_config_file (node->nn->ln->device, offset, len, data, + pci_device_cfg_write); if (!err) - { - /* Update mtime and ctime */ - UPDATE_TIMES (node->nn->ln, TOUCH_MTIME | TOUCH_CTIME); - } + { + /* Update mtime and ctime */ + UPDATE_TIMES (node->nn->ln, TOUCH_MTIME | TOUCH_CTIME); + } } else if (!strncmp (node->nn->ln->name, FILE_REGION_NAME, strlen (FILE_REGION_NAME))) diff --git a/pci-arbiter/pci-ops.c b/pci-arbiter/pci-ops.c index 328db5b2..3b42c705 100644 --- a/pci-arbiter/pci-ops.c +++ b/pci-arbiter/pci-ops.c @@ -25,7 +25,7 @@ #include #include -#include "pci_access.h" +#include #include "pcifs.h" #include "func_files.h" @@ -85,7 +85,7 @@ S_pci_conf_read (struct protid * master, int reg, char **data, error_t err; pthread_mutex_t *lock; struct pcifs_dirent *e; - + if (!master) return EOPNOTSUPP; @@ -112,7 +112,7 @@ S_pci_conf_read (struct protid * master, int reg, char **data, * libnetfs which is multi-threaded. A lock is needed for arbitration. */ pthread_mutex_lock (lock); - err = pci_sys->read (e->bus, e->dev, e->func, reg, *data, amount); + err = pci_device_cfg_read (e->device, *data, reg, amount, NULL); pthread_mutex_unlock (lock); if (!err) @@ -133,7 +133,7 @@ S_pci_conf_write (struct protid * master, int reg, char *data, size_t datalen, error_t err; pthread_mutex_t *lock; struct pcifs_dirent *e; - + if (!master) return EOPNOTSUPP; @@ -149,7 +149,7 @@ S_pci_conf_write (struct protid * master, int reg, char *data, size_t datalen, return err; pthread_mutex_lock (lock); - err = pci_sys->write (e->bus, e->dev, e->func, reg, data, datalen); + err = pci_device_cfg_write (e->device, data, reg, datalen, NULL); pthread_mutex_unlock (lock); if (!err) @@ -260,7 +260,7 @@ S_pci_get_dev_rom (struct protid * master, char **data, size_t * datalen) } /* Copy the regions info */ - rom.base_addr = e->device->rom_base; + rom.base_addr = 0; // pci_device_private only rom.size = e->device->rom_size; memcpy (*data, &rom, size); diff --git a/pci-arbiter/pci_access.c b/pci-arbiter/pci_access.c deleted file mode 100644 index 4d7fc68f..00000000 --- a/pci-arbiter/pci_access.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * (C) Copyright IBM Corporation 2006 - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * on the rights to use, copy, modify, merge, publish, distribute, sub - * license, and/or sell copies of the Software, and to permit persons to whom - * the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/* - * PCI access general header. - * - * Following code is borrowed from libpciaccess: - * https://cgit.freedesktop.org/xorg/lib/libpciaccess/ - */ - -#include "pci_access.h" - -#include - -#include "x86_pci.h" - -/* Configure PCI parameters */ -int -pci_system_init (void) -{ - int err = ENOSYS; - -#ifdef __GNU__ - err = pci_system_x86_create (); -#else -#error "Unsupported OS" -#endif - - return err; -} diff --git a/pci-arbiter/pci_access.h b/pci-arbiter/pci_access.h deleted file mode 100644 index cf42cf62..00000000 --- a/pci-arbiter/pci_access.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * (C) Copyright IBM Corporation 2006 - * Copyright 2009 Red Hat, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * on the rights to use, copy, modify, merge, publish, distribute, sub - * license, and/or sell copies of the Software, and to permit persons to whom - * the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -/* - * Copyright (c) 2007 Paulo R. Zanoni, Tiago Vignatti - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -/* - * PCI access general header. - * - * Following code is borrowed from libpciaccess: - * https://cgit.freedesktop.org/xorg/lib/libpciaccess/ - */ - -#ifndef PCI_ACCESS_H -#define PCI_ACCESS_H - -#include -#include -#include - -typedef uint64_t pciaddr_t; - -/* - * BAR descriptor for a PCI device. - */ -struct pci_mem_region -{ - /* - * When the region is mapped, this is the pointer to the memory. - */ - void *memory; - - /* - * Base physical address of the region from the CPU's point of view. - * - * This address is typically passed to \c pci_device_map_range to create - * a mapping of the region to the CPU's virtual address space. - */ - pciaddr_t base_addr; - - - /* - * Size, in bytes, of the region. - */ - pciaddr_t size; - - - /* - * Is the region I/O ports or memory? - */ - unsigned is_IO:1; - - /* - * Is the memory region prefetchable? - * - * \note - * This can only be set if \c is_IO is not set. - */ - unsigned is_prefetchable:1; - - - /* - * Is the memory at a 64-bit address? - * - * \note - * This can only be set if \c is_IO is not set. - */ - unsigned is_64:1; -}; - -/* - * PCI device. - * - * Contains all of the information about a particular PCI device. - */ -struct pci_device -{ - /* - * Complete bus identification, including domain, of the device. On - * platforms that do not support PCI domains (e.g., 32-bit x86 hardware), - * the domain will always be zero. - */ - uint16_t domain; - uint8_t bus; - uint8_t dev; - uint8_t func; - - /* - * Device's class, subclass, and programming interface packed into a - * single 32-bit value. The class is at bits [23:16], subclass is at - * bits [15:8], and programming interface is at [7:0]. - */ - uint32_t device_class; - - /* - * BAR descriptors for the device. - */ - struct pci_mem_region regions[6]; - - /* - * Size, in bytes, of the device's expansion ROM. - */ - pciaddr_t rom_size; - - /* - * Physical address of the ROM - */ - pciaddr_t rom_base; - - /* - * Mapped ROM - */ - void *rom_memory; - - /* - * Size of the configuration space - */ - size_t config_size; -}; - -typedef error_t (*pci_io_op_t) (unsigned bus, unsigned dev, unsigned func, - pciaddr_t reg, void *data, unsigned size); - -typedef error_t (*pci_refresh_dev_op_t) (struct pci_device * dev, - int num_region, int rom); - -/* Global PCI data */ -struct pci_system -{ - size_t num_devices; - struct pci_device *devices; - - /* Callbacks */ - pci_io_op_t read; - pci_io_op_t write; - pci_refresh_dev_op_t device_refresh; -}; - -struct pci_system *pci_sys; - -int pci_system_init (void); - -#endif /* PCI_ACCESS_H */ diff --git a/pci-arbiter/pcifs.c b/pci-arbiter/pcifs.c index e7f495e1..5f3da1f2 100644 --- a/pci-arbiter/pcifs.c +++ b/pci-arbiter/pcifs.c @@ -133,7 +133,7 @@ init_file_system (file_t underlying_node, struct pcifs * fs) } error_t -create_fs_tree (struct pcifs * fs, struct pci_system * pci_sys) +create_fs_tree (struct pcifs * fs) { error_t err = 0; int c_domain, c_bus, c_dev, i, j; @@ -143,11 +143,17 @@ create_fs_tree (struct pcifs * fs, struct pci_system * pci_sys) *func_parent, *list; struct stat e_stat; char entry_name[NAME_SIZE]; + const struct pci_slot_match match = + { PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0 }; + /* domain bus device func */ + struct pci_device_iterator *iter; nentries = 1; /* Skip root entry */ c_domain = c_bus = c_dev = -1; - for (i = 0, device = pci_sys->devices; i < pci_sys->num_devices; - i++, device++) + iter = pci_slot_match_iterator_create(&match); + device = pci_device_next(iter); + + for (i = 0; device != NULL; i++, device = pci_device_next(iter) ) { if (device->domain != c_domain) { @@ -180,6 +186,8 @@ create_fs_tree (struct pcifs * fs, struct pci_system * pci_sys) nentries++; /* + rom */ } + pci_iterator_destroy(iter); + list = realloc (fs->entries, nentries * sizeof (struct pcifs_dirent)); if (!list) return ENOMEM; @@ -187,8 +195,10 @@ create_fs_tree (struct pcifs * fs, struct pci_system * pci_sys) e = list + 1; c_domain = c_bus = c_dev = -1; domain_parent = bus_parent = dev_parent = func_parent = 0; - for (i = 0, device = pci_sys->devices; i < pci_sys->num_devices; - i++, device++) + iter = pci_slot_match_iterator_create(&match); + device = pci_device_next(iter); + + for (i = 0; device != NULL; i++, device = pci_device_next(iter)) { if (device->domain != c_domain) { @@ -266,7 +276,7 @@ create_fs_tree (struct pcifs * fs, struct pci_system * pci_sys) e_stat = func_parent->stat; e_stat.st_mode &= ~(S_IFDIR | S_IXUSR | S_IXGRP); e_stat.st_mode |= S_IFREG | S_IWUSR | S_IWGRP; - e_stat.st_size = device->config_size; + e_stat.st_size = PCI_CONFIG_SIZE; // FIXME: Hardcoded /* Create config entry */ strncpy (entry_name, FILE_CONFIG_NAME, NAME_SIZE); @@ -310,6 +320,8 @@ create_fs_tree (struct pcifs * fs, struct pci_system * pci_sys) } } + pci_iterator_destroy(iter); + /* The root node points to the first element of the entry list */ fs->entries = list; fs->num_entries = nentries; diff --git a/pci-arbiter/pcifs.h b/pci-arbiter/pcifs.h index 7a35c77d..deb57b06 100644 --- a/pci-arbiter/pcifs.h +++ b/pci-arbiter/pcifs.h @@ -27,8 +27,11 @@ #include #include -#include "pci_access.h" -#include "netfs_impl.h" +#include +// FIXME: Hardcoded PCI config size +#define PCI_CONFIG_SIZE 256 + +#include /* Size of a directory entry name */ #ifndef NAME_SIZE @@ -200,9 +203,9 @@ volatile struct mapped_time_value *pcifs_maptime; /* FS manipulation functions */ error_t alloc_file_system (struct pcifs **fs); error_t init_file_system (file_t underlying_node, struct pcifs *fs); -error_t create_fs_tree (struct pcifs *fs, struct pci_system *pci_sys); +error_t create_fs_tree (struct pcifs *fs); error_t fs_set_permissions (struct pcifs *fs); error_t entry_check_perms (struct iouser *user, struct pcifs_dirent *e, - int flags); + int flags); #endif /* PCIFS_H */ diff --git a/pci-arbiter/x86_pci.c b/pci-arbiter/x86_pci.c deleted file mode 100644 index 9cf1f54a..00000000 --- a/pci-arbiter/x86_pci.c +++ /dev/null @@ -1,843 +0,0 @@ -/* - * Copyright (c) 2017 Joan Lledó - * Copyright (c) 2009, 2012, 2018 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. - */ - -/* - * PCI backend for x86 (32 and 64 bit) architectures. - * - * Following code is borrowed from libpciaccess: - * https://cgit.freedesktop.org/xorg/lib/libpciaccess/ - */ - -#include "x86_pci.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "pci_access.h" - -#define PCI_VENDOR(reg) ((reg) & 0xFFFF) -#define PCI_VENDOR_INVALID 0xFFFF - -#define PCI_VENDOR_ID 0x00 -#define PCI_VENDOR_ID_COMPAQ 0x0e11 -#define PCI_VENDOR_ID_INTEL 0x8086 - -#define PCI_CLASS 0x08 -#define PCI_CLASS_DEVICE 0x0a -#define PCI_CLASS_DISPLAY_VGA 0x0300 -#define PCI_CLASS_BRIDGE_HOST 0x0600 - -#define PCI_BAR_ADDR_0 0x10 -#define PCI_XROMBAR_ADDR_00 0x30 -#define PCI_XROMBAR_ADDR_01 0x38 - -#define PCI_HDRTYPE 0x0E -#define PCI_HDRTYPE_DEVICE 0x00 -#define PCI_HDRTYPE_BRIDGE 0x01 -#define PCI_HDRTYPE_CARDBUS 0x02 - -#define PCI_COMMAND 0x04 -#define PCI_SECONDARY_BUS 0x19 - -#define PCI_CONFIG_SIZE 256 - -static error_t -x86_enable_io (void) -{ - if (!ioperm (0, 0xffff, 1)) - return 0; - return errno; -} - -static error_t -x86_disable_io (void) -{ - if (!ioperm (0, 0xffff, 0)) - return 0; - return errno; -} - -static error_t -pci_system_x86_conf1_probe (void) -{ - unsigned long sav; - int res = ENODEV; - - outb (0x01, 0xCFB); - sav = inl (0xCF8); - outl (0x80000000, 0xCF8); - if (inl (0xCF8) == 0x80000000) - res = 0; - outl (sav, 0xCF8); - - return res; -} - -static error_t -pci_system_x86_conf1_read (unsigned bus, unsigned dev, unsigned func, - pciaddr_t reg, void *data, unsigned size) -{ - unsigned addr = 0xCFC + (reg & 3); - unsigned long sav; - error_t ret = 0; - - if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 - || size == 3) - return EIO; - - sav = inl (0xCF8); - outl (0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), - 0xCF8); - /* NOTE: x86 is already LE */ - switch (size) - { - case 1: - { - uint8_t *val = data; - *val = inb (addr); - break; - } - case 2: - { - uint16_t *val = data; - *val = inw (addr); - break; - } - case 4: - { - uint32_t *val = data; - *val = inl (addr); - break; - } - } - outl (sav, 0xCF8); - - return ret; -} - -static error_t -pci_system_x86_conf1_write (unsigned bus, unsigned dev, unsigned func, - pciaddr_t reg, void *data, unsigned size) -{ - unsigned addr = 0xCFC + (reg & 3); - unsigned long sav; - error_t ret = 0; - - if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 - || size == 3) - return EIO; - - sav = inl (0xCF8); - outl (0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), - 0xCF8); - /* NOTE: x86 is already LE */ - switch (size) - { - case 1: - { - const uint8_t *val = data; - outb (*val, addr); - break; - } - case 2: - { - const uint16_t *val = data; - outw (*val, addr); - break; - } - case 4: - { - const uint32_t *val = data; - outl (*val, addr); - break; - } - } - outl (sav, 0xCF8); - - return ret; -} - -static error_t -pci_system_x86_conf2_probe (void) -{ - outb (0, 0xCFB); - outb (0, 0xCF8); - outb (0, 0xCFA); - if (inb (0xCF8) == 0 && inb (0xCFA) == 0) - return 0; - - return ENODEV; -} - -static error_t -pci_system_x86_conf2_read (unsigned bus, unsigned dev, unsigned func, - pciaddr_t reg, void *data, unsigned size) -{ - unsigned addr = 0xC000 | dev << 8 | reg; - error_t ret = 0; - - if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100) - return EIO; - - outb ((func << 1) | 0xF0, 0xCF8); - outb (bus, 0xCFA); - /* NOTE: x86 is already LE */ - switch (size) - { - case 1: - { - uint8_t *val = data; - *val = inb (addr); - break; - } - case 2: - { - uint16_t *val = data; - *val = inw (addr); - break; - } - case 4: - { - uint32_t *val = data; - *val = inl (addr); - break; - } - default: - ret = EIO; - break; - } - outb (0, 0xCF8); - - return ret; -} - -static error_t -pci_system_x86_conf2_write (unsigned bus, unsigned dev, unsigned func, - pciaddr_t reg, void *data, unsigned size) -{ - unsigned addr = 0xC000 | dev << 8 | reg; - error_t ret = 0; - - if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100) - return EIO; - - outb ((func << 1) | 0xF0, 0xCF8); - outb (bus, 0xCFA); - /* NOTE: x86 is already LE */ - switch (size) - { - case 1: - { - const uint8_t *val = data; - outb (*val, addr); - break; - } - case 2: - { - const uint16_t *val = data; - outw (*val, addr); - break; - } - case 4: - { - const uint32_t *val = data; - outl (*val, addr); - break; - } - default: - ret = EIO; - break; - } - outb (0, 0xCF8); - - return ret; -} - -/* Returns the number of regions (base address registers) the device has */ -static int -pci_device_x86_get_num_regions (uint8_t header_type) -{ - switch (header_type & 0x7f) - { - case 0: - return 6; - case 1: - return 2; - case 2: - return 1; - default: - return 0; - } -} - -/* Masks out the flag bigs of the base address register value */ -static uint32_t -get_map_base (uint32_t val) -{ - if (val & 0x01) - return val & ~0x03; - else - return val & ~0x0f; -} - -/* Returns the size of a region based on the all-ones test value */ -static unsigned -get_test_val_size (uint32_t testval) -{ - unsigned size = 1; - - if (testval == 0) - return 0; - - /* Mask out the flag bits */ - testval = get_map_base (testval); - if (!testval) - return 0; - - while ((testval & 1) == 0) - { - size <<= 1; - testval >>= 1; - } - - return size; -} - -/* Read BAR `reg_num' in `dev' and map the data if any */ -static error_t -pci_device_x86_region_probe (struct pci_device *dev, int reg_num) -{ - error_t err; - uint8_t offset; - uint32_t reg, addr, testval; - int memfd; - - offset = PCI_BAR_ADDR_0 + 0x4 * reg_num; - - /* Get the base address */ - err = - pci_sys->read (dev->bus, dev->dev, dev->func, offset, &addr, - sizeof (addr)); - if (err) - return err; - - /* Test write all ones to the register, then restore it. */ - reg = 0xffffffff; - err = pci_sys->write (dev->bus, dev->dev, dev->func, offset, ®, - sizeof (reg)); - if (err) - return err; - err = pci_sys->read (dev->bus, dev->dev, dev->func, offset, &testval, - sizeof (testval)); - if (err) - return err; - err = pci_sys->write (dev->bus, dev->dev, dev->func, offset, &addr, - sizeof (addr)); - if (err) - return err; - - if (addr & 0x01) - dev->regions[reg_num].is_IO = 1; - if (addr & 0x04) - dev->regions[reg_num].is_64 = 1; - if (addr & 0x08) - dev->regions[reg_num].is_prefetchable = 1; - - /* Set the size */ - dev->regions[reg_num].size = get_test_val_size (testval); - - /* Set the base address value */ - dev->regions[reg_num].base_addr = get_map_base (addr); - - if (dev->regions[reg_num].is_64) - { - err = - pci_sys->read (dev->bus, dev->dev, dev->func, offset + 4, &addr, - sizeof (addr)); - if (err) - return err; - - dev->regions[reg_num].base_addr |= ((uint64_t) addr << 32); - } - - if (dev->regions[reg_num].is_IO) - { - /* Enable the I/O Space bit */ - err = - pci_sys->read (dev->bus, dev->dev, dev->func, PCI_COMMAND, ®, - sizeof (reg)); - if (err) - return err; - - if (!(reg & 0x1)) - { - reg |= 0x1; - - err = - pci_sys->write (dev->bus, dev->dev, dev->func, PCI_COMMAND, - ®, sizeof (reg)); - if (err) - return err; - } - - /* Clear the map pointer */ - dev->regions[reg_num].memory = 0; - } - else if (dev->regions[reg_num].size > 0) - { - /* Enable the Memory Space bit */ - err = - pci_sys->read (dev->bus, dev->dev, dev->func, PCI_COMMAND, ®, - sizeof (reg)); - if (err) - return err; - - if (!(reg & 0x2)) - { - reg |= 0x2; - - err = - pci_sys->write (dev->bus, dev->dev, dev->func, PCI_COMMAND, - ®, sizeof (reg)); - if (err) - return err; - } - - /* Map the region in our space */ - memfd = open ("/dev/mem", O_RDONLY | O_CLOEXEC); - if (memfd == -1) - return errno; - - dev->regions[reg_num].memory = - mmap (NULL, dev->regions[reg_num].size, PROT_READ | PROT_WRITE, 0, - memfd, dev->regions[reg_num].base_addr); - if (dev->regions[reg_num].memory == MAP_FAILED) - { - dev->regions[reg_num].memory = 0; - close (memfd); - return errno; - } - - close (memfd); - } - - return 0; -} - -/* Read the XROMBAR in `dev' and map the data if any */ -static error_t -pci_device_x86_rom_probe (struct pci_device *dev) -{ - error_t err; - uint8_t reg_8, xrombar_addr; - uint32_t reg, reg_back; - pciaddr_t rom_size; - pciaddr_t rom_base; - void *rom_mapped; - int memfd; - - /* First we need to know which type of header is this */ - err = pci_sys->read (dev->bus, dev->dev, dev->func, PCI_HDRTYPE, ®_8, - sizeof (reg_8)); - if (err) - return err; - - /* Get the XROMBAR register address */ - switch (reg_8 & 0x3) - { - case PCI_HDRTYPE_DEVICE: - xrombar_addr = PCI_XROMBAR_ADDR_00; - break; - case PCI_HDRTYPE_BRIDGE: - xrombar_addr = PCI_XROMBAR_ADDR_01; - break; - default: - return -1; - } - - /* Get size and physical address */ - err = pci_sys->read (dev->bus, dev->dev, dev->func, xrombar_addr, ®, - sizeof (reg)); - if (err) - return err; - - reg_back = reg; - reg = 0xFFFFF800; /* Base address: first 21 bytes */ - err = pci_sys->write (dev->bus, dev->dev, dev->func, xrombar_addr, ®, - sizeof (reg)); - if (err) - return err; - err = pci_sys->read (dev->bus, dev->dev, dev->func, xrombar_addr, ®, - sizeof (reg)); - if (err) - return err; - - rom_size = (~reg + 1); - rom_base = reg_back & reg; - - if (rom_size == 0) - return 0; - - /* Enable the address decoder and write the physical address back */ - reg_back |= 0x1; - err = pci_sys->write - (dev->bus, dev->dev, dev->func, xrombar_addr, ®_back, - sizeof (reg_back)); - if (err) - return err; - - /* Enable the Memory Space bit */ - err = pci_sys->read (dev->bus, dev->dev, dev->func, PCI_COMMAND, ®, - sizeof (reg)); - if (err) - return err; - - if (!(reg & 0x2)) - { - reg |= 0x2; - - err = - pci_sys->write (dev->bus, dev->dev, dev->func, PCI_COMMAND, ®, - sizeof (reg)); - if (err) - return err; - } - - /* Map the ROM in our space */ - memfd = open ("/dev/mem", O_RDONLY | O_CLOEXEC); - if (memfd == -1) - return errno; - - rom_mapped = mmap (NULL, rom_size, PROT_READ, 0, memfd, rom_base); - if (rom_mapped == MAP_FAILED) - { - close (memfd); - return errno; - } - - close (memfd); - - dev->rom_size = rom_size; - dev->rom_base = rom_base; - dev->rom_memory = rom_mapped; - - return 0; -} - -/* Configure BARs and ROM */ -static error_t -pci_device_x86_probe (struct pci_device *dev) -{ - error_t err; - uint8_t hdrtype; - int i; - - /* Probe BARs */ - err = pci_sys->read (dev->bus, dev->dev, dev->func, PCI_HDRTYPE, &hdrtype, - sizeof (hdrtype)); - if (err) - return err; - - for (i = 0; i < pci_device_x86_get_num_regions (hdrtype); i++) - { - err = pci_device_x86_region_probe (dev, i); - if (err) - return err; - - if (dev->regions[i].is_64) - /* Move the pointer one BAR ahead */ - i++; - } - - /* Probe ROM */ - err = pci_device_x86_rom_probe (dev); - if (err) - return err; - - return 0; -} - -/* - * Refresh the device. Check for updates in region `reg_num' - * or in ROM if `rom' = true. `reg_num' < 0 means no region check. - */ -static error_t -pci_device_x86_refresh (struct pci_device *dev, int reg_num, int rom) -{ - error_t err; - uint8_t offset, hdrtype; - uint32_t addr; - - if (reg_num >= 0 && dev->regions[reg_num].size > 0) - { - /* Read the BAR */ - offset = PCI_BAR_ADDR_0 + 0x4 * reg_num; - err = - pci_sys->read (dev->bus, dev->dev, dev->func, offset, &addr, - sizeof (addr)); - if (err) - return err; - - /* Check whether the region is outdated, if so, the refresh it */ - if (dev->regions[reg_num].base_addr != get_map_base (addr)) - { - err = pci_device_x86_region_probe (dev, reg_num); - if (err) - return err; - } - } - - if (rom && dev->rom_size > 0) - { - /* Read the BAR */ - err = - pci_sys->read (dev->bus, dev->dev, dev->func, PCI_HDRTYPE, &hdrtype, - sizeof (hdrtype)); - if (err) - return err; - - switch (hdrtype & 0x3) - { - case PCI_HDRTYPE_DEVICE: - offset = PCI_XROMBAR_ADDR_00; - break; - case PCI_HDRTYPE_BRIDGE: - offset = PCI_XROMBAR_ADDR_01; - break; - default: - return -1; - } - - err = pci_sys->read (dev->bus, dev->dev, dev->func, offset, &addr, - sizeof (addr)); - if (err) - return err; - - /* Check whether the ROM is outdated, if so, the refresh it */ - if (dev->rom_base != (addr & 0xFFFFF800)) - { - err = pci_device_x86_rom_probe (dev); - if (err) - return err; - } - } - - return 0; -} - -/* Check that this really looks like a PCI configuration. */ -static error_t -pci_system_x86_check (struct pci_system *pci_sys) -{ - int dev; - uint16_t class, vendor; - - /* Look on bus 0 for a device that is a host bridge, a VGA card, - * or an intel or compaq device. */ - - for (dev = 0; dev < 32; dev++) - { - if (pci_sys->read (0, dev, 0, PCI_CLASS_DEVICE, &class, sizeof (class))) - continue; - if (class == PCI_CLASS_BRIDGE_HOST || class == PCI_CLASS_DISPLAY_VGA) - return 0; - if (pci_sys->read (0, dev, 0, PCI_VENDOR_ID, &vendor, sizeof (vendor))) - continue; - if (vendor == PCI_VENDOR_ID_INTEL || class == PCI_VENDOR_ID_COMPAQ) - return 0; - } - - return ENODEV; -} - -/* Find out which conf access method use */ -static error_t -pci_probe (struct pci_system *pci_sys) -{ - if (pci_system_x86_conf1_probe () == 0) - { - pci_sys->read = pci_system_x86_conf1_read; - pci_sys->write = pci_system_x86_conf1_write; - if (pci_system_x86_check (pci_sys) == 0) - return 0; - } - - if (pci_system_x86_conf2_probe () == 0) - { - pci_sys->read = pci_system_x86_conf2_read; - pci_sys->write = pci_system_x86_conf2_write; - if (pci_system_x86_check (pci_sys) == 0) - return 0; - } - - return ENODEV; -} - -static error_t -pci_nfuncs (struct pci_system *pci_sys, int bus, int dev, uint8_t * nfuncs) -{ - uint8_t hdrtype; - error_t err; - - err = pci_sys->read (bus, dev, 0, PCI_HDRTYPE, &hdrtype, sizeof (hdrtype)); - if (err) - return err; - - *nfuncs = hdrtype & 0x80 ? 8 : 1; - - return 0; -} - -/* Recursively scan bus number `bus' */ -static error_t -pci_system_x86_scan_bus (struct pci_system *pci_sys, uint8_t bus) -{ - error_t err; - uint8_t dev, func, nfuncs, hdrtype, secbus; - uint32_t reg; - struct pci_device *d, *devices; - - for (dev = 0; dev < 32; dev++) - { - err = pci_nfuncs (pci_sys, bus, dev, &nfuncs); - if (err) - return err; - - for (func = 0; func < nfuncs; func++) - { - err = - pci_sys->read (bus, dev, func, PCI_VENDOR_ID, ®, sizeof (reg)); - if (err) - return err; - - if (PCI_VENDOR (reg) == PCI_VENDOR_INVALID || PCI_VENDOR (reg) == 0) - continue; - - err = pci_sys->read (bus, dev, func, PCI_CLASS, ®, sizeof (reg)); - if (err) - return err; - - err = - pci_sys->read (bus, dev, func, PCI_HDRTYPE, &hdrtype, - sizeof (hdrtype)); - if (err) - return err; - - devices = - realloc (pci_sys->devices, - (pci_sys->num_devices + 1) * sizeof (struct pci_device)); - if (!devices) - return ENOMEM; - - d = devices + pci_sys->num_devices; - memset (d, 0, sizeof (struct pci_device)); - - /* Fixed values as PCI express is still not supported */ - d->domain = 0; - d->config_size = PCI_CONFIG_SIZE; - - d->bus = bus; - d->dev = dev; - d->func = func; - - d->device_class = reg >> 8; - - err = pci_device_x86_probe (d); - if (err) - return err; - - pci_sys->devices = devices; - pci_sys->num_devices++; - - switch (hdrtype & 0x3) - { - case PCI_HDRTYPE_DEVICE: - break; - case PCI_HDRTYPE_BRIDGE: - case PCI_HDRTYPE_CARDBUS: - { - err = - pci_sys->read (bus, dev, func, PCI_SECONDARY_BUS, &secbus, - sizeof (secbus)); - if (err) - return err; - - err = pci_system_x86_scan_bus (pci_sys, secbus); - if (err) - return err; - - break; - } - default: - /* Unknown header, do nothing */ - break; - } - } - } - - return 0; -} - -/* Initialize the x86 module */ -error_t -pci_system_x86_create (void) -{ - error_t err; - - err = x86_enable_io (); - if (err) - return err; - - pci_sys = calloc (1, sizeof (struct pci_system)); - if (pci_sys == NULL) - { - x86_disable_io (); - return ENOMEM; - } - - err = pci_probe (pci_sys); - if (err) - { - x86_disable_io (); - free (pci_sys); - return err; - } - pci_sys->device_refresh = pci_device_x86_refresh; - - /* Recursive scan */ - pci_sys->num_devices = 0; - err = pci_system_x86_scan_bus (pci_sys, 0); - if (err) - { - x86_disable_io (); - free (pci_sys); - pci_sys = NULL; - return err; - } - - return 0; -} diff --git a/pci-arbiter/x86_pci.h b/pci-arbiter/x86_pci.h deleted file mode 100644 index fb2374a6..00000000 --- a/pci-arbiter/x86_pci.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - */ - -/* - * PCI backend header for x86 (32 and 64 bit) architectures. - * - * Following code is borrowed from libpciaccess: - * https://cgit.freedesktop.org/xorg/lib/libpciaccess/ - */ - -#ifndef X86_PCI_H -#define X86_PCI_H - -int pci_system_x86_create (void); - -#endif /* X86_PCI_H */ -- 2.17.1