diff --git a/Makefile.in b/Makefile.in index e0edbdb04..1733f1c01 100644 --- a/Makefile.in +++ b/Makefile.in @@ -100,12 +100,14 @@ endif AWK = @AWK@ LIBCURSES = @LIBCURSES@ LIBUSB = @LIBUSB@ +LIBPCIACCESS = @LIBPCIACCESS@ YACC = @YACC@ UNIFONT_BDF = @UNIFONT_BDF@ # Options. enable_grub_emu = @enable_grub_emu@ enable_grub_emu_usb = @enable_grub_emu_usb@ +enable_grub_emu_pci = @enable_grub_emu_pci@ enable_grub_fstest = @enable_grub_fstest@ enable_grub_pe2elf = @enable_grub_pe2elf@ enable_grub_mkfont = @enable_grub_mkfont@ diff --git a/bus/pci.c b/bus/pci.c index 2c29c03ab..fe4cad181 100644 --- a/bus/pci.c +++ b/bus/pci.c @@ -21,41 +21,40 @@ #include grub_pci_address_t -grub_pci_make_address (int bus, int device, int function, int reg) +grub_pci_make_address (grub_pci_device_t dev, int reg) { - return (1 << 31) | (bus << 16) | (device << 11) | (function << 8) | (reg << 2); + return (1 << 31) | (dev.bus << 16) | (dev.device << 11) + | (dev.function << 8) | (reg << 2); } void grub_pci_iterate (grub_pci_iteratefunc_t hook) { - int bus; - int dev; - int func; + grub_pci_device_t dev; grub_pci_address_t addr; grub_pci_id_t id; grub_uint32_t hdr; - for (bus = 0; bus < 256; bus++) + for (dev.bus = 0; dev.bus < 256; dev.bus++) { - for (dev = 0; dev < 32; dev++) + for (dev.device = 0; dev.device < 32; dev.device++) { - for (func = 0; func < 8; func++) + for (dev.function = 0; dev.function < 8; dev.function++) { - addr = grub_pci_make_address (bus, dev, func, 0); + addr = grub_pci_make_address (dev, 0); id = grub_pci_read (addr); /* Check if there is a device present. */ if (id >> 16 == 0xFFFF) continue; - if (hook (bus, dev, func, id)) + if (hook (dev, id)) return; /* Probe only func = 0 if the device if not multifunction */ - if (func == 0) + if (dev.function == 0) { - addr = grub_pci_make_address (bus, dev, func, 3); + addr = grub_pci_make_address (dev, 3); hdr = grub_pci_read (addr); if (!(hdr & 0x800000)) break; diff --git a/bus/usb/ohci.c b/bus/usb/ohci.c index 388f65928..163cee2eb 100644 --- a/bus/usb/ohci.c +++ b/bus/usb/ohci.c @@ -116,7 +116,7 @@ grub_ohci_writereg32 (struct grub_ohci *o, /* Iterate over all PCI devices. Determine if a device is an OHCI controller. If this is the case, initialize it. */ static int NESTED_FUNC_ATTR -grub_ohci_pci_iter (int bus, int device, int func, +grub_ohci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__((unused))) { grub_uint32_t class_code; @@ -129,7 +129,7 @@ grub_ohci_pci_iter (int bus, int device, int func, grub_uint32_t revision; grub_uint32_t frame_interval; - addr = grub_pci_make_address (bus, device, func, 2); + addr = grub_pci_make_address (dev, 2); class_code = grub_pci_read (addr) >> 8; interf = class_code & 0xFF; @@ -141,7 +141,7 @@ grub_ohci_pci_iter (int bus, int device, int func, return 0; /* Determine IO base address. */ - addr = grub_pci_make_address (bus, device, func, 4); + addr = grub_pci_make_address (dev, 4); base = grub_pci_read (addr); #if 0 diff --git a/bus/usb/uhci.c b/bus/usb/uhci.c index 88ff5b3d8..0d3daa5f1 100644 --- a/bus/usb/uhci.c +++ b/bus/usb/uhci.c @@ -138,7 +138,7 @@ grub_uhci_portstatus (grub_usb_controller_t dev, /* Iterate over all PCI devices. Determine if a device is an UHCI controller. If this is the case, initialize it. */ static int NESTED_FUNC_ATTR -grub_uhci_pci_iter (int bus, int device, int func, +grub_uhci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__((unused))) { grub_uint32_t class_code; @@ -151,7 +151,7 @@ grub_uhci_pci_iter (int bus, int device, int func, struct grub_uhci *u; int i; - addr = grub_pci_make_address (bus, device, func, 2); + addr = grub_pci_make_address (dev, 2); class_code = grub_pci_read (addr) >> 8; interf = class_code & 0xFF; @@ -163,7 +163,7 @@ grub_uhci_pci_iter (int bus, int device, int func, return 0; /* Determine IO base address. */ - addr = grub_pci_make_address (bus, device, func, 8); + addr = grub_pci_make_address (dev, 8); base = grub_pci_read (addr); /* Stop if there is no IO space base address defined. */ if (! (base & 1)) diff --git a/commands/lspci.c b/commands/lspci.c index 5b3360a37..bcaafa4f8 100644 --- a/commands/lspci.c +++ b/commands/lspci.c @@ -115,15 +115,16 @@ grub_pci_get_class (int class, int subclass) } static int NESTED_FUNC_ATTR -grub_lspci_iter (int bus, int dev, int func, grub_pci_id_t pciid) +grub_lspci_iter (grub_pci_device_t dev, grub_pci_id_t pciid) { grub_uint32_t class; const char *sclass; grub_pci_address_t addr; - grub_printf ("%02x:%02x.%x %04x:%04x", bus, dev, func, pciid & 0xFFFF, - pciid >> 16); - addr = grub_pci_make_address (bus, dev, func, 2); + grub_printf ("%02x:%02x.%x %04x:%04x", grub_pci_get_bus (dev), + grub_pci_get_device (dev), grub_pci_get_function (dev), + pciid & 0xFFFF, pciid >> 16); + addr = grub_pci_make_address (dev, 2); class = grub_pci_read (addr); /* Lookup the class name, if there isn't a specific one, @@ -156,13 +157,13 @@ grub_cmd_lspci (grub_command_t cmd __attribute__ ((unused)), static grub_command_t cmd; -GRUB_MOD_INIT(pci) +GRUB_MOD_INIT(lspci) { cmd = grub_register_command ("lspci", grub_cmd_lspci, 0, "List PCI devices"); } -GRUB_MOD_FINI(pci) +GRUB_MOD_FINI(lspci) { grub_unregister_command (cmd); } diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 74125eaa5..73e54bc05 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -165,7 +165,12 @@ grub_emu_LDFLAGS = $(LIBCURSES) ifeq ($(enable_grub_emu_usb), yes) grub_emu_SOURCES += disk/usbms.c util/usb.c bus/usb/usb.c \ commands/usbtest.c -grub_emu_LDFLAGS += $(LIBCURSES) $(LIBUSB) +grub_emu_LDFLAGS += $(LIBUSB) +endif + +ifeq ($(enable_grub_emu_pci), yes) +grub_emu_SOURCES += util/pci.c commands/lspci.c +grub_emu_LDFLAGS += $(LIBPCIACCESS) endif # Scripts. diff --git a/configure.ac b/configure.ac index 0e5ee5900..46b972229 100644 --- a/configure.ac +++ b/configure.ac @@ -520,6 +520,10 @@ AC_ARG_ENABLE([grub-emu], AC_ARG_ENABLE([grub-emu-usb], [AS_HELP_STRING([--enable-grub-emu-usb], [build and install the `grub-emu' debugging utility with USB support (default=guessed)])]) +AC_ARG_ENABLE([grub-emu-pci], + [AS_HELP_STRING([--enable-grub-emu-pci], + [build and install the `grub-emu' debugging utility with PCI support (potentially dangerous) (default=no)])]) + if test x"$enable_grub_emu" = xno ; then grub_emu_excuse="explicitly disabled" fi @@ -548,9 +552,14 @@ else enable_grub_emu=no grub_emu_usb_excuse="grub-emu isn't built" fi +if test x"$enable_grub_emu_pci" = xyes ; then + grub_emu_usb_excuse="conflicts with PCI support" +fi + if test x"$enable_grub_emu_usb" = xno ; then grub_emu_usb_excuse="explicitly disabled" fi + [if [ x"$grub_emu_usb_excuse" = x ]; then # Check for libusb libraries.] AC_CHECK_LIB([usb], [usb_claim_interface], [LIBUSB="-lusb"], @@ -571,8 +580,35 @@ else enable_grub_emu_usb=no fi +if test x"$enable_grub_emu_pci" != xyes ; then + grub_emu_pci_excuse="not enabled" +fi + +if test x"$enable_grub_emu_usb" = xyes ; then + grub_emu_pci_excuse="conflicts with USB support" +fi + +[if [ x"$grub_emu_pci_excuse" = x ]; then + # Check for libpci libraries.] + AC_CHECK_LIB([pciaccess], [pci_system_init], [LIBPCIACCESS="-lpciaccess"], + [grub_emu_pci_excuse=["need libpciaccess library"]]) + AC_SUBST([LIBPCIACCESS]) +[fi] +[if [ x"$grub_emu_pci_excuse" = x ]; then + # Check for headers.] + AC_CHECK_HEADERS([pci/pci.h], [], + [grub_emu_pci_excuse=["need libpciaccess headers"]]) +[fi] + +if test x"$grub_emu_pci_excuse" = x ; then +enable_grub_emu_pci=yes +else +enable_grub_emu_pci=no +fi + AC_SUBST([enable_grub_emu]) AC_SUBST([enable_grub_emu_usb]) +AC_SUBST([enable_grub_emu_pci]) AC_ARG_ENABLE([grub-fstest], [AS_HELP_STRING([--enable-grub-fstest], @@ -646,6 +682,12 @@ echo USB support for grub-emu: Yes else echo USB support for grub-emu: No "($grub_emu_usb_excuse)" fi +if [ x"$grub_emu_pci_excuse" = x ]; then +echo PCI support for grub-emu: Yes +else +echo PCI support for grub-emu: No "($grub_emu_pci_excuse)" +fi + if [ x"$enable_mm_debug" = xyes ]; then echo With memory debugging: Yes else diff --git a/disk/ata.c b/disk/ata.c index b8ce88df3..00e370960 100644 --- a/disk/ata.c +++ b/disk/ata.c @@ -389,7 +389,7 @@ grub_ata_device_initialize (int port, int device, int addr, int addr2) } static int NESTED_FUNC_ATTR -grub_ata_pciinit (int bus, int device, int func, +grub_ata_pciinit (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__((unused))) { static int compat_use[2] = { 0 }; @@ -403,7 +403,7 @@ grub_ata_pciinit (int bus, int device, int func, static int controller = 0; /* Read class. */ - addr = grub_pci_make_address (bus, device, func, 2); + addr = grub_pci_make_address (dev, 2); class = grub_pci_read (addr); /* Check if this class ID matches that of a PCI IDE Controller. */ @@ -430,9 +430,9 @@ grub_ata_pciinit (int bus, int device, int func, { /* Read the BARs, which either contain a mmapped IO address or the IO port address. */ - addr = grub_pci_make_address (bus, device, func, 4 + 2 * i); + addr = grub_pci_make_address (dev, 4 + 2 * i); bar1 = grub_pci_read (addr); - addr = grub_pci_make_address (bus, device, func, 5 + 2 * i); + addr = grub_pci_make_address (dev, 5 + 2 * i); bar2 = grub_pci_read (addr); /* Check if the BARs describe an IO region. */ @@ -445,7 +445,8 @@ grub_ata_pciinit (int bus, int device, int func, grub_dprintf ("ata", "PCI dev (%d,%d,%d) compat=%d rega=0x%x regb=0x%x\n", - bus, device, func, compat, rega, regb); + grub_pci_get_bus (dev), grub_pci_get_device (dev), + grub_pci_get_function (dev), compat, rega, regb); if (rega && regb) { diff --git a/include/grub/i386/pci.h b/include/grub/i386/pci.h index 996f64245..5b5f5f0df 100644 --- a/include/grub/i386/pci.h +++ b/include/grub/i386/pci.h @@ -67,4 +67,20 @@ grub_pci_write_byte (grub_pci_address_t addr, grub_uint8_t data) grub_outb (data, GRUB_PCI_DATA_REG + (addr & 3)); } +static inline void * +grub_pci_device_map_range (grub_pci_device_t dev __attribute__ ((unused)), + grub_addr_t base, + grub_size_t size __attribute__ ((unused))) +{ + return (void *) base; +} + +static inline void +grub_pci_device_unmap_range (grub_pci_device_t dev __attribute__ ((unused)), + void *mem __attribute__ ((unused)), + grub_size_t size __attribute__ ((unused))) +{ +} + + #endif /* GRUB_CPU_PCI_H */ diff --git a/include/grub/pci.h b/include/grub/pci.h index 7c8b50528..2bea05410 100644 --- a/include/grub/pci.h +++ b/include/grub/pci.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,15 +36,44 @@ #define GRUB_PCI_ADDR_IO_MASK ~0x03 typedef grub_uint32_t grub_pci_id_t; -typedef int NESTED_FUNC_ATTR (*grub_pci_iteratefunc_t) - (int bus, int device, int func, grub_pci_id_t pciid); -typedef grub_uint32_t grub_pci_address_t; -grub_pci_address_t EXPORT_FUNC(grub_pci_make_address) (int bus, int device, - int function, int reg); +#ifdef GRUB_UTIL +#include +#else +typedef grub_uint32_t grub_pci_address_t; +struct grub_pci_device +{ + int bus; + int device; + int function; +}; +typedef struct grub_pci_device grub_pci_device_t; +static inline int +grub_pci_get_bus (grub_pci_device_t dev) +{ + return dev.bus; +} + +static inline int +grub_pci_get_device (grub_pci_device_t dev) +{ + return dev.device; +} + +static inline int +grub_pci_get_function (grub_pci_device_t dev) +{ + return dev.function; +} +#include +#endif + +typedef int NESTED_FUNC_ATTR (*grub_pci_iteratefunc_t) + (grub_pci_device_t dev, grub_pci_id_t pciid); + +grub_pci_address_t EXPORT_FUNC(grub_pci_make_address) (grub_pci_device_t dev, + int reg); void EXPORT_FUNC(grub_pci_iterate) (grub_pci_iteratefunc_t hook); -#include - #endif /* GRUB_PCI_H */ diff --git a/include/grub/pciutils.h b/include/grub/pciutils.h new file mode 100644 index 000000000..36d47e5c8 --- /dev/null +++ b/include/grub/pciutils.h @@ -0,0 +1,103 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_PCIUTILS_H +#define GRUB_PCIUTILS_H 1 + +#include + +typedef struct pci_device *grub_pci_device_t; + +static inline int +grub_pci_get_bus (grub_pci_device_t dev) +{ + return dev->bus; +} + +static inline int +grub_pci_get_device (grub_pci_device_t dev) +{ + return dev->dev; +} + +static inline int +grub_pci_get_function (grub_pci_device_t dev) +{ + return dev->func; +} + +struct grub_pci_address +{ + grub_pci_device_t dev; + int pos; +}; + +typedef struct grub_pci_address grub_pci_address_t; + +static inline grub_uint32_t +grub_pci_read (grub_pci_address_t addr) +{ + grub_uint32_t ret; + pci_device_cfg_read_u32 (addr.dev, &ret, addr.pos); + return ret; +} + +static inline grub_uint16_t +grub_pci_read_word (grub_pci_address_t addr) +{ + grub_uint16_t ret; + pci_device_cfg_read_u16 (addr.dev, &ret, addr.pos); + return ret; +} + +static inline grub_uint8_t +grub_pci_read_byte (grub_pci_address_t addr) +{ + grub_uint8_t ret; + pci_device_cfg_read_u8 (addr.dev, &ret, addr.pos); + return ret; +} + +static inline void +grub_pci_write (grub_pci_address_t addr, grub_uint32_t data) +{ + pci_device_cfg_write_u32 (addr.dev, data, addr.pos); +} + +static inline void +grub_pci_write_word (grub_pci_address_t addr, grub_uint16_t data) +{ + pci_device_cfg_write_u16 (addr.dev, data, addr.pos); +} + +static inline void +grub_pci_write_byte (grub_pci_address_t addr, grub_uint8_t data) +{ + pci_device_cfg_write_u8 (addr.dev, data, addr.pos); +} + +void * +grub_pci_device_map_range (grub_pci_device_t dev, grub_addr_t base, + grub_size_t size); + +void +grub_pci_device_unmap_range (grub_pci_device_t dev, void *mem, + grub_size_t size); + + +#endif /* GRUB_PCIUTILS_H */ diff --git a/util/pci.c b/util/pci.c new file mode 100644 index 000000000..8915068aa --- /dev/null +++ b/util/pci.c @@ -0,0 +1,76 @@ +/* pci.c - Generic PCI interfaces. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007,2009 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include + +grub_pci_address_t +grub_pci_make_address (grub_pci_device_t dev, int reg) +{ + grub_pci_address_t ret; + ret.dev = dev; + ret.pos = reg << 2; + return ret; +} + +void +grub_pci_iterate (grub_pci_iteratefunc_t hook) +{ + struct pci_device_iterator *iter; + struct pci_slot_match slot; + struct pci_device *dev; + slot.domain = PCI_MATCH_ANY; + slot.bus = PCI_MATCH_ANY; + slot.dev = PCI_MATCH_ANY; + slot.func = PCI_MATCH_ANY; + iter = pci_slot_match_iterator_create (&slot); + while ((dev = pci_device_next (iter))) + hook (dev, dev->vendor_id | (dev->device_id << 16)); + pci_iterator_destroy (iter); +} + +void * +grub_pci_device_map_range (grub_pci_device_t dev, grub_addr_t base, + grub_size_t size) +{ + void *addr; + int err; + err = pci_device_map_range(dev, base, size, PCI_DEV_MAP_FLAG_WRITABLE, &addr); + if (err) + grub_util_error ("mapping 0x%x failed (error %d)\n", base, err); + return addr; +} + +void +grub_pci_device_unmap_range (grub_pci_device_t dev, void *mem, + grub_size_t size) +{ + pci_device_unmap_range (dev, mem, size); +} + +GRUB_MOD_INIT (pci) +{ + pci_system_init (); +} + +GRUB_MOD_FINI (pci) +{ + pci_system_cleanup (); +}