diff -urN qemu.orig/Makefile.target qemu/Makefile.target --- qemu.orig/Makefile.target 2004-06-15 03:02:36.000000000 +0100 +++ qemu/Makefile.target 2004-06-15 03:03:49.000000000 +0100 @@ -232,7 +232,7 @@ endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o monitor.o pci.o +VL_OBJS=vl.o osdep.o block.o monitor.o pci.o pciproxy.o ifeq ($(TARGET_ARCH), i386) # Hardware support diff -urN qemu.orig/configure qemu/configure --- qemu.orig/configure 2004-06-15 03:02:36.000000000 +0100 +++ qemu/configure 2004-06-15 03:03:49.000000000 +0100 @@ -391,6 +391,11 @@ elif test -f "/usr/include/byteswap.h" ; then echo "#define HAVE_BYTESWAP_H 1" >> $config_h fi +if test -f "/usr/include/sys/io.h"; then + echo "#define HAVE_SYS_IO_H 1" >> $config_h + echo "#define HAVE_IOPL 1" >> $config_h + echo "#define HAVE_IOPERM 1" >> $config_h +fi if test "$gdbstub" = "yes" ; then echo "CONFIG_GDBSTUB=yes" >> $config_mak echo "#define CONFIG_GDBSTUB 1" >> $config_h diff -urN qemu.orig/hw/pc.c qemu/hw/pc.c --- qemu.orig/hw/pc.c 2004-06-15 03:02:36.000000000 +0100 +++ qemu/hw/pc.c 2004-06-15 03:03:49.000000000 +0100 @@ -394,6 +394,8 @@ if (pci_enabled) { i440fx_init(); piix3_init(); + if ( pciproxy_devpath ) + pciproxy_add_device(pciproxy_devpath); } /* init basic PC hardware */ diff -urN qemu.orig/hw/pciproxy.c qemu/hw/pciproxy.c --- qemu.orig/hw/pciproxy.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu/hw/pciproxy.c 2004-06-15 03:23:06.000000000 +0100 @@ -0,0 +1,744 @@ +/* + * QEMU PCI Host proxy v0.3 + * Copyright (c) 2004 Gianni Tedesco + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This code is dedicated towards my muse, my inspiration, Broadcom Corporation. + * Without your spite I would not have been compelled to write this code. + * + * TODO: + * o Data logging support + * o Support multiple devices fully + * o Consistent error messages + * o Test with PCMCIA + * o AGP support +*/ + +static const char copyright[] = + "pciproxy.c: v0.3 Copyright (c) Gianni Tedesco 2004"; + +#include "vl.h" +#include +#include +#if HAVE_SYS_IO_H +#include +#endif +#include + +/* Ioctls for /proc/bus/pci/X/Y nodes. */ +#define PCIIOC_BASE ('P' << 24 | 'C' << 16 | 'I' << 8) +/* Get controller for PCI device. */ +#define PCIIOC_CONTROLLER (PCIIOC_BASE | 0x00) +/* Set mmap state to I/O space. */ +#define PCIIOC_MMAP_IS_IO (PCIIOC_BASE | 0x01) +/* Set mmap state to MEM space. */ +#define PCIIOC_MMAP_IS_MEM (PCIIOC_BASE | 0x02) +/* Enable/disable write-combining. */ +#define PCIIOC_WRITE_COMBINE (PCIIOC_BASE | 0x03) +/* Send user-defined signal for irqs */ +#define PCIIOC_SIGIRQ (PCIIOC_BASE | 0x04) +struct pci_sigirq { + int sig; + void *ptr; +}; + +struct proxyres { + uint32_t qemu_map; + uint32_t len; + uint32_t bar; + void *map; + int iomem_region; + short io_allowed; + short rom; +}; + +struct pciproxy { + struct PCIDevice pcidev; + struct proxyres res[PCI_NUM_REGIONS]; + int fd; + int dev, bus, fn; +}; + +#if 0 +#define lprintf printf +#else +#define lprintf(...) +#endif + +#define PROC_DEVICES "/proc/bus/pci/devices" + +static const char sigirq_patch[]="*** WARNING: You will not be able to " + "receive IRQs for your pciproxy devices without patching your kernel " + "with: http://www.scaramanga.co.uk/stuff/linux-sigirq.diff"; + +static __inline__ const char *sys_err(void) +{ + return strerror(errno); +} + +/* Explode, for parsing proc files */ +static int easy_explode(char *str, char split, char **toks, int max_toks) +{ + char *tmp; + int tok; + int state; + + for(tmp=str,state=tok=0; *tmp && tok < max_toks; tmp++) { + if ( state == 0 ) { + if ( *tmp == split ) { + toks[tok++] = NULL; + }else if ( !isspace(*tmp) ) { + state = 1; + toks[tok++] = tmp; + } + }else if ( state == 1 ) { + if ( *tmp == split || isspace(*tmp) ) { + *tmp = '\0'; + state = 0; + } + } + } + + return tok; +} + +/* Whether a config space read/write needs forwarding to device or not */ +static int config_space_forwarded(uint32_t addr, uint32_t len) +{ + static const struct { + uint32_t begin; + uint32_t end; + }nofwd[]={ + {0x10, 0x28}, /* BARs */ + {0x30, 0x34}, /* ROM Base */ + {0x3c, 0x3e}, /* IRQ/INT */ + }; + size_t num = sizeof(nofwd)/sizeof(*nofwd); + uint32_t end = addr + len; + int i; + + /* If our request is not totally inside one of our no-forward + * ranges, then by definition we need to forward.. + */ + for(i=0; i < num; i++) { + if ( addr >= nofwd[i].begin && end < nofwd[i].end ) + return 0; + } + + return 1; +} + +/* Perform a read from an MMIO region */ +static uint32_t mem_read(struct proxyres *res, target_phys_addr_t addr, int len) +{ + uint32_t ret, ofs; + + ofs = addr - res->qemu_map; + switch ( len ) { + case 1: + ret = *(uint8_t *)(res->map + ofs); + break; + case 2: + ret = *(uint16_t *)(res->map + ofs); + break; + case 4: + ret = *(uint32_t *)(res->map + ofs); + break; + default: + return 0xffffffff; + } + + printf("mem read: 0x%.8x address@hidden", ret, len, ofs); + return ret; +} + +/* Perform a write to a MMIO region */ +static void mem_write(struct proxyres *res, + target_phys_addr_t addr, + int len, uint32_t value) +{ + uint32_t ofs; + + ofs = addr - res->qemu_map; + switch ( len ) { + case 1: + *(uint8_t *)(res->map + ofs) = value; + break; + case 2: + *(uint16_t *)(res->map + ofs) = value; + break; + case 4: + *(uint32_t *)(res->map + ofs) = value; + break; + default: + return; + } + + lprintf("mem write: 0x%.8x address@hidden", value, len, ofs); +} + +static uint32_t mem_readb(void *ptr, target_phys_addr_t addr) +{ + return mem_read(ptr, addr, 1); +} +static uint32_t mem_readw(void *ptr, target_phys_addr_t addr) +{ + return mem_read(ptr, addr, 2); +} +static uint32_t mem_readl(void *ptr, target_phys_addr_t addr) +{ + return mem_read(ptr, addr, 4); +} +static void mem_writeb(void *ptr, target_phys_addr_t addr, uint32_t value) +{ + return mem_write(ptr, addr, 1, value); +} +static void mem_writew(void *ptr, target_phys_addr_t addr, uint32_t value) +{ + return mem_write(ptr, addr, 2, value); +} +static void mem_writel(void *ptr, target_phys_addr_t addr, uint32_t value) +{ + return mem_write(ptr, addr, 4, value); +} + +static CPUReadMemoryFunc *cpu_callback_read[3]={ + mem_readb, + mem_readw, + mem_readl, +}; +static CPUWriteMemoryFunc *cpu_callback_write[3]={ + mem_writeb, + mem_writew, + mem_writel, +}; + +/* Uses /proc/bus/devices to grab the length of the resources on our PCI + * device in a platform independant way. + */ +static int peek_resources(struct pciproxy *pci) +{ + FILE *f; + char buf[512]; + char *tok[18]; + uint32_t num; + int n, i; + + f = fopen(PROC_DEVICES, "r"); + if ( f == NULL ) { + fprintf(stderr, "%s: open(): %s\n", PROC_DEVICES, sys_err()); + return 0; + } + + while ( fgets(buf, sizeof(buf), f) ) { + char *ptr; + + ptr = strchr(buf, '\r'); + if ( ptr == NULL ) + ptr = strchr(buf, '\n'); + if ( ptr == NULL ) + break; + *ptr = '\0'; + + n = easy_explode(buf, '\0', tok, 18); + if ( n < 17 ) + continue; + + num = strtoul(tok[0], NULL, 16); + if ( pci->bus != ((num & 0xff00) >> 8) ) + continue; + if ( pci->dev != ((num & 0x00ff) >> 3) ) + continue; + if ( pci->fn != (num & 0x7) ) + continue; + + for(i=0; i < PCI_NUM_REGIONS; i++) { + num = strtoul(tok[10 + i], NULL, 16); + pci->res[i].len = num; + } + + fclose(f); + return 1; + } + + fclose(f); + return 0; +} + +/* Final fallback path if mmap and ioperm fails, we just use iopl to raise + * our I/O priv level so that we can do any I/O we like. + */ +static int map_with_iopl(struct proxyres *res) +{ +#if HAVE_IOPL + int ret; + + ret = iopl(3); + if ( ret == 0 ) { + res->io_allowed = 1; + return 1; + } + + fprintf(stderr, "iopl(): %s\n", sys_err()); +#endif + return 0; +} + +/* First fallback path if mmap failes, try to use ioperm for granular + * permission granting to the I/O ports. + */ +static int map_with_ioperm(struct proxyres *res, uint32_t bar) +{ +#if HAVE_IOPERM + u_int32_t from, to; + int ret; + + from = bar & ~0x3; + to = from + res->len; + + ret = ioperm(from, to, 1); + if ( ret < 0 ) + return map_with_iopl(res); + res->io_allowed = 1; + return 1; +#else + if ( !map_with_iopl(res) ) { + fprintf(stderr, "ioperm() slot %i: %s\n", i, sys_err()); + } + + return 0; +#endif +} + +/* Check if resource is mapped and accessible */ +static int resource_is_mapped(struct proxyres *res) +{ + if ( res->map ) + return 1; + if ( res->io_allowed ) + return 1; + return 0; +} + +/* Try to mmap a given PCI resource from the /proc/bus/pci/XX/YY.Z file */ +static int map_resource(struct proxyres *res, int fd) +{ + uint32_t base, flags, len, ofs, pgmask, bar; + int prot, ioc; + void *map; + + len = res->len; + bar = res->bar; + + if ( res->rom ) { + prot = PROT_READ; + }else{ + prot = PROT_READ|PROT_WRITE; + } + + if ( res->rom || !(bar & PCI_ADDRESS_SPACE_IO) ) { + flags = (bar & 0xf); + base = (bar & ~0xf); + ioc = PCIIOC_MMAP_IS_MEM; + }else{ + flags = (bar & 0x3); + base = (bar & ~0x3); + ioc = PCIIOC_MMAP_IS_IO; + } + + /* Round base address down to the nearest page boundary and length + * up to the the nearest page boundary in order that we may mmap + * the resource range. + * + * XXX: Assumes page size is a power of two. (big deal) + */ + pgmask = sysconf(_SC_PAGESIZE) - 1; + + ofs = base & pgmask; + base &= ~pgmask; + len += pgmask; + len &= ~pgmask; + + if ( ioctl(fd, ioc) ) { + fprintf(stderr, "ioctl(): %s\n", sys_err()); + return 0; + } + + map = mmap(NULL, len, prot, MAP_SHARED, fd, base); + if ( (map == MAP_FAILED) ) { + int ret = 0 ; + + if ( !res->rom && (flags & PCI_ADDRESS_SPACE_IO ) ) + ret = map_with_ioperm(res, bar); + + if ( ret == 0 ) + fprintf(stderr, "mmap(): %s\n", sys_err()); + + return ret; + } + + res->map = map + ofs; + return 1; +} + +/* Construct the filename of the /proc/bus/pci/XX/YY.Z file to open for our + * device and open it. + */ +static int open_proc_bus_pci(struct pciproxy *pci) +{ + char path[1024]; + ssize_t ret; + + snprintf(path, sizeof(path), "/proc/bus/pci/%.2x/%.2x.%x", + pci->bus, pci->dev, pci->fn); + + pci->fd = open(path, O_RDWR); + if ( pci->fd < 0 ) { + fprintf(stderr, "%s: open(): %s\n", path, sys_err()); + return 0; + } + + ret = pread(pci->fd, pci->pcidev.config, sizeof(pci->pcidev.config), 0); + if ( ret != (ssize_t)sizeof(pci->pcidev.config) ) { + fprintf(stderr, "%s: pread() %u bytes of config space: %s\n", + path, sizeof(pci->pcidev.config), sys_err()); + goto err_close; + } + + /* Directly read the bar because on some architectures like PPC, the + * kernels mapped base doesn't correspond to the address we need + * to mmap on this FD. Also we need this info later on... + */ + pci->res[0].bar = le32_to_cpu(*(uint32_t *)(pci->pcidev.config + 0x10)); + pci->res[1].bar = le32_to_cpu(*(uint32_t *)(pci->pcidev.config + 0x14)); + pci->res[2].bar = le32_to_cpu(*(uint32_t *)(pci->pcidev.config + 0x18)); + pci->res[3].bar = le32_to_cpu(*(uint32_t *)(pci->pcidev.config + 0x1c)); + pci->res[4].bar = le32_to_cpu(*(uint32_t *)(pci->pcidev.config + 0x20)); + pci->res[5].bar = le32_to_cpu(*(uint32_t *)(pci->pcidev.config + 0x24)); + pci->res[6].bar = le32_to_cpu(*(uint32_t *)(pci->pcidev.config + 0x30)); + pci->res[6].rom = 1; + + return 1; +err_close: + if ( close(pci->fd) && errno == EINTR ) + goto err_close; + return 0; +} + +/* Perform a write to an I/O mapped region */ +static void iowrite(void *ptr, uint32_t addr, uint32_t data, uint32_t len) +{ + struct proxyres *res= (struct proxyres *)ptr; + uint32_t ofs; + return; + + ofs = addr - res->qemu_map; + addr = res->bar & ~0x03; + + if ( res->map ) { + switch( len ) { + case 1: + *(uint8_t *)(res->map + ofs) = data; + break; + case 2: + *(uint16_t *)(res->map + ofs) = data; + break; + case 4: + *(uint32_t *)(res->map + ofs) = data; + break; + default: + return; + } + }else{ +#if HAVE_SYS_IO_H + if ( !res->io_allowed ) { + fprintf(stderr, "pciproxy: illegal write on slot\n"); + return; + } + + switch ( len ) { + case 1: + outb(data, addr + ofs); + break; + case 2: + outw(data, addr + ofs); + break; + case 4: + outl(data, addr + ofs); + break; + default: + return; + } +#endif + } + + lprintf("io write: 0x%.8x address@hidden", data, len, ofs); +} + +/* Perform a read from an I/O mapped region */ +static uint32_t ioread(void *ptr, uint32_t addr, uint32_t len) +{ + struct proxyres *res = (struct proxyres *)ptr; + uint32_t ret, ofs; + + ofs = addr - res->qemu_map; + addr = res->bar & ~0x03; + + if ( res->map ) { + switch( len ) { + case 1: + ret = *(uint8_t *)(res->map + ofs); + break; + case 2: + ret = *(uint16_t *)(res->map + ofs); + break; + case 4: + ret = *(uint32_t *)(res->map + ofs); + break; + default: + return 0xffffffff; + } +#if HAVE_SYS_IO_H + }else{ + if ( !res->io_allowed ) { + fprintf(stderr, "pciproxy: illegal read on slot\n"); + return 0xffffffff; + } + + switch ( len ) { + case 1: + ret = inb(addr + ofs); + break; + case 2: + ret = inw(addr + ofs); + break; + case 4: + ret = inl(addr + ofs); + break; + default: + return 0xffffffff; + } +#endif + } + + lprintf("io read: 0x%.8x address@hidden", ret, len, ofs); + return ret; +} + +static void iowritel(void *ptr, uint32_t addr, uint32_t data) +{ + iowrite(ptr, addr, data, 4); +} +static void iowritew(void *ptr, uint32_t addr, uint32_t data) +{ + iowrite(ptr, addr, data, 2); +} +static void iowriteb(void *ptr, uint32_t addr, uint32_t data) +{ + iowrite(ptr, addr, data, 1); +} +static uint32_t ioreadl(void *ptr, uint32_t addr) +{ + return ioread(ptr, addr, 4); +} +static uint32_t ioreadw(void *ptr, uint32_t addr) +{ + return ioread(ptr, addr, 2); +} +static uint32_t ioreadb(void *ptr, uint32_t addr) +{ + return ioread(ptr, addr, 1); +} + +static void mapfunc(PCIDevice *pci_dev, int i, + uint32_t addr, uint32_t size, int type) +{ + struct pciproxy *pci = (struct pciproxy *)pci_dev; + struct proxyres *res = &pci->res[i]; + + if ( type == PCI_ADDRESS_SPACE_IO ) { + uint32_t len = res->len; + + if ( !resource_is_mapped(res) && + !map_resource(res, pci->fd) ) + return; + + res->qemu_map = addr; + + register_ioport_read(addr, len, 4, ioreadl, res); + register_ioport_read(addr, len, 2, ioreadw, res); + register_ioport_read(addr, len, 1, ioreadb, res); + register_ioport_write(addr, len, 4, iowritel, res); + register_ioport_write(addr, len, 2, iowritew, res); + register_ioport_write(addr, len, 1, iowriteb, res); + }else{ + unsigned long size; + + if ( !resource_is_mapped(res) && + !map_resource(res, pci->fd) ) + return; + + size = (res->len + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; + + if ( res->iomem_region == 0 ) + res->iomem_region = cpu_register_io_memory(0, + cpu_callback_read, + cpu_callback_write, + res); + + cpu_register_physical_memory(addr, size, + res->iomem_region); + + res->qemu_map = addr; + } +} + +/* Signal (IRQ) handler */ +static void sighand(int signum, siginfo_t *si, void *ptr) +{ + lprintf("pciproxy IRQ\n"); + pci_set_irq(ptr, 0, 1); +} + +/* Setup irq handling on a PCI device */ +static void receive_irqs(struct pciproxy *pci) +{ + struct pci_sigirq si; + struct sigaction sa; + int signum = SIGRTMIN; + + sa.sa_sigaction = sighand; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + sigaction(signum, &sa, NULL); + + si.sig = signum; + si.ptr = pci; + + if ( ioctl(pci->fd, PCIIOC_SIGIRQ, &si) == 0 ) + return; + + if ( errno == EINVAL ) { + fprintf(stderr, "%s\n", sigirq_patch); + }else if ( errno == ESRCH ) { + /* No IRQ handler is needed for this device */ + return; + }else if ( errno == EIO ) { + fprintf(stderr, "%.2x:%.2x.%x: Host device can't be allowed " + "to share an IRQ yet, sorry, interrupts disabled.\n", + pci->bus, pci->dev, pci->fn); + }else{ + fprintf(stderr, "%.2x:%.2x.%x: ioctl(SIGIRQ): %s\n", + pci->bus, pci->dev, pci->fn, sys_err()); + } +} + +static uint32_t cread(PCIDevice *pci_dev, uint32_t addr, int len) +{ + struct pciproxy *pci = (struct pciproxy *)pci_dev; + ssize_t sysret; + int ret; + int f; + + f = config_space_forwarded(addr, len); + if ( !f ) + goto no_forward; + + sysret = pread(pci->fd, pci_dev->config + addr, len, addr); + if ( sysret != (ssize_t)len ) + fprintf(stderr, "pread() of config space: %s\n", sys_err()); + +no_forward: + ret = pci_default_read_config(pci_dev, addr, len); + lprintf("config read: 0x%.8x address@hidden", + ret, len, addr, f ? " (forwarded)" : ""); + return ret; +} + +static void cwrite(PCIDevice *pci_dev, uint32_t addr, uint32_t data, int len) +{ + struct pciproxy *pci = (struct pciproxy *)pci_dev; + ssize_t sysret; + int f; + + f = config_space_forwarded(addr, len); + pci_default_write_config(pci_dev, addr, data, len); + + lprintf("config write: 0x%.8x address@hidden", + data, len, addr, f ? " (forwarded)" : ""); + + if ( f == 0 ) + return; + + sysret = pwrite(pci->fd, pci_dev->config + addr, len, addr); + if ( sysret != (ssize_t)len ) + fprintf(stderr, "pwrite() of config space: %s\n", sys_err()); +} + +void pciproxy_add_device(char *devpath) +{ + char *tok[3] = {NULL}; + struct pciproxy *pci; + int i; + + easy_explode(devpath, '.', &tok[1], 2); + if ( easy_explode(devpath, ':', &tok[0], 2) == 1 ) { + tok[1] = tok[0]; + tok[0] = NULL; + } + for(i=0; i < 3; i++) + if ( tok[i] == NULL ) + tok[i] = "0"; + + pci = (struct pciproxy *)pci_register_device("pciproxy", + sizeof(*pci), 0, -1, + cread, cwrite); + + if ( pci == NULL ) { + fprintf(stderr, "pciproxy: Adding device failed\n"); + return; + } + + pci->bus = strtol(tok[0], NULL, 16); + pci->dev = strtol(tok[1], NULL, 16); + pci->fn = strtol(tok[2], NULL, 16); + + printf("Adding PCI Host Proxy device: %.2x:%.2x:%x\n", + pci->bus, pci->dev, pci->fn); + + peek_resources(pci); + + if ( !open_proc_bus_pci(pci) ) + return; + + for(i=0; i < PCI_NUM_REGIONS; i++) { + struct proxyres *res = &pci->res[i]; + uint32_t type; + + type = (res->bar & PCI_ADDRESS_SPACE_IO) ? + PCI_ADDRESS_SPACE_IO : + PCI_ADDRESS_SPACE_MEM ; + + if ( res->rom ) + type = PCI_ADDRESS_SPACE_MEM; + + if ( res->bar ) + pci_register_io_region((struct PCIDevice *)pci, + i, res->len, type, mapfunc); + } + + receive_irqs(pci); +} diff -urN qemu.orig/vl.c qemu/vl.c --- qemu.orig/vl.c 2004-06-15 03:02:36.000000000 +0100 +++ qemu/vl.c 2004-06-15 20:33:35.000000000 +0100 @@ -104,6 +104,7 @@ /* XXX: use a two level table to limit memory usage */ #define MAX_IOPORTS 65536 +char *pciproxy_devpath = NULL; const char *bios_dir = CONFIG_QEMU_SHAREDIR; char phys_ram_file[1024]; CPUState *global_env; @@ -1081,7 +1082,7 @@ return -1; } memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE; pstrcpy(ifr.ifr_name, IFNAMSIZ, "tun%d"); ret = ioctl(fd, TUNSETIFF, (void *) &ifr); if (ret != 0) { @@ -2052,6 +2053,7 @@ QEMU_OPTION_L, QEMU_OPTION_no_code_copy, QEMU_OPTION_pci, + QEMU_OPTION_pciproxy, QEMU_OPTION_prep, QEMU_OPTION_localtime, QEMU_OPTION_cirrusvga, @@ -2102,6 +2104,7 @@ #ifdef TARGET_PPC { "prep", 0, QEMU_OPTION_prep }, #endif + { "pciproxy", HAS_ARG, QEMU_OPTION_pciproxy }, { "localtime", 0, QEMU_OPTION_localtime }, /* temporary options */ @@ -2389,6 +2392,9 @@ case QEMU_OPTION_cirrusvga: cirrus_vga_enabled = 1; break; + case QEMU_OPTION_pciproxy: + pciproxy_devpath = (char *)optarg; + break; } } } diff -urN qemu.orig/vl.h qemu/vl.h --- qemu.orig/vl.h 2004-06-15 03:02:36.000000000 +0100 +++ qemu/vl.h 2004-06-15 03:03:49.000000000 +0100 @@ -515,6 +515,10 @@ void pci_pmac_init(void); void pci_ppc_bios_init(void); +/* pciproxy.c */ +extern char *pciproxy_devpath; +void pciproxy_add_device(char *devpath); + /* vga.c */ #define VGA_RAM_SIZE (4096 * 1024)