Nico Huber (nico.h@gmx.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4695
-gerrit
commit f1adc72ec897a1749a6394a0907d146dd0d4b20c Author: Nico Huber nico.h@gmx.de Date: Wed Jan 1 20:47:55 2014 +0100
uio_usbdebug: User-space-i/o framework for usbdebug
uio_usbdebug enables you to debug coreboot's usbdebug driver inside a running operating system (only Linux at this time). This comes very handy if you're hacking the usbdebug driver and don't have any other debug output from coreboot itself.
Change-Id: Iaf0bcd4b4c01ae0b099d1206d553344054a62f31 Signed-off-by: Nico Huber nico.h@gmx.de --- util/uio_usbdebug/Makefile | 42 +++++++++++++ util/uio_usbdebug/README | 77 ++++++++++++++++++++++++ util/uio_usbdebug/console/printk.c | 34 +++++++++++ util/uio_usbdebug/device/device_util.c | 24 ++++++++ util/uio_usbdebug/device/pci_device.c | 12 ++++ util/uio_usbdebug/device/pci_ops.c | 7 +++ util/uio_usbdebug/lib/cbmem.c | 8 +++ util/uio_usbdebug/linux/Makefile | 13 ++++ util/uio_usbdebug/linux/uio_ehci_pci.c | 107 +++++++++++++++++++++++++++++++++ util/uio_usbdebug/uio_usbdebug.c | 60 ++++++++++++++++++ util/uio_usbdebug/uio_usbdebug_intel.c | 40 ++++++++++++ 11 files changed, 424 insertions(+)
diff --git a/util/uio_usbdebug/Makefile b/util/uio_usbdebug/Makefile new file mode 100644 index 0000000..c0fce30 --- /dev/null +++ b/util/uio_usbdebug/Makefile @@ -0,0 +1,42 @@ +include ../../.config + +ARCHDIR-$(CONFIG_ARCH_ARMV7) := armv7 +ARCHDIR-$(CONFIG_ARCH_X86) := x86 + +# Only Intel chipsets supported, currently. +OBJ-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON) += uio_usbdebug_intel.o + +PROGRAM := uio_usbdebug + +CB_SRC := $(shell realpath ../../src) +CB_SOURCES := lib/usbdebug.c +OBJECTS := uio_usbdebug.o \ + console/printk.o \ + device/device_util.o device/pci_device.o device/pci_ops.o \ + lib/cbmem.o \ + $(OBJ-y) \ + $(patsubst %.c,%.o,$(CB_SOURCES)) + +CONFIG_H := ../../build/config.h + +CFLAGS += -m32 -g \ + -Wall -Wextra -Werror \ + -Wno-unused-parameter -Wno-error=sign-compare +CPPFLAGS += -I../../src/include/ -I../../src/arch/$(ARCHDIR-y)/include/ \ + -include$(CONFIG_H) + +all: $(PROGRAM) + +$(PROGRAM): $(OBJECTS) $(OBJ-y) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) + +$(CB_SOURCES): + @mkdir -p $(dir $@) + @ln -sf $(CB_SRC)/$@ $@ + +$(OBJECTS): $(CONFIG_H) + +clean: + -@rm -rf $(CB_SOURCES) $(OBJECTS) $(PROGRAM) + +.PHONY: all clean diff --git a/util/uio_usbdebug/README b/util/uio_usbdebug/README new file mode 100644 index 0000000..2d52338 --- /dev/null +++ b/util/uio_usbdebug/README @@ -0,0 +1,77 @@ + +uio_usbdebug - Run coreboot's usbdebug driver in userspace +========================================================== + + +## Purpose + +uio_usbdebug enables you to debug coreboot's usbdebug driver inside a +running operating system (only Linux at this time). This comes very +handy if you're hacking the usbdebug driver and don't have any other +debug output from coreboot itself. + + +## State + +Currently only Intel chipsets are supported. Support for other chipsets +should be straightforward (normally just some port-enable code has to +be implemented). + +The Linux kernel driver (see linux/uio_ehci_pci.c) has only one PCI ID +hardcoded (for ICH7). The whole setup has been developed and tested on +a ThinkPad T60. + +### Files + +uio_usbdebug.c - The userspace part of the uio interface. + +uio_usbdebug_intel.c - Port enable code for Intel chipsets. + +linux/uio_ehci_pci.c - Kernel part of the uio interface. + +console/printk.c - A do_printk() implementation so you can see debug + output with CONFIG_DEBUG_USBDEBUG enabled. + +device/*.c lib/*.c - Some stubs for (hopefully) unneeded functions for + proper linking. + + +## Usage + +### Preparations + +The MMIO space has to be a whole 4K page in size and alignment to be +mapped into userspace. This is very uncommon, so you'll most probably +have to remap the MMIO space. The Linux kernel does that for you with +the `pci=resource_alignment=<pci address>` kernel parameter (e.g. +`pci=resource_alignment=0:1d.7` for ICH7). + +If your PCI device isn't listed in the kernel driver yet, you might want +to add it to the `ehci_pci_ids` table in `linux/uio_ehci_pci.c` (or do +some module alias magic if you know how to). + +### Build / Install + +Somehow like this: + +$ # Configure coreboot for your board and enable CONFIG_USBDEBUG +$ make menuconfig +$ cd util/uio_usbdebug/ +$ make -Clinux/ +$ sudo make -Clinux/ install +$ make + +### Run + +$ # Unload Linux' EHCI driver (high-speed devices will stop working) +$ sudo modprobe -r ehci-pci +$ # Load the uio driver +$ sudo modprobe uio-ehci-pci +$ # Find your uio device +$ ls /sys/module/uio_ehci_pci/drivers/*/*/uio/ +uio0 +$ # Run uio_usbdebug on this device +$ sudo ./uio_usbdebug /dev/uio0 + +Sadly, uio_usbdebug has to be run with root privileges since there are +port-80 writes in the usbdebug driver. diff --git a/util/uio_usbdebug/console/printk.c b/util/uio_usbdebug/console/printk.c new file mode 100644 index 0000000..3786103 --- /dev/null +++ b/util/uio_usbdebug/console/printk.c @@ -0,0 +1,34 @@ +/* + * This file is part of uio_usbdebug + * + * Copyright (C) 2013 Nico Huber nico.h@gmx.de + * + * This program 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; version 2 of the License. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdio.h> +#include <stdarg.h> +#include <console/console.h> + +int do_printk(int msg_level, const char *const fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i = vfprintf (stderr, fmt, args); + va_end(args); + + return i; +} diff --git a/util/uio_usbdebug/device/device_util.c b/util/uio_usbdebug/device/device_util.c new file mode 100644 index 0000000..5284101 --- /dev/null +++ b/util/uio_usbdebug/device/device_util.c @@ -0,0 +1,24 @@ + +#include <device/device.h> + +static char g_path[] = { '\0' }; + +const char *dev_path(device_t dev) +{ + return g_path; +} + +struct resource *find_resource(device_t dev, unsigned index) +{ + return NULL; +} + +void report_resource_stored(device_t dev, struct resource *resource, + const char *comment) +{ +} + +struct device *dev_find_slot(unsigned int bus, unsigned int devfn) +{ + return NULL; +} diff --git a/util/uio_usbdebug/device/pci_device.c b/util/uio_usbdebug/device/pci_device.c new file mode 100644 index 0000000..97acb05 --- /dev/null +++ b/util/uio_usbdebug/device/pci_device.c @@ -0,0 +1,12 @@ + +#include <device/pci.h> +#include <device/device.h> + +unsigned int pci_match_simple_dev(device_t dev, pci_devfn_t sdev) +{ + return 0; +} + +void pci_dev_read_resources(struct device *dev) +{ +} diff --git a/util/uio_usbdebug/device/pci_ops.c b/util/uio_usbdebug/device/pci_ops.c new file mode 100644 index 0000000..cd1b3a5 --- /dev/null +++ b/util/uio_usbdebug/device/pci_ops.c @@ -0,0 +1,7 @@ + +#include <device/device.h> + +u32 pci_read_config32(device_t dev, unsigned int where) +{ + return 0; +} diff --git a/util/uio_usbdebug/lib/cbmem.c b/util/uio_usbdebug/lib/cbmem.c new file mode 100644 index 0000000..6d87880 --- /dev/null +++ b/util/uio_usbdebug/lib/cbmem.c @@ -0,0 +1,8 @@ + +#include <stdint.h> +#include <stddef.h> + +void *cbmem_find(u32 id) +{ + return NULL; +} diff --git a/util/uio_usbdebug/linux/Makefile b/util/uio_usbdebug/linux/Makefile new file mode 100644 index 0000000..fd60b4f --- /dev/null +++ b/util/uio_usbdebug/linux/Makefile @@ -0,0 +1,13 @@ + +obj-m := uio_ehci_pci.o + +all: uio_ehci_pci.c + @$(MAKE) -C/lib/modules/`uname -r`/build M=$(CURDIR) modules + +install: + @$(MAKE) -C/lib/modules/`uname -r`/build M=$(CURDIR) modules_install + +clean: + -@$(MAKE) -C/lib/modules/`uname -r`/build M=$(CURDIR) clean + +.PHONY: all install clean diff --git a/util/uio_usbdebug/linux/uio_ehci_pci.c b/util/uio_usbdebug/linux/uio_ehci_pci.c new file mode 100644 index 0000000..185b4d6 --- /dev/null +++ b/util/uio_usbdebug/linux/uio_ehci_pci.c @@ -0,0 +1,107 @@ +/* + * uio_ehci_pci - UIO driver for PCI EHCI devices + * + * Copyright (C) 2013 Nico Huber nico.h@gmx.de + * + * This only implements MMIO access (no interrupts). + * + * This program 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; version 2 of the License. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + */ + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/uio_driver.h> + +#define DRIVER_VERSION "0.0.0" +#define DRIVER_AUTHOR "Nico Huber nico.h@gmx.de" +#define DRIVER_DESC "UIO driver for PCI EHCI devices" +#define DRIVER_TAG "uio_ehci_pci" + +static int +probe(struct pci_dev *const pci_dev, const struct pci_device_id *const did) +{ + struct uio_info *info; + int ret; + + ret = pci_enable_device(pci_dev); + if (ret) + goto return_; + + ret = pci_request_regions(pci_dev, DRIVER_TAG); + if (ret) + goto return_disable; + + info = kzalloc(sizeof(struct uio_info), GFP_KERNEL); + if (!info) { + ret = -ENOMEM; + goto return_release; + } + + info->name = DRIVER_TAG; + info->version = DRIVER_VERSION; + + info->mem[0].name = "EHCI MMIO area"; + info->mem[0].addr = pci_resource_start(pci_dev, 0); + if (!info->mem[0].addr) { + ret = -ENODEV; + goto return_free; + } + info->mem[0].size = pci_resource_len(pci_dev, 0); + info->mem[0].memtype = UIO_MEM_PHYS; + + ret = uio_register_device(&pci_dev->dev, info); + if (ret) + goto return_free; + pci_set_drvdata(pci_dev, info); + + return 0; +return_free: + kfree(info); +return_release: + pci_release_regions(pci_dev); +return_disable: + pci_disable_device(pci_dev); +return_: + return ret; +} + +static void +remove(struct pci_dev *const pci_dev) +{ + struct uio_info *const info = pci_get_drvdata(pci_dev); + + uio_unregister_device(info); + kfree(info); + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); +} + +static DEFINE_PCI_DEVICE_TABLE(ehci_pci_ids) = { + { PCI_DEVICE(0x8086, 0x27cc) }, + { 0, } +}; + +static struct pci_driver uio_ehci_pci_driver = { + .name = DRIVER_TAG, + .id_table = ehci_pci_ids, + .probe = probe, + .remove = remove, +}; + +module_pci_driver(uio_ehci_pci_driver); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/util/uio_usbdebug/uio_usbdebug.c b/util/uio_usbdebug/uio_usbdebug.c new file mode 100644 index 0000000..375cfa6 --- /dev/null +++ b/util/uio_usbdebug/uio_usbdebug.c @@ -0,0 +1,60 @@ +/* + * uio_usbdebug - Run coreboot's usbdebug driver in userspace + * + * Copyright (C) 2013 Nico Huber nico.h@gmx.de + * + * This program 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; version 2 of the License. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdio.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> + +/* coreboot's arch/io.h conflicts with libc's sys/io.h, so declare this here: */ +int ioperm(unsigned long from, unsigned long num, int turn_on); + +#include <arch/io.h> +#include <usbdebug.h> + +void *ehci_bar; + +int main(int argc, char *argv[]) +{ + if (argc != 2) { + fprintf(stderr, "Usage: %s <uio-dev>\n", argv[0]); + return 1; + } + const int fd = open(argv[1], O_RDWR); + if (fd < 0) { + perror("Failed to open uio device"); + return 2; + } + ehci_bar = + mmap(NULL, 1 << 8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (MAP_FAILED == ehci_bar) { + perror("Failed to map ehci bar"); + close(fd); + return 3; + } + + ioperm(0x80, 1, 1); + + usbdebug_init((unsigned)ehci_bar); + + munmap(ehci_bar, 1 << 8); + close(fd); + return 0; +} diff --git a/util/uio_usbdebug/uio_usbdebug_intel.c b/util/uio_usbdebug/uio_usbdebug_intel.c new file mode 100644 index 0000000..fa9e1a4 --- /dev/null +++ b/util/uio_usbdebug/uio_usbdebug_intel.c @@ -0,0 +1,40 @@ +/* + * This file is part of uio_usbdebug + * + * Copyright (C) 2013 Nico Huber nico.h@gmx.de + * + * This program 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; version 2 of the License. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <arch/io.h> +#include <usbdebug.h> + +extern void *ehci_bar; + +pci_devfn_t pci_ehci_dbg_dev(unsigned hcd_idx) +{ + return 0; +} + +void pci_ehci_dbg_set_port(pci_devfn_t dev, unsigned int port) +{ + /* claim usb debug port */ + const unsigned long dbgctl_addr = + ((unsigned long)ehci_bar) + CONFIG_EHCI_DEBUG_OFFSET; + write32(dbgctl_addr, read32(dbgctl_addr) | (1 << 30)); +} + +void pci_ehci_dbg_enable(pci_devfn_t dev, unsigned long base) +{ +}