diff -urN qemu.orig/Makefile.target qemu/Makefile.target
--- qemu.orig/Makefile.target	2004-05-31 16:53:24.000000000 +0100
+++ qemu/Makefile.target	2004-05-31 16:53:19.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-05-31 16:53:24.000000000 +0100
+++ qemu/configure	2004-05-31 16:53:19.000000000 +0100
@@ -390,6 +390,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-05-31 16:53:24.000000000 +0100
+++ qemu/hw/pc.c	2004-05-31 16:53:19.000000000 +0100
@@ -386,6 +386,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-05-31 17:33:13.000000000 +0100
@@ -0,0 +1,577 @@
+/*
+ * QEMU PCI Host proxy
+ * Copyright (c) 2004 Gianni Tedesco
+ * This code is released under the terms of the GNU GPL v2.
+ *
+ * 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 Support memory mapped resources
+ *  o Support ROM resources
+ *  o Map IRQs
+*/
+
+#include "vl.h"
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#if HAVE_SYS_IO_H
+#include <sys/io.h>
+#endif
+
+#define PROC_DEVICES "/proc/bus/pci/devices"
+#define PCIPROXY_RESOURCES 7
+#define PCIPROXY_ROM_SLOT 6
+
+/* 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 pciproxy {
+	struct PCIDevice pcidev;
+	uint32_t len[PCIPROXY_RESOURCES];
+	uint32_t qemu_map[PCIPROXY_RESOURCES];
+	void *map[PCIPROXY_RESOURCES];
+	uint32_t io_allowed;
+	uint32_t bar[PCIPROXY_RESOURCES];
+	int dev, bus, fn;
+	int fd;
+};
+
+static inline const char *sys_err(void)
+{
+	return strerror(errno);
+}
+
+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;
+}
+
+#if 0
+static int read_config_dword(struct pciproxy *pci, uint32_t idx, uint32_t *word)
+{
+	ssize_t ret = pread(pci->fd, word, sizeof(*word), idx);
+	*word = le32_to_cpu(*word);
+	return (ret == (ssize_t)sizeof(*word));
+}
+
+static int read_config_word(struct pciproxy *pci, uint32_t idx, uint16_t *word)
+{
+	ssize_t ret = pread(pci->fd, word, sizeof(*word), idx);
+	*word = le16_to_cpu(*word);
+	return (ret == (ssize_t)sizeof(*word));
+}
+
+static int read_config_byte(struct pciproxy *pci, uint32_t idx, uint8_t *word)
+{
+	ssize_t ret = pread(pci->fd, word, sizeof(*word), idx);
+	return (ret == (ssize_t)sizeof(*word));
+}
+
+static int write_config_dword(struct pciproxy *pci, uint32_t idx, uint32_t word)
+{
+	ssize_t ret;
+	word = cpu_to_le32(word);
+	ret = pwrite(pci->fd, &word, sizeof(word), idx);
+	return (ret == (ssize_t)sizeof(word));
+}
+
+static int write_config_word(struct pciproxy *pci, uint32_t idx, uint16_t word)
+{
+	ssize_t ret;
+	word = cpu_to_le16(word);
+	ret = pwrite(pci->fd, &word, sizeof(word), idx);
+	return (ret == (ssize_t)sizeof(word));
+}
+
+static int write_config_byte(struct pciproxy *pci, uint32_t idx, uint8_t word)
+{
+	ssize_t ret;
+	ret = pwrite(pci->fd, &word, sizeof(word), idx);
+	return (ret == (ssize_t)sizeof(word));
+}
+#endif
+
+/* 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 < PCIPROXY_RESOURCES; i++) {
+			num = strtoul(tok[10 + i], NULL, 16);
+			pci->len[i] = 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 pciproxy *pci, int i)
+{
+#if HAVE_IOPERM
+	int ret;
+
+	ret = iopl(3);
+	if ( ret == 0 ) {
+		pci->io_allowed |= (1<<i);
+		return 1;
+	}
+
+	fprintf(stderr, "%.2x:%.2x.%x iopl() slot %i: %s\n",
+		pci->bus, pci->dev, pci->fn, i, sys_err());
+#else
+	fprintf(stderr, "%.2x:%.2x.%x ioperm() slot %i: %s\n",
+		pci->bus, pci->dev, pci->fn, i, 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 pciproxy *pci, int i, uint32_t bar)
+{
+#if HAVE_IOPERM
+	u_int32_t from, to;
+	int ret;
+
+	from = bar & ~0x3;
+	to = from + pci->len[i];
+
+	ret = ioperm(from, to, 1);
+	if ( ret < 0 )
+		return map_with_iopl(pci, i);
+	pci->io_allowed |= (1<<i);
+	return 1;
+#else
+	fprintf(stderr, "%.2x:%.2x.%x mmap() slot %i: %s\n",
+		pci->bus, pci->dev, pci->fn, i, sys_err());
+	return 0;
+#endif
+}
+
+/* Try to mmap a given PCI resource from the /proc/bus/pci/XX/YY.Z file */
+static int map_resource(struct pciproxy *pci, int i, void *start_addr)
+{
+	uint32_t base, flags, len, ofs, pgmask, bar;
+	int prot, ioc, mmflags;
+	void *map;
+
+	len = pci->len[i];
+	bar = pci->bar[i];
+
+	if ( start_addr ) {
+		mmflags = MAP_SHARED | MAP_FIXED;
+	}else{
+		mmflags = MAP_SHARED;
+	}
+
+	if ( i == PCIPROXY_ROM_SLOT ) {
+		prot = PROT_READ;
+	}else{
+		prot = PROT_READ|PROT_WRITE;
+	}
+
+	if ( bar & PCI_ADDRESS_SPACE_IO ) {
+		flags = (bar & 0x3);
+		base = (bar & ~0x3);
+		ioc = PCIIOC_MMAP_IS_IO;
+	}else{
+		flags = (bar & 0xf);
+		base = (bar & ~0xf);
+		ioc = PCIIOC_MMAP_IS_MEM;
+	}
+
+	/* 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(pci->fd, ioc) ) {
+		fprintf(stderr, "%.2x:%.2x.%x ioctl() slot %i: %s\n",
+			pci->bus, pci->dev, pci->fn, i, sys_err());
+		return 0;
+	}
+
+	map = mmap(start_addr, len, prot, mmflags, pci->fd, base);
+	if ( (map == MAP_FAILED) ) {
+		if ( (flags & PCI_ADDRESS_SPACE_IO ) )
+			return map_with_ioperm(pci, i, bar);
+		fprintf(stderr, "%.2x:%.2x.%x mmap() slot %i: %s\n",
+			pci->bus, pci->dev, pci->fn, i, sys_err());
+		return 0;
+	}
+
+	pci->map[i] = 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) ) {
+intr:
+		if ( close(pci->fd) && errno == EINTR )
+			goto intr;
+		return 0;
+	}
+
+	/* 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->bar[0] = le32_to_cpu(*(uint32_t *)(pci->pcidev.config + 0x10));
+	pci->bar[1] = le32_to_cpu(*(uint32_t *)(pci->pcidev.config + 0x14));
+	pci->bar[2] = le32_to_cpu(*(uint32_t *)(pci->pcidev.config + 0x18));
+	pci->bar[3] = le32_to_cpu(*(uint32_t *)(pci->pcidev.config + 0x1c));
+	pci->bar[4] = le32_to_cpu(*(uint32_t *)(pci->pcidev.config + 0x20));
+	pci->bar[5] = le32_to_cpu(*(uint32_t *)(pci->pcidev.config + 0x24));
+	pci->bar[6] = le32_to_cpu(*(uint32_t *)(pci->pcidev.config + 0x30));
+
+	return 1;
+}
+
+static void iowrite(void *ptr, uint32_t addr, uint32_t data, uint32_t len)
+{
+	struct pciproxy *pci = (struct pciproxy *)ptr;
+	uint32_t ofs;
+	int i;
+
+	for(i=0; i < PCIPROXY_RESOURCES; i++) {
+		if ( pci->bar[i] && 
+			addr >= pci->qemu_map[i] &&
+			addr <= pci->qemu_map[i] + pci->len[i] ) {
+			break;
+		}
+	}
+
+	if ( i >= PCIPROXY_RESOURCES ) {
+		fprintf(stderr, "Write to unknown I/O resource (0x%.8x/%u)\n",
+				addr, len);
+		return;
+	}
+
+	ofs = addr - pci->qemu_map[i];
+	addr = pci->bar[i] & ~0x03;
+
+	if ( pci->map[i] ) {
+		/* TODO */
+		return;
+	}else{
+#if HAVE_SYS_IO_H
+		if ( !(pci->io_allowed & (1<<i)) ) 
+			return;
+
+		switch ( len ) {
+		case 1:
+			outb(data, addr + ofs);
+			break;
+		case 2:
+			outw(data, addr + ofs);
+			break;
+		case 3:
+			outl(data, addr + ofs);
+			break;
+		default:
+			return;
+		}
+#endif
+	}
+
+	printf("%u byte write 0x%.x/0x%.x(%u) wrote 0x%.8x\n",
+		len, addr + ofs, pci->qemu_map[i] + ofs, ofs, data);
+}
+
+static uint32_t ioread(void *ptr, uint32_t addr, uint32_t len)
+{
+	struct pciproxy *pci = (struct pciproxy *)ptr;
+	uint32_t ret, ofs;
+	int i;
+
+	for(i=0; i < PCIPROXY_RESOURCES; i++) {
+		if ( pci->bar[i] && 
+			addr >= pci->qemu_map[i] &&
+			addr <= pci->qemu_map[i] + pci->len[i] ) {
+			break;
+		}
+	}
+
+	if ( i >= PCIPROXY_RESOURCES ) {
+		fprintf(stderr, "Read from unknown I/O resource (0x%.8x/%u)\n",
+				addr, len);
+		return 0xffffffff;
+	}
+
+	ofs = addr - pci->qemu_map[i];
+	addr = pci->bar[i] & ~0x03;
+
+	if ( pci->map[i] ) {
+		/* TODO */
+		printf("Memory mapped I/O registers\n");
+		return 0xffffffff;
+	}else{
+#if HAVE_SYS_IO_H
+		if ( !(pci->io_allowed & (1<<i)) ) {
+			printf("IO not allowed\n");
+			return 0xffffffff;
+		}
+
+		switch ( len ) {
+		case 1:
+			ret = inb(addr + ofs);
+			break;
+		case 2:
+			ret = inw(addr + ofs);
+			break;
+		case 3:
+			ret = inl(addr + ofs);
+			break;
+		default:
+			ret = 0xffffffff;
+		}
+#endif
+	}
+
+	printf("%u byte read 0x%.x/0x%.x(%u) returned 0x%.8x\n",
+		len, addr + ofs, pci->qemu_map[i] + ofs, ofs, ret);
+	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;
+
+	pci->qemu_map[i] = addr;
+
+#if 0
+	if ( pci->map[i] ) {
+		uint32_t map;
+		uint32_t len;
+		uint32_t pgmask  = sysconf(_SC_PAGESIZE) - 1;
+		void *ret;
+
+		map = (uint32_t)pci->map[i];
+		len = pci->len[i];
+
+		map &= ~pgmask;
+		len += pgmask;
+		len &= ~pgmask;
+		printf("Unmapping slot #%i 0x%.8x %u\n", i, map, len);
+		munmap((void *)map, (size_t)len);
+		ret = mmap((void *)map, (size_t)len,
+			PROT_READ|PROT_WRITE|PROT_EXEC,
+			MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+		if ( ret != (void *)map )
+			printf("FAILED\n");
+	}
+#endif
+
+	if ( type == PCI_ADDRESS_SPACE_IO ) {
+		uint32_t len = pci->len[i];
+
+		if ( !map_resource(pci, i, NULL) )
+			return;
+
+		register_ioport_read(addr, len, 4, ioreadl, pci);
+		register_ioport_read(addr, len, 2, ioreadw, pci);
+		register_ioport_read(addr, len, 1, ioreadb, pci);
+		register_ioport_write(addr, len, 4, iowritel, pci);
+		register_ioport_write(addr, len, 2, iowritew, pci);
+		register_ioport_write(addr, len, 1, iowriteb, pci);
+
+		printf("Mapped io slot #%i [0x%.8x] 0x%.8x (len=%u)\n",
+			i, pci->bar[i], addr, len);
+	}else{
+#if 0
+		if ( !map_resource(pci, i, phys_ram_base + addr) )
+			return;
+
+		printf("Mapped mem slot #%i [0x%.8x] 0x%.8x / %p - %p\n",
+			i, pci->bar[i], addr, phys_ram_base,
+			phys_ram_base + addr);
+#endif
+	}
+}
+
+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,
+				NULL, NULL);
+
+	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) ) {
+		printf("OI\n");
+		return;
+	}
+
+	for(i=0; i < PCIPROXY_RESOURCES; i++) {
+		uint32_t type;
+
+		/* XXX: Not yet implemented */
+		if ( i == PCIPROXY_ROM_SLOT )
+			continue;
+
+		type = (pci->bar[i] & PCI_ADDRESS_SPACE_IO) ?
+			PCI_ADDRESS_SPACE_IO :
+			PCI_ADDRESS_SPACE_MEM ;
+
+		if ( pci->bar[i] ) {
+			printf("Registering region %i\n", i);
+			pci_register_io_region((struct PCIDevice *)pci,
+					i, pci->len[i], type, mapfunc);
+		}
+	}
+
+	/* TODO: Setup sigirg if present, if not, warn */
+}
diff -urN qemu.orig/vl.c qemu/vl.c
--- qemu.orig/vl.c	2004-05-31 16:53:24.000000000 +0100
+++ qemu/vl.c	2004-05-31 17:35:45.000000000 +0100
@@ -129,6 +129,7 @@
 int audio_enabled = 0;
 int pci_enabled = 0;
 int prep_enabled = 0;
+char *pciproxy_devpath = NULL;
 
 /***********************************************************/
 /* x86 ISA bus support */
@@ -2015,6 +2016,7 @@
     QEMU_OPTION_no_code_copy,
     QEMU_OPTION_pci,
     QEMU_OPTION_prep,
+    QEMU_OPTION_pciproxy,
 };
 
 typedef struct QEMUOption {
@@ -2065,6 +2067,7 @@
 #ifdef TARGET_PPC
     { "prep", 0, QEMU_OPTION_prep },
 #endif
+    { "pciproxy", HAS_ARG, QEMU_OPTION_pciproxy },
     { NULL },
 };
 
@@ -2341,6 +2344,9 @@
             case QEMU_OPTION_prep:
                 prep_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-05-31 16:53:24.000000000 +0100
+++ qemu/vl.h	2004-05-31 16:53:19.000000000 +0100
@@ -434,6 +434,10 @@
 void pci_pmac_init(void);
 void pci_ppc_bios_init(void);
 
+/* pciproxy.c */
+void pciproxy_add_device(char *devpath);
+extern char *pciproxy_devpath;
+
 /* vga.c */
 
 #define VGA_RAM_SIZE (4096 * 1024)
