--- Makefile | 1 + hurd/hurd_types.defs | 19 ++- hurd/hurd_types.h | 1 + hurd/paths.h | 1 + hurd/pci_conf.defs | 50 +++++++ hurd/subsystems | 1 + pci_arbiter/Makefile | 40 ++++++ pci_arbiter/config.h | 5 + pci_arbiter/main.c | 116 ++++++++++++++++ pci_arbiter/mig-mutate.h | 28 ++++ pci_arbiter/pci_access.c | 51 +++++++ pci_arbiter/pci_access.h | 78 +++++++++++ pci_arbiter/pci_arbiter.h | 46 +++++++ pci_arbiter/pci_conf-ops.c | 90 ++++++++++++ pci_arbiter/x86_pci.c | 331 +++++++++++++++++++++++++++++++++++++++++++++ pci_arbiter/x86_pci.h | 42 ++++++ 16 files changed, 899 insertions(+), 1 deletion(-) create mode 100644 hurd/pci_conf.defs create mode 100644 pci_arbiter/Makefile create mode 100644 pci_arbiter/config.h create mode 100644 pci_arbiter/main.c create mode 100644 pci_arbiter/mig-mutate.h create mode 100644 pci_arbiter/pci_access.c create mode 100644 pci_arbiter/pci_access.h create mode 100644 pci_arbiter/pci_arbiter.h create mode 100644 pci_arbiter/pci_conf-ops.c create mode 100644 pci_arbiter/x86_pci.c create mode 100644 pci_arbiter/x86_pci.h
diff --git a/Makefile b/Makefile index 119f130b..a46f0140 100644 --- a/Makefile +++ b/Makefile @@ -45,6 +45,7 @@ prog-subdirs = auth proc exec term \ init \ devnode \ eth-multiplexer \ + pci_arbiter ifeq ($(HAVE_SUN_RPC),yes) prog-subdirs += nfs nfsd diff --git a/hurd/hurd_types.defs b/hurd/hurd_types.defs index 4d7013c8..53fad15c 100644 --- a/hurd/hurd_types.defs +++ b/hurd/hurd_types.defs @@ -1,5 +1,5 @@ /* MiG type declarations for Hurd interfaces -*- C -*- - Copyright (C) 1993,94,95,96,98,2001,02 Free Software Foundation, Inc. + Copyright (C) 1993,94,95,96,98,2001,02,17 Free Software Foundation, Inc. This file is part of the GNU Hurd. @@ -296,6 +296,23 @@ destructor: INTERRUPT_DESTRUCTOR #endif ; +/* PCI arbiter */ +type pci_conf_t = mach_port_copy_send_t +#ifdef PCI_CONF_INTRAN +intran: PCI_CONF_INTRAN +intranpayload: PCI_CONF_INTRAN_PAYLOAD +#else +#ifdef HURD_DEFAULT_PAYLOAD_TO_PORT +intranpayload: pci_conf_t HURD_DEFAULT_PAYLOAD_TO_PORT +#endif +#endif +#ifdef PCI_CONF_OUTTRAN +outtran: PCI_CONF_OUTTRAN +#endif +#ifdef PCI_CONF_DESTRUCTOR +destructor: PCI_CONF_DESTRUCTOR +#endif +; type proccoll_t = mach_port_copy_send_t; diff --git a/hurd/hurd_types.h b/hurd/hurd_types.h index 2960a294..db03ec31 100644 --- a/hurd/hurd_types.h +++ b/hurd/hurd_types.h @@ -50,6 +50,7 @@ typedef mach_port_t exec_startup_t; typedef mach_port_t interrupt_t; typedef mach_port_t proccoll_t; typedef mach_port_t ctty_t; +typedef mach_port_t pci_conf_t; #include <errno.h> /* Defines `error_t'. */ diff --git a/hurd/paths.h b/hurd/paths.h index e1b00e90..e4da819a 100644 --- a/hurd/paths.h +++ b/hurd/paths.h @@ -30,6 +30,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define _SERVERS_PROC _SERVERS "proc" #define _SERVERS_PASSWORD _SERVERS "password" #define _SERVERS_DEFPAGER _SERVERS "default-pager" +#define _SERVERS_PCI_CONF _SERVERS "pci" /* Directory containing naming points for socket servers. Entries are named by the string representing the domain number diff --git a/hurd/pci_conf.defs b/hurd/pci_conf.defs new file mode 100644 index 00000000..f3eccbb0 --- /dev/null +++ b/hurd/pci_conf.defs @@ -0,0 +1,50 @@ +/* Definitions for pci-specific calls + Copyright (C) 2017 Free Software Foundation, Inc. + +This file is part of the GNU Hurd. + +The GNU Hurd is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +The GNU Hurd is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the GNU Hurd; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +subsystem pci_conf 39000; + +#include <hurd/hurd_types.defs> + +#ifdef PCI_CONF_IMPORTS +PCI_CONF_IMPORTS +#endif + +INTR_INTERFACE + +/* Read 'amount' bytes from B/D/F + 'reg' and store it in 'data' */ +routine pci_conf_read ( + master: pci_conf_t; + bus: int; + dev: int; + func: int; + reg: int; + out data: data_t, dealloc; + amount: vm_size_t +); + +/* Write 'amount' bytes from 'data' to B/D/F + 'reg' */ +routine pci_conf_write( + master: pci_conf_t; + bus: int; + dev: int; + func: int; + reg: int; + data: data_t; + out amount: vm_size_t +); diff --git a/hurd/subsystems b/hurd/subsystems index c05895c2..9518172c 100644 --- a/hurd/subsystems +++ b/hurd/subsystems @@ -36,6 +36,7 @@ tape 35000 Special control operations for magtapes login 36000 Database of logged-in users pfinet 37000 Internet configuration calls password 38000 Password checker +pci_conf 39000 PCI arbiter <ioctl space> 100000- First subsystem of ioctl class 'f' (lowest class) tioctl 156000 Ioctl class 't' (terminals) tioctl 156200 (continued) diff --git a/pci_arbiter/Makefile b/pci_arbiter/Makefile new file mode 100644 index 00000000..b152de13 --- /dev/null +++ b/pci_arbiter/Makefile @@ -0,0 +1,40 @@ +# Copyright (C) 2017 Free Software Foundation, Inc. +# +# This file is part of the GNU Hurd. +# +# The GNU Hurd is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2, or (at +# your option) any later version. +# +# The GNU Hurd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. + +dir = pci_arbiter +makemode = server + +PORTDIR = $(srcdir)/port + +SRCS = main.c pci_conf-ops.c pci_access.c x86_pci.c +MIGSRCS = pci_confServer.c +OBJS = $(patsubst %.S,%.o,$(patsubst %.c,%.o, $(SRCS) $(MIGSRCS))) + +HURDLIBS= trivfs fshelp ports shouldbeinlibc + +target = pci_arbiter + +include ../Makeconf + +CFLAGS += -I$(PORTDIR)/include + +CPPFLAGS += -imacros $(srcdir)/config.h +pci_conf-MIGSFLAGS = -imacros $(srcdir)/mig-mutate.h + +# cpp doesn't automatically make dependencies for -imacros dependencies. argh. +pci_conf_S.h pci_confServer.c: mig-mutate.h +$(OBJS): config.h diff --git a/pci_arbiter/config.h b/pci_arbiter/config.h new file mode 100644 index 00000000..b0d5196d --- /dev/null +++ b/pci_arbiter/config.h @@ -0,0 +1,5 @@ +#define __KERNEL__ 1 +#undef __SMP__ + +#define _HURD_ 1 + diff --git a/pci_arbiter/main.c b/pci_arbiter/main.c new file mode 100644 index 00000000..5c7b868a --- /dev/null +++ b/pci_arbiter/main.c @@ -0,0 +1,116 @@ +/* + Copyright (C) 2017 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* Translator initialization and demuxing */ + +#include <pci_arbiter.h> + +#include <error.h> +#include <fcntl.h> +#include <hurd/trivfs.h> + +#include <pci_access.h> +#include <pci_conf_S.h> + +int trivfs_fstype = FSTYPE_MISC; +int trivfs_fsid = 0; +int trivfs_support_read = 0; +int trivfs_support_write = 0; +int trivfs_support_exec = 0; +int trivfs_allow_open = O_READ | O_WRITE; + +void +trivfs_modify_stat (struct trivfs_protid *cred, io_statbuf_t * st) +{ +} + +error_t +trivfs_goaway (struct trivfs_control *fsys, int flags) +{ + exit (0); +} + +int +pci_demuxer (mach_msg_header_t * inp, mach_msg_header_t * outp) +{ + mig_routine_t routine; + if ((routine = pci_conf_server_routine (inp)) || + (routine = NULL, trivfs_demuxer (inp, outp))) + { + if (routine) + (*routine) (inp, outp); + return TRUE; + } + else + return FALSE; +} + +int +main (int argc, char **argv) +{ + error_t err; + struct stat st; + mach_port_t bootstrap; + + pci_bucket = ports_create_bucket (); + + mach_port_allocate (mach_task_self (), + MACH_PORT_RIGHT_RECEIVE, &fsys_identity); + + task_get_bootstrap_port (mach_task_self (), &bootstrap); + if (bootstrap == MACH_PORT_NULL) + error (-1, 0, "Must be started as a translator"); + + err = trivfs_add_protid_port_class (&pci_protid_portclass); + if (err) + error (1, err, "Error creating protid port class"); + + err = trivfs_add_control_port_class (&pci_cntl_portclass); + if (err) + error (1, err, "Error creating control port class"); + + /* Reply to our parent */ + err = trivfs_startup (bootstrap, 0, + pci_cntl_portclass, + pci_bucket, + pci_protid_portclass, pci_bucket, &pcicntl); + mach_port_deallocate (mach_task_self (), bootstrap); + if (err) + { + return (-1); + } + + /* Initialize status from underlying node. */ + pci_owner = pci_group = 0; + err = io_stat (pcicntl->underlying, &st); + if (!err) + { + pci_owner = st.st_uid; + pci_group = st.st_gid; + } + + /* Start the PCI system */ + err = pci_system_init (); + if (err) + error (1, err, "Error starting the PCI system"); + + ports_manage_port_operations_one_thread (pci_bucket, pci_demuxer, 0); + + return 0; +} diff --git a/pci_arbiter/mig-mutate.h b/pci_arbiter/mig-mutate.h new file mode 100644 index 00000000..ca62aafe --- /dev/null +++ b/pci_arbiter/mig-mutate.h @@ -0,0 +1,28 @@ +/* + Copyright (C) 2017 Free Software Foundation, Inc. + Written by Michael I. Bushnell, p/BSG. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* Only CPP macro definitions should go in this file. */ + +#define PCI_CONF_IMPORTS \ + import "../libtrivfs/mig-decls.h"; \ + +#define PCI_CONF_INTRAN trivfs_protid_t trivfs_begin_using_protid (pci_conf_t) +#define PCI_CONF_INTRAN_PAYLOAD trivfs_protid_t trivfs_begin_using_protid_payload +#define PCI_CONF_DESTRUCTOR trivfs_end_using_protid (trivfs_protid_t) diff --git a/pci_arbiter/pci_access.c b/pci_arbiter/pci_access.c new file mode 100644 index 00000000..eded1bff --- /dev/null +++ b/pci_arbiter/pci_access.c @@ -0,0 +1,51 @@ +/* + * (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 <errno.h> + +#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 new file mode 100644 index 00000000..8735ea77 --- /dev/null +++ b/pci_arbiter/pci_access.h @@ -0,0 +1,78 @@ +/* + * (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 <stdint.h> + +typedef uint64_t pciaddr_t; + + /* Common interface */ +struct pci_iface +{ + int (*read) (unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, + void *data, unsigned size); + int (*write) (unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, + const void *data, unsigned size); +}; + +struct pci_iface *pci_ifc; + +int pci_system_init (void); + +#endif /* PCI_ACCESS_H */ diff --git a/pci_arbiter/pci_arbiter.h b/pci_arbiter/pci_arbiter.h new file mode 100644 index 00000000..73540e8e --- /dev/null +++ b/pci_arbiter/pci_arbiter.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2017 Free Software Foundation, Inc. + + Written by Michael I. Bushnell, p/BSG. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* Translator global declarations */ + +#ifndef PCI_ARBITER_H +#define PCI_ARBITER_H + +#include <hurd/ports.h> + +/* Libports stuff */ +struct port_bucket *pci_bucket; + +struct port_class *pci_protid_portclass; +struct port_class *pci_cntl_portclass; + +mach_port_t fsys_identity; + +/* Trivfs control structure for lwip. */ +struct trivfs_control *pcicntl; + +/* Owner of the underlying node. */ +uid_t pci_owner; + +/* Group of the underlying node. */ +uid_t pci_group; + +#endif /* PCI_ARBITER_H */ diff --git a/pci_arbiter/pci_conf-ops.c b/pci_arbiter/pci_conf-ops.c new file mode 100644 index 00000000..b532158a --- /dev/null +++ b/pci_arbiter/pci_conf-ops.c @@ -0,0 +1,90 @@ +/* + Copyright (C) 2017 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* Implementation of PCI operations */ + +#include <pci_conf_S.h> + +#include <hurd/fshelp.h> +#include <hurd/trivfs.h> + +#include <pci_arbiter.h> +#include <pci_access.h> + +error_t +S_pci_conf_read (struct trivfs_protid * master, int bus, int dev, int func, + int reg, char **data, size_t * datalen, + mach_msg_type_number_t amount) +{ + error_t err; + + if (!master) + return EOPNOTSUPP; + + if (!master->isroot) + { + struct stat st; + + st.st_uid = pci_owner; + st.st_gid = pci_group; + + err = fshelp_isowner (&st, master->user); + if (err) + return EPERM; + } + + if (amount > *datalen) + amount = *datalen; + + err = pci_ifc->read (bus, dev, func, reg, *data, amount); + + if (!err) + *datalen = amount; + + return err; +} + +error_t +S_pci_conf_write (struct trivfs_protid * master, int bus, int dev, int func, + int reg, char *data, size_t datalen, + mach_msg_type_number_t * amount) +{ + error_t err; + + if (!master) + return EOPNOTSUPP; + + if (!master->isroot) + { + struct stat st; + + st.st_uid = pci_owner; + st.st_gid = pci_group; + + err = fshelp_isowner (&st, master->user); + if (err) + return EPERM; + } + + err = pci_ifc->write (bus, dev, func, reg, data, datalen); + + *amount = datalen; + + return err; +} diff --git a/pci_arbiter/x86_pci.c b/pci_arbiter/x86_pci.c new file mode 100644 index 00000000..abae4938 --- /dev/null +++ b/pci_arbiter/x86_pci.c @@ -0,0 +1,331 @@ +/* + * 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 access backend. + * + * Following code is borrowed from libpciaccess: + * https://cgit.freedesktop.org/xorg/lib/libpciaccess/ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <x86_pci.h> + +#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 <sys/io.h> + +#include <pci_access.h> + +static int +x86_enable_io (void) +{ + if (!ioperm (0, 0xffff, 1)) + return 0; + return errno; +} + +static int +x86_disable_io (void) +{ + if (!ioperm (0, 0xffff, 0)) + return 0; + return errno; +} + +static int +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 int +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; + int 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 int +pci_system_x86_conf1_write (unsigned bus, unsigned dev, unsigned func, + pciaddr_t reg, const void *data, unsigned size) +{ + unsigned addr = 0xCFC + (reg & 3); + unsigned long sav; + int 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 int +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 int +pci_system_x86_conf2_read (unsigned bus, unsigned dev, unsigned func, + pciaddr_t reg, void *data, unsigned size) +{ + unsigned addr = 0xC000 | dev << 8 | reg; + int 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 int +pci_system_x86_conf2_write (unsigned bus, unsigned dev, unsigned func, + pciaddr_t reg, const void *data, unsigned size) +{ + unsigned addr = 0xC000 | dev << 8 | reg; + int 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; +} + +/* Check that this really looks like a PCI configuration. */ +static int +pci_system_x86_check (struct pci_iface *pci_ifc) +{ + 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_ifc->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_ifc->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; +} + +static int +pci_probe (struct pci_iface *pci_ifc) +{ + if (pci_system_x86_conf1_probe () == 0) + { + pci_ifc->read = pci_system_x86_conf1_read; + pci_ifc->write = pci_system_x86_conf1_write; + if (pci_system_x86_check (pci_ifc) == 0) + return 0; + } + + if (pci_system_x86_conf2_probe () == 0) + { + pci_ifc->read = pci_system_x86_conf2_read; + pci_ifc->write = pci_system_x86_conf2_write; + if (pci_system_x86_check (pci_ifc) == 0) + return 0; + } + + return ENODEV; +} + +int +pci_system_x86_create (void) +{ + int ret; + + ret = x86_enable_io (); + if (ret) + return ret; + + pci_ifc = calloc (1, sizeof (struct pci_iface)); + if (pci_ifc == NULL) + { + x86_disable_io (); + return ENOMEM; + } + + ret = pci_probe (pci_ifc); + if (ret) + { + x86_disable_io (); + free (pci_ifc); + return ret; + } + + return 0; +} diff --git a/pci_arbiter/x86_pci.h b/pci_arbiter/x86_pci.h new file mode 100644 index 00000000..fe507d67 --- /dev/null +++ b/pci_arbiter/x86_pci.h @@ -0,0 +1,42 @@ +/* + * 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 access backend header. + * + * Following code is borrowed from libpciaccess: + * https://cgit.freedesktop.org/xorg/lib/libpciaccess/ + */ + +#ifndef X86_PCI_H +#define X86_PCI_H + +#define PCI_VENDOR_ID 0x00 +#define PCI_VENDOR_ID_COMPAQ 0x0e11 +#define PCI_VENDOR_ID_INTEL 0x8086 + +#define PCI_CLASS_DEVICE 0x0a +#define PCI_CLASS_DISPLAY_VGA 0x0300 +#define PCI_CLASS_BRIDGE_HOST 0x0600 + +int pci_system_x86_create (void); + +#endif /* X86_PCI_H */ -- 2.14.0