All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
@ 2006-01-30 13:24 Ryan
  2006-01-30 15:06 ` Anthony Liguori
  0 siblings, 1 reply; 15+ messages in thread
From: Ryan @ 2006-01-30 13:24 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: Type: text/plain, Size: 2696 bytes --]

This patch contains the PCI backend and frontend drivers for Linux
2.6.12. There are a couple of compile-time options in the backend and
frontend although the defaults should be sufficient to get you up and
running.

In the PCI backend, there are two modes of operation: pass-through and
virtual PCI bus. The virtual PCI bus mode renumbers the slot addresses
and places all of the exported devices on bus 0. For example, a device
at 06:01.0 will appear to the PCI frontend to be at 00:00.0 (a 2nd
exported device will show up at 00:01.0 and so on...). In pass-through
mode, no renumbering occurs. A device at 06:01.0 will appear at 06:01.0
to the PCI frontend (this is more similar to how things worked in Xen
2.0.x). In both modes, PCI bridges are not currently exported. While
virtual PCI bus mode can somewhat mask the real slot addresses to the
frontend (they're still visible in Xenstore at present), it may break
certain specialized devices and drivers which need to know the location
of other PCI devices (pass-through mode may be better suited for this
scenario).

There are two methods for the PCI frontend as well. The default method
integrates with the architecture-specific PCI code (in this case, i386).
This allows some PCI things that are architecture-specific to keep
working (like pci_mmap_page_range) that can't be handled by the
architecture-specific code in the backend. The other method is an
attempt at an architecture-independent driver that replaces the
architecture-specific PCI code in Linux with one that exclusively uses
Xen. It requires less patching to the architecture-specific code (I just
prevent it from compiling at all). While not tested on architectures
other than x86, it *should* enable easy porting of the PCI frontend to
ia64 and other architectures that Xen will support. I believe this
method also demonstrates that by leveraging the PCI backend, a driver
domain does not have to be concerned with as many architecture-specific
details regarding the PCI bus and devices. It's not yet clear to me
which method is best for the PCI frontend and I'd like to pick one or
the other so that there aren't two mutually-exclusive code paths to
maintain. Please let me know if you have problems with either method and
if you have any suggestions/comments on the merits of each approach.

If you have problems, there is a compile-time debug option that enables
some extra logging that may be useful in tracking down the problem.
There is also a run-time module parameter ("verbose_request") in the
frontend and backend that will output each configuration space request
that is sent/received across the shared page.

Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>

[-- Attachment #2: pci-ddi.patch --]
[-- Type: text/x-patch, Size: 81595 bytes --]

diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/Kconfig
--- a/linux-2.6-xen-sparse/arch/xen/Kconfig	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/Kconfig	Fri Jan 27 18:57:35 2006
@@ -38,6 +38,85 @@
 	  (e.g., hard drives, network cards). This allows you to configure
 	  such devices and also includes some low-level support that is
 	  otherwise not compiled into the kernel.
+
+config XEN_PCIDEV_BACKEND
+	bool "PCI device backend driver"
+	depends on XEN_PHYSDEV_ACCESS
+	select PCI
+	default y if XEN_PRIVILEGED_GUEST
+	help
+	  The PCI device backend driver allows the kernel to export arbitrary
+	  PCI devices to other guests.
+
+choice
+	prompt "PCI Backend Mode"
+	depends on XEN_PCIDEV_BACKEND
+	default XEN_PCIDEV_BACKEND_VPCI
+
+config XEN_PCIDEV_BACKEND_VPCI
+	bool "Virtual PCI"
+	---help---
+	  This PCI Backend hides the true PCI topology and makes the frontend
+	  think there is a single PCI bus with only the exported devices on it.
+	  For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
+	  second device at 02:1a.0 will be re-assigned to 00:01.0.
+
+config XEN_PCIDEV_BACKEND_PASS
+	bool "Passthrough"
+	---help---
+	  This PCI Backend provides a real view of the PCI topology to the
+	  frontend (for example, a device at 06:01.b will still appear at
+	  06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
+	  PCI devices to its driver domains. This may be required for drivers
+	  which depend on finding their hardward in certain bus/slot
+	  locations.
+
+endchoice
+
+config XEN_PCIDEV_BE_DEBUG
+	bool "PCI Backend Debugging"
+	depends on XEN_PCIDEV_BACKEND
+	default n
+
+# This won't work in 2.6.12 due to what appears to be a kernel bug (related
+# to reading the resources of transparent bridges in pci_read_bridge_bases).
+# This bug appears to be fixed in 2.6.13:
+# http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=90b54929b626c80056262d9d99b3f48522e404d0
+#config XEN_PCIDEV_BACKEND_ALLOC
+#	bool "Re-allocate PCI Resources (DANGEROUS)"
+#	depends on XEN_PCIDEV_BACKEND
+#	default n
+#	---help---
+#	  This forces the PCI Backend to try and re-allocate all of the resources
+#	  on the PCI bus in an attempt to ensure that they fall entirely within
+#	  boundaries that Xen can control.
+
+config XEN_PCIDEV_FRONTEND
+	bool "PCI device frontend driver"
+	depends on XEN_PHYSDEV_ACCESS
+	select PCI
+	default y if !XEN_PRIVILEGED_GUEST
+	help
+	  The PCI device frontend driver allows the kernel to import arbitrary
+	  PCI devices from a PCI backend.
+
+config XEN_PCIDEV_FE_DEBUG
+	bool "PCI Frontend Debugging"
+	depends on XEN_PCIDEV_FRONTEND
+	default n
+
+config XEN_PCI_FE_ARCH_REPLACE
+	bool "PCI frontend driver - arch-independent (EXPERIMENTAL)"
+	depends on XEN_PCIDEV_FRONTEND && EXPERIMENTAL
+	default n
+	help
+	  This selects an implementation of the PCI frontend driver that is
+	  architecture independent (i.e. it replaces the real architecture's
+	  PCI code). The default is to use an implementation that works with
+	  the architecture dependent PCI code (and you probably want the
+	  default).
+
+	  If unsure, say N.
 
 config XEN_BLKDEV_BACKEND
 	bool "Block-device backend driver"
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/i386/Kconfig
--- a/linux-2.6-xen-sparse/arch/xen/i386/Kconfig	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/Kconfig	Fri Jan 27 18:57:35 2006
@@ -788,9 +788,17 @@
 	  information about which PCI hardware does work under Linux and which
 	  doesn't.
 
+# need to enable this on other platforms to support XEN_PCI_FE_ARCH_REPLACE
+config PCI_NATIVE
+	bool
+	depends on PCI
+	default y if !XEN_PCI_FE_ARCH_REPLACE
+    ---help---
+	  Compile in Native PCI access (as opposed to Xen's PCI Frontend).
+
 choice
 	prompt "PCI access mode"
-	depends on PCI && !X86_VISWS
+	depends on PCI_NATIVE && !X86_VISWS
 	default PCI_GOANY
 	---help---
 	  On PCI systems, the BIOS can be used to detect the PCI devices and
@@ -810,6 +818,15 @@
 #config PCI_GOBIOS
 #	bool "BIOS"
 
+config PCI_GOXEN_PCI_FE_STUB
+	bool "Xen PCI Frontend Stub"
+	depends on XEN_PCIDEV_FRONTEND
+	---help---
+	  The Xen PCI Frontend stub replaces the architecture's means of talking
+	  directly to the PCI host bridge with a "dummy" handler which will act
+	  as somewhat of a placeholder until the real Xen PCI Frontend is
+	  initialized.
+
 config PCI_GOMMCONFIG
 	bool "MMConfig"
 
@@ -835,6 +852,11 @@
 	bool
 	depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
 	select ACPI_BOOT
+	default y
+
+config XEN_PCI_FE_STUB
+	bool
+	depends on PCI && XEN_PCIDEV_FRONTEND && !XEN_PCI_FE_ARCH_REPLACE && (PCI_GOXEN_PCI_FE_STUB || PCI_GOANY)
 	default y
 
 source "drivers/pci/pcie/Kconfig"
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/i386/Makefile
--- a/linux-2.6-xen-sparse/arch/xen/i386/Makefile	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/Makefile	Fri Jan 27 18:57:35 2006
@@ -82,7 +82,7 @@
 # \
 #					   arch/xen/$(mcore-y)/
 drivers-$(CONFIG_MATH_EMULATION)	+= arch/i386/math-emu/
-drivers-$(CONFIG_PCI)			+= arch/xen/i386/pci/
+drivers-$(CONFIG_PCI_NATIVE)		+= arch/xen/i386/pci/
 # must be linked after kernel/
 drivers-$(CONFIG_OPROFILE)		+= arch/i386/oprofile/
 drivers-$(CONFIG_PM)			+= arch/i386/power/
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile
--- a/linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile	Fri Jan 27 18:57:35 2006
@@ -7,6 +7,7 @@
 #c-obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
 c-obj-$(CONFIG_PCI_MMCONFIG)	+= mmconfig.o
 c-obj-$(CONFIG_PCI_DIRECT)	+= direct.o
+c-obj-$(CONFIG_XEN_PCI_FE_STUB) += pcifront.o
 
 c-pci-y				:= fixup.o
 c-pci-$(CONFIG_ACPI_PCI)	+= acpi.o
@@ -30,4 +31,6 @@
 # Make sure irq.o gets linked in before common.o
 obj-y	+= $(patsubst common.o,$(l-pci-y) common.o,$(c-obj-y))
 
+obj-$(CONFIG_XEN_PCIDEV_BACKEND_ALLOC) += alloc.o
+
 clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-) $(c-link))
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c
--- a/linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c	Fri Jan 27 18:57:35 2006
@@ -58,6 +58,13 @@
 			res->start = start;
 		}
 	}
+#ifdef CONFIG_XEN_PCIDEV_BACKEND_ALLOC
+	/* Ensure i/o memory is allocated on page boundaries */
+	else if (res->flags & IORESOURCE_MEM) {
+		unsigned long alignto = max(align,PAGE_SIZE);
+		res->start = ALIGN(res->start,alignto);
+	}
+#endif
 }
 
 
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Fri Jan 27 18:57:35 2006
@@ -16,4 +16,6 @@
 obj-$(CONFIG_XEN_NETDEV_FRONTEND)	+= netfront/
 obj-$(CONFIG_XEN_BLKDEV_TAP)    	+= blktap/
 obj-$(CONFIG_XEN_TPMDEV_FRONTEND)	+= tpmfront/
+obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= pciback/
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront/
 
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h
--- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h	Fri Jan 27 18:57:35 2006
@@ -124,6 +124,10 @@
 
 #endif /* __KERNEL__ */
 
+#ifdef CONFIG_XEN_PCIDEV_FRONTEND
+#include <asm-xen/pcifront.h>
+#endif /* CONFIG_XEN_PCIDEV_FRONTEND */
+
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
 #include <asm-generic/pci-dma-compat.h>
 
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/i386/pci/alloc.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/alloc.c	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,16 @@
+/*
+ * PCI Backend - Try to force a re-assignment of resources so that all
+ *               memory resources are allocated on page boundaries
+ */
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+
+static __init int pciback_alloc(void)
+{
+	printk(KERN_INFO "pciback: Attempt to re-allocate PCI resources\n");
+	pci_assign_unassigned_resources();
+	return 0;
+}
+
+subsys_initcall(pciback_alloc);
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/i386/pci/pcifront.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/pcifront.c	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,48 @@
+/*
+ * PCI Frontend Stub - puts some "dummy" functions in to the Linux x86 PCI core
+ *                     to support the Xen PCI Frontend's operation
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include "pci.h"
+
+static int pcifront_enable_irq(struct pci_dev *dev)
+{
+	u8 irq;
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	dev->irq = irq;
+
+	return 0;
+}
+
+extern u8 pci_cache_line_size;
+
+static int __init pcifront_x86_stub_init(void)
+{
+	struct cpuinfo_x86 *c = &boot_cpu_data;
+
+	/* Only install our method if we haven't found real hardware already */
+	if (raw_pci_ops)
+		return 0;
+
+	printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
+
+	/* Copied from arch/i386/pci/common.c */
+	pci_cache_line_size = 32 >> 2;
+	if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
+		pci_cache_line_size = 64 >> 2;	/* K7 & K8 */
+	else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL)
+		pci_cache_line_size = 128 >> 2;	/* P4 */
+
+	/* On x86, we need to disable the normal IRQ routing table and
+	 * just ask the backend
+	 */
+	pcibios_enable_irq = pcifront_enable_irq;
+
+	return 0;
+}
+
+arch_initcall(pcifront_x86_stub_init);
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/Makefile
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,11 @@
+obj-y += pciback.o
+
+pciback-y := pci_stub.o pciback_ops.o xenbus.o
+pciback-y += conf_space.o conf_space_header.o
+pciback-${CONFIG_XEN_PCIDEV_BACKEND_VPCI} += vpci.o
+pciback-${CONFIG_XEN_PCIDEV_BACKEND_PASS} += passthrough.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
+CFLAGS_pci_stub.o += -DDEBUG
+CFLAGS_xenbus.o += -DDEBUG
+endif
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,315 @@
+/*
+ * PCI Backend - Functions for creating a virtual configuration space for
+ *               exported PCI Devices.
+ *               It's dangerous to allow PCI Driver Domains to change their
+ *               device's resources (memory, i/o ports, interrupts). We need to
+ *               restrict changes to certain PCI Configuration registers:
+ *               BARs, INTERRUPT_PIN, most registers in the header...
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+
+#define DEFINE_PCI_CONFIG(op,size,type) 					\
+int pciback_##op##_config_##size 							\
+(struct pci_dev *dev, int offset, type value, void *data)	\
+{															\
+	return pci_##op##_config_##size (dev, offset, value);	\
+}
+
+DEFINE_PCI_CONFIG(read, byte, u8 *)
+DEFINE_PCI_CONFIG(read, word, u16 *)
+DEFINE_PCI_CONFIG(read, dword, u32 *)
+
+DEFINE_PCI_CONFIG(write, byte, u8)
+DEFINE_PCI_CONFIG(write, word, u16)
+DEFINE_PCI_CONFIG(write, dword, u32)
+
+static int conf_space_read(struct pci_dev *dev,
+		struct config_field_entry *entry, int offset, u32 *value)
+{
+	int ret = 0;
+	struct config_field *field = entry->field;
+
+	*value = 0;
+
+	switch (field->size) {
+		case 1:
+			if (field->u.b.read)
+				ret = field->u.b.read(dev, offset, (u8*)value, entry->data);
+			break;
+		case 2:
+			if (field->u.w.read)
+				ret = field->u.w.read(dev, offset, (u16*)value, entry->data);
+			break;
+		case 4:
+			if (field->u.dw.read)
+				ret = field->u.dw.read(dev, offset, value, entry->data);
+			break;
+	}
+	return ret;
+}
+
+static int conf_space_write(struct pci_dev *dev,
+		struct config_field_entry *entry, int offset, u32 value)
+{
+	int ret = 0;
+	struct config_field *field = entry->field;
+
+	switch (field->size) {
+		case 1:
+			if (field->u.b.write)
+				ret = field->u.b.write(dev, offset, (u8)value, entry->data);
+			break;
+		case 2:
+			if (field->u.w.write)
+				ret = field->u.w.write(dev, offset, (u16)value, entry->data);
+			break;
+		case 4:
+			if (field->u.dw.write)
+				ret = field->u.dw.write(dev, offset, value, entry->data);
+			break;
+	}
+	return ret;
+}
+
+static inline u32 get_mask(int size)
+{
+	if (size==1)
+		return 0xff;
+	else if (size==2)
+		return 0xffff;
+	else
+		return 0xffffffff;
+}
+
+static inline int valid_request(int offset, int size)
+{
+	/* Validate request (no un-aligned requests) */
+	if ((size==1 || size==2 || size==4) && (offset%size)==0)
+		return 1;
+	return 0;
+}
+
+static inline u32 merge_value( u32 val, u32 new_val, u32 new_val_mask,
+		u32 offset)
+{
+	if (offset>=0) {
+		new_val_mask <<= (offset*8);
+		new_val <<= (offset*8);
+	}
+	else {
+		new_val_mask >>= (offset*-8);
+		new_val >>= (offset*-8);
+	}
+	val = (val&~new_val_mask)|(new_val&new_val_mask);
+
+	return val;
+}
+
+static int pcibios_err_to_errno(int err)
+{
+	switch (err) {
+		case PCIBIOS_SUCCESSFUL:
+			return XEN_PCI_ERR_success;
+		case PCIBIOS_DEVICE_NOT_FOUND:
+			return XEN_PCI_ERR_dev_not_found;
+		case PCIBIOS_BAD_REGISTER_NUMBER:
+			return XEN_PCI_ERR_invalid_offset;
+		case PCIBIOS_FUNC_NOT_SUPPORTED:
+			return XEN_PCI_ERR_not_implemented;
+		case PCIBIOS_SET_FAILED:
+			return XEN_PCI_ERR_access_denied;
+	}
+	return err;
+}
+
+int pciback_config_read(struct pci_dev *dev, int offset, int size, u32 *ret_val)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+	int req_start, req_end, field_start, field_end;
+	/* if read fails for any reason, return 0 (as if device didn't respond) */
+	u32 value = 0, tmp_val;
+
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n",
+				pci_name(dev), size, offset);
+
+	if (!valid_request(offset, size)) {
+		err = XEN_PCI_ERR_invalid_offset;
+		goto out;
+	}
+
+	/* Get the real value first, then modify as appropriate */
+	switch (size) {
+		case 1:
+			err = pci_read_config_byte(dev,offset, (u8*)&value);
+			break;
+		case 2:
+			err = pci_read_config_word(dev,offset, (u16*)&value);
+			break;
+		case 4:
+			err = pci_read_config_dword(dev,offset, &value);
+			break;
+	}
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		req_start = offset;
+		req_end = offset+size;
+		field_start = field->offset;
+		field_end = field->offset + field->size;
+
+		if ((req_start>=field_start && req_start<field_end)
+				|| (req_end>field_start && req_end<=field_end)) {
+			err = conf_space_read(dev, cfg_entry, offset, &tmp_val);
+			if (err)
+				goto out;
+
+			value = merge_value(value, tmp_val, get_mask(field->size),
+					field_start - req_start);
+		}
+	}
+
+out:
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
+				pci_name(dev), size, offset, value);
+
+	*ret_val = value;
+	return pcibios_err_to_errno(err);
+}
+
+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+	u32 tmp_val;
+	int req_start, req_end, field_start, field_end;
+
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG "pciback: %s: write request %d bytes at 0x%x = %x\n",
+				pci_name(dev), size, offset, value);
+
+	if (!valid_request(offset, size))
+		return XEN_PCI_ERR_invalid_offset;
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		req_start = offset;
+		req_end = offset+size;
+		field_start = field->offset;
+		field_end = field->offset + field->size;
+
+		if ((req_start>=field_start && req_start<field_end)
+				|| (req_end>field_start && req_end<=field_end)) {
+			tmp_val = 0;
+
+			err = pciback_config_read(dev, offset, size, &tmp_val);
+			if (err)
+				break;
+
+			tmp_val = merge_value(tmp_val, value, get_mask(size),
+					field_start - req_start);
+
+			err = conf_space_write(dev, cfg_entry, offset, tmp_val);
+		}
+	}
+
+	return pcibios_err_to_errno(err);
+}
+
+void pciback_config_reset(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		if (field->reset)
+			field->reset(dev, field->offset, cfg_entry->data);
+	}
+}
+
+void pciback_config_free(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry, *t;
+	struct config_field *field;
+
+	list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
+		list_del(&cfg_entry->list);
+
+		field = cfg_entry->field;
+
+		if (field->release)
+			field->release(dev, field->offset, cfg_entry->data);
+
+		kfree(cfg_entry);
+	}
+}
+
+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	void *tmp;
+   
+	cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
+	if (!cfg_entry) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	cfg_entry->data  = NULL;
+	cfg_entry->field = field;
+
+	if (field->init) {
+		tmp = field->init(dev, field->offset);
+
+		if (IS_ERR(tmp)) {
+			err = PTR_ERR(tmp);
+			goto out;
+		}
+
+		cfg_entry->data = tmp;
+	}
+
+	list_add_tail(&cfg_entry->list, &dev_data->config_fields);
+
+out:
+	if (err)
+		kfree(cfg_entry);
+
+	return err;
+}
+
+/* This sets up the device's virtual configuration space to keep track of 
+ * certain registers (like the base address registers (BARs) so that we can
+ * keep the client from manipulating them directly.
+ */
+int pciback_config_init(struct pci_dev *dev)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+
+	INIT_LIST_HEAD(&dev_data->config_fields);
+
+	err = pciback_config_header_add_fields(dev);
+
+	return err;
+}
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,97 @@
+/*
+ * PCI Backend - Common data structures for overriding the configuration space
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#ifndef __XEN_PCIBACK_CONF_SPACE_H__
+#define __XEN_PCIBACK_CONF_SPACE_H__
+
+#include <linux/list.h>
+
+typedef void *(*conf_field_init)(struct pci_dev *dev, int offset);
+typedef void (*conf_field_reset)(struct pci_dev *dev, int offset, void *data);
+typedef void (*conf_field_free)(struct pci_dev *dev, int offset, void *data);
+
+typedef int (*conf_dword_write)(struct pci_dev *dev, int offset, u32 value,
+		void *data);
+typedef int (*conf_word_write)(struct pci_dev *dev, int offset, u16 value,
+		void *data);
+typedef int (*conf_byte_write)(struct pci_dev *dev, int offset, u8 value,
+		void *data);
+typedef int (*conf_dword_read)(struct pci_dev *dev, int offset, u32 *value,
+		void *data);
+typedef int (*conf_word_read)(struct pci_dev *dev, int offset, u16 *value,
+		void *data);
+typedef int (*conf_byte_read)(struct pci_dev *dev, int offset, u8 *value,
+		void *data);
+
+/* These are the fields within the configuration space which we
+ * are interested in intercepting reads/writes to and changing their
+ * values.
+ */
+struct config_field {
+	unsigned int     offset;
+	unsigned int     size;
+	conf_field_init  init;
+	conf_field_reset reset;
+	conf_field_free  release;
+	union {
+		struct {
+			conf_dword_write write;
+			conf_dword_read  read;
+		} dw;
+		struct {
+			conf_word_write write;
+			conf_word_read  read;
+		} w;
+		struct {
+			conf_byte_write write;
+			conf_byte_read  read;
+		} b;
+	} u;
+};
+
+struct config_field_entry {
+	struct list_head      list;
+	struct config_field  *field;
+	void                 *data;
+};
+
+/* Add fields to a device - the add_fields macro expects to get a pointer to
+ * the first entry in an array (of which the ending is marked by size==0)
+ */
+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field);
+static inline int pciback_config_add_fields(struct pci_dev *dev,
+		struct config_field *field)
+{
+	int i, err = 0;
+	for (i=0; field[i].size!=0; i++) {
+		err = pciback_config_add_field(dev, &field[i]);
+		if (err)
+			break;
+	}
+	return err;
+}
+
+/* Initializers which add fields to the virtual configuration space
+ * ** We could add initializers to allow a guest domain to touch
+ * the capability lists (for power management, the AGP bridge, etc.)
+ */
+int pciback_config_header_add_fields(struct pci_dev *dev);
+
+/* Read/Write the real configuration space */
+int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 *value,
+		void *data);
+int pciback_read_config_word(struct pci_dev *dev, int offset, u16 *value,
+		void *data);
+int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 *value,
+		void *data);
+int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
+		void *data);
+int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value,
+		void *data);
+int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
+		void *data);
+
+#endif /* __XEN_PCIBACK_CONF_SPACE_H__ */
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,324 @@
+/*
+ * PCI Backend - Handles the virtual fields in the configuration space headers.
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+
+struct pci_bar_info {
+	u32 val;
+	u32 len_val;
+	int which;
+};
+
+#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
+#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
+
+static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
+{
+	if (!dev->is_enabled && is_enable_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: enable\n",
+					pci_name(dev));
+		dev->is_enabled = 1;
+		pcibios_enable_device(dev, (1<<PCI_NUM_RESOURCES)-1);
+	}
+	else if (dev->is_enabled && !is_enable_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: disable\n",
+					pci_name(dev));
+		pciback_disable_device(dev);
+	}
+
+	if (!dev->is_busmaster && is_master_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: set bus master\n",
+					pci_name(dev));
+		dev->is_busmaster = 1;
+		pcibios_set_master(dev);
+	}
+
+	if (value & PCI_COMMAND_INVALIDATE) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: enable memory-write-invalidate\n",
+					pci_name(dev));
+		pci_set_mwi(dev);
+	}
+
+	return pci_write_config_word(dev, offset, value);
+}
+
+static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
+{
+	struct pci_bar_info *bar = data;
+	int i;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+				pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	bar->which = 0;
+	/* Because writes *could* occur in bytes, if any byte is all 1s, switch */
+	for (i=0; i<4; i++)
+		if (((value>>(i*8))&0xff)==0xff)
+			bar->which = 1;
+
+	/* Do we need to support enabling/disabling the rom address here? */
+
+	return 0;
+}
+
+/* For the BARs, only allow writes which write ~0 or
+ * the correct resource information
+ * (Needed for when the driver probes the resource usage)
+ */
+static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
+{
+	int i;
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+				pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	bar->which = 0;
+	/* Because writes *could* occur in bytes, if any byte is all 1s, switch */
+	for (i=0; i<4; i++)
+		if (((value>>(i*8))&0xff)==0xff)
+			bar->which = 1;
+
+	return 0;
+}
+
+static int bar_read(struct pci_dev *dev, int offset, u32 *value, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+				pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	*value = bar->which ? bar->len_val : bar->val;
+
+	return 0;
+}
+
+static inline void read_dev_bar(struct pci_dev *dev, struct pci_bar_info *bar_info,
+		int offset, u32 len_mask)
+{
+	pci_read_config_dword(dev, offset, &bar_info->val);
+	pci_write_config_dword(dev, offset, len_mask);
+	pci_read_config_dword(dev, offset, &bar_info->len_val);
+	pci_write_config_dword(dev, offset, bar_info->val);
+}
+
+static void *bar_init(struct pci_dev *dev, int offset)
+{
+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
+
+	if (!bar)
+		return ERR_PTR(-ENOMEM);
+
+	read_dev_bar(dev, bar, offset, ~0);
+	bar->which = 0;
+
+	return bar;
+}
+
+static void *rom_init(struct pci_dev *dev, int offset)
+{
+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
+
+	if (!bar)
+		return ERR_PTR(-ENOMEM);
+
+	read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
+	bar->which = 0;
+
+	return bar;
+}
+
+static void bar_reset(struct pci_dev *dev, int offset, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	bar->which = 0;
+}
+
+static void bar_release(struct pci_dev *dev, int offset, void *data)
+{
+	kfree(data);
+}
+
+static int interrupt_read(struct pci_dev *dev, int offset, u8 *value,
+		void *data)
+{
+	*value = (u8)dev->irq;
+
+	return 0;
+}
+
+struct config_field header_common[] = {
+	{
+		.offset     = PCI_COMMAND,
+		.size       = 2,
+		.u.w.read   = pciback_read_config_word,
+		.u.w.write  = command_write,
+	},
+	{
+		.offset     = PCI_INTERRUPT_LINE,
+		.size       = 1,
+		.u.b.read   = interrupt_read,
+		.u.b.write  = NULL,
+	},
+	{
+		/* Any side effects of letting driver domain control cache line? */
+		.offset     = PCI_CACHE_LINE_SIZE,
+		.size       = 1,
+		.u.b.read   = pciback_read_config_byte,
+		.u.b.write  = pciback_write_config_byte,
+	},
+	{
+		.size           = 0,
+	},
+};
+
+struct config_field header_0[] = {
+	{
+		.offset     = PCI_BASE_ADDRESS_0,
+		.size       = 4,
+		.init       = bar_init,
+		.reset      = bar_reset,
+		.release    = bar_release,
+		.u.dw.read  = bar_read,
+		.u.dw.write = bar_write,
+	},
+	{
+		.offset     = PCI_BASE_ADDRESS_1,
+		.size       = 4,
+		.init       = bar_init,
+		.reset      = bar_reset,
+		.release    = bar_release,
+		.u.dw.read  = bar_read,
+		.u.dw.write = bar_write,
+	},
+	{
+		.offset     = PCI_BASE_ADDRESS_2,
+		.size       = 4,
+		.init       = bar_init,
+		.reset      = bar_reset,
+		.release    = bar_release,
+		.u.dw.read  = bar_read,
+		.u.dw.write = bar_write,
+	},
+	{
+		.offset     = PCI_BASE_ADDRESS_3,
+		.size       = 4,
+		.init       = bar_init,
+		.reset      = bar_reset,
+		.release    = bar_release,
+		.u.dw.read  = bar_read,
+		.u.dw.write = bar_write,
+	},
+	{
+		.offset     = PCI_BASE_ADDRESS_4,
+		.size       = 4,
+		.init       = bar_init,
+		.reset      = bar_reset,
+		.release    = bar_release,
+		.u.dw.read  = bar_read,
+		.u.dw.write = bar_write,
+	},
+	{
+		.offset     = PCI_BASE_ADDRESS_5,
+		.size       = 4,
+		.init       = bar_init,
+		.reset      = bar_reset,
+		.release    = bar_release,
+		.u.dw.read  = bar_read,
+		.u.dw.write = bar_write,
+	},
+	{
+		.offset     = PCI_ROM_ADDRESS,
+		.size       = 4,
+		.init       = rom_init,
+		.reset      = bar_reset,
+		.release    = bar_release,
+		.u.dw.read  = bar_read,
+		.u.dw.write = rom_write,
+	},
+	{
+		.size       = 0,
+	},
+};
+
+struct config_field header_1[] = {
+	{
+		.offset     = PCI_BASE_ADDRESS_0,
+		.size       = 4,
+		.init       = bar_init,
+		.reset      = bar_reset,
+		.release    = bar_release,
+		.u.dw.read  = bar_read,
+		.u.dw.write = bar_write,
+	},
+	{
+		.offset     = PCI_BASE_ADDRESS_1,
+		.size       = 4,
+		.init       = bar_init,
+		.reset      = bar_reset,
+		.release    = bar_release,
+		.u.dw.read  = bar_read,
+		.u.dw.write = bar_write,
+	},
+	{
+		.offset     = PCI_ROM_ADDRESS1,
+		.size       = 4,
+		.init       = rom_init,
+		.reset      = bar_reset,
+		.release    = bar_release,
+		.u.dw.read  = bar_read,
+		.u.dw.write = rom_write,
+	},
+	{
+		.size           = 0,
+	},
+};
+
+int pciback_config_header_add_fields(struct pci_dev *dev)
+{
+	int err;
+
+	err = pciback_config_add_fields(dev, header_common);
+	if (err)
+		goto out;
+
+	switch (dev->hdr_type) {
+		case PCI_HEADER_TYPE_NORMAL:
+			err = pciback_config_add_fields(dev, header_0);
+			break;
+
+		case PCI_HEADER_TYPE_BRIDGE:
+			err = pciback_config_add_fields(dev, header_1);
+			break;
+
+		default:
+			err = -EINVAL;
+			printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
+					pci_name(dev), dev->hdr_type);
+			break;
+	}
+
+out:
+	return err;
+}
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,112 @@
+/*
+ * PCI Backend - Provides restricted access to the real PCI bus topology
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/list.h>
+#include <linux/pci.h>
+#include "pciback.h"
+
+typedef struct {
+	struct list_head dev_list;
+} passthrough_dev_data_t;
+
+struct pci_dev * pciback_get_pci_dev(struct pciback_device *pdev,
+		unsigned int domain, unsigned int bus, unsigned int devfn)
+{
+	passthrough_dev_data_t *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry;
+
+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
+		if (domain==(unsigned int)pci_domain_nr(dev_entry->dev->bus)
+				&& bus==(unsigned int)dev_entry->dev->bus->number
+				&& devfn==dev_entry->dev->devfn)
+			return dev_entry->dev;
+	}
+		
+	return NULL;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+	passthrough_dev_data_t *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry;
+
+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
+	if (!dev_entry)
+		return -ENOMEM;
+	dev_entry->dev = dev;
+
+	list_add_tail(&dev_entry->list, &dev_data->dev_list);
+
+	return 0;
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+	passthrough_dev_data_t *dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
+	if (!dev_data)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&dev_data->dev_list);
+
+	pdev->pci_dev_data = dev_data;
+
+	return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+		publish_pci_root_cb publish_root_cb)
+{
+	int err = 0;
+	passthrough_dev_data_t *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry, *e;
+	struct pci_dev *dev;
+	int found;
+
+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
+
+		/* Only publish this device as a root if none of its parent bridges
+		 * are exported
+		 */
+		found = 0;
+		dev = dev_entry->dev->bus->self;
+		for (; !found && dev!=NULL; dev=dev->bus->self) {
+			list_for_each_entry(e, &dev_data->dev_list, list) {
+				if (dev==e->dev) {
+					found = 1;
+					break;
+				}
+			}
+		}
+
+		if (!found) {
+			err = publish_root_cb(pdev,
+					(unsigned int)pci_domain_nr(dev_entry->dev->bus),
+				(unsigned int)dev_entry->dev->bus->number);
+			if (err)
+				break;
+		}
+	}
+
+	return err;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+	passthrough_dev_data_t *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry, *t;
+
+	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
+		list_del(&dev_entry->list);
+		pcistub_put_pci_dev(dev_entry->dev);
+		kfree(dev_entry);
+	}
+
+	kfree(dev_data);
+	pdev->pci_dev_data = NULL;
+}
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,368 @@
+/*
+ * PCI Stub Driver - Grabs devices in backend to be exported later
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include "pciback.h"
+
+static char * pci_devs_to_hide = NULL;
+module_param_named(hide,pci_devs_to_hide,charp,0444);
+
+struct pci_stub_device_id {
+	struct list_head slot_list;
+	int domain;
+	unsigned char bus;
+	unsigned int devfn;
+};
+LIST_HEAD(pci_stub_device_ids);
+
+struct pci_stub_device {
+	struct list_head dev_list;
+	struct pci_dev *dev;
+	atomic_t in_use;
+};
+/* Access to pci_stub_devices & seized_devices lists and the initialize_devices
+ * flag must be locked with pci_stub_devices_lock
+ */
+DEFINE_SPINLOCK(pci_stub_devices_lock);
+LIST_HEAD(pci_stub_devices);
+
+/* wait for device_initcall before initializing our devices
+ * (see pcistub_init_devices_late)
+ */
+static int initialize_devices = 0;
+LIST_HEAD(seized_devices);
+
+static inline struct pci_dev * get_pci_dev(struct pci_stub_device *psdev)
+{
+	if (atomic_dec_and_test(&psdev->in_use))
+		return psdev->dev;
+	else {
+		atomic_inc(&psdev->in_use);
+		return NULL;
+	}
+}
+
+struct pci_dev * pcistub_get_pci_dev_by_slot(int domain, int bus,
+		int slot, int func)
+{
+	struct pci_stub_device *psdev;
+	struct pci_dev *found_dev = NULL;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if( psdev->dev!=NULL
+				&& domain==pci_domain_nr(psdev->dev->bus)
+				&& bus==psdev->dev->bus->number
+				&& PCI_DEVFN(slot,func)==psdev->dev->devfn ) {
+			found_dev = get_pci_dev(psdev);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+	return found_dev;
+}
+
+struct pci_dev * pcistub_get_pci_dev(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+	struct pci_dev *found_dev = NULL;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if( psdev->dev==dev ) {
+			found_dev = get_pci_dev(psdev);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+	return found_dev;
+}
+
+void pcistub_put_pci_dev(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if( psdev->dev==dev ) {
+			/* Cleanup our device (so it's ready for the next domain) */
+			pciback_reset_device(psdev->dev);
+
+			atomic_inc(&psdev->in_use);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+}
+
+static int __devinit pcistub_match(struct pci_dev *dev,
+		struct pci_stub_device_id *pdev_id)
+{
+	/* Match the specified device by domain, bus, slot, func and also if
+	 * any of the device's parent bridges match.
+	 */
+	for(; dev!=NULL; dev=dev->bus->self) {
+		if (pci_domain_nr(dev->bus)==pdev_id->domain
+					&& dev->bus->number==pdev_id->bus
+					&& dev->devfn==pdev_id->devfn)
+			return 1;
+	}
+
+	return 0;
+}
+
+static int __devinit pcistub_init_device(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data;
+	int err = 0;
+
+	/* The PCI backend is not intended to be a module (or to work with
+	 * removable PCI devices (yet). If it were, pciback_config_free()
+	 * would need to be called somewhere to free the memory allocated
+	 * here and then to call kfree(pci_get_drvdata(psdev->dev)).
+	 */
+	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
+	if (!dev_data) {
+		err = -ENOMEM;
+		goto out;
+	}
+	pci_set_drvdata(dev, dev_data);
+
+	err = pciback_config_init(dev);
+	if (err)
+		goto out;
+
+	/* HACK: Force device (& ACPI) to determine what IRQ it's on - we
+	 * must do this here because pcibios_enable_device may specify
+	 * the pci device's true irq (and possibly its other resources)
+	 * if they differ from what's in the configuration space.
+	 * This makes the assumption that the device's resources won't
+	 * change after this point (otherwise this code may break!)
+	 */
+	err = pci_enable_device(dev);
+	if (err)
+		goto config_release;
+
+	/* Now disable the device (this also ensures some private device
+	 * data is setup before we export)
+	 * This calls pciback_config_reset(dev)
+	 */
+	pciback_reset_device(dev);
+
+	return 0;
+
+config_release:
+	pciback_config_free(dev);
+
+out:
+	pci_set_drvdata(dev, NULL);
+	kfree(dev_data);
+	return err;
+}
+
+/*
+ * Because some initialization still happens on
+ * devices during fs_initcall, we need to defer
+ * full initialization of our devices until
+ * device_initcall.
+ */
+static int __init pcistub_init_devices_late(void)
+{
+	struct pci_stub_device *psdev, *t;
+	int err = 0;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry_safe(psdev, t, &seized_devices, dev_list) {
+		list_del(&psdev->dev_list);
+		err = pcistub_init_device(psdev->dev);
+		if (err) {
+			printk(KERN_ERR "pciback: error %d initializing device %s\n",
+					err, pci_name(psdev->dev));
+			kfree(psdev);
+			continue;
+		}
+
+		list_add_tail(&psdev->dev_list, &pci_stub_devices);
+	}
+
+	initialize_devices = 1;
+
+	spin_unlock(&pci_stub_devices_lock);
+
+	return 0;
+}
+device_initcall(pcistub_init_devices_late);
+
+static int __devinit pcistub_seize(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+	int err = 0;
+
+	psdev = kmalloc(sizeof(*psdev), GFP_KERNEL);
+	if (!psdev)
+		return -ENOMEM;
+
+	psdev->dev = dev;
+	atomic_set(&psdev->in_use,1);
+
+	spin_lock(&pci_stub_devices_lock);
+
+	if (initialize_devices) {
+		err = pcistub_init_device(psdev->dev);
+		if (err)
+			goto out;
+
+		list_add(&psdev->dev_list, &pci_stub_devices);
+	}
+	else
+		list_add(&psdev->dev_list, &seized_devices);
+
+out:
+	spin_unlock(&pci_stub_devices_lock);
+
+	if (err)
+		kfree(psdev);
+
+	return err;
+}
+
+static int __devinit pcistub_probe(struct pci_dev *dev,
+		const struct pci_device_id *id)
+{
+	struct pci_stub_device_id *pdev_id;
+	struct pci_dev *seized_dev;
+	int err = 0;
+
+	list_for_each_entry(pdev_id, &pci_stub_device_ids, slot_list) {
+
+		if (!pcistub_match(dev, pdev_id))
+			continue;
+
+		if (dev->hdr_type!=PCI_HEADER_TYPE_NORMAL
+				&& dev->hdr_type!=PCI_HEADER_TYPE_BRIDGE) {
+			printk(KERN_ERR "pciback: can't export pci devices that don't "
+					"have a normal (0) or bridge (1) header type! dev=%s\n",
+					pci_name(dev));
+			break;
+		}
+
+		pr_info("pciback: seizing PCI device %s\n", pci_name(dev));
+		seized_dev = pci_dev_get(dev);
+
+		if (seized_dev) {
+			err = pcistub_seize(seized_dev);
+			if (err) {
+				pci_dev_put(dev);
+				goto out;
+			}
+
+			/* Success! */
+			goto out;
+		}
+	}
+
+	/* Didn't find the device */
+	err = -ENODEV;
+
+out:
+	return err;
+}
+
+struct pci_device_id pcistub_ids[] = {
+	{ 
+		.vendor = PCI_ANY_ID,
+		.device = PCI_ANY_ID,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_ANY_ID,
+	},
+	{ 0, },
+};
+
+/*
+ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't
+ * for a normal device. I don't want it to be loaded automatically.
+ */
+
+struct pci_driver pciback_pci_driver = {
+	.name = "pciback",
+	.id_table = pcistub_ids,
+	.probe = pcistub_probe,
+};
+
+static int __init pcistub_init(void)
+{
+	int pos=0;
+	struct pci_stub_device_id *pci_dev_id;
+	int err = 0;
+	int domain, bus, slot, func;
+	int parsed;
+
+	if (pci_devs_to_hide && *pci_devs_to_hide) {
+		do {
+			parsed = 0;
+
+			err = sscanf(pci_devs_to_hide+pos," (%x:%x:%x.%x) %n",
+						&domain, &bus, &slot, &func, &parsed);
+			if (err!=4) {
+				domain = 0;
+				err = sscanf(pci_devs_to_hide+pos," (%x:%x.%x) %n",
+						&bus, &slot, &func, &parsed);
+				if (err!=3)
+					goto parse_error;
+			}
+
+			pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
+			if (!pci_dev_id) {
+				err = -ENOMEM;
+				goto out;
+			}
+			pci_dev_id->domain = domain;
+			pci_dev_id->bus = bus;
+			pci_dev_id->devfn = PCI_DEVFN(slot,func);
+
+			pr_debug("pciback: wants to seize %04x:%02x:%02x.%01x\n",
+					domain, bus, slot, func);
+
+			list_add_tail(&pci_dev_id->slot_list,&pci_stub_device_ids);
+
+			/* if parsed<=0, we've reached the end of the string */
+			pos+=parsed;
+		} while (parsed>0 && pci_devs_to_hide[pos]);
+
+		/* If we're the first PCI Device Driver to register, we're the
+		 * first one to get offered PCI devices as they become
+		 * available (and thus we can be the first to grab them)
+		 */
+		pci_register_driver(&pciback_pci_driver);
+	}
+
+out:
+	return err;
+
+parse_error:
+	printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n",
+			pci_devs_to_hide+pos);
+	return -EINVAL;
+}
+
+/*
+ * fs_initcall happens before device_initcall
+ * so pciback *should* get called first (b/c we 
+ * want to suck up any device before other drivers
+ * get a chance by being the first pci device
+ * driver to register)
+ */
+fs_initcall(pcistub_init);
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,72 @@
+/*
+ * PCI Backend Common Data Structures & Function Declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCIBACK_H__
+#define __XEN_PCIBACK_H__
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <asm-xen/xenbus.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm-xen/xen-public/io/pciif.h>
+
+struct pci_dev_entry {
+	struct list_head list;
+	struct pci_dev *dev;
+};
+
+struct pciback_device {
+	void *pci_dev_data;
+	spinlock_t dev_lock;
+
+	struct xenbus_device *xdev;
+
+	struct xenbus_watch be_watch;
+	u8 be_watching;
+
+	int evtchn_irq;
+
+	struct xen_pci_sharedinfo * sh_info;
+};
+
+struct pciback_dev_data {
+	struct list_head config_fields;
+};
+
+/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
+struct pci_dev * pcistub_get_pci_dev_by_slot(int domain, int bus,
+		int slot, int func);
+struct pci_dev * pcistub_get_pci_dev(struct pci_dev *dev);
+void pcistub_put_pci_dev(struct pci_dev *dev);
+
+/* Ensure a device is turned off or reset */
+void pciback_disable_device(struct pci_dev *dev);
+void pciback_reset_device(struct pci_dev *pdev);
+
+/* Access a virtual configuration space for a PCI device */
+int pciback_config_init(struct pci_dev *dev);
+void pciback_config_reset(struct pci_dev *dev);
+void pciback_config_free(struct pci_dev *dev);
+int pciback_config_read(struct pci_dev *dev, int offset, int size,
+		u32 *ret_val);
+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
+
+/* Handle requests for specific devices from the frontend */
+typedef int (*publish_pci_root_cb)(struct pciback_device *pdev,
+		unsigned int domain, unsigned int bus);
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
+struct pci_dev * pciback_get_pci_dev(struct pciback_device *pdev,
+		unsigned int domain, unsigned int bus, unsigned int devfn);
+int pciback_init_devices(struct pciback_device *pdev);
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+		publish_pci_root_cb cb);
+void pciback_release_devices(struct pciback_device *pdev);
+
+/* Handles events from front-end */
+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
+
+extern int verbose_request;
+#endif
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,84 @@
+/*
+ * PCI Backend Operations - respond to PCI requests from Frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <asm/bitops.h>
+#include "pciback.h"
+
+int verbose_request = 0;
+module_param(verbose_request,int,0644);
+
+/* For those architectures without a pcibios_disable_device */
+void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {}
+
+void pciback_disable_device(struct pci_dev *dev)
+{
+	if (dev->is_enabled) {
+		dev->is_enabled = 0;
+		pcibios_disable_device(dev);
+	}
+}
+
+/* Ensure a device is "turned off" and ready to be exported.
+ * This also sets up the device's private data to keep track of what should
+ * be in the base address registers (BARs) so that we can keep the
+ * client from manipulating them directly.
+ */
+void pciback_reset_device(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	/* Disable devices (but not bridges) */
+	if (dev->hdr_type==PCI_HEADER_TYPE_NORMAL) {
+		pciback_disable_device(dev);
+
+		pci_write_config_word(dev, PCI_COMMAND, 0);
+
+		dev->is_enabled = 0;
+		dev->is_busmaster = 0;
+	}
+	else {
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		if (cmd&(PCI_COMMAND_INVALIDATE)) {
+			cmd &= ~(PCI_COMMAND_INVALIDATE);
+			pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+			dev->is_busmaster = 0;
+		}
+	}
+
+	pciback_config_reset(dev);
+}
+
+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pciback_device *pdev = dev_id;
+	struct pci_dev *dev;
+	struct xen_pci_op *op = &pdev->sh_info->op;
+	
+	if (unlikely(!test_bit(_XEN_PCIF_active,
+					(unsigned long *)&pdev->sh_info->flags))) {
+		printk(KERN_DEBUG "pciback: interrupt, but no active operation\n");
+		goto out;
+	}
+
+	dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
+
+	if (dev==NULL)
+		op->err = XEN_PCI_ERR_dev_not_found;
+	else if (op->cmd == XEN_PCI_OP_conf_read)
+		op->err = pciback_config_read(dev, op->offset, op->size, &op->value);
+	else if (op->cmd == XEN_PCI_OP_conf_write)
+		op->err = pciback_config_write(dev, op->offset, op->size, op->value);
+	else
+		op->err = XEN_PCI_ERR_not_implemented;
+
+	wmb();
+	clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+
+out:
+	return IRQ_HANDLED;
+}
+
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,147 @@
+/*
+ * PCI Backend - Provides a Virtual PCI bus (with real devices)
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include "pciback.h"
+
+#define PCI_SLOT_MAX 32
+
+typedef struct {
+	struct list_head dev_list[PCI_SLOT_MAX];
+} vpci_dev_data_t;
+
+static inline struct list_head * list_first(struct list_head *head)
+{
+	return head->next;
+}
+
+struct pci_dev * pciback_get_pci_dev(struct pciback_device *pdev,
+		unsigned int domain, unsigned int bus, unsigned int devfn)
+{
+	struct pci_dev_entry *dev_entry;
+	vpci_dev_data_t *vpci_dev = pdev->pci_dev_data;
+
+	if (domain!=0 || bus!=0)
+		return NULL;
+
+	if (PCI_SLOT(devfn)<PCI_SLOT_MAX) {
+		/* we don't need to lock the list here because once the backend
+		 * is in operation, it won't have any more devices addeded
+		 * (or removed).
+		 */
+		list_for_each_entry(dev_entry, &vpci_dev->dev_list[PCI_SLOT(devfn)],
+				list) {
+			if (PCI_FUNC(dev_entry->dev->devfn)==PCI_FUNC(devfn))
+				return dev_entry->dev;
+		}
+	}
+	return NULL;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+	int err=0, i;
+	struct pci_dev_entry *t, *dev_entry;
+	vpci_dev_data_t *vpci_dev = pdev->pci_dev_data;
+
+	if ((dev->class>>24)==PCI_BASE_CLASS_BRIDGE) {
+		err = -EFAULT;
+		xenbus_dev_fatal(pdev->xdev, err,
+				"Can't export bridges on the virtual PCI bus");
+		goto out;
+	}
+
+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
+	if (!dev_entry) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(pdev->xdev, err,
+				"Error adding entry to virtual PCI bus");
+		goto out;
+	}
+	
+	dev_entry->dev = dev;
+
+	/* Keep multi-function devices together on the virtual PCI bus */
+	for (i=0; i<PCI_SLOT_MAX; i++) {
+		if (!list_empty(&vpci_dev->dev_list[i])) {
+			t = list_entry(list_first(&vpci_dev->dev_list[i]),
+					struct pci_dev_entry, list);
+
+			if (pci_domain_nr(t->dev->bus)==pci_domain_nr(dev->bus)
+					&& t->dev->bus->number==dev->bus->number
+					&& PCI_SLOT(t->dev->devfn)==PCI_SLOT(dev->devfn)) {
+				printk(KERN_INFO
+						"pciback: vpci: assign %s to virtual slot %d func %d\n",
+						pci_name(dev), i, PCI_FUNC(dev->devfn));
+				list_add_tail(&dev_entry->list, &vpci_dev->dev_list[i]);
+				goto out;
+			}
+		}
+	}
+
+	/* Assign to a new slot on the virtual PCI bus */
+	for (i=0; i<PCI_SLOT_MAX; i++) {
+		if (list_empty(&vpci_dev->dev_list[i])) {
+			printk(KERN_INFO "pciback: vpci: assign %s to virtual slot %d\n",
+					pci_name(dev),i);
+			list_add_tail(&dev_entry->list, &vpci_dev->dev_list[i]);
+			goto out;
+		}
+	}
+
+	err = -ENOMEM;
+	xenbus_dev_fatal(pdev->xdev, err, "No more space on root virtual PCI bus");
+
+out:
+	return err;
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+	int i;
+	vpci_dev_data_t *vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
+
+	if (!vpci_dev)
+		return -ENOMEM;
+
+	for (i=0; i<PCI_SLOT_MAX; i++) {
+		INIT_LIST_HEAD(&vpci_dev->dev_list[i]);
+	}
+
+	pdev->pci_dev_data = vpci_dev;
+
+	return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+		publish_pci_root_cb publish_cb)
+{
+	/* The Virtual PCI bus has only one root */
+	return publish_cb(pdev, 0, 0);
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+	int i;
+	vpci_dev_data_t *vpci_dev = pdev->pci_dev_data;
+
+	for (i=0; i<PCI_SLOT_MAX; i++) {
+		struct pci_dev_entry *e,*tmp;
+		list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[i], list) {
+			list_del(&e->list);
+			pcistub_put_pci_dev(e->dev);
+			kfree(e);
+		}
+	}
+
+	kfree(vpci_dev);
+	pdev->pci_dev_data = NULL;
+}
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,422 @@
+/*
+ * PCI Backend Xenbus Setup - handles setup with frontend and xend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <asm-xen/xenbus.h>
+#include <asm-xen/evtchn.h>
+#include "pciback.h"
+
+#define INVALID_EVTCHN_IRQ  (-1)
+
+struct pciback_device * alloc_pdev(struct xenbus_device *xdev)
+{
+	struct pciback_device *pdev;
+
+	pdev = kmalloc(sizeof(struct pciback_device), GFP_KERNEL);
+	if (pdev==NULL)
+		goto out;
+	dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
+
+	pdev->xdev = xdev;
+	xdev->data = pdev;
+
+	spin_lock_init(&pdev->dev_lock);
+
+	pdev->sh_info = NULL;
+	pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
+	pdev->be_watching = 0;
+
+	if (pciback_init_devices(pdev)) {
+		kfree(pdev);
+		pdev = NULL;
+	}
+out:
+	return pdev;
+}
+
+void free_pdev(struct pciback_device *pdev)
+{
+	if (pdev->be_watching)
+		unregister_xenbus_watch(&pdev->be_watch);
+
+	/* Ensure the guest can't trigger our handler before removing devices */
+	if (pdev->evtchn_irq!=INVALID_EVTCHN_IRQ)
+		unbind_from_irqhandler(pdev->evtchn_irq, pdev);
+
+	if (pdev->sh_info)
+		xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
+
+	pciback_release_devices(pdev);
+
+	pdev->xdev->data = NULL;
+	pdev->xdev = NULL;
+
+	kfree(pdev);
+}
+
+static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
+		int remote_evtchn)
+{
+	int err = 0;
+	int evtchn;
+	dev_dbg(&pdev->xdev->dev,
+			"Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
+			gnt_ref, remote_evtchn);
+
+	err = xenbus_map_ring_valloc(pdev->xdev, gnt_ref, (void **)&pdev->sh_info);
+	if (err)
+		goto out;
+
+	err = xenbus_bind_evtchn(pdev->xdev, remote_evtchn, &evtchn);
+	if (err)
+		goto out;
+
+	err = bind_evtchn_to_irqhandler(evtchn, pciback_handle_event,
+			SA_SAMPLE_RANDOM, "pciback", pdev);
+	if (err<0) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				"Error binding event channel to IRQ" );
+		goto out;
+	}
+	pdev->evtchn_irq = err;
+	err = 0;
+
+	dev_dbg(&pdev->xdev->dev, "Attached!\n");
+out:
+	return err;
+}
+
+static int pciback_attach(struct pciback_device *pdev)
+{
+	int err=0;
+	int gnt_ref, remote_evtchn;
+	char *magic=NULL;
+
+	spin_lock(&pdev->dev_lock);
+
+	/* Make sure we only do this setup once */
+	if (xenbus_read_driver_state(pdev->xdev->nodename)!=XenbusStateInitialised)
+		goto out;
+
+	/* Wait for frontend to state that it has published the configuration */
+	if (xenbus_read_driver_state(pdev->xdev->otherend)!=XenbusStateInitialised)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
+
+	err = xenbus_gather(XBT_NULL, pdev->xdev->otherend,
+			"pci-op-ref", "%u", &gnt_ref,
+			"event-channel", "%u", &remote_evtchn,
+			"magic", NULL, &magic,
+			NULL );
+	if (err) {
+		/* If configuration didn't get read correctly, wait longer */
+		xenbus_dev_fatal(pdev->xdev, err,
+				"Error reading configuration from frontend");
+		goto out;
+	}
+
+	if (magic==NULL || strcmp(magic,XEN_PCI_MAGIC)!=0) {
+		xenbus_dev_fatal(pdev->xdev, -EFAULT,
+				"version mismatch (%s/%s) with pcifront - halting pciback",
+				magic, XEN_PCI_MAGIC);
+		goto out;
+	}
+
+	err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
+	if (err)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "Connecting...\n");
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
+	if (err)
+		xenbus_dev_fatal(pdev->xdev, err,
+				"Error switching to connected state!");
+
+	dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
+out:
+	spin_unlock(&pdev->dev_lock);
+
+	if (magic)
+		kfree(magic);
+
+	return err;
+}
+
+static void pciback_frontend_changed(struct xenbus_device *xdev,
+		XenbusState fe_state)
+{
+	struct pciback_device *pdev = xdev->data;
+
+	dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
+	switch (fe_state) {
+		case XenbusStateInitialised:
+			pciback_attach(pdev);
+			break;
+
+		case XenbusStateClosing:
+			xenbus_switch_state(xdev, XBT_NULL, XenbusStateClosing);
+			break;
+
+		case XenbusStateClosed:
+			dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
+			device_unregister(&xdev->dev);
+			break;
+
+		default:
+			break;
+	}
+}
+
+static int pciback_publish_pci_root(struct pciback_device *pdev,
+		unsigned int domain, unsigned int bus)
+{
+	unsigned int d, b;
+	int i, root_num, len, err;
+	char str[64];
+
+	dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
+			"root_num", "%d", &root_num);
+	if (err==0 || err==-ENOENT)
+		root_num = 0;
+	else if (err<0)
+		goto out;
+
+	/* Verify that we haven't already published this pci root */
+	for (i=0; i<root_num; i++) {
+		len = snprintf(str, sizeof(str), "root-%d", i);
+		if (unlikely(len>=(sizeof(str)-1))) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
+				str, "%x:%x", &d, &b);
+		if (err<0)
+			goto out;
+		if (err!=2) {
+			err = -EINVAL;
+			goto out;
+		}
+
+		if (d==domain && b==bus) {
+			err = 0;
+			goto out;
+		}
+	}
+
+	len = snprintf(str, sizeof(str), "root-%d", root_num);
+	if (unlikely(len>=(sizeof(str)-1))) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
+			root_num, domain, bus);
+
+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename, str,
+			"%04x:%02x", domain, bus);
+	if (err)
+		goto out;
+
+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename,
+			"root_num","%d", (root_num+1));
+
+out:
+	return err;
+}
+
+static int pciback_export_device(struct pciback_device *pdev,
+		int domain, int bus, int slot, int func)
+{
+	struct pci_dev *dev;
+	int err = 0;
+
+	dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
+			domain, bus, slot, func);
+
+	dev = pcistub_get_pci_dev_by_slot(domain, bus, slot, func);
+	if (!dev) {
+		err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				"Couldn't locate PCI device (%04x:%02x:%02x.%01x)! "
+				"perhaps already in-use?", domain, bus, slot, func);
+		goto out;
+	}
+
+	err = pciback_add_pci_dev(pdev, dev);
+	if (err)
+		goto out;
+
+	/* TODO: If this is a bridge, export all the children (this won't work for
+	 * children dynamically added to the bus later!) - This is trivial in
+	 * kernels >= 2.6.14 with pci_walk_bus(dev->subordinate)
+	 */
+out:
+	return err;
+}
+
+static int pciback_setup_backend(struct pciback_device *pdev)
+{
+	/* Get configuration from xend (if available now) */
+	int domain, bus, slot, func;
+	int err = 0;
+	int i, num_devs;
+	char dev_str[64];
+
+	spin_lock(&pdev->dev_lock);
+
+	/* It's possible we could get the call to setup twice, so make sure
+	 * we're not already connected.
+	 */
+	if (xenbus_read_driver_state(pdev->xdev->nodename)!=XenbusStateInitWait)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "getting be setup\n");
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, "num_devs", "%d", &num_devs);
+	if (err!=1) {
+		if (err>=0)
+			err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err, "Error reading number of devices");
+		goto out;
+	}
+
+	for (i=0; i<num_devs; i++) {
+		int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
+		if (unlikely(l>=(sizeof(dev_str)-1))) {
+			err = -ENOMEM;
+			xenbus_dev_fatal(pdev->xdev, err,
+					"String overflow while reading configuration");
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, dev_str,
+				"%x:%x:%x.%x", &domain, &bus, &slot, &func);
+		if (err<0) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					"Error reading device configuration");
+			goto out;
+		}
+		if (err!=4) {
+			err = -EINVAL;
+			xenbus_dev_fatal(pdev->xdev, err,
+					"Error parsing pci device configuration");
+			goto out;
+		}
+
+		err = pciback_export_device(pdev, domain, bus, slot, func);
+		if (err)
+			goto out;
+	}
+
+	err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				"Error while publish PCI root buses for frontend");
+		goto out;
+	}
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateInitialised);
+	if (err)
+		xenbus_dev_fatal(pdev->xdev, err,
+				"Error switching to initialised state!");
+
+out:
+	spin_unlock(&pdev->dev_lock);
+
+	if (!err)
+		/* see if pcifront is already configured (if not, we'll wait) */
+		pciback_attach(pdev);
+
+	return err;
+}
+
+static void pciback_be_watch(struct xenbus_watch *watch,
+		const char **vec, unsigned int len)
+{
+	struct pciback_device *pdev =
+		container_of(watch, struct pciback_device, be_watch);
+	
+	switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
+		case XenbusStateInitWait:
+			pciback_setup_backend(pdev);
+			break;
+
+		default:
+			break;
+	}
+}
+
+static int pciback_xenbus_probe(struct xenbus_device *dev,
+		const struct xenbus_device_id *id)
+{
+	int err = 0;
+	struct pciback_device * pdev = alloc_pdev(dev);
+
+	if( pdev==NULL ) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(dev, err,
+				"Error allocating pciback_device struct");
+		goto out;
+	}
+
+	/* wait for xend to configure us */
+	err = xenbus_switch_state(dev, XBT_NULL, XenbusStateInitWait);
+	if (err)
+		goto out;
+
+	/* watch the backend node for backend configuration information */
+	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
+			pciback_be_watch);
+	if (err) 
+		goto out;
+	pdev->be_watching = 1;
+
+	/* We need to force a call to our callback here in case
+	 * xend already configured us!
+	 */
+	pciback_be_watch(&pdev->be_watch, NULL, 0);
+
+out:
+	return err;
+}
+
+static int pciback_xenbus_remove(struct xenbus_device *dev)
+{
+	struct pciback_device *pdev = dev->data;
+
+	if (pdev!=NULL)
+		free_pdev(pdev);
+
+	return 0;
+}
+
+static struct xenbus_device_id xenpci_ids[] = {
+	{ "pci" },
+	{ { 0 } },
+};
+
+static struct xenbus_driver xenbus_pciback_driver = {
+	.name = "pciback",
+	.owner = THIS_MODULE,
+	.ids = xenpci_ids,
+	.probe = pciback_xenbus_probe,
+	.remove = pciback_xenbus_remove,
+	.otherend_changed = pciback_frontend_changed,
+};
+
+static __init int pciback_xenbus_register(void)
+{
+	return xenbus_register_backend(&xenbus_pciback_driver);
+}
+
+/* Must only initialize our xenbus driver after the pcistub driver */
+device_initcall(pciback_xenbus_register);
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,8 @@
+obj-y += pcifront.o
+
+pcifront-y := pci_op.o xenbus.o pci.o
+pcifront-$(CONFIG_XEN_PCI_FE_ARCH_REPLACE) += arch.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y)
+CFLAGS_xenbus.o += -DDEBUG
+endif
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pcifront/arch.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/arch.c	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,95 @@
+/*
+ * PCI Frontend Arch Replacement Code - replaces an architecture's PCI access
+ *              code with a generic, Xen version (Experimental)
+ * - This file *should* be arch-independent (except for
+ *   pci_mmap_page_range) and should replace an arch's PCI implementation
+ * - You must prevent an architecture's PCI code from compiling into the kernel
+ *   when you use the code contained here.
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+/* More or less copied from other architectures */
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+	u16 cmd, oldcmd;
+	u8 irq;
+	int i;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	oldcmd = cmd;
+
+	for (i=0; i<PCI_NUM_RESOURCES; i++) {
+		struct resource *r = &dev->resource[i];
+
+		if (!(mask&(1<<i)))
+			continue;
+
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+
+	if (cmd!=oldcmd) {
+		printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n",
+				pci_name(dev), cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	dev->irq = irq;
+
+	return 0;
+}
+
+void pcibios_disable_device(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+	if (cmd&(PCI_COMMAND_IO|PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER)) {
+		cmd &= ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER);
+
+		printk(KERN_DEBUG "PCI: Disabling device: (%s), cmd %x\n",
+				pci_name(dev), cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+}
+
+char *pcibios_setup(char *str)
+{
+	/** Return NULL if we accept an option, str if we don't */
+	return str;
+}
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+	/* Handled by backend when we turn the master
+	 * bit on in the PCI_COMMAND register */
+}
+
+void pcibios_align_resource(void *data, struct resource *res,
+		unsigned long size, unsigned long align)
+{
+}
+
+void pcibios_fixup_bus(struct pci_bus *bus)
+{
+}
+
+unsigned int pcibios_assign_all_busses(void)
+{
+	return 0;
+}
+
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+		enum pci_mmap_state mmap_state, int write_combine)
+{
+	printk(KERN_ERR "%s: mmap_page_range not implemented!\n", pci_name(dev));
+	return -EINVAL;
+}
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,43 @@
+/*
+ * PCI Frontend Operations - ensure only one PCI frontend runs at a time
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include "pcifront.h"
+
+DEFINE_SPINLOCK(pcifront_dev_lock);
+static struct pcifront_device *pcifront_dev = NULL;
+
+int pcifront_connect(struct pcifront_device *pdev)
+{
+	int err = 0;
+
+	spin_lock(&pcifront_dev_lock);
+
+	if (!pcifront_dev)
+		dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
+	else {
+		dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
+		err = -EEXIST;
+	}
+
+	spin_unlock(&pcifront_dev_lock);
+
+	return err;
+}
+
+void pcifront_disconnect(struct pcifront_device *pdev)
+{
+	spin_lock(&pcifront_dev_lock);
+
+	if (pdev==pcifront_dev) {
+		dev_info(&pdev->xdev->dev, "Disconnecting PCI Frontend Buses\n");
+		pcifront_dev = NULL;
+	}
+
+	spin_unlock(&pcifront_dev_lock);
+}
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,220 @@
+/*
+ * PCI Frontend Operations - Communicates with frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <asm-xen/evtchn.h>
+#include "pcifront.h"
+
+int verbose_request = 0;
+module_param(verbose_request,int,0644);
+
+static int errno_to_pcibios_err(int errno)
+{
+	switch(errno) {
+		case XEN_PCI_ERR_success:
+			return PCIBIOS_SUCCESSFUL;
+
+		case XEN_PCI_ERR_dev_not_found:
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+		case XEN_PCI_ERR_invalid_offset:
+		case XEN_PCI_ERR_op_failed:
+			return PCIBIOS_BAD_REGISTER_NUMBER;
+
+		case XEN_PCI_ERR_not_implemented:
+			return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+		case XEN_PCI_ERR_access_denied:
+			return PCIBIOS_SET_FAILED;
+	}
+	return errno;
+}
+
+static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
+{
+	int err = 0;
+	struct xen_pci_op *active_op = &pdev->sh_info->op;
+	unsigned long irq_flags;
+
+	unsigned int volatile ttl = (1U<<29);
+
+	spin_lock_irqsave(&pdev->sh_info_lock,irq_flags);
+
+	memcpy(active_op, op, sizeof(struct xen_pci_op));
+
+	/* Go */
+	wmb();
+	set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+	notify_remote_via_evtchn(pdev->evtchn);
+
+	/* IRQs are disabled for the pci config. space reads/writes,
+	 * which means no event channel to notify us that the backend
+	 * is done so spin while waiting for the answer */
+	while (test_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)) {
+		if (!ttl) {
+			dev_err(&pdev->xdev->dev, "pciback not responding!!!\n");
+			clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+			err = XEN_PCI_ERR_dev_not_found;
+			goto out;
+		}
+		ttl--;
+	}
+
+	memcpy(op, active_op, sizeof(struct xen_pci_op));
+
+	err = op->err;
+out:
+	spin_unlock_irqrestore(&pdev->sh_info_lock,irq_flags);
+	return err;
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
+		int where, int size, u32 *val)
+{
+	int err = 0;
+	struct xen_pci_op op = {
+		.cmd = XEN_PCI_OP_conf_read,
+		.domain = pci_domain_nr(bus),
+		.bus = bus->number,
+		.devfn = devfn,
+		.offset = where,
+		.size = size,
+	};
+	struct pcifront_sd *sd = bus->sysdata;
+	struct pcifront_device *pdev = sd->pdev;
+
+	if (verbose_request)
+		dev_info(&pdev->xdev->dev,
+				"read dev=%04x:%02x:%02x.%01x - offset %x size %d\n",
+				pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
+				PCI_FUNC(devfn), where, size);
+
+	err = do_pci_op(pdev, &op);
+
+	if (likely(!err)) {
+		if (verbose_request)
+			dev_info(&pdev->xdev->dev,"read got back value %x\n", op.value);
+
+		*val = op.value;
+	}
+	else if (err==-ENODEV) {
+		/* No device here, pretend that it just returned 0 */
+		err = 0;
+		*val = 0;
+	}
+
+	return errno_to_pcibios_err(err);
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
+		int where, int size, u32 val)
+{
+	struct xen_pci_op op = {
+		.cmd = XEN_PCI_OP_conf_write,
+		.domain = pci_domain_nr(bus),
+		.bus = bus->number,
+		.devfn = devfn,
+		.offset = where,
+		.size = size,
+		.value = val,
+	};
+	struct pcifront_sd *sd = bus->sysdata;
+	struct pcifront_device *pdev = sd->pdev;
+
+	if (verbose_request)
+		dev_info(&pdev->xdev->dev,
+				"write dev=%04x:%02x:%02x.%01x - offset %x size %d val %x\n",
+				pci_domain_nr(bus), bus->number,
+				PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
+
+	return errno_to_pcibios_err(do_pci_op(pdev, &op));
+}
+
+struct pci_ops pcifront_bus_ops = {
+	.read = pcifront_bus_read,
+	.write = pcifront_bus_write,
+};
+
+int pcifront_scan_root(struct pcifront_device *pdev,
+		unsigned int domain, unsigned int bus)
+{
+	struct pci_bus *b;
+	struct pcifront_sd *sd = NULL;
+	struct pci_bus_entry *bus_entry = NULL;
+	int err = 0;
+
+#ifndef CONFIG_PCI_DOMAINS
+	if (domain!=0) {
+		dev_err(&pdev->xdev->dev, "PCI Root in non-zero (%d) PCI Domain!\n",
+				domain);
+		dev_err(&pdev->xdev->dev, "Please compile with CONFIG_PCI_DOMAINS\n");
+		err = -EINVAL;
+		goto err_out;
+	}
+#endif
+
+	dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
+			domain, bus);
+
+	bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
+	sd = kmalloc(sizeof(*sd), GFP_KERNEL);
+	if (!bus_entry || !sd) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+	sd->domain = domain;
+	sd->pdev = pdev;
+
+	b = pci_scan_bus_parented(&pdev->xdev->dev, bus,
+			&pcifront_bus_ops, sd);
+	if (!b) {
+		dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+	bus_entry->bus = b;
+
+	list_add(&bus_entry->list, &pdev->root_buses);
+
+	/* In kernels >= 2.6.13, we need to:
+	   pci_bus_add_devices(b); */
+
+	return 0;
+
+err_out:
+	kfree(bus_entry);
+	kfree(sd);
+
+	return err;
+}
+
+void pcifront_free_roots(struct pcifront_device *pdev)
+{
+	struct pci_bus_entry *bus_entry, *t;
+
+	list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
+		/* TODO: Removing a PCI Bus is untested (as it normally just goes
+		 * away on domain shutdown)
+		 */
+		list_del(&bus_entry->list);
+
+		spin_lock(&pci_bus_lock);
+		list_del(&bus_entry->bus->node);
+		spin_unlock(&pci_bus_lock);
+
+		kfree(bus_entry->bus->sysdata);
+
+		device_unregister(bus_entry->bus->bridge);
+
+		/* Do we need to free() the bus itself? */
+
+		kfree(bus_entry);
+	}
+}
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,40 @@
+/*
+ * PCI Frontend - Common data structures & function declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCIFRONT_H__
+#define __XEN_PCIFRONT_H__
+
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <asm-xen/xenbus.h>
+#include <asm-xen/xen-public/io/pciif.h>
+#include <asm-xen/pcifront.h>
+
+struct pci_bus_entry {
+	struct list_head list;
+	struct pci_bus *bus;
+};
+
+struct pcifront_device {
+	struct xenbus_device *xdev;
+	struct list_head root_buses;
+	spinlock_t dev_lock;
+
+	int evtchn;
+	int gnt_ref;
+
+	/* Lock this when doing any operations in sh_info */
+	spinlock_t sh_info_lock;
+	struct xen_pci_sharedinfo *sh_info;
+};
+
+int pcifront_connect(struct pcifront_device *pdev);
+void pcifront_disconnect(struct pcifront_device *pdev);
+
+int pcifront_scan_root(struct pcifront_device *pdev,
+		unsigned int domain, unsigned int bus);
+void pcifront_free_roots(struct pcifront_device *pdev);
+
+#endif /* __XEN_PCIFRONT_H__ */
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,286 @@
+/*
+ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn)
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <asm-xen/xenbus.h>
+#include "pcifront.h"
+
+#define INVALID_GRANT_REF (0)
+#define INVALID_EVTCHN    (-1)
+
+static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
+{
+	struct pcifront_device *pdev;
+
+	pdev = kmalloc(sizeof(struct pcifront_device), GFP_KERNEL);
+	if (pdev==NULL)
+		goto out;
+
+	pdev->sh_info = (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
+	if (pdev->sh_info==NULL) {
+		kfree(pdev);
+		pdev = NULL;
+		goto out;
+	}
+	pdev->sh_info->flags = 0;
+
+	xdev->data = pdev;
+	pdev->xdev = xdev;
+
+	INIT_LIST_HEAD(&pdev->root_buses);
+
+	spin_lock_init(&pdev->dev_lock);
+	spin_lock_init(&pdev->sh_info_lock);
+
+	pdev->evtchn = INVALID_EVTCHN;
+	pdev->gnt_ref = INVALID_GRANT_REF;
+
+	dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n",
+			pdev, pdev->sh_info);
+out:
+	return pdev;
+}
+
+static void free_pdev(struct pcifront_device *pdev)
+{
+	dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev);
+
+	if (pdev->evtchn!=INVALID_EVTCHN)
+		xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
+
+	if (pdev->gnt_ref!=INVALID_GRANT_REF)
+		gnttab_end_foreign_access(pdev->gnt_ref, 0,
+				(unsigned long)pdev->sh_info);
+
+	pdev->xdev->data = NULL;
+
+	kfree(pdev);
+}
+
+static int pcifront_publish_info(struct pcifront_device *pdev)
+{
+	int err=0;
+	xenbus_transaction_t trans;
+
+	err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info));
+	if (err<0)
+		goto out;
+
+	pdev->gnt_ref = err;
+
+	err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
+	if (err)
+		goto out;
+
+do_publish:
+	err = xenbus_transaction_start(&trans);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				"Error writing configuration for backend (start transaction)");
+		goto out;
+	}
+
+	err = xenbus_printf(trans, pdev->xdev->nodename,
+			"pci-op-ref", "%u", pdev->gnt_ref);
+	if (!err)
+		err = xenbus_printf(trans, pdev->xdev->nodename, "event-channel", "%u",
+				pdev->evtchn);
+	if (!err)
+		err = xenbus_printf(trans, pdev->xdev->nodename,
+				"magic", XEN_PCI_MAGIC);
+	if (!err)
+		err = xenbus_switch_state(pdev->xdev, trans, XenbusStateInitialised); 
+
+	if (err) {
+		xenbus_transaction_end(trans, 1);
+		xenbus_dev_fatal(pdev->xdev, err,
+				"Error writing configuration for backend");
+		goto out;
+	}
+	else {
+		err = xenbus_transaction_end(trans, 0);
+		if (err == -EAGAIN) 
+			goto do_publish;
+		else if (err) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					"Error completing transaction for backend");
+			goto out;
+		}
+	}
+
+	dev_dbg(&pdev->xdev->dev, "publishing successful!\n");
+
+out:
+	return err;
+}
+
+static int pcifront_try_connect(struct pcifront_device *pdev)
+{
+	int err = -EFAULT;
+	int i, num_roots, len;
+	char str[64];
+	unsigned int domain, bus;
+
+	spin_lock(&pdev->dev_lock);
+
+	/* Only connect once */
+	if (xenbus_read_driver_state(pdev->xdev->nodename)!=XenbusStateInitialised)
+		goto out;
+
+	err = pcifront_connect(pdev);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err, "Error connecting PCI Frontend");
+		goto out;
+	}
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend, "root_num",
+			"%d", &num_roots);
+	if (err==-ENOENT) {
+		xenbus_dev_error(pdev->xdev, err, "No PCI Roots found, trying 0000:00");
+		err = pcifront_scan_root(pdev, 0, 0);
+		num_roots = 0;
+	}
+	else if (err!=1) {
+		if (err==0)
+			err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err, "Error reading number of PCI roots");
+		goto out;
+	}
+
+	for (i=0; i<num_roots; i++) {
+		len = snprintf(str, sizeof(str), "root-%d", i);
+		if (unlikely(len>=(sizeof(str)-1))) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend, str,
+				"%x:%x", &domain, &bus);
+		if (err!=2) {
+			if (err>=0)
+				err = -EINVAL;
+			xenbus_dev_fatal(pdev->xdev, err, "Error reading PCI root %d", i);
+			goto out;
+		}
+
+		err = pcifront_scan_root(pdev, domain, bus);
+		if (err) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					"Error scanning PCI root %04x:%02x", domain, bus);
+			goto out;
+		}
+	}
+	
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
+	if (err)
+		goto out;
+
+out:
+	spin_unlock(&pdev->dev_lock);
+	return err;
+}
+
+static int pcifront_try_disconnect(struct pcifront_device *pdev)
+{
+	int err=0;
+	XenbusState prev_state;
+
+	spin_lock(&pdev->dev_lock);
+
+	prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
+
+	if (prev_state<XenbusStateClosing)
+		err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateClosing);
+
+	if (!err && prev_state==XenbusStateConnected)
+		pcifront_disconnect(pdev);
+
+	spin_unlock(&pdev->dev_lock);
+
+	return err;
+}
+
+static void pcifront_backend_changed(struct xenbus_device *xdev,
+		XenbusState be_state)
+{
+	struct pcifront_device *pdev = xdev->data;
+
+	switch (be_state)
+	{
+		case XenbusStateClosing:
+			dev_warn(&xdev->dev, "backend going away!\n");
+			pcifront_try_disconnect(pdev);
+			break;
+
+		case XenbusStateClosed:
+			dev_warn(&xdev->dev, "backend went away!\n");
+			pcifront_try_disconnect(pdev);
+
+			device_unregister(&pdev->xdev->dev);
+			break;
+
+		case XenbusStateConnected:
+			pcifront_try_connect(pdev);
+			break;
+
+		default:
+			break;
+	}
+}
+
+static int pcifront_xenbus_probe(struct xenbus_device *xdev,
+		const struct xenbus_device_id *id)
+{
+	int err = 0;
+	struct pcifront_device *pdev = alloc_pdev(xdev);
+
+	if (pdev == NULL) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(xdev, err,
+			"Error allocating pcifront_device struct");
+		goto out;
+	}
+
+	err = pcifront_publish_info(pdev);
+
+out:
+	return err;
+}
+
+static int pcifront_xenbus_remove(struct xenbus_device *xdev)
+{
+	if (xdev->data)
+		free_pdev(xdev->data);
+
+	return 0;
+}
+
+static struct xenbus_device_id xenpci_ids[] = {
+	{ "pci" },
+	{ { 0 } },
+};
+
+static struct xenbus_driver xenbus_pcifront_driver = {
+	.name = "pcifront",
+	.owner = THIS_MODULE,
+	.ids = xenpci_ids,
+	.probe = pcifront_xenbus_probe,
+	.remove = pcifront_xenbus_remove,
+	.otherend_changed = pcifront_backend_changed,
+};
+
+static int __init pcifront_init(void)
+{
+	int err = 0;
+
+	err = xenbus_register_frontend(&xenbus_pcifront_driver);
+
+	return err;
+}
+
+/* Initialize after the Xen PCI Frontend Stub is initialized */
+subsys_initcall(pcifront_init);
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/include/asm-xen/pcifront.h
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/include/asm-xen/pcifront.h	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,39 @@
+/*
+ * PCI Frontend - arch-dependendent declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_ASM_PCIFRONT_H__
+#define __XEN_ASM_PCIFRONT_H__
+
+#include <linux/config.h>
+#include <linux/spinlock.h>
+
+#ifdef __KERNEL__
+
+struct pcifront_device;
+
+struct pcifront_sd {
+	int domain;
+	struct pcifront_device *pdev;
+};
+
+struct pci_bus;
+
+#ifdef CONFIG_PCI_DOMAINS
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+	struct pcifront_sd *sd = bus->sysdata;
+	return sd->domain;
+}
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+	return pci_domain_nr(bus);
+}
+#endif /* CONFIG_PCI_DOMAINS */
+
+extern spinlock_t pci_bus_lock;
+
+#endif /* __KERNEL__ */
+
+#endif /* __XEN_ASM_PCIFRONT_H__ */
diff -r 2add7a262530 -r 5278641a6ea0 xen/include/public/io/pciif.h
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/xen/include/public/io/pciif.h	Fri Jan 27 18:57:35 2006
@@ -0,0 +1,55 @@
+/*
+ * PCI Backend/Frontend Common Data Structures & Macros
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCI_COMMON_H__
+#define __XEN_PCI_COMMON_H__
+
+/* Be sure to bump this number if you change this file */
+#define XEN_PCI_MAGIC		"7"
+
+/* xen_pci_sharedinfo flags */
+#define _XEN_PCIF_active     (0)
+#define XEN_PCIF_active      (1<<_XEN_PCI_active)
+
+/* xen_pci_op commands */
+#define XEN_PCI_OP_conf_read    (0)
+#define XEN_PCI_OP_conf_write   (1)
+
+/* xen_pci_op error numbers */
+#define XEN_PCI_ERR_success          (0)
+#define XEN_PCI_ERR_dev_not_found   (-1)
+#define XEN_PCI_ERR_invalid_offset  (-2)
+#define XEN_PCI_ERR_access_denied   (-3)
+#define XEN_PCI_ERR_not_implemented (-4)
+/* XEN_PCI_ERR_op_failed - backend failed to complete the operation */
+#define XEN_PCI_ERR_op_failed       (-5)
+
+struct xen_pci_op {
+	/* IN: what action to perform: XEN_PCI_OP_* */
+	uint32_t cmd;
+
+	/* OUT: will contain an error number (if any) from errno.h */
+	int32_t err;
+
+	/* IN: which device to touch */
+	uint32_t domain; /* PCI Domain/Segment */
+	uint32_t bus;
+	uint32_t devfn;
+
+	/* IN: which configuration registers to touch */
+	int32_t offset;
+	int32_t size;
+
+	/* IN/OUT: Contains the result after a READ or the value to WRITE */
+	uint32_t value;
+};
+
+struct xen_pci_sharedinfo {
+	/* flags - XEN_PCIF_* */
+	uint32_t flags;
+	struct xen_pci_op op;
+};
+
+#endif /* __XEN_PCI_COMMON_H__ */

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
  2006-01-30 13:24 [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend Ryan
@ 2006-01-30 15:06 ` Anthony Liguori
  2006-01-30 18:43   ` Ryan
  0 siblings, 1 reply; 15+ messages in thread
From: Anthony Liguori @ 2006-01-30 15:06 UTC (permalink / raw)
  To: Ryan; +Cc: xen-devel

Hi Ryan,

It would be nice if you could run your patches through lindent and 
resubmit.  You do a couple things that don't follow kernel style 
guidelines (lack of spaces around operators and else clauses on 
newlines).  Strictly adhering to the CodingStyle now will make upstream 
merge significantly easier in the future.

Thanks,

Anthony Liguori

Ryan wrote:

>This patch contains the PCI backend and frontend drivers for Linux
>2.6.12. There are a couple of compile-time options in the backend and
>frontend although the defaults should be sufficient to get you up and
>running.
>
>In the PCI backend, there are two modes of operation: pass-through and
>virtual PCI bus. The virtual PCI bus mode renumbers the slot addresses
>and places all of the exported devices on bus 0. For example, a device
>at 06:01.0 will appear to the PCI frontend to be at 00:00.0 (a 2nd
>exported device will show up at 00:01.0 and so on...). In pass-through
>mode, no renumbering occurs. A device at 06:01.0 will appear at 06:01.0
>to the PCI frontend (this is more similar to how things worked in Xen
>2.0.x). In both modes, PCI bridges are not currently exported. While
>virtual PCI bus mode can somewhat mask the real slot addresses to the
>frontend (they're still visible in Xenstore at present), it may break
>certain specialized devices and drivers which need to know the location
>of other PCI devices (pass-through mode may be better suited for this
>scenario).
>
>There are two methods for the PCI frontend as well. The default method
>integrates with the architecture-specific PCI code (in this case, i386).
>This allows some PCI things that are architecture-specific to keep
>working (like pci_mmap_page_range) that can't be handled by the
>architecture-specific code in the backend. The other method is an
>attempt at an architecture-independent driver that replaces the
>architecture-specific PCI code in Linux with one that exclusively uses
>Xen. It requires less patching to the architecture-specific code (I just
>prevent it from compiling at all). While not tested on architectures
>other than x86, it *should* enable easy porting of the PCI frontend to
>ia64 and other architectures that Xen will support. I believe this
>method also demonstrates that by leveraging the PCI backend, a driver
>domain does not have to be concerned with as many architecture-specific
>details regarding the PCI bus and devices. It's not yet clear to me
>which method is best for the PCI frontend and I'd like to pick one or
>the other so that there aren't two mutually-exclusive code paths to
>maintain. Please let me know if you have problems with either method and
>if you have any suggestions/comments on the merits of each approach.
>
>If you have problems, there is a compile-time debug option that enables
>some extra logging that may be useful in tracking down the problem.
>There is also a run-time module parameter ("verbose_request") in the
>frontend and backend that will output each configuration space request
>that is sent/received across the shared page.
>
>Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>
>  
>
>------------------------------------------------------------------------
>
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/Kconfig
>--- a/linux-2.6-xen-sparse/arch/xen/Kconfig	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/arch/xen/Kconfig	Fri Jan 27 18:57:35 2006
>@@ -38,6 +38,85 @@
> 	  (e.g., hard drives, network cards). This allows you to configure
> 	  such devices and also includes some low-level support that is
> 	  otherwise not compiled into the kernel.
>+
>+config XEN_PCIDEV_BACKEND
>+	bool "PCI device backend driver"
>+	depends on XEN_PHYSDEV_ACCESS
>+	select PCI
>+	default y if XEN_PRIVILEGED_GUEST
>+	help
>+	  The PCI device backend driver allows the kernel to export arbitrary
>+	  PCI devices to other guests.
>+
>+choice
>+	prompt "PCI Backend Mode"
>+	depends on XEN_PCIDEV_BACKEND
>+	default XEN_PCIDEV_BACKEND_VPCI
>+
>+config XEN_PCIDEV_BACKEND_VPCI
>+	bool "Virtual PCI"
>+	---help---
>+	  This PCI Backend hides the true PCI topology and makes the frontend
>+	  think there is a single PCI bus with only the exported devices on it.
>+	  For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
>+	  second device at 02:1a.0 will be re-assigned to 00:01.0.
>+
>+config XEN_PCIDEV_BACKEND_PASS
>+	bool "Passthrough"
>+	---help---
>+	  This PCI Backend provides a real view of the PCI topology to the
>+	  frontend (for example, a device at 06:01.b will still appear at
>+	  06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
>+	  PCI devices to its driver domains. This may be required for drivers
>+	  which depend on finding their hardward in certain bus/slot
>+	  locations.
>+
>+endchoice
>+
>+config XEN_PCIDEV_BE_DEBUG
>+	bool "PCI Backend Debugging"
>+	depends on XEN_PCIDEV_BACKEND
>+	default n
>+
>+# This won't work in 2.6.12 due to what appears to be a kernel bug (related
>+# to reading the resources of transparent bridges in pci_read_bridge_bases).
>+# This bug appears to be fixed in 2.6.13:
>+# http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=90b54929b626c80056262d9d99b3f48522e404d0
>+#config XEN_PCIDEV_BACKEND_ALLOC
>+#	bool "Re-allocate PCI Resources (DANGEROUS)"
>+#	depends on XEN_PCIDEV_BACKEND
>+#	default n
>+#	---help---
>+#	  This forces the PCI Backend to try and re-allocate all of the resources
>+#	  on the PCI bus in an attempt to ensure that they fall entirely within
>+#	  boundaries that Xen can control.
>+
>+config XEN_PCIDEV_FRONTEND
>+	bool "PCI device frontend driver"
>+	depends on XEN_PHYSDEV_ACCESS
>+	select PCI
>+	default y if !XEN_PRIVILEGED_GUEST
>+	help
>+	  The PCI device frontend driver allows the kernel to import arbitrary
>+	  PCI devices from a PCI backend.
>+
>+config XEN_PCIDEV_FE_DEBUG
>+	bool "PCI Frontend Debugging"
>+	depends on XEN_PCIDEV_FRONTEND
>+	default n
>+
>+config XEN_PCI_FE_ARCH_REPLACE
>+	bool "PCI frontend driver - arch-independent (EXPERIMENTAL)"
>+	depends on XEN_PCIDEV_FRONTEND && EXPERIMENTAL
>+	default n
>+	help
>+	  This selects an implementation of the PCI frontend driver that is
>+	  architecture independent (i.e. it replaces the real architecture's
>+	  PCI code). The default is to use an implementation that works with
>+	  the architecture dependent PCI code (and you probably want the
>+	  default).
>+
>+	  If unsure, say N.
> 
> config XEN_BLKDEV_BACKEND
> 	bool "Block-device backend driver"
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/i386/Kconfig
>--- a/linux-2.6-xen-sparse/arch/xen/i386/Kconfig	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/arch/xen/i386/Kconfig	Fri Jan 27 18:57:35 2006
>@@ -788,9 +788,17 @@
> 	  information about which PCI hardware does work under Linux and which
> 	  doesn't.
> 
>+# need to enable this on other platforms to support XEN_PCI_FE_ARCH_REPLACE
>+config PCI_NATIVE
>+	bool
>+	depends on PCI
>+	default y if !XEN_PCI_FE_ARCH_REPLACE
>+    ---help---
>+	  Compile in Native PCI access (as opposed to Xen's PCI Frontend).
>+
> choice
> 	prompt "PCI access mode"
>-	depends on PCI && !X86_VISWS
>+	depends on PCI_NATIVE && !X86_VISWS
> 	default PCI_GOANY
> 	---help---
> 	  On PCI systems, the BIOS can be used to detect the PCI devices and
>@@ -810,6 +818,15 @@
> #config PCI_GOBIOS
> #	bool "BIOS"
> 
>+config PCI_GOXEN_PCI_FE_STUB
>+	bool "Xen PCI Frontend Stub"
>+	depends on XEN_PCIDEV_FRONTEND
>+	---help---
>+	  The Xen PCI Frontend stub replaces the architecture's means of talking
>+	  directly to the PCI host bridge with a "dummy" handler which will act
>+	  as somewhat of a placeholder until the real Xen PCI Frontend is
>+	  initialized.
>+
> config PCI_GOMMCONFIG
> 	bool "MMConfig"
> 
>@@ -835,6 +852,11 @@
> 	bool
> 	depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
> 	select ACPI_BOOT
>+	default y
>+
>+config XEN_PCI_FE_STUB
>+	bool
>+	depends on PCI && XEN_PCIDEV_FRONTEND && !XEN_PCI_FE_ARCH_REPLACE && (PCI_GOXEN_PCI_FE_STUB || PCI_GOANY)
> 	default y
> 
> source "drivers/pci/pcie/Kconfig"
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/i386/Makefile
>--- a/linux-2.6-xen-sparse/arch/xen/i386/Makefile	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/arch/xen/i386/Makefile	Fri Jan 27 18:57:35 2006
>@@ -82,7 +82,7 @@
> # \
> #					   arch/xen/$(mcore-y)/
> drivers-$(CONFIG_MATH_EMULATION)	+= arch/i386/math-emu/
>-drivers-$(CONFIG_PCI)			+= arch/xen/i386/pci/
>+drivers-$(CONFIG_PCI_NATIVE)		+= arch/xen/i386/pci/
> # must be linked after kernel/
> drivers-$(CONFIG_OPROFILE)		+= arch/i386/oprofile/
> drivers-$(CONFIG_PM)			+= arch/i386/power/
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile
>--- a/linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile	Fri Jan 27 18:57:35 2006
>@@ -7,6 +7,7 @@
> #c-obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
> c-obj-$(CONFIG_PCI_MMCONFIG)	+= mmconfig.o
> c-obj-$(CONFIG_PCI_DIRECT)	+= direct.o
>+c-obj-$(CONFIG_XEN_PCI_FE_STUB) += pcifront.o
> 
> c-pci-y				:= fixup.o
> c-pci-$(CONFIG_ACPI_PCI)	+= acpi.o
>@@ -30,4 +31,6 @@
> # Make sure irq.o gets linked in before common.o
> obj-y	+= $(patsubst common.o,$(l-pci-y) common.o,$(c-obj-y))
> 
>+obj-$(CONFIG_XEN_PCIDEV_BACKEND_ALLOC) += alloc.o
>+
> clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-) $(c-link))
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c
>--- a/linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c	Fri Jan 27 18:57:35 2006
>@@ -58,6 +58,13 @@
> 			res->start = start;
> 		}
> 	}
>+#ifdef CONFIG_XEN_PCIDEV_BACKEND_ALLOC
>+	/* Ensure i/o memory is allocated on page boundaries */
>+	else if (res->flags & IORESOURCE_MEM) {
>+		unsigned long alignto = max(align,PAGE_SIZE);
>+		res->start = ALIGN(res->start,alignto);
>+	}
>+#endif
> }
> 
> 
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/Makefile
>--- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Fri Jan 27 18:57:35 2006
>@@ -16,4 +16,6 @@
> obj-$(CONFIG_XEN_NETDEV_FRONTEND)	+= netfront/
> obj-$(CONFIG_XEN_BLKDEV_TAP)    	+= blktap/
> obj-$(CONFIG_XEN_TPMDEV_FRONTEND)	+= tpmfront/
>+obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= pciback/
>+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront/
> 
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h
>--- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h	Fri Jan 27 18:57:35 2006
>@@ -124,6 +124,10 @@
> 
> #endif /* __KERNEL__ */
> 
>+#ifdef CONFIG_XEN_PCIDEV_FRONTEND
>+#include <asm-xen/pcifront.h>
>+#endif /* CONFIG_XEN_PCIDEV_FRONTEND */
>+
> /* implement the pci_ DMA API in terms of the generic device dma_ one */
> #include <asm-generic/pci-dma-compat.h>
> 
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/i386/pci/alloc.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/alloc.c	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,16 @@
>+/*
>+ * PCI Backend - Try to force a re-assignment of resources so that all
>+ *               memory resources are allocated on page boundaries
>+ */
>+#include <linux/kernel.h>
>+#include <linux/pci.h>
>+#include <linux/list.h>
>+
>+static __init int pciback_alloc(void)
>+{
>+	printk(KERN_INFO "pciback: Attempt to re-allocate PCI resources\n");
>+	pci_assign_unassigned_resources();
>+	return 0;
>+}
>+
>+subsys_initcall(pciback_alloc);
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/i386/pci/pcifront.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/pcifront.c	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,48 @@
>+/*
>+ * PCI Frontend Stub - puts some "dummy" functions in to the Linux x86 PCI core
>+ *                     to support the Xen PCI Frontend's operation
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <linux/init.h>
>+#include <linux/pci.h>
>+#include "pci.h"
>+
>+static int pcifront_enable_irq(struct pci_dev *dev)
>+{
>+	u8 irq;
>+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
>+	dev->irq = irq;
>+
>+	return 0;
>+}
>+
>+extern u8 pci_cache_line_size;
>+
>+static int __init pcifront_x86_stub_init(void)
>+{
>+	struct cpuinfo_x86 *c = &boot_cpu_data;
>+
>+	/* Only install our method if we haven't found real hardware already */
>+	if (raw_pci_ops)
>+		return 0;
>+
>+	printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
>+
>+	/* Copied from arch/i386/pci/common.c */
>+	pci_cache_line_size = 32 >> 2;
>+	if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
>+		pci_cache_line_size = 64 >> 2;	/* K7 & K8 */
>+	else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL)
>+		pci_cache_line_size = 128 >> 2;	/* P4 */
>+
>+	/* On x86, we need to disable the normal IRQ routing table and
>+	 * just ask the backend
>+	 */
>+	pcibios_enable_irq = pcifront_enable_irq;
>+
>+	return 0;
>+}
>+
>+arch_initcall(pcifront_x86_stub_init);
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/Makefile
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,11 @@
>+obj-y += pciback.o
>+
>+pciback-y := pci_stub.o pciback_ops.o xenbus.o
>+pciback-y += conf_space.o conf_space_header.o
>+pciback-${CONFIG_XEN_PCIDEV_BACKEND_VPCI} += vpci.o
>+pciback-${CONFIG_XEN_PCIDEV_BACKEND_PASS} += passthrough.o
>+
>+ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
>+CFLAGS_pci_stub.o += -DDEBUG
>+CFLAGS_xenbus.o += -DDEBUG
>+endif
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,315 @@
>+/*
>+ * PCI Backend - Functions for creating a virtual configuration space for
>+ *               exported PCI Devices.
>+ *               It's dangerous to allow PCI Driver Domains to change their
>+ *               device's resources (memory, i/o ports, interrupts). We need to
>+ *               restrict changes to certain PCI Configuration registers:
>+ *               BARs, INTERRUPT_PIN, most registers in the header...
>+ *
>+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+
>+#include <linux/kernel.h>
>+#include <linux/pci.h>
>+#include "pciback.h"
>+#include "conf_space.h"
>+
>+#define DEFINE_PCI_CONFIG(op,size,type) 					\
>+int pciback_##op##_config_##size 							\
>+(struct pci_dev *dev, int offset, type value, void *data)	\
>+{															\
>+	return pci_##op##_config_##size (dev, offset, value);	\
>+}
>+
>+DEFINE_PCI_CONFIG(read, byte, u8 *)
>+DEFINE_PCI_CONFIG(read, word, u16 *)
>+DEFINE_PCI_CONFIG(read, dword, u32 *)
>+
>+DEFINE_PCI_CONFIG(write, byte, u8)
>+DEFINE_PCI_CONFIG(write, word, u16)
>+DEFINE_PCI_CONFIG(write, dword, u32)
>+
>+static int conf_space_read(struct pci_dev *dev,
>+		struct config_field_entry *entry, int offset, u32 *value)
>+{
>+	int ret = 0;
>+	struct config_field *field = entry->field;
>+
>+	*value = 0;
>+
>+	switch (field->size) {
>+		case 1:
>+			if (field->u.b.read)
>+				ret = field->u.b.read(dev, offset, (u8*)value, entry->data);
>+			break;
>+		case 2:
>+			if (field->u.w.read)
>+				ret = field->u.w.read(dev, offset, (u16*)value, entry->data);
>+			break;
>+		case 4:
>+			if (field->u.dw.read)
>+				ret = field->u.dw.read(dev, offset, value, entry->data);
>+			break;
>+	}
>+	return ret;
>+}
>+
>+static int conf_space_write(struct pci_dev *dev,
>+		struct config_field_entry *entry, int offset, u32 value)
>+{
>+	int ret = 0;
>+	struct config_field *field = entry->field;
>+
>+	switch (field->size) {
>+		case 1:
>+			if (field->u.b.write)
>+				ret = field->u.b.write(dev, offset, (u8)value, entry->data);
>+			break;
>+		case 2:
>+			if (field->u.w.write)
>+				ret = field->u.w.write(dev, offset, (u16)value, entry->data);
>+			break;
>+		case 4:
>+			if (field->u.dw.write)
>+				ret = field->u.dw.write(dev, offset, value, entry->data);
>+			break;
>+	}
>+	return ret;
>+}
>+
>+static inline u32 get_mask(int size)
>+{
>+	if (size==1)
>+		return 0xff;
>+	else if (size==2)
>+		return 0xffff;
>+	else
>+		return 0xffffffff;
>+}
>+
>+static inline int valid_request(int offset, int size)
>+{
>+	/* Validate request (no un-aligned requests) */
>+	if ((size==1 || size==2 || size==4) && (offset%size)==0)
>+		return 1;
>+	return 0;
>+}
>+
>+static inline u32 merge_value( u32 val, u32 new_val, u32 new_val_mask,
>+		u32 offset)
>+{
>+	if (offset>=0) {
>+		new_val_mask <<= (offset*8);
>+		new_val <<= (offset*8);
>+	}
>+	else {
>+		new_val_mask >>= (offset*-8);
>+		new_val >>= (offset*-8);
>+	}
>+	val = (val&~new_val_mask)|(new_val&new_val_mask);
>+
>+	return val;
>+}
>+
>+static int pcibios_err_to_errno(int err)
>+{
>+	switch (err) {
>+		case PCIBIOS_SUCCESSFUL:
>+			return XEN_PCI_ERR_success;
>+		case PCIBIOS_DEVICE_NOT_FOUND:
>+			return XEN_PCI_ERR_dev_not_found;
>+		case PCIBIOS_BAD_REGISTER_NUMBER:
>+			return XEN_PCI_ERR_invalid_offset;
>+		case PCIBIOS_FUNC_NOT_SUPPORTED:
>+			return XEN_PCI_ERR_not_implemented;
>+		case PCIBIOS_SET_FAILED:
>+			return XEN_PCI_ERR_access_denied;
>+	}
>+	return err;
>+}
>+
>+int pciback_config_read(struct pci_dev *dev, int offset, int size, u32 *ret_val)
>+{
>+	int err = 0;
>+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
>+	struct config_field_entry *cfg_entry;
>+	struct config_field *field;
>+	int req_start, req_end, field_start, field_end;
>+	/* if read fails for any reason, return 0 (as if device didn't respond) */
>+	u32 value = 0, tmp_val;
>+
>+	if (unlikely(verbose_request))
>+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n",
>+				pci_name(dev), size, offset);
>+
>+	if (!valid_request(offset, size)) {
>+		err = XEN_PCI_ERR_invalid_offset;
>+		goto out;
>+	}
>+
>+	/* Get the real value first, then modify as appropriate */
>+	switch (size) {
>+		case 1:
>+			err = pci_read_config_byte(dev,offset, (u8*)&value);
>+			break;
>+		case 2:
>+			err = pci_read_config_word(dev,offset, (u16*)&value);
>+			break;
>+		case 4:
>+			err = pci_read_config_dword(dev,offset, &value);
>+			break;
>+	}
>+
>+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
>+		field = cfg_entry->field;
>+
>+		req_start = offset;
>+		req_end = offset+size;
>+		field_start = field->offset;
>+		field_end = field->offset + field->size;
>+
>+		if ((req_start>=field_start && req_start<field_end)
>+				|| (req_end>field_start && req_end<=field_end)) {
>+			err = conf_space_read(dev, cfg_entry, offset, &tmp_val);
>+			if (err)
>+				goto out;
>+
>+			value = merge_value(value, tmp_val, get_mask(field->size),
>+					field_start - req_start);
>+		}
>+	}
>+
>+out:
>+	if (unlikely(verbose_request))
>+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
>+				pci_name(dev), size, offset, value);
>+
>+	*ret_val = value;
>+	return pcibios_err_to_errno(err);
>+}
>+
>+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
>+{
>+	int err = 0;
>+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
>+	struct config_field_entry *cfg_entry;
>+	struct config_field *field;
>+	u32 tmp_val;
>+	int req_start, req_end, field_start, field_end;
>+
>+	if (unlikely(verbose_request))
>+		printk(KERN_DEBUG "pciback: %s: write request %d bytes at 0x%x = %x\n",
>+				pci_name(dev), size, offset, value);
>+
>+	if (!valid_request(offset, size))
>+		return XEN_PCI_ERR_invalid_offset;
>+
>+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
>+		field = cfg_entry->field;
>+
>+		req_start = offset;
>+		req_end = offset+size;
>+		field_start = field->offset;
>+		field_end = field->offset + field->size;
>+
>+		if ((req_start>=field_start && req_start<field_end)
>+				|| (req_end>field_start && req_end<=field_end)) {
>+			tmp_val = 0;
>+
>+			err = pciback_config_read(dev, offset, size, &tmp_val);
>+			if (err)
>+				break;
>+
>+			tmp_val = merge_value(tmp_val, value, get_mask(size),
>+					field_start - req_start);
>+
>+			err = conf_space_write(dev, cfg_entry, offset, tmp_val);
>+		}
>+	}
>+
>+	return pcibios_err_to_errno(err);
>+}
>+
>+void pciback_config_reset(struct pci_dev *dev)
>+{
>+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
>+	struct config_field_entry *cfg_entry;
>+	struct config_field *field;
>+
>+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
>+		field = cfg_entry->field;
>+
>+		if (field->reset)
>+			field->reset(dev, field->offset, cfg_entry->data);
>+	}
>+}
>+
>+void pciback_config_free(struct pci_dev *dev)
>+{
>+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
>+	struct config_field_entry *cfg_entry, *t;
>+	struct config_field *field;
>+
>+	list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
>+		list_del(&cfg_entry->list);
>+
>+		field = cfg_entry->field;
>+
>+		if (field->release)
>+			field->release(dev, field->offset, cfg_entry->data);
>+
>+		kfree(cfg_entry);
>+	}
>+}
>+
>+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field)
>+{
>+	int err = 0;
>+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
>+	struct config_field_entry *cfg_entry;
>+	void *tmp;
>+   
>+	cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
>+	if (!cfg_entry) {
>+		err = -ENOMEM;
>+		goto out;
>+	}
>+
>+	cfg_entry->data  = NULL;
>+	cfg_entry->field = field;
>+
>+	if (field->init) {
>+		tmp = field->init(dev, field->offset);
>+
>+		if (IS_ERR(tmp)) {
>+			err = PTR_ERR(tmp);
>+			goto out;
>+		}
>+
>+		cfg_entry->data = tmp;
>+	}
>+
>+	list_add_tail(&cfg_entry->list, &dev_data->config_fields);
>+
>+out:
>+	if (err)
>+		kfree(cfg_entry);
>+
>+	return err;
>+}
>+
>+/* This sets up the device's virtual configuration space to keep track of 
>+ * certain registers (like the base address registers (BARs) so that we can
>+ * keep the client from manipulating them directly.
>+ */
>+int pciback_config_init(struct pci_dev *dev)
>+{
>+	int err = 0;
>+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
>+
>+	INIT_LIST_HEAD(&dev_data->config_fields);
>+
>+	err = pciback_config_header_add_fields(dev);
>+
>+	return err;
>+}
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,97 @@
>+/*
>+ * PCI Backend - Common data structures for overriding the configuration space
>+ *
>+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+
>+#ifndef __XEN_PCIBACK_CONF_SPACE_H__
>+#define __XEN_PCIBACK_CONF_SPACE_H__
>+
>+#include <linux/list.h>
>+
>+typedef void *(*conf_field_init)(struct pci_dev *dev, int offset);
>+typedef void (*conf_field_reset)(struct pci_dev *dev, int offset, void *data);
>+typedef void (*conf_field_free)(struct pci_dev *dev, int offset, void *data);
>+
>+typedef int (*conf_dword_write)(struct pci_dev *dev, int offset, u32 value,
>+		void *data);
>+typedef int (*conf_word_write)(struct pci_dev *dev, int offset, u16 value,
>+		void *data);
>+typedef int (*conf_byte_write)(struct pci_dev *dev, int offset, u8 value,
>+		void *data);
>+typedef int (*conf_dword_read)(struct pci_dev *dev, int offset, u32 *value,
>+		void *data);
>+typedef int (*conf_word_read)(struct pci_dev *dev, int offset, u16 *value,
>+		void *data);
>+typedef int (*conf_byte_read)(struct pci_dev *dev, int offset, u8 *value,
>+		void *data);
>+
>+/* These are the fields within the configuration space which we
>+ * are interested in intercepting reads/writes to and changing their
>+ * values.
>+ */
>+struct config_field {
>+	unsigned int     offset;
>+	unsigned int     size;
>+	conf_field_init  init;
>+	conf_field_reset reset;
>+	conf_field_free  release;
>+	union {
>+		struct {
>+			conf_dword_write write;
>+			conf_dword_read  read;
>+		} dw;
>+		struct {
>+			conf_word_write write;
>+			conf_word_read  read;
>+		} w;
>+		struct {
>+			conf_byte_write write;
>+			conf_byte_read  read;
>+		} b;
>+	} u;
>+};
>+
>+struct config_field_entry {
>+	struct list_head      list;
>+	struct config_field  *field;
>+	void                 *data;
>+};
>+
>+/* Add fields to a device - the add_fields macro expects to get a pointer to
>+ * the first entry in an array (of which the ending is marked by size==0)
>+ */
>+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field);
>+static inline int pciback_config_add_fields(struct pci_dev *dev,
>+		struct config_field *field)
>+{
>+	int i, err = 0;
>+	for (i=0; field[i].size!=0; i++) {
>+		err = pciback_config_add_field(dev, &field[i]);
>+		if (err)
>+			break;
>+	}
>+	return err;
>+}
>+
>+/* Initializers which add fields to the virtual configuration space
>+ * ** We could add initializers to allow a guest domain to touch
>+ * the capability lists (for power management, the AGP bridge, etc.)
>+ */
>+int pciback_config_header_add_fields(struct pci_dev *dev);
>+
>+/* Read/Write the real configuration space */
>+int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 *value,
>+		void *data);
>+int pciback_read_config_word(struct pci_dev *dev, int offset, u16 *value,
>+		void *data);
>+int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 *value,
>+		void *data);
>+int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
>+		void *data);
>+int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value,
>+		void *data);
>+int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
>+		void *data);
>+
>+#endif /* __XEN_PCIBACK_CONF_SPACE_H__ */
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,324 @@
>+/*
>+ * PCI Backend - Handles the virtual fields in the configuration space headers.
>+ *
>+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+
>+#include <linux/kernel.h>
>+#include <linux/pci.h>
>+#include "pciback.h"
>+#include "conf_space.h"
>+
>+struct pci_bar_info {
>+	u32 val;
>+	u32 len_val;
>+	int which;
>+};
>+
>+#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
>+#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
>+
>+static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
>+{
>+	if (!dev->is_enabled && is_enable_cmd(value)) {
>+		if (unlikely(verbose_request))
>+			printk(KERN_DEBUG "pciback: %s: enable\n",
>+					pci_name(dev));
>+		dev->is_enabled = 1;
>+		pcibios_enable_device(dev, (1<<PCI_NUM_RESOURCES)-1);
>+	}
>+	else if (dev->is_enabled && !is_enable_cmd(value)) {
>+		if (unlikely(verbose_request))
>+			printk(KERN_DEBUG "pciback: %s: disable\n",
>+					pci_name(dev));
>+		pciback_disable_device(dev);
>+	}
>+
>+	if (!dev->is_busmaster && is_master_cmd(value)) {
>+		if (unlikely(verbose_request))
>+			printk(KERN_DEBUG "pciback: %s: set bus master\n",
>+					pci_name(dev));
>+		dev->is_busmaster = 1;
>+		pcibios_set_master(dev);
>+	}
>+
>+	if (value & PCI_COMMAND_INVALIDATE) {
>+		if (unlikely(verbose_request))
>+			printk(KERN_DEBUG "pciback: %s: enable memory-write-invalidate\n",
>+					pci_name(dev));
>+		pci_set_mwi(dev);
>+	}
>+
>+	return pci_write_config_word(dev, offset, value);
>+}
>+
>+static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
>+{
>+	struct pci_bar_info *bar = data;
>+	int i;
>+
>+	if (unlikely(!bar)) {
>+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
>+				pci_name(dev));
>+		return XEN_PCI_ERR_op_failed;
>+	}
>+
>+	bar->which = 0;
>+	/* Because writes *could* occur in bytes, if any byte is all 1s, switch */
>+	for (i=0; i<4; i++)
>+		if (((value>>(i*8))&0xff)==0xff)
>+			bar->which = 1;
>+
>+	/* Do we need to support enabling/disabling the rom address here? */
>+
>+	return 0;
>+}
>+
>+/* For the BARs, only allow writes which write ~0 or
>+ * the correct resource information
>+ * (Needed for when the driver probes the resource usage)
>+ */
>+static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
>+{
>+	int i;
>+	struct pci_bar_info *bar = data;
>+
>+	if (unlikely(!bar)) {
>+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
>+				pci_name(dev));
>+		return XEN_PCI_ERR_op_failed;
>+	}
>+
>+	bar->which = 0;
>+	/* Because writes *could* occur in bytes, if any byte is all 1s, switch */
>+	for (i=0; i<4; i++)
>+		if (((value>>(i*8))&0xff)==0xff)
>+			bar->which = 1;
>+
>+	return 0;
>+}
>+
>+static int bar_read(struct pci_dev *dev, int offset, u32 *value, void *data)
>+{
>+	struct pci_bar_info *bar = data;
>+
>+	if (unlikely(!bar)) {
>+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
>+				pci_name(dev));
>+		return XEN_PCI_ERR_op_failed;
>+	}
>+
>+	*value = bar->which ? bar->len_val : bar->val;
>+
>+	return 0;
>+}
>+
>+static inline void read_dev_bar(struct pci_dev *dev, struct pci_bar_info *bar_info,
>+		int offset, u32 len_mask)
>+{
>+	pci_read_config_dword(dev, offset, &bar_info->val);
>+	pci_write_config_dword(dev, offset, len_mask);
>+	pci_read_config_dword(dev, offset, &bar_info->len_val);
>+	pci_write_config_dword(dev, offset, bar_info->val);
>+}
>+
>+static void *bar_init(struct pci_dev *dev, int offset)
>+{
>+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
>+
>+	if (!bar)
>+		return ERR_PTR(-ENOMEM);
>+
>+	read_dev_bar(dev, bar, offset, ~0);
>+	bar->which = 0;
>+
>+	return bar;
>+}
>+
>+static void *rom_init(struct pci_dev *dev, int offset)
>+{
>+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
>+
>+	if (!bar)
>+		return ERR_PTR(-ENOMEM);
>+
>+	read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
>+	bar->which = 0;
>+
>+	return bar;
>+}
>+
>+static void bar_reset(struct pci_dev *dev, int offset, void *data)
>+{
>+	struct pci_bar_info *bar = data;
>+
>+	bar->which = 0;
>+}
>+
>+static void bar_release(struct pci_dev *dev, int offset, void *data)
>+{
>+	kfree(data);
>+}
>+
>+static int interrupt_read(struct pci_dev *dev, int offset, u8 *value,
>+		void *data)
>+{
>+	*value = (u8)dev->irq;
>+
>+	return 0;
>+}
>+
>+struct config_field header_common[] = {
>+	{
>+		.offset     = PCI_COMMAND,
>+		.size       = 2,
>+		.u.w.read   = pciback_read_config_word,
>+		.u.w.write  = command_write,
>+	},
>+	{
>+		.offset     = PCI_INTERRUPT_LINE,
>+		.size       = 1,
>+		.u.b.read   = interrupt_read,
>+		.u.b.write  = NULL,
>+	},
>+	{
>+		/* Any side effects of letting driver domain control cache line? */
>+		.offset     = PCI_CACHE_LINE_SIZE,
>+		.size       = 1,
>+		.u.b.read   = pciback_read_config_byte,
>+		.u.b.write  = pciback_write_config_byte,
>+	},
>+	{
>+		.size           = 0,
>+	},
>+};
>+
>+struct config_field header_0[] = {
>+	{
>+		.offset     = PCI_BASE_ADDRESS_0,
>+		.size       = 4,
>+		.init       = bar_init,
>+		.reset      = bar_reset,
>+		.release    = bar_release,
>+		.u.dw.read  = bar_read,
>+		.u.dw.write = bar_write,
>+	},
>+	{
>+		.offset     = PCI_BASE_ADDRESS_1,
>+		.size       = 4,
>+		.init       = bar_init,
>+		.reset      = bar_reset,
>+		.release    = bar_release,
>+		.u.dw.read  = bar_read,
>+		.u.dw.write = bar_write,
>+	},
>+	{
>+		.offset     = PCI_BASE_ADDRESS_2,
>+		.size       = 4,
>+		.init       = bar_init,
>+		.reset      = bar_reset,
>+		.release    = bar_release,
>+		.u.dw.read  = bar_read,
>+		.u.dw.write = bar_write,
>+	},
>+	{
>+		.offset     = PCI_BASE_ADDRESS_3,
>+		.size       = 4,
>+		.init       = bar_init,
>+		.reset      = bar_reset,
>+		.release    = bar_release,
>+		.u.dw.read  = bar_read,
>+		.u.dw.write = bar_write,
>+	},
>+	{
>+		.offset     = PCI_BASE_ADDRESS_4,
>+		.size       = 4,
>+		.init       = bar_init,
>+		.reset      = bar_reset,
>+		.release    = bar_release,
>+		.u.dw.read  = bar_read,
>+		.u.dw.write = bar_write,
>+	},
>+	{
>+		.offset     = PCI_BASE_ADDRESS_5,
>+		.size       = 4,
>+		.init       = bar_init,
>+		.reset      = bar_reset,
>+		.release    = bar_release,
>+		.u.dw.read  = bar_read,
>+		.u.dw.write = bar_write,
>+	},
>+	{
>+		.offset     = PCI_ROM_ADDRESS,
>+		.size       = 4,
>+		.init       = rom_init,
>+		.reset      = bar_reset,
>+		.release    = bar_release,
>+		.u.dw.read  = bar_read,
>+		.u.dw.write = rom_write,
>+	},
>+	{
>+		.size       = 0,
>+	},
>+};
>+
>+struct config_field header_1[] = {
>+	{
>+		.offset     = PCI_BASE_ADDRESS_0,
>+		.size       = 4,
>+		.init       = bar_init,
>+		.reset      = bar_reset,
>+		.release    = bar_release,
>+		.u.dw.read  = bar_read,
>+		.u.dw.write = bar_write,
>+	},
>+	{
>+		.offset     = PCI_BASE_ADDRESS_1,
>+		.size       = 4,
>+		.init       = bar_init,
>+		.reset      = bar_reset,
>+		.release    = bar_release,
>+		.u.dw.read  = bar_read,
>+		.u.dw.write = bar_write,
>+	},
>+	{
>+		.offset     = PCI_ROM_ADDRESS1,
>+		.size       = 4,
>+		.init       = rom_init,
>+		.reset      = bar_reset,
>+		.release    = bar_release,
>+		.u.dw.read  = bar_read,
>+		.u.dw.write = rom_write,
>+	},
>+	{
>+		.size           = 0,
>+	},
>+};
>+
>+int pciback_config_header_add_fields(struct pci_dev *dev)
>+{
>+	int err;
>+
>+	err = pciback_config_add_fields(dev, header_common);
>+	if (err)
>+		goto out;
>+
>+	switch (dev->hdr_type) {
>+		case PCI_HEADER_TYPE_NORMAL:
>+			err = pciback_config_add_fields(dev, header_0);
>+			break;
>+
>+		case PCI_HEADER_TYPE_BRIDGE:
>+			err = pciback_config_add_fields(dev, header_1);
>+			break;
>+
>+		default:
>+			err = -EINVAL;
>+			printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
>+					pci_name(dev), dev->hdr_type);
>+			break;
>+	}
>+
>+out:
>+	return err;
>+}
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,112 @@
>+/*
>+ * PCI Backend - Provides restricted access to the real PCI bus topology
>+ *               to the frontend
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+
>+#include <linux/list.h>
>+#include <linux/pci.h>
>+#include "pciback.h"
>+
>+typedef struct {
>+	struct list_head dev_list;
>+} passthrough_dev_data_t;
>+
>+struct pci_dev * pciback_get_pci_dev(struct pciback_device *pdev,
>+		unsigned int domain, unsigned int bus, unsigned int devfn)
>+{
>+	passthrough_dev_data_t *dev_data = pdev->pci_dev_data;
>+	struct pci_dev_entry *dev_entry;
>+
>+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
>+		if (domain==(unsigned int)pci_domain_nr(dev_entry->dev->bus)
>+				&& bus==(unsigned int)dev_entry->dev->bus->number
>+				&& devfn==dev_entry->dev->devfn)
>+			return dev_entry->dev;
>+	}
>+		
>+	return NULL;
>+}
>+
>+/* Must hold pciback_device->dev_lock when calling this */
>+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
>+{
>+	passthrough_dev_data_t *dev_data = pdev->pci_dev_data;
>+	struct pci_dev_entry *dev_entry;
>+
>+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
>+	if (!dev_entry)
>+		return -ENOMEM;
>+	dev_entry->dev = dev;
>+
>+	list_add_tail(&dev_entry->list, &dev_data->dev_list);
>+
>+	return 0;
>+}
>+
>+int pciback_init_devices(struct pciback_device *pdev)
>+{
>+	passthrough_dev_data_t *dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
>+	if (!dev_data)
>+		return -ENOMEM;
>+
>+	INIT_LIST_HEAD(&dev_data->dev_list);
>+
>+	pdev->pci_dev_data = dev_data;
>+
>+	return 0;
>+}
>+
>+int pciback_publish_pci_roots(struct pciback_device *pdev,
>+		publish_pci_root_cb publish_root_cb)
>+{
>+	int err = 0;
>+	passthrough_dev_data_t *dev_data = pdev->pci_dev_data;
>+	struct pci_dev_entry *dev_entry, *e;
>+	struct pci_dev *dev;
>+	int found;
>+
>+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
>+
>+		/* Only publish this device as a root if none of its parent bridges
>+		 * are exported
>+		 */
>+		found = 0;
>+		dev = dev_entry->dev->bus->self;
>+		for (; !found && dev!=NULL; dev=dev->bus->self) {
>+			list_for_each_entry(e, &dev_data->dev_list, list) {
>+				if (dev==e->dev) {
>+					found = 1;
>+					break;
>+				}
>+			}
>+		}
>+
>+		if (!found) {
>+			err = publish_root_cb(pdev,
>+					(unsigned int)pci_domain_nr(dev_entry->dev->bus),
>+				(unsigned int)dev_entry->dev->bus->number);
>+			if (err)
>+				break;
>+		}
>+	}
>+
>+	return err;
>+}
>+
>+/* Must hold pciback_device->dev_lock when calling this */
>+void pciback_release_devices(struct pciback_device *pdev)
>+{
>+	passthrough_dev_data_t *dev_data = pdev->pci_dev_data;
>+	struct pci_dev_entry *dev_entry, *t;
>+
>+	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
>+		list_del(&dev_entry->list);
>+		pcistub_put_pci_dev(dev_entry->dev);
>+		kfree(dev_entry);
>+	}
>+
>+	kfree(dev_data);
>+	pdev->pci_dev_data = NULL;
>+}
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,368 @@
>+/*
>+ * PCI Stub Driver - Grabs devices in backend to be exported later
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <linux/init.h>
>+#include <linux/list.h>
>+#include <linux/spinlock.h>
>+#include <asm/atomic.h>
>+#include "pciback.h"
>+
>+static char * pci_devs_to_hide = NULL;
>+module_param_named(hide,pci_devs_to_hide,charp,0444);
>+
>+struct pci_stub_device_id {
>+	struct list_head slot_list;
>+	int domain;
>+	unsigned char bus;
>+	unsigned int devfn;
>+};
>+LIST_HEAD(pci_stub_device_ids);
>+
>+struct pci_stub_device {
>+	struct list_head dev_list;
>+	struct pci_dev *dev;
>+	atomic_t in_use;
>+};
>+/* Access to pci_stub_devices & seized_devices lists and the initialize_devices
>+ * flag must be locked with pci_stub_devices_lock
>+ */
>+DEFINE_SPINLOCK(pci_stub_devices_lock);
>+LIST_HEAD(pci_stub_devices);
>+
>+/* wait for device_initcall before initializing our devices
>+ * (see pcistub_init_devices_late)
>+ */
>+static int initialize_devices = 0;
>+LIST_HEAD(seized_devices);
>+
>+static inline struct pci_dev * get_pci_dev(struct pci_stub_device *psdev)
>+{
>+	if (atomic_dec_and_test(&psdev->in_use))
>+		return psdev->dev;
>+	else {
>+		atomic_inc(&psdev->in_use);
>+		return NULL;
>+	}
>+}
>+
>+struct pci_dev * pcistub_get_pci_dev_by_slot(int domain, int bus,
>+		int slot, int func)
>+{
>+	struct pci_stub_device *psdev;
>+	struct pci_dev *found_dev = NULL;
>+
>+	spin_lock(&pci_stub_devices_lock);
>+
>+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
>+		if( psdev->dev!=NULL
>+				&& domain==pci_domain_nr(psdev->dev->bus)
>+				&& bus==psdev->dev->bus->number
>+				&& PCI_DEVFN(slot,func)==psdev->dev->devfn ) {
>+			found_dev = get_pci_dev(psdev);
>+			break;
>+		}
>+	}
>+
>+	spin_unlock(&pci_stub_devices_lock);
>+	return found_dev;
>+}
>+
>+struct pci_dev * pcistub_get_pci_dev(struct pci_dev *dev)
>+{
>+	struct pci_stub_device *psdev;
>+	struct pci_dev *found_dev = NULL;
>+
>+	spin_lock(&pci_stub_devices_lock);
>+
>+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
>+		if( psdev->dev==dev ) {
>+			found_dev = get_pci_dev(psdev);
>+			break;
>+		}
>+	}
>+
>+	spin_unlock(&pci_stub_devices_lock);
>+	return found_dev;
>+}
>+
>+void pcistub_put_pci_dev(struct pci_dev *dev)
>+{
>+	struct pci_stub_device *psdev;
>+
>+	spin_lock(&pci_stub_devices_lock);
>+
>+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
>+		if( psdev->dev==dev ) {
>+			/* Cleanup our device (so it's ready for the next domain) */
>+			pciback_reset_device(psdev->dev);
>+
>+			atomic_inc(&psdev->in_use);
>+			break;
>+		}
>+	}
>+
>+	spin_unlock(&pci_stub_devices_lock);
>+}
>+
>+static int __devinit pcistub_match(struct pci_dev *dev,
>+		struct pci_stub_device_id *pdev_id)
>+{
>+	/* Match the specified device by domain, bus, slot, func and also if
>+	 * any of the device's parent bridges match.
>+	 */
>+	for(; dev!=NULL; dev=dev->bus->self) {
>+		if (pci_domain_nr(dev->bus)==pdev_id->domain
>+					&& dev->bus->number==pdev_id->bus
>+					&& dev->devfn==pdev_id->devfn)
>+			return 1;
>+	}
>+
>+	return 0;
>+}
>+
>+static int __devinit pcistub_init_device(struct pci_dev *dev)
>+{
>+	struct pciback_dev_data *dev_data;
>+	int err = 0;
>+
>+	/* The PCI backend is not intended to be a module (or to work with
>+	 * removable PCI devices (yet). If it were, pciback_config_free()
>+	 * would need to be called somewhere to free the memory allocated
>+	 * here and then to call kfree(pci_get_drvdata(psdev->dev)).
>+	 */
>+	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
>+	if (!dev_data) {
>+		err = -ENOMEM;
>+		goto out;
>+	}
>+	pci_set_drvdata(dev, dev_data);
>+
>+	err = pciback_config_init(dev);
>+	if (err)
>+		goto out;
>+
>+	/* HACK: Force device (& ACPI) to determine what IRQ it's on - we
>+	 * must do this here because pcibios_enable_device may specify
>+	 * the pci device's true irq (and possibly its other resources)
>+	 * if they differ from what's in the configuration space.
>+	 * This makes the assumption that the device's resources won't
>+	 * change after this point (otherwise this code may break!)
>+	 */
>+	err = pci_enable_device(dev);
>+	if (err)
>+		goto config_release;
>+
>+	/* Now disable the device (this also ensures some private device
>+	 * data is setup before we export)
>+	 * This calls pciback_config_reset(dev)
>+	 */
>+	pciback_reset_device(dev);
>+
>+	return 0;
>+
>+config_release:
>+	pciback_config_free(dev);
>+
>+out:
>+	pci_set_drvdata(dev, NULL);
>+	kfree(dev_data);
>+	return err;
>+}
>+
>+/*
>+ * Because some initialization still happens on
>+ * devices during fs_initcall, we need to defer
>+ * full initialization of our devices until
>+ * device_initcall.
>+ */
>+static int __init pcistub_init_devices_late(void)
>+{
>+	struct pci_stub_device *psdev, *t;
>+	int err = 0;
>+
>+	spin_lock(&pci_stub_devices_lock);
>+
>+	list_for_each_entry_safe(psdev, t, &seized_devices, dev_list) {
>+		list_del(&psdev->dev_list);
>+		err = pcistub_init_device(psdev->dev);
>+		if (err) {
>+			printk(KERN_ERR "pciback: error %d initializing device %s\n",
>+					err, pci_name(psdev->dev));
>+			kfree(psdev);
>+			continue;
>+		}
>+
>+		list_add_tail(&psdev->dev_list, &pci_stub_devices);
>+	}
>+
>+	initialize_devices = 1;
>+
>+	spin_unlock(&pci_stub_devices_lock);
>+
>+	return 0;
>+}
>+device_initcall(pcistub_init_devices_late);
>+
>+static int __devinit pcistub_seize(struct pci_dev *dev)
>+{
>+	struct pci_stub_device *psdev;
>+	int err = 0;
>+
>+	psdev = kmalloc(sizeof(*psdev), GFP_KERNEL);
>+	if (!psdev)
>+		return -ENOMEM;
>+
>+	psdev->dev = dev;
>+	atomic_set(&psdev->in_use,1);
>+
>+	spin_lock(&pci_stub_devices_lock);
>+
>+	if (initialize_devices) {
>+		err = pcistub_init_device(psdev->dev);
>+		if (err)
>+			goto out;
>+
>+		list_add(&psdev->dev_list, &pci_stub_devices);
>+	}
>+	else
>+		list_add(&psdev->dev_list, &seized_devices);
>+
>+out:
>+	spin_unlock(&pci_stub_devices_lock);
>+
>+	if (err)
>+		kfree(psdev);
>+
>+	return err;
>+}
>+
>+static int __devinit pcistub_probe(struct pci_dev *dev,
>+		const struct pci_device_id *id)
>+{
>+	struct pci_stub_device_id *pdev_id;
>+	struct pci_dev *seized_dev;
>+	int err = 0;
>+
>+	list_for_each_entry(pdev_id, &pci_stub_device_ids, slot_list) {
>+
>+		if (!pcistub_match(dev, pdev_id))
>+			continue;
>+
>+		if (dev->hdr_type!=PCI_HEADER_TYPE_NORMAL
>+				&& dev->hdr_type!=PCI_HEADER_TYPE_BRIDGE) {
>+			printk(KERN_ERR "pciback: can't export pci devices that don't "
>+					"have a normal (0) or bridge (1) header type! dev=%s\n",
>+					pci_name(dev));
>+			break;
>+		}
>+
>+		pr_info("pciback: seizing PCI device %s\n", pci_name(dev));
>+		seized_dev = pci_dev_get(dev);
>+
>+		if (seized_dev) {
>+			err = pcistub_seize(seized_dev);
>+			if (err) {
>+				pci_dev_put(dev);
>+				goto out;
>+			}
>+
>+			/* Success! */
>+			goto out;
>+		}
>+	}
>+
>+	/* Didn't find the device */
>+	err = -ENODEV;
>+
>+out:
>+	return err;
>+}
>+
>+struct pci_device_id pcistub_ids[] = {
>+	{ 
>+		.vendor = PCI_ANY_ID,
>+		.device = PCI_ANY_ID,
>+		.subvendor = PCI_ANY_ID,
>+		.subdevice = PCI_ANY_ID,
>+	},
>+	{ 0, },
>+};
>+
>+/*
>+ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't
>+ * for a normal device. I don't want it to be loaded automatically.
>+ */
>+
>+struct pci_driver pciback_pci_driver = {
>+	.name = "pciback",
>+	.id_table = pcistub_ids,
>+	.probe = pcistub_probe,
>+};
>+
>+static int __init pcistub_init(void)
>+{
>+	int pos=0;
>+	struct pci_stub_device_id *pci_dev_id;
>+	int err = 0;
>+	int domain, bus, slot, func;
>+	int parsed;
>+
>+	if (pci_devs_to_hide && *pci_devs_to_hide) {
>+		do {
>+			parsed = 0;
>+
>+			err = sscanf(pci_devs_to_hide+pos," (%x:%x:%x.%x) %n",
>+						&domain, &bus, &slot, &func, &parsed);
>+			if (err!=4) {
>+				domain = 0;
>+				err = sscanf(pci_devs_to_hide+pos," (%x:%x.%x) %n",
>+						&bus, &slot, &func, &parsed);
>+				if (err!=3)
>+					goto parse_error;
>+			}
>+
>+			pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
>+			if (!pci_dev_id) {
>+				err = -ENOMEM;
>+				goto out;
>+			}
>+			pci_dev_id->domain = domain;
>+			pci_dev_id->bus = bus;
>+			pci_dev_id->devfn = PCI_DEVFN(slot,func);
>+
>+			pr_debug("pciback: wants to seize %04x:%02x:%02x.%01x\n",
>+					domain, bus, slot, func);
>+
>+			list_add_tail(&pci_dev_id->slot_list,&pci_stub_device_ids);
>+
>+			/* if parsed<=0, we've reached the end of the string */
>+			pos+=parsed;
>+		} while (parsed>0 && pci_devs_to_hide[pos]);
>+
>+		/* If we're the first PCI Device Driver to register, we're the
>+		 * first one to get offered PCI devices as they become
>+		 * available (and thus we can be the first to grab them)
>+		 */
>+		pci_register_driver(&pciback_pci_driver);
>+	}
>+
>+out:
>+	return err;
>+
>+parse_error:
>+	printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n",
>+			pci_devs_to_hide+pos);
>+	return -EINVAL;
>+}
>+
>+/*
>+ * fs_initcall happens before device_initcall
>+ * so pciback *should* get called first (b/c we 
>+ * want to suck up any device before other drivers
>+ * get a chance by being the first pci device
>+ * driver to register)
>+ */
>+fs_initcall(pcistub_init);
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,72 @@
>+/*
>+ * PCI Backend Common Data Structures & Function Declarations
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#ifndef __XEN_PCIBACK_H__
>+#define __XEN_PCIBACK_H__
>+
>+#include <linux/pci.h>
>+#include <linux/interrupt.h>
>+#include <asm-xen/xenbus.h>
>+#include <linux/list.h>
>+#include <linux/spinlock.h>
>+#include <asm-xen/xen-public/io/pciif.h>
>+
>+struct pci_dev_entry {
>+	struct list_head list;
>+	struct pci_dev *dev;
>+};
>+
>+struct pciback_device {
>+	void *pci_dev_data;
>+	spinlock_t dev_lock;
>+
>+	struct xenbus_device *xdev;
>+
>+	struct xenbus_watch be_watch;
>+	u8 be_watching;
>+
>+	int evtchn_irq;
>+
>+	struct xen_pci_sharedinfo * sh_info;
>+};
>+
>+struct pciback_dev_data {
>+	struct list_head config_fields;
>+};
>+
>+/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
>+struct pci_dev * pcistub_get_pci_dev_by_slot(int domain, int bus,
>+		int slot, int func);
>+struct pci_dev * pcistub_get_pci_dev(struct pci_dev *dev);
>+void pcistub_put_pci_dev(struct pci_dev *dev);
>+
>+/* Ensure a device is turned off or reset */
>+void pciback_disable_device(struct pci_dev *dev);
>+void pciback_reset_device(struct pci_dev *pdev);
>+
>+/* Access a virtual configuration space for a PCI device */
>+int pciback_config_init(struct pci_dev *dev);
>+void pciback_config_reset(struct pci_dev *dev);
>+void pciback_config_free(struct pci_dev *dev);
>+int pciback_config_read(struct pci_dev *dev, int offset, int size,
>+		u32 *ret_val);
>+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
>+
>+/* Handle requests for specific devices from the frontend */
>+typedef int (*publish_pci_root_cb)(struct pciback_device *pdev,
>+		unsigned int domain, unsigned int bus);
>+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
>+struct pci_dev * pciback_get_pci_dev(struct pciback_device *pdev,
>+		unsigned int domain, unsigned int bus, unsigned int devfn);
>+int pciback_init_devices(struct pciback_device *pdev);
>+int pciback_publish_pci_roots(struct pciback_device *pdev,
>+		publish_pci_root_cb cb);
>+void pciback_release_devices(struct pciback_device *pdev);
>+
>+/* Handles events from front-end */
>+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
>+
>+extern int verbose_request;
>+#endif
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,84 @@
>+/*
>+ * PCI Backend Operations - respond to PCI requests from Frontend
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <asm/bitops.h>
>+#include "pciback.h"
>+
>+int verbose_request = 0;
>+module_param(verbose_request,int,0644);
>+
>+/* For those architectures without a pcibios_disable_device */
>+void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {}
>+
>+void pciback_disable_device(struct pci_dev *dev)
>+{
>+	if (dev->is_enabled) {
>+		dev->is_enabled = 0;
>+		pcibios_disable_device(dev);
>+	}
>+}
>+
>+/* Ensure a device is "turned off" and ready to be exported.
>+ * This also sets up the device's private data to keep track of what should
>+ * be in the base address registers (BARs) so that we can keep the
>+ * client from manipulating them directly.
>+ */
>+void pciback_reset_device(struct pci_dev *dev)
>+{
>+	u16 cmd;
>+
>+	/* Disable devices (but not bridges) */
>+	if (dev->hdr_type==PCI_HEADER_TYPE_NORMAL) {
>+		pciback_disable_device(dev);
>+
>+		pci_write_config_word(dev, PCI_COMMAND, 0);
>+
>+		dev->is_enabled = 0;
>+		dev->is_busmaster = 0;
>+	}
>+	else {
>+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
>+		if (cmd&(PCI_COMMAND_INVALIDATE)) {
>+			cmd &= ~(PCI_COMMAND_INVALIDATE);
>+			pci_write_config_word(dev, PCI_COMMAND, cmd);
>+
>+			dev->is_busmaster = 0;
>+		}
>+	}
>+
>+	pciback_config_reset(dev);
>+}
>+
>+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
>+{
>+	struct pciback_device *pdev = dev_id;
>+	struct pci_dev *dev;
>+	struct xen_pci_op *op = &pdev->sh_info->op;
>+	
>+	if (unlikely(!test_bit(_XEN_PCIF_active,
>+					(unsigned long *)&pdev->sh_info->flags))) {
>+		printk(KERN_DEBUG "pciback: interrupt, but no active operation\n");
>+		goto out;
>+	}
>+
>+	dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
>+
>+	if (dev==NULL)
>+		op->err = XEN_PCI_ERR_dev_not_found;
>+	else if (op->cmd == XEN_PCI_OP_conf_read)
>+		op->err = pciback_config_read(dev, op->offset, op->size, &op->value);
>+	else if (op->cmd == XEN_PCI_OP_conf_write)
>+		op->err = pciback_config_write(dev, op->offset, op->size, op->value);
>+	else
>+		op->err = XEN_PCI_ERR_not_implemented;
>+
>+	wmb();
>+	clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
>+
>+out:
>+	return IRQ_HANDLED;
>+}
>+
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,147 @@
>+/*
>+ * PCI Backend - Provides a Virtual PCI bus (with real devices)
>+ *               to the frontend
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+
>+#include <linux/list.h>
>+#include <linux/slab.h>
>+#include <linux/pci.h>
>+#include "pciback.h"
>+
>+#define PCI_SLOT_MAX 32
>+
>+typedef struct {
>+	struct list_head dev_list[PCI_SLOT_MAX];
>+} vpci_dev_data_t;
>+
>+static inline struct list_head * list_first(struct list_head *head)
>+{
>+	return head->next;
>+}
>+
>+struct pci_dev * pciback_get_pci_dev(struct pciback_device *pdev,
>+		unsigned int domain, unsigned int bus, unsigned int devfn)
>+{
>+	struct pci_dev_entry *dev_entry;
>+	vpci_dev_data_t *vpci_dev = pdev->pci_dev_data;
>+
>+	if (domain!=0 || bus!=0)
>+		return NULL;
>+
>+	if (PCI_SLOT(devfn)<PCI_SLOT_MAX) {
>+		/* we don't need to lock the list here because once the backend
>+		 * is in operation, it won't have any more devices addeded
>+		 * (or removed).
>+		 */
>+		list_for_each_entry(dev_entry, &vpci_dev->dev_list[PCI_SLOT(devfn)],
>+				list) {
>+			if (PCI_FUNC(dev_entry->dev->devfn)==PCI_FUNC(devfn))
>+				return dev_entry->dev;
>+		}
>+	}
>+	return NULL;
>+}
>+
>+/* Must hold pciback_device->dev_lock when calling this */
>+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
>+{
>+	int err=0, i;
>+	struct pci_dev_entry *t, *dev_entry;
>+	vpci_dev_data_t *vpci_dev = pdev->pci_dev_data;
>+
>+	if ((dev->class>>24)==PCI_BASE_CLASS_BRIDGE) {
>+		err = -EFAULT;
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				"Can't export bridges on the virtual PCI bus");
>+		goto out;
>+	}
>+
>+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
>+	if (!dev_entry) {
>+		err = -ENOMEM;
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				"Error adding entry to virtual PCI bus");
>+		goto out;
>+	}
>+	
>+	dev_entry->dev = dev;
>+
>+	/* Keep multi-function devices together on the virtual PCI bus */
>+	for (i=0; i<PCI_SLOT_MAX; i++) {
>+		if (!list_empty(&vpci_dev->dev_list[i])) {
>+			t = list_entry(list_first(&vpci_dev->dev_list[i]),
>+					struct pci_dev_entry, list);
>+
>+			if (pci_domain_nr(t->dev->bus)==pci_domain_nr(dev->bus)
>+					&& t->dev->bus->number==dev->bus->number
>+					&& PCI_SLOT(t->dev->devfn)==PCI_SLOT(dev->devfn)) {
>+				printk(KERN_INFO
>+						"pciback: vpci: assign %s to virtual slot %d func %d\n",
>+						pci_name(dev), i, PCI_FUNC(dev->devfn));
>+				list_add_tail(&dev_entry->list, &vpci_dev->dev_list[i]);
>+				goto out;
>+			}
>+		}
>+	}
>+
>+	/* Assign to a new slot on the virtual PCI bus */
>+	for (i=0; i<PCI_SLOT_MAX; i++) {
>+		if (list_empty(&vpci_dev->dev_list[i])) {
>+			printk(KERN_INFO "pciback: vpci: assign %s to virtual slot %d\n",
>+					pci_name(dev),i);
>+			list_add_tail(&dev_entry->list, &vpci_dev->dev_list[i]);
>+			goto out;
>+		}
>+	}
>+
>+	err = -ENOMEM;
>+	xenbus_dev_fatal(pdev->xdev, err, "No more space on root virtual PCI bus");
>+
>+out:
>+	return err;
>+}
>+
>+int pciback_init_devices(struct pciback_device *pdev)
>+{
>+	int i;
>+	vpci_dev_data_t *vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
>+
>+	if (!vpci_dev)
>+		return -ENOMEM;
>+
>+	for (i=0; i<PCI_SLOT_MAX; i++) {
>+		INIT_LIST_HEAD(&vpci_dev->dev_list[i]);
>+	}
>+
>+	pdev->pci_dev_data = vpci_dev;
>+
>+	return 0;
>+}
>+
>+int pciback_publish_pci_roots(struct pciback_device *pdev,
>+		publish_pci_root_cb publish_cb)
>+{
>+	/* The Virtual PCI bus has only one root */
>+	return publish_cb(pdev, 0, 0);
>+}
>+
>+/* Must hold pciback_device->dev_lock when calling this */
>+void pciback_release_devices(struct pciback_device *pdev)
>+{
>+	int i;
>+	vpci_dev_data_t *vpci_dev = pdev->pci_dev_data;
>+
>+	for (i=0; i<PCI_SLOT_MAX; i++) {
>+		struct pci_dev_entry *e,*tmp;
>+		list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[i], list) {
>+			list_del(&e->list);
>+			pcistub_put_pci_dev(e->dev);
>+			kfree(e);
>+		}
>+	}
>+
>+	kfree(vpci_dev);
>+	pdev->pci_dev_data = NULL;
>+}
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,422 @@
>+/*
>+ * PCI Backend Xenbus Setup - handles setup with frontend and xend
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <linux/init.h>
>+#include <linux/list.h>
>+#include <asm-xen/xenbus.h>
>+#include <asm-xen/evtchn.h>
>+#include "pciback.h"
>+
>+#define INVALID_EVTCHN_IRQ  (-1)
>+
>+struct pciback_device * alloc_pdev(struct xenbus_device *xdev)
>+{
>+	struct pciback_device *pdev;
>+
>+	pdev = kmalloc(sizeof(struct pciback_device), GFP_KERNEL);
>+	if (pdev==NULL)
>+		goto out;
>+	dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
>+
>+	pdev->xdev = xdev;
>+	xdev->data = pdev;
>+
>+	spin_lock_init(&pdev->dev_lock);
>+
>+	pdev->sh_info = NULL;
>+	pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
>+	pdev->be_watching = 0;
>+
>+	if (pciback_init_devices(pdev)) {
>+		kfree(pdev);
>+		pdev = NULL;
>+	}
>+out:
>+	return pdev;
>+}
>+
>+void free_pdev(struct pciback_device *pdev)
>+{
>+	if (pdev->be_watching)
>+		unregister_xenbus_watch(&pdev->be_watch);
>+
>+	/* Ensure the guest can't trigger our handler before removing devices */
>+	if (pdev->evtchn_irq!=INVALID_EVTCHN_IRQ)
>+		unbind_from_irqhandler(pdev->evtchn_irq, pdev);
>+
>+	if (pdev->sh_info)
>+		xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
>+
>+	pciback_release_devices(pdev);
>+
>+	pdev->xdev->data = NULL;
>+	pdev->xdev = NULL;
>+
>+	kfree(pdev);
>+}
>+
>+static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
>+		int remote_evtchn)
>+{
>+	int err = 0;
>+	int evtchn;
>+	dev_dbg(&pdev->xdev->dev,
>+			"Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
>+			gnt_ref, remote_evtchn);
>+
>+	err = xenbus_map_ring_valloc(pdev->xdev, gnt_ref, (void **)&pdev->sh_info);
>+	if (err)
>+		goto out;
>+
>+	err = xenbus_bind_evtchn(pdev->xdev, remote_evtchn, &evtchn);
>+	if (err)
>+		goto out;
>+
>+	err = bind_evtchn_to_irqhandler(evtchn, pciback_handle_event,
>+			SA_SAMPLE_RANDOM, "pciback", pdev);
>+	if (err<0) {
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				"Error binding event channel to IRQ" );
>+		goto out;
>+	}
>+	pdev->evtchn_irq = err;
>+	err = 0;
>+
>+	dev_dbg(&pdev->xdev->dev, "Attached!\n");
>+out:
>+	return err;
>+}
>+
>+static int pciback_attach(struct pciback_device *pdev)
>+{
>+	int err=0;
>+	int gnt_ref, remote_evtchn;
>+	char *magic=NULL;
>+
>+	spin_lock(&pdev->dev_lock);
>+
>+	/* Make sure we only do this setup once */
>+	if (xenbus_read_driver_state(pdev->xdev->nodename)!=XenbusStateInitialised)
>+		goto out;
>+
>+	/* Wait for frontend to state that it has published the configuration */
>+	if (xenbus_read_driver_state(pdev->xdev->otherend)!=XenbusStateInitialised)
>+		goto out;
>+
>+	dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
>+
>+	err = xenbus_gather(XBT_NULL, pdev->xdev->otherend,
>+			"pci-op-ref", "%u", &gnt_ref,
>+			"event-channel", "%u", &remote_evtchn,
>+			"magic", NULL, &magic,
>+			NULL );
>+	if (err) {
>+		/* If configuration didn't get read correctly, wait longer */
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				"Error reading configuration from frontend");
>+		goto out;
>+	}
>+
>+	if (magic==NULL || strcmp(magic,XEN_PCI_MAGIC)!=0) {
>+		xenbus_dev_fatal(pdev->xdev, -EFAULT,
>+				"version mismatch (%s/%s) with pcifront - halting pciback",
>+				magic, XEN_PCI_MAGIC);
>+		goto out;
>+	}
>+
>+	err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
>+	if (err)
>+		goto out;
>+
>+	dev_dbg(&pdev->xdev->dev, "Connecting...\n");
>+
>+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
>+	if (err)
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				"Error switching to connected state!");
>+
>+	dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
>+out:
>+	spin_unlock(&pdev->dev_lock);
>+
>+	if (magic)
>+		kfree(magic);
>+
>+	return err;
>+}
>+
>+static void pciback_frontend_changed(struct xenbus_device *xdev,
>+		XenbusState fe_state)
>+{
>+	struct pciback_device *pdev = xdev->data;
>+
>+	dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
>+	switch (fe_state) {
>+		case XenbusStateInitialised:
>+			pciback_attach(pdev);
>+			break;
>+
>+		case XenbusStateClosing:
>+			xenbus_switch_state(xdev, XBT_NULL, XenbusStateClosing);
>+			break;
>+
>+		case XenbusStateClosed:
>+			dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
>+			device_unregister(&xdev->dev);
>+			break;
>+
>+		default:
>+			break;
>+	}
>+}
>+
>+static int pciback_publish_pci_root(struct pciback_device *pdev,
>+		unsigned int domain, unsigned int bus)
>+{
>+	unsigned int d, b;
>+	int i, root_num, len, err;
>+	char str[64];
>+
>+	dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
>+
>+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
>+			"root_num", "%d", &root_num);
>+	if (err==0 || err==-ENOENT)
>+		root_num = 0;
>+	else if (err<0)
>+		goto out;
>+
>+	/* Verify that we haven't already published this pci root */
>+	for (i=0; i<root_num; i++) {
>+		len = snprintf(str, sizeof(str), "root-%d", i);
>+		if (unlikely(len>=(sizeof(str)-1))) {
>+			err = -ENOMEM;
>+			goto out;
>+		}
>+
>+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
>+				str, "%x:%x", &d, &b);
>+		if (err<0)
>+			goto out;
>+		if (err!=2) {
>+			err = -EINVAL;
>+			goto out;
>+		}
>+
>+		if (d==domain && b==bus) {
>+			err = 0;
>+			goto out;
>+		}
>+	}
>+
>+	len = snprintf(str, sizeof(str), "root-%d", root_num);
>+	if (unlikely(len>=(sizeof(str)-1))) {
>+		err = -ENOMEM;
>+		goto out;
>+	}
>+
>+	dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
>+			root_num, domain, bus);
>+
>+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename, str,
>+			"%04x:%02x", domain, bus);
>+	if (err)
>+		goto out;
>+
>+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename,
>+			"root_num","%d", (root_num+1));
>+
>+out:
>+	return err;
>+}
>+
>+static int pciback_export_device(struct pciback_device *pdev,
>+		int domain, int bus, int slot, int func)
>+{
>+	struct pci_dev *dev;
>+	int err = 0;
>+
>+	dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
>+			domain, bus, slot, func);
>+
>+	dev = pcistub_get_pci_dev_by_slot(domain, bus, slot, func);
>+	if (!dev) {
>+		err = -EINVAL;
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				"Couldn't locate PCI device (%04x:%02x:%02x.%01x)! "
>+				"perhaps already in-use?", domain, bus, slot, func);
>+		goto out;
>+	}
>+
>+	err = pciback_add_pci_dev(pdev, dev);
>+	if (err)
>+		goto out;
>+
>+	/* TODO: If this is a bridge, export all the children (this won't work for
>+	 * children dynamically added to the bus later!) - This is trivial in
>+	 * kernels >= 2.6.14 with pci_walk_bus(dev->subordinate)
>+	 */
>+out:
>+	return err;
>+}
>+
>+static int pciback_setup_backend(struct pciback_device *pdev)
>+{
>+	/* Get configuration from xend (if available now) */
>+	int domain, bus, slot, func;
>+	int err = 0;
>+	int i, num_devs;
>+	char dev_str[64];
>+
>+	spin_lock(&pdev->dev_lock);
>+
>+	/* It's possible we could get the call to setup twice, so make sure
>+	 * we're not already connected.
>+	 */
>+	if (xenbus_read_driver_state(pdev->xdev->nodename)!=XenbusStateInitWait)
>+		goto out;
>+
>+	dev_dbg(&pdev->xdev->dev, "getting be setup\n");
>+
>+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, "num_devs", "%d", &num_devs);
>+	if (err!=1) {
>+		if (err>=0)
>+			err = -EINVAL;
>+		xenbus_dev_fatal(pdev->xdev, err, "Error reading number of devices");
>+		goto out;
>+	}
>+
>+	for (i=0; i<num_devs; i++) {
>+		int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
>+		if (unlikely(l>=(sizeof(dev_str)-1))) {
>+			err = -ENOMEM;
>+			xenbus_dev_fatal(pdev->xdev, err,
>+					"String overflow while reading configuration");
>+			goto out;
>+		}
>+
>+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, dev_str,
>+				"%x:%x:%x.%x", &domain, &bus, &slot, &func);
>+		if (err<0) {
>+			xenbus_dev_fatal(pdev->xdev, err,
>+					"Error reading device configuration");
>+			goto out;
>+		}
>+		if (err!=4) {
>+			err = -EINVAL;
>+			xenbus_dev_fatal(pdev->xdev, err,
>+					"Error parsing pci device configuration");
>+			goto out;
>+		}
>+
>+		err = pciback_export_device(pdev, domain, bus, slot, func);
>+		if (err)
>+			goto out;
>+	}
>+
>+	err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
>+	if (err) {
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				"Error while publish PCI root buses for frontend");
>+		goto out;
>+	}
>+
>+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateInitialised);
>+	if (err)
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				"Error switching to initialised state!");
>+
>+out:
>+	spin_unlock(&pdev->dev_lock);
>+
>+	if (!err)
>+		/* see if pcifront is already configured (if not, we'll wait) */
>+		pciback_attach(pdev);
>+
>+	return err;
>+}
>+
>+static void pciback_be_watch(struct xenbus_watch *watch,
>+		const char **vec, unsigned int len)
>+{
>+	struct pciback_device *pdev =
>+		container_of(watch, struct pciback_device, be_watch);
>+	
>+	switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
>+		case XenbusStateInitWait:
>+			pciback_setup_backend(pdev);
>+			break;
>+
>+		default:
>+			break;
>+	}
>+}
>+
>+static int pciback_xenbus_probe(struct xenbus_device *dev,
>+		const struct xenbus_device_id *id)
>+{
>+	int err = 0;
>+	struct pciback_device * pdev = alloc_pdev(dev);
>+
>+	if( pdev==NULL ) {
>+		err = -ENOMEM;
>+		xenbus_dev_fatal(dev, err,
>+				"Error allocating pciback_device struct");
>+		goto out;
>+	}
>+
>+	/* wait for xend to configure us */
>+	err = xenbus_switch_state(dev, XBT_NULL, XenbusStateInitWait);
>+	if (err)
>+		goto out;
>+
>+	/* watch the backend node for backend configuration information */
>+	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
>+			pciback_be_watch);
>+	if (err) 
>+		goto out;
>+	pdev->be_watching = 1;
>+
>+	/* We need to force a call to our callback here in case
>+	 * xend already configured us!
>+	 */
>+	pciback_be_watch(&pdev->be_watch, NULL, 0);
>+
>+out:
>+	return err;
>+}
>+
>+static int pciback_xenbus_remove(struct xenbus_device *dev)
>+{
>+	struct pciback_device *pdev = dev->data;
>+
>+	if (pdev!=NULL)
>+		free_pdev(pdev);
>+
>+	return 0;
>+}
>+
>+static struct xenbus_device_id xenpci_ids[] = {
>+	{ "pci" },
>+	{ { 0 } },
>+};
>+
>+static struct xenbus_driver xenbus_pciback_driver = {
>+	.name = "pciback",
>+	.owner = THIS_MODULE,
>+	.ids = xenpci_ids,
>+	.probe = pciback_xenbus_probe,
>+	.remove = pciback_xenbus_remove,
>+	.otherend_changed = pciback_frontend_changed,
>+};
>+
>+static __init int pciback_xenbus_register(void)
>+{
>+	return xenbus_register_backend(&xenbus_pciback_driver);
>+}
>+
>+/* Must only initialize our xenbus driver after the pcistub driver */
>+device_initcall(pciback_xenbus_register);
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,8 @@
>+obj-y += pcifront.o
>+
>+pcifront-y := pci_op.o xenbus.o pci.o
>+pcifront-$(CONFIG_XEN_PCI_FE_ARCH_REPLACE) += arch.o
>+
>+ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y)
>+CFLAGS_xenbus.o += -DDEBUG
>+endif
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pcifront/arch.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/arch.c	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,95 @@
>+/*
>+ * PCI Frontend Arch Replacement Code - replaces an architecture's PCI access
>+ *              code with a generic, Xen version (Experimental)
>+ * - This file *should* be arch-independent (except for
>+ *   pci_mmap_page_range) and should replace an arch's PCI implementation
>+ * - You must prevent an architecture's PCI code from compiling into the kernel
>+ *   when you use the code contained here.
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <linux/init.h>
>+#include <linux/pci.h>
>+
>+/* More or less copied from other architectures */
>+int pcibios_enable_device(struct pci_dev *dev, int mask)
>+{
>+	u16 cmd, oldcmd;
>+	u8 irq;
>+	int i;
>+
>+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
>+	oldcmd = cmd;
>+
>+	for (i=0; i<PCI_NUM_RESOURCES; i++) {
>+		struct resource *r = &dev->resource[i];
>+
>+		if (!(mask&(1<<i)))
>+			continue;
>+
>+		if (r->flags & IORESOURCE_IO)
>+			cmd |= PCI_COMMAND_IO;
>+		if (r->flags & IORESOURCE_MEM)
>+			cmd |= PCI_COMMAND_MEMORY;
>+	}
>+
>+	if (cmd!=oldcmd) {
>+		printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n",
>+				pci_name(dev), cmd);
>+		pci_write_config_word(dev, PCI_COMMAND, cmd);
>+	}
>+
>+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
>+	dev->irq = irq;
>+
>+	return 0;
>+}
>+
>+void pcibios_disable_device(struct pci_dev *dev)
>+{
>+	u16 cmd;
>+
>+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
>+
>+	if (cmd&(PCI_COMMAND_IO|PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER)) {
>+		cmd &= ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER);
>+
>+		printk(KERN_DEBUG "PCI: Disabling device: (%s), cmd %x\n",
>+				pci_name(dev), cmd);
>+		pci_write_config_word(dev, PCI_COMMAND, cmd);
>+	}
>+}
>+
>+char *pcibios_setup(char *str)
>+{
>+	/** Return NULL if we accept an option, str if we don't */
>+	return str;
>+}
>+
>+void pcibios_set_master(struct pci_dev *dev)
>+{
>+	/* Handled by backend when we turn the master
>+	 * bit on in the PCI_COMMAND register */
>+}
>+
>+void pcibios_align_resource(void *data, struct resource *res,
>+		unsigned long size, unsigned long align)
>+{
>+}
>+
>+void pcibios_fixup_bus(struct pci_bus *bus)
>+{
>+}
>+
>+unsigned int pcibios_assign_all_busses(void)
>+{
>+	return 0;
>+}
>+
>+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
>+		enum pci_mmap_state mmap_state, int write_combine)
>+{
>+	printk(KERN_ERR "%s: mmap_page_range not implemented!\n", pci_name(dev));
>+	return -EINVAL;
>+}
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,43 @@
>+/*
>+ * PCI Frontend Operations - ensure only one PCI frontend runs at a time
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <linux/init.h>
>+#include <linux/pci.h>
>+#include <linux/spinlock.h>
>+#include "pcifront.h"
>+
>+DEFINE_SPINLOCK(pcifront_dev_lock);
>+static struct pcifront_device *pcifront_dev = NULL;
>+
>+int pcifront_connect(struct pcifront_device *pdev)
>+{
>+	int err = 0;
>+
>+	spin_lock(&pcifront_dev_lock);
>+
>+	if (!pcifront_dev)
>+		dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
>+	else {
>+		dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
>+		err = -EEXIST;
>+	}
>+
>+	spin_unlock(&pcifront_dev_lock);
>+
>+	return err;
>+}
>+
>+void pcifront_disconnect(struct pcifront_device *pdev)
>+{
>+	spin_lock(&pcifront_dev_lock);
>+
>+	if (pdev==pcifront_dev) {
>+		dev_info(&pdev->xdev->dev, "Disconnecting PCI Frontend Buses\n");
>+		pcifront_dev = NULL;
>+	}
>+
>+	spin_unlock(&pcifront_dev_lock);
>+}
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,220 @@
>+/*
>+ * PCI Frontend Operations - Communicates with frontend
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <linux/init.h>
>+#include <linux/pci.h>
>+#include <linux/spinlock.h>
>+#include <asm-xen/evtchn.h>
>+#include "pcifront.h"
>+
>+int verbose_request = 0;
>+module_param(verbose_request,int,0644);
>+
>+static int errno_to_pcibios_err(int errno)
>+{
>+	switch(errno) {
>+		case XEN_PCI_ERR_success:
>+			return PCIBIOS_SUCCESSFUL;
>+
>+		case XEN_PCI_ERR_dev_not_found:
>+			return PCIBIOS_DEVICE_NOT_FOUND;
>+
>+		case XEN_PCI_ERR_invalid_offset:
>+		case XEN_PCI_ERR_op_failed:
>+			return PCIBIOS_BAD_REGISTER_NUMBER;
>+
>+		case XEN_PCI_ERR_not_implemented:
>+			return PCIBIOS_FUNC_NOT_SUPPORTED;
>+
>+		case XEN_PCI_ERR_access_denied:
>+			return PCIBIOS_SET_FAILED;
>+	}
>+	return errno;
>+}
>+
>+static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
>+{
>+	int err = 0;
>+	struct xen_pci_op *active_op = &pdev->sh_info->op;
>+	unsigned long irq_flags;
>+
>+	unsigned int volatile ttl = (1U<<29);
>+
>+	spin_lock_irqsave(&pdev->sh_info_lock,irq_flags);
>+
>+	memcpy(active_op, op, sizeof(struct xen_pci_op));
>+
>+	/* Go */
>+	wmb();
>+	set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
>+	notify_remote_via_evtchn(pdev->evtchn);
>+
>+	/* IRQs are disabled for the pci config. space reads/writes,
>+	 * which means no event channel to notify us that the backend
>+	 * is done so spin while waiting for the answer */
>+	while (test_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)) {
>+		if (!ttl) {
>+			dev_err(&pdev->xdev->dev, "pciback not responding!!!\n");
>+			clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
>+			err = XEN_PCI_ERR_dev_not_found;
>+			goto out;
>+		}
>+		ttl--;
>+	}
>+
>+	memcpy(op, active_op, sizeof(struct xen_pci_op));
>+
>+	err = op->err;
>+out:
>+	spin_unlock_irqrestore(&pdev->sh_info_lock,irq_flags);
>+	return err;
>+}
>+
>+/* Access to this function is spinlocked in drivers/pci/access.c */
>+static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
>+		int where, int size, u32 *val)
>+{
>+	int err = 0;
>+	struct xen_pci_op op = {
>+		.cmd = XEN_PCI_OP_conf_read,
>+		.domain = pci_domain_nr(bus),
>+		.bus = bus->number,
>+		.devfn = devfn,
>+		.offset = where,
>+		.size = size,
>+	};
>+	struct pcifront_sd *sd = bus->sysdata;
>+	struct pcifront_device *pdev = sd->pdev;
>+
>+	if (verbose_request)
>+		dev_info(&pdev->xdev->dev,
>+				"read dev=%04x:%02x:%02x.%01x - offset %x size %d\n",
>+				pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
>+				PCI_FUNC(devfn), where, size);
>+
>+	err = do_pci_op(pdev, &op);
>+
>+	if (likely(!err)) {
>+		if (verbose_request)
>+			dev_info(&pdev->xdev->dev,"read got back value %x\n", op.value);
>+
>+		*val = op.value;
>+	}
>+	else if (err==-ENODEV) {
>+		/* No device here, pretend that it just returned 0 */
>+		err = 0;
>+		*val = 0;
>+	}
>+
>+	return errno_to_pcibios_err(err);
>+}
>+
>+/* Access to this function is spinlocked in drivers/pci/access.c */
>+static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
>+		int where, int size, u32 val)
>+{
>+	struct xen_pci_op op = {
>+		.cmd = XEN_PCI_OP_conf_write,
>+		.domain = pci_domain_nr(bus),
>+		.bus = bus->number,
>+		.devfn = devfn,
>+		.offset = where,
>+		.size = size,
>+		.value = val,
>+	};
>+	struct pcifront_sd *sd = bus->sysdata;
>+	struct pcifront_device *pdev = sd->pdev;
>+
>+	if (verbose_request)
>+		dev_info(&pdev->xdev->dev,
>+				"write dev=%04x:%02x:%02x.%01x - offset %x size %d val %x\n",
>+				pci_domain_nr(bus), bus->number,
>+				PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
>+
>+	return errno_to_pcibios_err(do_pci_op(pdev, &op));
>+}
>+
>+struct pci_ops pcifront_bus_ops = {
>+	.read = pcifront_bus_read,
>+	.write = pcifront_bus_write,
>+};
>+
>+int pcifront_scan_root(struct pcifront_device *pdev,
>+		unsigned int domain, unsigned int bus)
>+{
>+	struct pci_bus *b;
>+	struct pcifront_sd *sd = NULL;
>+	struct pci_bus_entry *bus_entry = NULL;
>+	int err = 0;
>+
>+#ifndef CONFIG_PCI_DOMAINS
>+	if (domain!=0) {
>+		dev_err(&pdev->xdev->dev, "PCI Root in non-zero (%d) PCI Domain!\n",
>+				domain);
>+		dev_err(&pdev->xdev->dev, "Please compile with CONFIG_PCI_DOMAINS\n");
>+		err = -EINVAL;
>+		goto err_out;
>+	}
>+#endif
>+
>+	dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
>+			domain, bus);
>+
>+	bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
>+	sd = kmalloc(sizeof(*sd), GFP_KERNEL);
>+	if (!bus_entry || !sd) {
>+		err = -ENOMEM;
>+		goto err_out;
>+	}
>+	sd->domain = domain;
>+	sd->pdev = pdev;
>+
>+	b = pci_scan_bus_parented(&pdev->xdev->dev, bus,
>+			&pcifront_bus_ops, sd);
>+	if (!b) {
>+		dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n");
>+		err = -ENOMEM;
>+		goto err_out;
>+	}
>+	bus_entry->bus = b;
>+
>+	list_add(&bus_entry->list, &pdev->root_buses);
>+
>+	/* In kernels >= 2.6.13, we need to:
>+	   pci_bus_add_devices(b); */
>+
>+	return 0;
>+
>+err_out:
>+	kfree(bus_entry);
>+	kfree(sd);
>+
>+	return err;
>+}
>+
>+void pcifront_free_roots(struct pcifront_device *pdev)
>+{
>+	struct pci_bus_entry *bus_entry, *t;
>+
>+	list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
>+		/* TODO: Removing a PCI Bus is untested (as it normally just goes
>+		 * away on domain shutdown)
>+		 */
>+		list_del(&bus_entry->list);
>+
>+		spin_lock(&pci_bus_lock);
>+		list_del(&bus_entry->bus->node);
>+		spin_unlock(&pci_bus_lock);
>+
>+		kfree(bus_entry->bus->sysdata);
>+
>+		device_unregister(bus_entry->bus->bridge);
>+
>+		/* Do we need to free() the bus itself? */
>+
>+		kfree(bus_entry);
>+	}
>+}
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,40 @@
>+/*
>+ * PCI Frontend - Common data structures & function declarations
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#ifndef __XEN_PCIFRONT_H__
>+#define __XEN_PCIFRONT_H__
>+
>+#include <linux/spinlock.h>
>+#include <linux/pci.h>
>+#include <asm-xen/xenbus.h>
>+#include <asm-xen/xen-public/io/pciif.h>
>+#include <asm-xen/pcifront.h>
>+
>+struct pci_bus_entry {
>+	struct list_head list;
>+	struct pci_bus *bus;
>+};
>+
>+struct pcifront_device {
>+	struct xenbus_device *xdev;
>+	struct list_head root_buses;
>+	spinlock_t dev_lock;
>+
>+	int evtchn;
>+	int gnt_ref;
>+
>+	/* Lock this when doing any operations in sh_info */
>+	spinlock_t sh_info_lock;
>+	struct xen_pci_sharedinfo *sh_info;
>+};
>+
>+int pcifront_connect(struct pcifront_device *pdev);
>+void pcifront_disconnect(struct pcifront_device *pdev);
>+
>+int pcifront_scan_root(struct pcifront_device *pdev,
>+		unsigned int domain, unsigned int bus);
>+void pcifront_free_roots(struct pcifront_device *pdev);
>+
>+#endif /* __XEN_PCIFRONT_H__ */
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,286 @@
>+/*
>+ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn)
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <linux/init.h>
>+#include <linux/mm.h>
>+#include <asm-xen/xenbus.h>
>+#include "pcifront.h"
>+
>+#define INVALID_GRANT_REF (0)
>+#define INVALID_EVTCHN    (-1)
>+
>+static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
>+{
>+	struct pcifront_device *pdev;
>+
>+	pdev = kmalloc(sizeof(struct pcifront_device), GFP_KERNEL);
>+	if (pdev==NULL)
>+		goto out;
>+
>+	pdev->sh_info = (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
>+	if (pdev->sh_info==NULL) {
>+		kfree(pdev);
>+		pdev = NULL;
>+		goto out;
>+	}
>+	pdev->sh_info->flags = 0;
>+
>+	xdev->data = pdev;
>+	pdev->xdev = xdev;
>+
>+	INIT_LIST_HEAD(&pdev->root_buses);
>+
>+	spin_lock_init(&pdev->dev_lock);
>+	spin_lock_init(&pdev->sh_info_lock);
>+
>+	pdev->evtchn = INVALID_EVTCHN;
>+	pdev->gnt_ref = INVALID_GRANT_REF;
>+
>+	dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n",
>+			pdev, pdev->sh_info);
>+out:
>+	return pdev;
>+}
>+
>+static void free_pdev(struct pcifront_device *pdev)
>+{
>+	dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev);
>+
>+	if (pdev->evtchn!=INVALID_EVTCHN)
>+		xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
>+
>+	if (pdev->gnt_ref!=INVALID_GRANT_REF)
>+		gnttab_end_foreign_access(pdev->gnt_ref, 0,
>+				(unsigned long)pdev->sh_info);
>+
>+	pdev->xdev->data = NULL;
>+
>+	kfree(pdev);
>+}
>+
>+static int pcifront_publish_info(struct pcifront_device *pdev)
>+{
>+	int err=0;
>+	xenbus_transaction_t trans;
>+
>+	err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info));
>+	if (err<0)
>+		goto out;
>+
>+	pdev->gnt_ref = err;
>+
>+	err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
>+	if (err)
>+		goto out;
>+
>+do_publish:
>+	err = xenbus_transaction_start(&trans);
>+	if (err) {
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				"Error writing configuration for backend (start transaction)");
>+		goto out;
>+	}
>+
>+	err = xenbus_printf(trans, pdev->xdev->nodename,
>+			"pci-op-ref", "%u", pdev->gnt_ref);
>+	if (!err)
>+		err = xenbus_printf(trans, pdev->xdev->nodename, "event-channel", "%u",
>+				pdev->evtchn);
>+	if (!err)
>+		err = xenbus_printf(trans, pdev->xdev->nodename,
>+				"magic", XEN_PCI_MAGIC);
>+	if (!err)
>+		err = xenbus_switch_state(pdev->xdev, trans, XenbusStateInitialised); 
>+
>+	if (err) {
>+		xenbus_transaction_end(trans, 1);
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				"Error writing configuration for backend");
>+		goto out;
>+	}
>+	else {
>+		err = xenbus_transaction_end(trans, 0);
>+		if (err == -EAGAIN) 
>+			goto do_publish;
>+		else if (err) {
>+			xenbus_dev_fatal(pdev->xdev, err,
>+					"Error completing transaction for backend");
>+			goto out;
>+		}
>+	}
>+
>+	dev_dbg(&pdev->xdev->dev, "publishing successful!\n");
>+
>+out:
>+	return err;
>+}
>+
>+static int pcifront_try_connect(struct pcifront_device *pdev)
>+{
>+	int err = -EFAULT;
>+	int i, num_roots, len;
>+	char str[64];
>+	unsigned int domain, bus;
>+
>+	spin_lock(&pdev->dev_lock);
>+
>+	/* Only connect once */
>+	if (xenbus_read_driver_state(pdev->xdev->nodename)!=XenbusStateInitialised)
>+		goto out;
>+
>+	err = pcifront_connect(pdev);
>+	if (err) {
>+		xenbus_dev_fatal(pdev->xdev, err, "Error connecting PCI Frontend");
>+		goto out;
>+	}
>+
>+	err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend, "root_num",
>+			"%d", &num_roots);
>+	if (err==-ENOENT) {
>+		xenbus_dev_error(pdev->xdev, err, "No PCI Roots found, trying 0000:00");
>+		err = pcifront_scan_root(pdev, 0, 0);
>+		num_roots = 0;
>+	}
>+	else if (err!=1) {
>+		if (err==0)
>+			err = -EINVAL;
>+		xenbus_dev_fatal(pdev->xdev, err, "Error reading number of PCI roots");
>+		goto out;
>+	}
>+
>+	for (i=0; i<num_roots; i++) {
>+		len = snprintf(str, sizeof(str), "root-%d", i);
>+		if (unlikely(len>=(sizeof(str)-1))) {
>+			err = -ENOMEM;
>+			goto out;
>+		}
>+
>+		err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend, str,
>+				"%x:%x", &domain, &bus);
>+		if (err!=2) {
>+			if (err>=0)
>+				err = -EINVAL;
>+			xenbus_dev_fatal(pdev->xdev, err, "Error reading PCI root %d", i);
>+			goto out;
>+		}
>+
>+		err = pcifront_scan_root(pdev, domain, bus);
>+		if (err) {
>+			xenbus_dev_fatal(pdev->xdev, err,
>+					"Error scanning PCI root %04x:%02x", domain, bus);
>+			goto out;
>+		}
>+	}
>+	
>+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
>+	if (err)
>+		goto out;
>+
>+out:
>+	spin_unlock(&pdev->dev_lock);
>+	return err;
>+}
>+
>+static int pcifront_try_disconnect(struct pcifront_device *pdev)
>+{
>+	int err=0;
>+	XenbusState prev_state;
>+
>+	spin_lock(&pdev->dev_lock);
>+
>+	prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
>+
>+	if (prev_state<XenbusStateClosing)
>+		err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateClosing);
>+
>+	if (!err && prev_state==XenbusStateConnected)
>+		pcifront_disconnect(pdev);
>+
>+	spin_unlock(&pdev->dev_lock);
>+
>+	return err;
>+}
>+
>+static void pcifront_backend_changed(struct xenbus_device *xdev,
>+		XenbusState be_state)
>+{
>+	struct pcifront_device *pdev = xdev->data;
>+
>+	switch (be_state)
>+	{
>+		case XenbusStateClosing:
>+			dev_warn(&xdev->dev, "backend going away!\n");
>+			pcifront_try_disconnect(pdev);
>+			break;
>+
>+		case XenbusStateClosed:
>+			dev_warn(&xdev->dev, "backend went away!\n");
>+			pcifront_try_disconnect(pdev);
>+
>+			device_unregister(&pdev->xdev->dev);
>+			break;
>+
>+		case XenbusStateConnected:
>+			pcifront_try_connect(pdev);
>+			break;
>+
>+		default:
>+			break;
>+	}
>+}
>+
>+static int pcifront_xenbus_probe(struct xenbus_device *xdev,
>+		const struct xenbus_device_id *id)
>+{
>+	int err = 0;
>+	struct pcifront_device *pdev = alloc_pdev(xdev);
>+
>+	if (pdev == NULL) {
>+		err = -ENOMEM;
>+		xenbus_dev_fatal(xdev, err,
>+			"Error allocating pcifront_device struct");
>+		goto out;
>+	}
>+
>+	err = pcifront_publish_info(pdev);
>+
>+out:
>+	return err;
>+}
>+
>+static int pcifront_xenbus_remove(struct xenbus_device *xdev)
>+{
>+	if (xdev->data)
>+		free_pdev(xdev->data);
>+
>+	return 0;
>+}
>+
>+static struct xenbus_device_id xenpci_ids[] = {
>+	{ "pci" },
>+	{ { 0 } },
>+};
>+
>+static struct xenbus_driver xenbus_pcifront_driver = {
>+	.name = "pcifront",
>+	.owner = THIS_MODULE,
>+	.ids = xenpci_ids,
>+	.probe = pcifront_xenbus_probe,
>+	.remove = pcifront_xenbus_remove,
>+	.otherend_changed = pcifront_backend_changed,
>+};
>+
>+static int __init pcifront_init(void)
>+{
>+	int err = 0;
>+
>+	err = xenbus_register_frontend(&xenbus_pcifront_driver);
>+
>+	return err;
>+}
>+
>+/* Initialize after the Xen PCI Frontend Stub is initialized */
>+subsys_initcall(pcifront_init);
>diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/include/asm-xen/pcifront.h
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/include/asm-xen/pcifront.h	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,39 @@
>+/*
>+ * PCI Frontend - arch-dependendent declarations
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#ifndef __XEN_ASM_PCIFRONT_H__
>+#define __XEN_ASM_PCIFRONT_H__
>+
>+#include <linux/config.h>
>+#include <linux/spinlock.h>
>+
>+#ifdef __KERNEL__
>+
>+struct pcifront_device;
>+
>+struct pcifront_sd {
>+	int domain;
>+	struct pcifront_device *pdev;
>+};
>+
>+struct pci_bus;
>+
>+#ifdef CONFIG_PCI_DOMAINS
>+static inline int pci_domain_nr(struct pci_bus *bus)
>+{
>+	struct pcifront_sd *sd = bus->sysdata;
>+	return sd->domain;
>+}
>+static inline int pci_proc_domain(struct pci_bus *bus)
>+{
>+	return pci_domain_nr(bus);
>+}
>+#endif /* CONFIG_PCI_DOMAINS */
>+
>+extern spinlock_t pci_bus_lock;
>+
>+#endif /* __KERNEL__ */
>+
>+#endif /* __XEN_ASM_PCIFRONT_H__ */
>diff -r 2add7a262530 -r 5278641a6ea0 xen/include/public/io/pciif.h
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/xen/include/public/io/pciif.h	Fri Jan 27 18:57:35 2006
>@@ -0,0 +1,55 @@
>+/*
>+ * PCI Backend/Frontend Common Data Structures & Macros
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#ifndef __XEN_PCI_COMMON_H__
>+#define __XEN_PCI_COMMON_H__
>+
>+/* Be sure to bump this number if you change this file */
>+#define XEN_PCI_MAGIC		"7"
>+
>+/* xen_pci_sharedinfo flags */
>+#define _XEN_PCIF_active     (0)
>+#define XEN_PCIF_active      (1<<_XEN_PCI_active)
>+
>+/* xen_pci_op commands */
>+#define XEN_PCI_OP_conf_read    (0)
>+#define XEN_PCI_OP_conf_write   (1)
>+
>+/* xen_pci_op error numbers */
>+#define XEN_PCI_ERR_success          (0)
>+#define XEN_PCI_ERR_dev_not_found   (-1)
>+#define XEN_PCI_ERR_invalid_offset  (-2)
>+#define XEN_PCI_ERR_access_denied   (-3)
>+#define XEN_PCI_ERR_not_implemented (-4)
>+/* XEN_PCI_ERR_op_failed - backend failed to complete the operation */
>+#define XEN_PCI_ERR_op_failed       (-5)
>+
>+struct xen_pci_op {
>+	/* IN: what action to perform: XEN_PCI_OP_* */
>+	uint32_t cmd;
>+
>+	/* OUT: will contain an error number (if any) from errno.h */
>+	int32_t err;
>+
>+	/* IN: which device to touch */
>+	uint32_t domain; /* PCI Domain/Segment */
>+	uint32_t bus;
>+	uint32_t devfn;
>+
>+	/* IN: which configuration registers to touch */
>+	int32_t offset;
>+	int32_t size;
>+
>+	/* IN/OUT: Contains the result after a READ or the value to WRITE */
>+	uint32_t value;
>+};
>+
>+struct xen_pci_sharedinfo {
>+	/* flags - XEN_PCIF_* */
>+	uint32_t flags;
>+	struct xen_pci_op op;
>+};
>+
>+#endif /* __XEN_PCI_COMMON_H__ */
>  
>
>------------------------------------------------------------------------
>
>_______________________________________________
>Xen-devel mailing list
>Xen-devel@lists.xensource.com
>http://lists.xensource.com/xen-devel
>  
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
  2006-01-30 15:06 ` Anthony Liguori
@ 2006-01-30 18:43   ` Ryan
  2006-01-31  0:37     ` Anthony Liguori
  0 siblings, 1 reply; 15+ messages in thread
From: Ryan @ 2006-01-30 18:43 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: xen-devel

[-- Attachment #1: Type: text/plain, Size: 660 bytes --]

On Mon, 2006-01-30 at 09:06 -0600, Anthony Liguori wrote:
> Hi Ryan,
> 
> It would be nice if you could run your patches through lindent and 
> resubmit.  You do a couple things that don't follow kernel style 
> guidelines (lack of spaces around operators and else clauses on 
> newlines).  Strictly adhering to the CodingStyle now will make upstream 
> merge significantly easier in the future.
> 
> Thanks,
> 
> Anthony Liguori
> 
<snip>

Is the attached file better formatted? I used lindent. I also added a
couple of macros to simplify readability and reduce code size (lindent
changed some formatting that brought some code duplication to my
attention).


[-- Attachment #2: pci-ddi.patch --]
[-- Type: text/x-patch, Size: 82063 bytes --]

diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/arch/xen/Kconfig
--- a/linux-2.6-xen-sparse/arch/xen/Kconfig	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/Kconfig	Mon Jan 30 18:32:09 2006
@@ -38,6 +38,85 @@
 	  (e.g., hard drives, network cards). This allows you to configure
 	  such devices and also includes some low-level support that is
 	  otherwise not compiled into the kernel.
+
+config XEN_PCIDEV_BACKEND
+	bool "PCI device backend driver"
+	depends on XEN_PHYSDEV_ACCESS
+	select PCI
+	default y if XEN_PRIVILEGED_GUEST
+	help
+	  The PCI device backend driver allows the kernel to export arbitrary
+	  PCI devices to other guests.
+
+choice
+	prompt "PCI Backend Mode"
+	depends on XEN_PCIDEV_BACKEND
+	default XEN_PCIDEV_BACKEND_VPCI
+
+config XEN_PCIDEV_BACKEND_VPCI
+	bool "Virtual PCI"
+	---help---
+	  This PCI Backend hides the true PCI topology and makes the frontend
+	  think there is a single PCI bus with only the exported devices on it.
+	  For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
+	  second device at 02:1a.0 will be re-assigned to 00:01.0.
+
+config XEN_PCIDEV_BACKEND_PASS
+	bool "Passthrough"
+	---help---
+	  This PCI Backend provides a real view of the PCI topology to the
+	  frontend (for example, a device at 06:01.b will still appear at
+	  06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
+	  PCI devices to its driver domains. This may be required for drivers
+	  which depend on finding their hardward in certain bus/slot
+	  locations.
+
+endchoice
+
+config XEN_PCIDEV_BE_DEBUG
+	bool "PCI Backend Debugging"
+	depends on XEN_PCIDEV_BACKEND
+	default n
+
+# This won't work in 2.6.12 due to what appears to be a kernel bug (related
+# to reading the resources of transparent bridges in pci_read_bridge_bases).
+# This bug appears to be fixed in 2.6.13:
+# http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=90b54929b626c80056262d9d99b3f48522e404d0
+#config XEN_PCIDEV_BACKEND_ALLOC
+#	bool "Re-allocate PCI Resources (DANGEROUS)"
+#	depends on XEN_PCIDEV_BACKEND
+#	default n
+#	---help---
+#	  This forces the PCI Backend to try and re-allocate all of the resources
+#	  on the PCI bus in an attempt to ensure that they fall entirely within
+#	  boundaries that Xen can control.
+
+config XEN_PCIDEV_FRONTEND
+	bool "PCI device frontend driver"
+	depends on XEN_PHYSDEV_ACCESS
+	select PCI
+	default y if !XEN_PRIVILEGED_GUEST
+	help
+	  The PCI device frontend driver allows the kernel to import arbitrary
+	  PCI devices from a PCI backend.
+
+config XEN_PCIDEV_FE_DEBUG
+	bool "PCI Frontend Debugging"
+	depends on XEN_PCIDEV_FRONTEND
+	default n
+
+config XEN_PCI_FE_ARCH_REPLACE
+	bool "PCI frontend driver - arch-independent (EXPERIMENTAL)"
+	depends on XEN_PCIDEV_FRONTEND && EXPERIMENTAL
+	default n
+	help
+	  This selects an implementation of the PCI frontend driver that is
+	  architecture independent (i.e. it replaces the real architecture's
+	  PCI code). The default is to use an implementation that works with
+	  the architecture dependent PCI code (and you probably want the
+	  default).
+
+	  If unsure, say N.
 
 config XEN_BLKDEV_BACKEND
 	bool "Block-device backend driver"
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/arch/xen/i386/Kconfig
--- a/linux-2.6-xen-sparse/arch/xen/i386/Kconfig	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/Kconfig	Mon Jan 30 18:32:09 2006
@@ -788,9 +788,17 @@
 	  information about which PCI hardware does work under Linux and which
 	  doesn't.
 
+# need to enable this on other platforms to support XEN_PCI_FE_ARCH_REPLACE
+config PCI_NATIVE
+	bool
+	depends on PCI
+	default y if !XEN_PCI_FE_ARCH_REPLACE
+    ---help---
+	  Compile in Native PCI access (as opposed to Xen's PCI Frontend).
+
 choice
 	prompt "PCI access mode"
-	depends on PCI && !X86_VISWS
+	depends on PCI_NATIVE && !X86_VISWS
 	default PCI_GOANY
 	---help---
 	  On PCI systems, the BIOS can be used to detect the PCI devices and
@@ -810,6 +818,15 @@
 #config PCI_GOBIOS
 #	bool "BIOS"
 
+config PCI_GOXEN_PCI_FE_STUB
+	bool "Xen PCI Frontend Stub"
+	depends on XEN_PCIDEV_FRONTEND
+	---help---
+	  The Xen PCI Frontend stub replaces the architecture's means of talking
+	  directly to the PCI host bridge with a "dummy" handler which will act
+	  as somewhat of a placeholder until the real Xen PCI Frontend is
+	  initialized.
+
 config PCI_GOMMCONFIG
 	bool "MMConfig"
 
@@ -835,6 +852,11 @@
 	bool
 	depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
 	select ACPI_BOOT
+	default y
+
+config XEN_PCI_FE_STUB
+	bool
+	depends on PCI && XEN_PCIDEV_FRONTEND && !XEN_PCI_FE_ARCH_REPLACE && (PCI_GOXEN_PCI_FE_STUB || PCI_GOANY)
 	default y
 
 source "drivers/pci/pcie/Kconfig"
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/arch/xen/i386/Makefile
--- a/linux-2.6-xen-sparse/arch/xen/i386/Makefile	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/Makefile	Mon Jan 30 18:32:09 2006
@@ -82,7 +82,7 @@
 # \
 #					   arch/xen/$(mcore-y)/
 drivers-$(CONFIG_MATH_EMULATION)	+= arch/i386/math-emu/
-drivers-$(CONFIG_PCI)			+= arch/xen/i386/pci/
+drivers-$(CONFIG_PCI_NATIVE)		+= arch/xen/i386/pci/
 # must be linked after kernel/
 drivers-$(CONFIG_OPROFILE)		+= arch/i386/oprofile/
 drivers-$(CONFIG_PM)			+= arch/i386/power/
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile
--- a/linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile	Mon Jan 30 18:32:09 2006
@@ -7,6 +7,7 @@
 #c-obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
 c-obj-$(CONFIG_PCI_MMCONFIG)	+= mmconfig.o
 c-obj-$(CONFIG_PCI_DIRECT)	+= direct.o
+c-obj-$(CONFIG_XEN_PCI_FE_STUB) += pcifront.o
 
 c-pci-y				:= fixup.o
 c-pci-$(CONFIG_ACPI_PCI)	+= acpi.o
@@ -30,4 +31,6 @@
 # Make sure irq.o gets linked in before common.o
 obj-y	+= $(patsubst common.o,$(l-pci-y) common.o,$(c-obj-y))
 
+obj-$(CONFIG_XEN_PCIDEV_BACKEND_ALLOC) += alloc.o
+
 clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-) $(c-link))
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c
--- a/linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c	Mon Jan 30 18:32:09 2006
@@ -58,6 +58,13 @@
 			res->start = start;
 		}
 	}
+#ifdef CONFIG_XEN_PCIDEV_BACKEND_ALLOC
+	/* Ensure i/o memory is allocated on page boundaries */
+	else if (res->flags & IORESOURCE_MEM) {
+		unsigned long alignto = max(align,PAGE_SIZE);
+		res->start = ALIGN(res->start,alignto);
+	}
+#endif
 }
 
 
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Mon Jan 30 18:32:09 2006
@@ -16,4 +16,6 @@
 obj-$(CONFIG_XEN_NETDEV_FRONTEND)	+= netfront/
 obj-$(CONFIG_XEN_BLKDEV_TAP)    	+= blktap/
 obj-$(CONFIG_XEN_TPMDEV_FRONTEND)	+= tpmfront/
+obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= pciback/
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront/
 
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h
--- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h	Mon Jan 30 18:32:09 2006
@@ -124,6 +124,10 @@
 
 #endif /* __KERNEL__ */
 
+#ifdef CONFIG_XEN_PCIDEV_FRONTEND
+#include <asm-xen/pcifront.h>
+#endif /* CONFIG_XEN_PCIDEV_FRONTEND */
+
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
 #include <asm-generic/pci-dma-compat.h>
 
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/arch/xen/i386/pci/alloc.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/alloc.c	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,16 @@
+/*
+ * PCI Backend - Try to force a re-assignment of resources so that all
+ *               memory resources are allocated on page boundaries
+ */
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+
+static __init int pciback_alloc(void)
+{
+	printk(KERN_INFO "pciback: Attempt to re-allocate PCI resources\n");
+	pci_assign_unassigned_resources();
+	return 0;
+}
+
+subsys_initcall(pciback_alloc);
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/arch/xen/i386/pci/pcifront.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/pcifront.c	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,48 @@
+/*
+ * PCI Frontend Stub - puts some "dummy" functions in to the Linux x86 PCI core
+ *                     to support the Xen PCI Frontend's operation
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include "pci.h"
+
+static int pcifront_enable_irq(struct pci_dev *dev)
+{
+	u8 irq;
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	dev->irq = irq;
+
+	return 0;
+}
+
+extern u8 pci_cache_line_size;
+
+static int __init pcifront_x86_stub_init(void)
+{
+	struct cpuinfo_x86 *c = &boot_cpu_data;
+
+	/* Only install our method if we haven't found real hardware already */
+	if (raw_pci_ops)
+		return 0;
+
+	printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
+
+	/* Copied from arch/i386/pci/common.c */
+	pci_cache_line_size = 32 >> 2;
+	if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
+		pci_cache_line_size = 64 >> 2;	/* K7 & K8 */
+	else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL)
+		pci_cache_line_size = 128 >> 2;	/* P4 */
+
+	/* On x86, we need to disable the normal IRQ routing table and
+	 * just ask the backend
+	 */
+	pcibios_enable_irq = pcifront_enable_irq;
+
+	return 0;
+}
+
+arch_initcall(pcifront_x86_stub_init);
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/Makefile
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,10 @@
+obj-y += pciback.o
+
+pciback-y := pci_stub.o pciback_ops.o xenbus.o
+pciback-y += conf_space.o conf_space_header.o
+pciback-${CONFIG_XEN_PCIDEV_BACKEND_VPCI} += vpci.o
+pciback-${CONFIG_XEN_PCIDEV_BACKEND_PASS} += passthrough.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,324 @@
+/*
+ * PCI Backend - Functions for creating a virtual configuration space for
+ *               exported PCI Devices.
+ *               It's dangerous to allow PCI Driver Domains to change their
+ *               device's resources (memory, i/o ports, interrupts). We need to
+ *               restrict changes to certain PCI Configuration registers:
+ *               BARs, INTERRUPT_PIN, most registers in the header...
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+
+#define DEFINE_PCI_CONFIG(op,size,type) 					\
+int pciback_##op##_config_##size 							\
+(struct pci_dev *dev, int offset, type value, void *data)	\
+{															\
+	return pci_##op##_config_##size (dev, offset, value);	\
+}
+
+DEFINE_PCI_CONFIG(read, byte, u8 *)
+DEFINE_PCI_CONFIG(read, word, u16 *)
+DEFINE_PCI_CONFIG(read, dword, u32 *)
+
+DEFINE_PCI_CONFIG(write, byte, u8)
+DEFINE_PCI_CONFIG(write, word, u16)
+DEFINE_PCI_CONFIG(write, dword, u32)
+
+static int conf_space_read(struct pci_dev *dev,
+			   struct config_field_entry *entry, int offset,
+			   u32 * value)
+{
+	int ret = 0;
+	struct config_field *field = entry->field;
+
+	*value = 0;
+
+	switch (field->size) {
+	case 1:
+		if (field->u.b.read)
+			ret = field->u.b.read(dev, offset, (u8 *) value,
+					      entry->data);
+		break;
+	case 2:
+		if (field->u.w.read)
+			ret = field->u.w.read(dev, offset, (u16 *) value,
+					      entry->data);
+		break;
+	case 4:
+		if (field->u.dw.read)
+			ret = field->u.dw.read(dev, offset, value, entry->data);
+		break;
+	}
+	return ret;
+}
+
+static int conf_space_write(struct pci_dev *dev,
+			    struct config_field_entry *entry, int offset,
+			    u32 value)
+{
+	int ret = 0;
+	struct config_field *field = entry->field;
+
+	switch (field->size) {
+	case 1:
+		if (field->u.b.write)
+			ret = field->u.b.write(dev, offset, (u8) value,
+					       entry->data);
+		break;
+	case 2:
+		if (field->u.w.write)
+			ret = field->u.w.write(dev, offset, (u16) value,
+					       entry->data);
+		break;
+	case 4:
+		if (field->u.dw.write)
+			ret = field->u.dw.write(dev, offset, value,
+					        entry->data);
+		break;
+	}
+	return ret;
+}
+
+static inline u32 get_mask(int size)
+{
+	if (size == 1)
+		return 0xff;
+	else if (size == 2)
+		return 0xffff;
+	else
+		return 0xffffffff;
+}
+
+static inline int valid_request(int offset, int size)
+{
+	/* Validate request (no un-aligned requests) */
+	if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0)
+		return 1;
+	return 0;
+}
+
+static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
+			      u32 offset)
+{
+	if (offset >= 0) {
+		new_val_mask <<= (offset * 8);
+		new_val <<= (offset * 8);
+	} else {
+		new_val_mask >>= (offset * -8);
+		new_val >>= (offset * -8);
+	}
+	val = (val & ~new_val_mask) | (new_val & new_val_mask);
+
+	return val;
+}
+
+static int pcibios_err_to_errno(int err)
+{
+	switch (err) {
+	case PCIBIOS_SUCCESSFUL:
+		return XEN_PCI_ERR_success;
+	case PCIBIOS_DEVICE_NOT_FOUND:
+		return XEN_PCI_ERR_dev_not_found;
+	case PCIBIOS_BAD_REGISTER_NUMBER:
+		return XEN_PCI_ERR_invalid_offset;
+	case PCIBIOS_FUNC_NOT_SUPPORTED:
+		return XEN_PCI_ERR_not_implemented;
+	case PCIBIOS_SET_FAILED:
+		return XEN_PCI_ERR_access_denied;
+	}
+	return err;
+}
+
+int pciback_config_read(struct pci_dev *dev, int offset, int size,
+			u32 * ret_val)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+	int req_start, req_end, field_start, field_end;
+	/* if read fails for any reason, return 0 (as if device didn't respond) */
+	u32 value = 0, tmp_val;
+
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n",
+		       pci_name(dev), size, offset);
+
+	if (!valid_request(offset, size)) {
+		err = XEN_PCI_ERR_invalid_offset;
+		goto out;
+	}
+
+	/* Get the real value first, then modify as appropriate */
+	switch (size) {
+	case 1:
+		err = pci_read_config_byte(dev, offset, (u8 *) & value);
+		break;
+	case 2:
+		err = pci_read_config_word(dev, offset, (u16 *) & value);
+		break;
+	case 4:
+		err = pci_read_config_dword(dev, offset, &value);
+		break;
+	}
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		req_start = offset;
+		req_end = offset + size;
+		field_start = field->offset;
+		field_end = field->offset + field->size;
+
+		if ((req_start >= field_start && req_start < field_end)
+		    || (req_end > field_start && req_end <= field_end)) {
+			err = conf_space_read(dev, cfg_entry, offset, &tmp_val);
+			if (err)
+				goto out;
+
+			value = merge_value(value, tmp_val,
+					    get_mask(field->size),
+					    field_start - req_start);
+		}
+	}
+
+      out:
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
+		       pci_name(dev), size, offset, value);
+
+	*ret_val = value;
+	return pcibios_err_to_errno(err);
+}
+
+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+	u32 tmp_val;
+	int req_start, req_end, field_start, field_end;
+
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG
+		       "pciback: %s: write request %d bytes at 0x%x = %x\n",
+		       pci_name(dev), size, offset, value);
+
+	if (!valid_request(offset, size))
+		return XEN_PCI_ERR_invalid_offset;
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		req_start = offset;
+		req_end = offset + size;
+		field_start = field->offset;
+		field_end = field->offset + field->size;
+
+		if ((req_start >= field_start && req_start < field_end)
+		    || (req_end > field_start && req_end <= field_end)) {
+			tmp_val = 0;
+
+			err = pciback_config_read(dev, offset, size, &tmp_val);
+			if (err)
+				break;
+
+			tmp_val = merge_value(tmp_val, value, get_mask(size),
+					      field_start - req_start);
+
+			err = conf_space_write(dev, cfg_entry, offset, tmp_val);
+		}
+	}
+
+	return pcibios_err_to_errno(err);
+}
+
+void pciback_config_reset(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		if (field->reset)
+			field->reset(dev, field->offset, cfg_entry->data);
+	}
+}
+
+void pciback_config_free(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry, *t;
+	struct config_field *field;
+
+	list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
+		list_del(&cfg_entry->list);
+
+		field = cfg_entry->field;
+
+		if (field->release)
+			field->release(dev, field->offset, cfg_entry->data);
+
+		kfree(cfg_entry);
+	}
+}
+
+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	void *tmp;
+
+	cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
+	if (!cfg_entry) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	cfg_entry->data = NULL;
+	cfg_entry->field = field;
+
+	if (field->init) {
+		tmp = field->init(dev, field->offset);
+
+		if (IS_ERR(tmp)) {
+			err = PTR_ERR(tmp);
+			goto out;
+		}
+
+		cfg_entry->data = tmp;
+	}
+
+	list_add_tail(&cfg_entry->list, &dev_data->config_fields);
+
+      out:
+	if (err)
+		kfree(cfg_entry);
+
+	return err;
+}
+
+/* This sets up the device's virtual configuration space to keep track of 
+ * certain registers (like the base address registers (BARs) so that we can
+ * keep the client from manipulating them directly.
+ */
+int pciback_config_init(struct pci_dev *dev)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+
+	INIT_LIST_HEAD(&dev_data->config_fields);
+
+	err = pciback_config_header_add_fields(dev);
+
+	return err;
+}
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,97 @@
+/*
+ * PCI Backend - Common data structures for overriding the configuration space
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#ifndef __XEN_PCIBACK_CONF_SPACE_H__
+#define __XEN_PCIBACK_CONF_SPACE_H__
+
+#include <linux/list.h>
+
+typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
+typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data);
+typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
+
+typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value,
+				 void *data);
+typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value,
+				void *data);
+typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value,
+				void *data);
+typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value,
+				void *data);
+typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value,
+			       void *data);
+typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
+			       void *data);
+
+/* These are the fields within the configuration space which we
+ * are interested in intercepting reads/writes to and changing their
+ * values.
+ */
+struct config_field {
+	unsigned int     offset;
+	unsigned int     size;
+	conf_field_init  init;
+	conf_field_reset reset;
+	conf_field_free  release;
+	union {
+		struct {
+			conf_dword_write write;
+			conf_dword_read read;
+		} dw;
+		struct {
+			conf_word_write write;
+			conf_word_read read;
+		} w;
+		struct {
+			conf_byte_write write;
+			conf_byte_read read;
+		} b;
+	} u;
+};
+
+struct config_field_entry {
+	struct list_head list;
+	struct config_field *field;
+	void *data;
+};
+
+/* Add fields to a device - the add_fields macro expects to get a pointer to
+ * the first entry in an array (of which the ending is marked by size==0)
+ */
+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field);
+static inline int pciback_config_add_fields(struct pci_dev *dev,
+					    struct config_field *field)
+{
+	int i, err = 0;
+	for (i = 0; field[i].size != 0; i++) {
+		err = pciback_config_add_field(dev, &field[i]);
+		if (err)
+			break;
+	}
+	return err;
+}
+
+/* Initializers which add fields to the virtual configuration space
+ * ** We could add initializers to allow a guest domain to touch
+ * the capability lists (for power management, the AGP bridge, etc.)
+ */
+int pciback_config_header_add_fields(struct pci_dev *dev);
+
+/* Read/Write the real configuration space */
+int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
+			     void *data);
+int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value,
+			     void *data);
+int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value,
+			      void *data);
+int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
+			      void *data);
+int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value,
+			      void *data);
+int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
+			       void *data);
+
+#endif				/* __XEN_PCIBACK_CONF_SPACE_H__ */
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,270 @@
+/*
+ * PCI Backend - Handles the virtual fields in the configuration space headers.
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+
+struct pci_bar_info {
+	u32 val;
+	u32 len_val;
+	int which;
+};
+
+#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
+#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
+
+static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
+{
+	if (!dev->is_enabled && is_enable_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: enable\n",
+			       pci_name(dev));
+		dev->is_enabled = 1;
+		pcibios_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
+	} else if (dev->is_enabled && !is_enable_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: disable\n",
+			       pci_name(dev));
+		pciback_disable_device(dev);
+	}
+
+	if (!dev->is_busmaster && is_master_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: set bus master\n",
+			       pci_name(dev));
+		dev->is_busmaster = 1;
+		pcibios_set_master(dev);
+	}
+
+	if (value & PCI_COMMAND_INVALIDATE) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG
+			       "pciback: %s: enable memory-write-invalidate\n",
+			       pci_name(dev));
+		pci_set_mwi(dev);
+	}
+
+	return pci_write_config_word(dev, offset, value);
+}
+
+static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
+{
+	struct pci_bar_info *bar = data;
+	int i;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	bar->which = 0;
+	/* Because writes *could* occur in bytes, if any byte is all 1s, switch */
+	for (i = 0; i < 4; i++)
+		if (((value >> (i * 8)) & 0xff) == 0xff)
+			bar->which = 1;
+
+	/* Do we need to support enabling/disabling the rom address here? */
+
+	return 0;
+}
+
+/* For the BARs, only allow writes which write ~0 or
+ * the correct resource information
+ * (Needed for when the driver probes the resource usage)
+ */
+static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
+{
+	int i;
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	bar->which = 0;
+
+	/* Because writes *could* occur in bytes,
+	 * if any byte is all 1s, switch
+	 */
+	for (i = 0; i < 4; i++)
+		if (((value >> (i * 8)) & 0xff) == 0xff)
+			bar->which = 1;
+
+	return 0;
+}
+
+static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	*value = bar->which ? bar->len_val : bar->val;
+
+	return 0;
+}
+
+static inline void read_dev_bar(struct pci_dev *dev,
+				struct pci_bar_info *bar_info, int offset,
+				u32 len_mask)
+{
+	pci_read_config_dword(dev, offset, &bar_info->val);
+	pci_write_config_dword(dev, offset, len_mask);
+	pci_read_config_dword(dev, offset, &bar_info->len_val);
+	pci_write_config_dword(dev, offset, bar_info->val);
+}
+
+static void *bar_init(struct pci_dev *dev, int offset)
+{
+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
+
+	if (!bar)
+		return ERR_PTR(-ENOMEM);
+
+	read_dev_bar(dev, bar, offset, ~0);
+	bar->which = 0;
+
+	return bar;
+}
+
+static void *rom_init(struct pci_dev *dev, int offset)
+{
+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
+
+	if (!bar)
+		return ERR_PTR(-ENOMEM);
+
+	read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
+	bar->which = 0;
+
+	return bar;
+}
+
+static void bar_reset(struct pci_dev *dev, int offset, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	bar->which = 0;
+}
+
+static void bar_release(struct pci_dev *dev, int offset, void *data)
+{
+	kfree(data);
+}
+
+static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
+			  void *data)
+{
+	*value = (u8) dev->irq;
+
+	return 0;
+}
+
+struct config_field header_common[] = {
+	{
+	 .offset    = PCI_COMMAND,
+	 .size      = 2,
+	 .u.w.read  = pciback_read_config_word,
+	 .u.w.write = command_write,
+	 },
+	{
+	 .offset    = PCI_INTERRUPT_LINE,
+	 .size      = 1,
+	 .u.b.read  = interrupt_read,
+	 .u.b.write = NULL,
+	 },
+	{
+	 /* Any side effects of letting driver domain control cache line? */
+	 .offset    = PCI_CACHE_LINE_SIZE,
+	 .size      = 1,
+	 .u.b.read  = pciback_read_config_byte,
+	 .u.b.write = pciback_write_config_byte,
+	 },
+	{
+	 .size = 0,
+	 },
+};
+
+#define CFG_FIELD_BAR(reg_offset) 			\
+	{ 						\
+	 .offset     = reg_offset, 			\
+	 .size       = 4, 				\
+	 .init       = bar_init, 			\
+	 .reset      = bar_reset, 			\
+	 .release    = bar_release, 			\
+	 .u.dw.read  = bar_read, 			\
+	 .u.dw.write = bar_write, 			\
+	 }
+
+#define CFG_FIELD_ROM(reg_offset) 			\
+	{ 						\
+	 .offset     = reg_offset, 			\
+	 .size       = 4, 				\
+	 .init       = rom_init, 			\
+	 .reset      = bar_reset, 			\
+	 .release    = bar_release, 			\
+	 .u.dw.read  = bar_read, 			\
+	 .u.dw.write = rom_write, 			\
+	 }
+
+struct config_field header_0[] = {
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
+	CFG_FIELD_ROM(PCI_ROM_ADDRESS),
+	{
+	 .size = 0,
+	 },
+};
+
+struct config_field header_1[] = {
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
+	CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
+	{
+	 .size = 0,
+	 },
+};
+
+int pciback_config_header_add_fields(struct pci_dev *dev)
+{
+	int err;
+
+	err = pciback_config_add_fields(dev, header_common);
+	if (err)
+		goto out;
+
+	switch (dev->hdr_type) {
+	case PCI_HEADER_TYPE_NORMAL:
+		err = pciback_config_add_fields(dev, header_0);
+		break;
+
+	case PCI_HEADER_TYPE_BRIDGE:
+		err = pciback_config_add_fields(dev, header_1);
+		break;
+
+	default:
+		err = -EINVAL;
+		printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
+		       pci_name(dev), dev->hdr_type);
+		break;
+	}
+
+      out:
+	return err;
+}
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,117 @@
+/*
+ * PCI Backend - Provides restricted access to the real PCI bus topology
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/list.h>
+#include <linux/pci.h>
+#include "pciback.h"
+
+struct passthrough_dev_data {
+	struct list_head dev_list;
+};
+
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry;
+
+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
+		if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
+		    && bus == (unsigned int)dev_entry->dev->bus->number
+		    && devfn == dev_entry->dev->devfn)
+			return dev_entry->dev;
+	}
+
+	return NULL;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry;
+
+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
+	if (!dev_entry)
+		return -ENOMEM;
+	dev_entry->dev = dev;
+
+	list_add_tail(&dev_entry->list, &dev_data->dev_list);
+
+	return 0;
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+	struct passthrough_dev_data *dev_data;
+
+	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
+	if (!dev_data)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&dev_data->dev_list);
+
+	pdev->pci_dev_data = dev_data;
+
+	return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb publish_root_cb)
+{
+	int err = 0;
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry, *e;
+	struct pci_dev *dev;
+	int found;
+	unsigned int domain, bus;
+
+	domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
+	bus = (unsigned int)dev_entry->dev->bus->number;
+
+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
+
+		/* Only publish this device as a root if none of its
+		 * parent bridges are exported
+		 */
+		found = 0;
+		dev = dev_entry->dev->bus->self;
+		for (; !found && dev != NULL; dev = dev->bus->self) {
+			list_for_each_entry(e, &dev_data->dev_list, list) {
+				if (dev == e->dev) {
+					found = 1;
+					break;
+				}
+			}
+		}
+
+		if (!found) {
+			err = publish_root_cb(pdev, domain, bus);
+			if (err)
+				break;
+		}
+	}
+
+	return err;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry, *t;
+
+	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
+		list_del(&dev_entry->list);
+		pcistub_put_pci_dev(dev_entry->dev);
+		kfree(dev_entry);
+	}
+
+	kfree(dev_data);
+	pdev->pci_dev_data = NULL;
+}
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,377 @@
+/*
+ * PCI Stub Driver - Grabs devices in backend to be exported later
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include "pciback.h"
+
+static char *pci_devs_to_hide = NULL;
+module_param_named(hide, pci_devs_to_hide, charp, 0444);
+
+struct pci_stub_device_id {
+	struct list_head slot_list;
+	int domain;
+	unsigned char bus;
+	unsigned int devfn;
+};
+LIST_HEAD(pci_stub_device_ids);
+
+struct pci_stub_device {
+	struct list_head dev_list;
+	struct pci_dev *dev;
+	atomic_t in_use;
+};
+/* Access to pci_stub_devices & seized_devices lists and the initialize_devices
+ * flag must be locked with pci_stub_devices_lock
+ */
+DEFINE_SPINLOCK(pci_stub_devices_lock);
+LIST_HEAD(pci_stub_devices);
+
+/* wait for device_initcall before initializing our devices
+ * (see pcistub_init_devices_late)
+ */
+static int initialize_devices = 0;
+LIST_HEAD(seized_devices);
+
+static inline struct pci_dev *get_pci_dev(struct pci_stub_device *psdev)
+{
+	if (atomic_dec_and_test(&psdev->in_use))
+		return psdev->dev;
+	else {
+		atomic_inc(&psdev->in_use);
+		return NULL;
+	}
+}
+
+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
+					    int slot, int func)
+{
+	struct pci_stub_device *psdev;
+	struct pci_dev *found_dev = NULL;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev != NULL
+		    && domain == pci_domain_nr(psdev->dev->bus)
+		    && bus == psdev->dev->bus->number
+		    && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
+			found_dev = get_pci_dev(psdev);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+	return found_dev;
+}
+
+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+	struct pci_dev *found_dev = NULL;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev == dev) {
+			found_dev = get_pci_dev(psdev);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+	return found_dev;
+}
+
+void pcistub_put_pci_dev(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev == dev) {
+			/* Cleanup our device
+			 * (so it's ready for the next domain)
+			 */
+			pciback_reset_device(psdev->dev);
+
+			atomic_inc(&psdev->in_use);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+}
+
+static int __devinit pcistub_match(struct pci_dev *dev,
+				   struct pci_stub_device_id *pdev_id)
+{
+	/* Match the specified device by domain, bus, slot, func and also if
+	 * any of the device's parent bridges match.
+	 */
+	for (; dev != NULL; dev = dev->bus->self) {
+		if (pci_domain_nr(dev->bus) == pdev_id->domain
+		    && dev->bus->number == pdev_id->bus
+		    && dev->devfn == pdev_id->devfn)
+			return 1;
+	}
+
+	return 0;
+}
+
+static int __devinit pcistub_init_device(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data;
+	int err = 0;
+
+	/* The PCI backend is not intended to be a module (or to work with
+	 * removable PCI devices (yet). If it were, pciback_config_free()
+	 * would need to be called somewhere to free the memory allocated
+	 * here and then to call kfree(pci_get_drvdata(psdev->dev)).
+	 */
+	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
+	if (!dev_data) {
+		err = -ENOMEM;
+		goto out;
+	}
+	pci_set_drvdata(dev, dev_data);
+
+	err = pciback_config_init(dev);
+	if (err)
+		goto out;
+
+	/* HACK: Force device (& ACPI) to determine what IRQ it's on - we
+	 * must do this here because pcibios_enable_device may specify
+	 * the pci device's true irq (and possibly its other resources)
+	 * if they differ from what's in the configuration space.
+	 * This makes the assumption that the device's resources won't
+	 * change after this point (otherwise this code may break!)
+	 */
+	err = pci_enable_device(dev);
+	if (err)
+		goto config_release;
+
+	/* Now disable the device (this also ensures some private device
+	 * data is setup before we export)
+	 * This calls pciback_config_reset(dev)
+	 */
+	pciback_reset_device(dev);
+
+	return 0;
+
+      config_release:
+	pciback_config_free(dev);
+
+      out:
+	pci_set_drvdata(dev, NULL);
+	kfree(dev_data);
+	return err;
+}
+
+/*
+ * Because some initialization still happens on
+ * devices during fs_initcall, we need to defer
+ * full initialization of our devices until
+ * device_initcall.
+ */
+static int __init pcistub_init_devices_late(void)
+{
+	struct pci_stub_device *psdev, *t;
+	int err = 0;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry_safe(psdev, t, &seized_devices, dev_list) {
+		list_del(&psdev->dev_list);
+		err = pcistub_init_device(psdev->dev);
+		if (err) {
+			printk(KERN_ERR
+			       "pciback: %s error %d initializing device\n",
+			       pci_name(psdev->dev), err);
+			kfree(psdev);
+			continue;
+		}
+
+		list_add_tail(&psdev->dev_list, &pci_stub_devices);
+	}
+
+	initialize_devices = 1;
+
+	spin_unlock(&pci_stub_devices_lock);
+
+	return 0;
+}
+
+device_initcall(pcistub_init_devices_late);
+
+static int __devinit pcistub_seize(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+	int err = 0;
+
+	psdev = kmalloc(sizeof(*psdev), GFP_KERNEL);
+	if (!psdev)
+		return -ENOMEM;
+
+	psdev->dev = dev;
+	atomic_set(&psdev->in_use, 1);
+
+	spin_lock(&pci_stub_devices_lock);
+
+	if (initialize_devices) {
+		err = pcistub_init_device(psdev->dev);
+		if (err)
+			goto out;
+
+		list_add(&psdev->dev_list, &pci_stub_devices);
+	} else
+		list_add(&psdev->dev_list, &seized_devices);
+
+      out:
+	spin_unlock(&pci_stub_devices_lock);
+
+	if (err)
+		kfree(psdev);
+
+	return err;
+}
+
+static int __devinit pcistub_probe(struct pci_dev *dev,
+				   const struct pci_device_id *id)
+{
+	struct pci_stub_device_id *pdev_id;
+	struct pci_dev *seized_dev;
+	int err = 0;
+
+	list_for_each_entry(pdev_id, &pci_stub_device_ids, slot_list) {
+
+		if (!pcistub_match(dev, pdev_id))
+			continue;
+
+		if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
+		    && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
+			printk(KERN_ERR
+			       "pciback: %s: can't export pci devices that "
+			       "don't have a normal (0) or bridge (1) "
+			       "header type!\n", pci_name(dev));
+			break;
+		}
+
+		pr_info("pciback: seizing PCI device %s\n", pci_name(dev));
+		seized_dev = pci_dev_get(dev);
+
+		if (seized_dev) {
+			err = pcistub_seize(seized_dev);
+			if (err) {
+				pci_dev_put(dev);
+				goto out;
+			}
+
+			/* Success! */
+			goto out;
+		}
+	}
+
+	/* Didn't find the device */
+	err = -ENODEV;
+
+      out:
+	return err;
+}
+
+struct pci_device_id pcistub_ids[] = {
+	{
+	 .vendor = PCI_ANY_ID,
+	 .device = PCI_ANY_ID,
+	 .subvendor = PCI_ANY_ID,
+	 .subdevice = PCI_ANY_ID,
+	 },
+	{0,},
+};
+
+/*
+ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't
+ * for a normal device. I don't want it to be loaded automatically.
+ */
+
+struct pci_driver pciback_pci_driver = {
+	.name = "pciback",
+	.id_table = pcistub_ids,
+	.probe = pcistub_probe,
+};
+
+static int __init pcistub_init(void)
+{
+	int pos = 0;
+	struct pci_stub_device_id *pci_dev_id;
+	int err = 0;
+	int domain, bus, slot, func;
+	int parsed;
+
+	if (pci_devs_to_hide && *pci_devs_to_hide) {
+		do {
+			parsed = 0;
+
+			err = sscanf(pci_devs_to_hide + pos,
+				     " (%x:%x:%x.%x) %n",
+				     &domain, &bus, &slot, &func, &parsed);
+			if (err != 4) {
+				domain = 0;
+				err = sscanf(pci_devs_to_hide + pos,
+					     " (%x:%x.%x) %n",
+					     &bus, &slot, &func, &parsed);
+				if (err != 3)
+					goto parse_error;
+			}
+
+			pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
+			if (!pci_dev_id) {
+				err = -ENOMEM;
+				goto out;
+			}
+
+			pci_dev_id->domain = domain;
+			pci_dev_id->bus = bus;
+			pci_dev_id->devfn = PCI_DEVFN(slot, func);
+
+			pr_debug
+			    ("pciback: wants to seize %04x:%02x:%02x.%01x\n",
+			     domain, bus, slot, func);
+
+			list_add_tail(&pci_dev_id->slot_list,
+				      &pci_stub_device_ids);
+
+			/* if parsed<=0, we've reached the end of the string */
+			pos += parsed;
+		} while (parsed > 0 && pci_devs_to_hide[pos]);
+
+		/* If we're the first PCI Device Driver to register, we're the
+		 * first one to get offered PCI devices as they become
+		 * available (and thus we can be the first to grab them)
+		 */
+		pci_register_driver(&pciback_pci_driver);
+	}
+
+      out:
+	return err;
+
+      parse_error:
+	printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n",
+	       pci_devs_to_hide + pos);
+	return -EINVAL;
+}
+
+/*
+ * fs_initcall happens before device_initcall
+ * so pciback *should* get called first (b/c we 
+ * want to suck up any device before other drivers
+ * get a chance by being the first pci device
+ * driver to register)
+ */
+fs_initcall(pcistub_init);
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,73 @@
+/*
+ * PCI Backend Common Data Structures & Function Declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCIBACK_H__
+#define __XEN_PCIBACK_H__
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <asm-xen/xenbus.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm-xen/xen-public/io/pciif.h>
+
+struct pci_dev_entry {
+	struct list_head list;
+	struct pci_dev *dev;
+};
+
+struct pciback_device {
+	void *pci_dev_data;
+	spinlock_t dev_lock;
+
+	struct xenbus_device *xdev;
+
+	struct xenbus_watch be_watch;
+	u8 be_watching;
+
+	int evtchn_irq;
+
+	struct xen_pci_sharedinfo *sh_info;
+};
+
+struct pciback_dev_data {
+	struct list_head config_fields;
+};
+
+/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
+					    int slot, int func);
+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev);
+void pcistub_put_pci_dev(struct pci_dev *dev);
+
+/* Ensure a device is turned off or reset */
+void pciback_disable_device(struct pci_dev *dev);
+void pciback_reset_device(struct pci_dev *pdev);
+
+/* Access a virtual configuration space for a PCI device */
+int pciback_config_init(struct pci_dev *dev);
+void pciback_config_reset(struct pci_dev *dev);
+void pciback_config_free(struct pci_dev *dev);
+int pciback_config_read(struct pci_dev *dev, int offset, int size,
+			u32 * ret_val);
+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
+
+/* Handle requests for specific devices from the frontend */
+typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
+				    unsigned int domain, unsigned int bus);
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn);
+int pciback_init_devices(struct pciback_device *pdev);
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb cb);
+void pciback_release_devices(struct pciback_device *pdev);
+
+/* Handles events from front-end */
+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
+
+extern int verbose_request;
+#endif
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,84 @@
+/*
+ * PCI Backend Operations - respond to PCI requests from Frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <asm/bitops.h>
+#include "pciback.h"
+
+int verbose_request = 0;
+module_param(verbose_request, int, 0644);
+
+/* For those architectures without a pcibios_disable_device */
+void __attribute__ ((weak)) pcibios_disable_device(struct pci_dev *dev) { }
+
+void pciback_disable_device(struct pci_dev *dev)
+{
+	if (dev->is_enabled) {
+		dev->is_enabled = 0;
+		pcibios_disable_device(dev);
+	}
+}
+
+/* Ensure a device is "turned off" and ready to be exported.
+ * This also sets up the device's private data to keep track of what should
+ * be in the base address registers (BARs) so that we can keep the
+ * client from manipulating them directly.
+ */
+void pciback_reset_device(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	/* Disable devices (but not bridges) */
+	if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
+		pciback_disable_device(dev);
+
+		pci_write_config_word(dev, PCI_COMMAND, 0);
+
+		dev->is_enabled = 0;
+		dev->is_busmaster = 0;
+	} else {
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		if (cmd & (PCI_COMMAND_INVALIDATE)) {
+			cmd &= ~(PCI_COMMAND_INVALIDATE);
+			pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+			dev->is_busmaster = 0;
+		}
+	}
+
+	pciback_config_reset(dev);
+}
+
+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pciback_device *pdev = dev_id;
+	struct pci_dev *dev;
+	struct xen_pci_op *op = &pdev->sh_info->op;
+
+	if (unlikely(!test_bit(_XEN_PCIF_active,
+			       (unsigned long *)&pdev->sh_info->flags))) {
+		pr_debug("pciback: interrupt, but no active operation\n");
+		goto out;
+	}
+
+	dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
+
+	if (dev == NULL)
+		op->err = XEN_PCI_ERR_dev_not_found;
+	else if (op->cmd == XEN_PCI_OP_conf_read)
+		op->err = pciback_config_read(dev, op->offset, op->size,
+					      &op->value);
+	else if (op->cmd == XEN_PCI_OP_conf_write)
+		op->err = pciback_config_write(dev, op->offset, op->size,
+					       op->value);
+	else
+		op->err = XEN_PCI_ERR_not_implemented;
+
+	wmb();
+	clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+
+      out:
+	return IRQ_HANDLED;
+}
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,163 @@
+/*
+ * PCI Backend - Provides a Virtual PCI bus (with real devices)
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include "pciback.h"
+
+#define PCI_SLOT_MAX 32
+
+struct vpci_dev_data {
+	struct list_head dev_list[PCI_SLOT_MAX];
+};
+
+static inline struct list_head *list_first(struct list_head *head)
+{
+	return head->next;
+}
+
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn)
+{
+	struct pci_dev_entry *dev_entry;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	if (domain != 0 || bus != 0)
+		return NULL;
+
+	if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
+		/* we don't need to lock the list here because once the backend
+		 * is in operation, it won't have any more devices addeded
+		 * (or removed).
+		 */
+		list_for_each_entry(dev_entry,
+				    &vpci_dev->dev_list[PCI_SLOT(devfn)],
+				    list) {
+			if (PCI_FUNC(dev_entry->dev->devfn) == PCI_FUNC(devfn))
+				return dev_entry->dev;
+		}
+	}
+	return NULL;
+}
+
+static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
+{
+	if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
+	    && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn))
+		return 1;
+
+	return 0;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+	int err = 0, slot;
+	struct pci_dev_entry *t, *dev_entry;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
+		err = -EFAULT;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Can't export bridges on the virtual PCI bus");
+		goto out;
+	}
+
+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
+	if (!dev_entry) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error adding entry to virtual PCI bus");
+		goto out;
+	}
+
+	dev_entry->dev = dev;
+
+	/* Keep multi-function devices together on the virtual PCI bus */
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		if (!list_empty(&vpci_dev->dev_list[slot])) {
+			t = list_entry(list_first(&vpci_dev->dev_list[slot]),
+				       struct pci_dev_entry, list);
+
+			if (match_slot(dev, t->dev)) {
+				pr_info("pciback: vpci: %s: "
+					"assign to virtual slot %d func %d\n",
+					pci_name(dev), slot,
+					PCI_FUNC(dev->devfn));
+				list_add_tail(&dev_entry->list,
+					      &vpci_dev->dev_list[slot]);
+				goto out;
+			}
+		}
+	}
+
+	/* Assign to a new slot on the virtual PCI bus */
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		if (list_empty(&vpci_dev->dev_list[slot])) {
+			printk(KERN_INFO
+			       "pciback: vpci: %s: assign to virtual slot %d\n",
+			       pci_name(dev), slot);
+			list_add_tail(&dev_entry->list,
+				      &vpci_dev->dev_list[slot]);
+			goto out;
+		}
+	}
+
+	err = -ENOMEM;
+	xenbus_dev_fatal(pdev->xdev, err,
+			 "No more space on root virtual PCI bus");
+
+      out:
+	return err;
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+	int slot;
+	struct vpci_dev_data *vpci_dev;
+
+	vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
+	if (!vpci_dev)
+		return -ENOMEM;
+
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
+	}
+
+	pdev->pci_dev_data = vpci_dev;
+
+	return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb publish_cb)
+{
+	/* The Virtual PCI bus has only one root */
+	return publish_cb(pdev, 0, 0);
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+	int slot;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		struct pci_dev_entry *e, *tmp;
+		list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
+					 list) {
+			list_del(&e->list);
+			pcistub_put_pci_dev(e->dev);
+			kfree(e);
+		}
+	}
+
+	kfree(vpci_dev);
+	pdev->pci_dev_data = NULL;
+}
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,435 @@
+/*
+ * PCI Backend Xenbus Setup - handles setup with frontend and xend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <asm-xen/xenbus.h>
+#include <asm-xen/evtchn.h>
+#include "pciback.h"
+
+#define INVALID_EVTCHN_IRQ  (-1)
+
+struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
+{
+	struct pciback_device *pdev;
+
+	pdev = kmalloc(sizeof(struct pciback_device), GFP_KERNEL);
+	if (pdev == NULL)
+		goto out;
+	dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
+
+	pdev->xdev = xdev;
+	xdev->data = pdev;
+
+	spin_lock_init(&pdev->dev_lock);
+
+	pdev->sh_info = NULL;
+	pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
+	pdev->be_watching = 0;
+
+	if (pciback_init_devices(pdev)) {
+		kfree(pdev);
+		pdev = NULL;
+	}
+      out:
+	return pdev;
+}
+
+void free_pdev(struct pciback_device *pdev)
+{
+	if (pdev->be_watching)
+		unregister_xenbus_watch(&pdev->be_watch);
+
+	/* Ensure the guest can't trigger our handler before removing devices */
+	if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ)
+		unbind_from_irqhandler(pdev->evtchn_irq, pdev);
+
+	if (pdev->sh_info)
+		xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
+
+	pciback_release_devices(pdev);
+
+	pdev->xdev->data = NULL;
+	pdev->xdev = NULL;
+
+	kfree(pdev);
+}
+
+static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
+			     int remote_evtchn)
+{
+	int err = 0;
+	int evtchn;
+	dev_dbg(&pdev->xdev->dev,
+		"Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
+		gnt_ref, remote_evtchn);
+
+	err =
+	    xenbus_map_ring_valloc(pdev->xdev, gnt_ref,
+				   (void **)&pdev->sh_info);
+	if (err)
+		goto out;
+
+	err = xenbus_bind_evtchn(pdev->xdev, remote_evtchn, &evtchn);
+	if (err)
+		goto out;
+
+	err = bind_evtchn_to_irqhandler(evtchn, pciback_handle_event,
+					SA_SAMPLE_RANDOM, "pciback", pdev);
+	if (err < 0) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error binding event channel to IRQ");
+		goto out;
+	}
+	pdev->evtchn_irq = err;
+	err = 0;
+
+	dev_dbg(&pdev->xdev->dev, "Attached!\n");
+      out:
+	return err;
+}
+
+static int pciback_attach(struct pciback_device *pdev)
+{
+	int err = 0;
+	int gnt_ref, remote_evtchn;
+	char *magic = NULL;
+
+	spin_lock(&pdev->dev_lock);
+
+	/* Make sure we only do this setup once */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	/* Wait for frontend to state that it has published the configuration */
+	if (xenbus_read_driver_state(pdev->xdev->otherend) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
+
+	err = xenbus_gather(XBT_NULL, pdev->xdev->otherend,
+			    "pci-op-ref", "%u", &gnt_ref,
+			    "event-channel", "%u", &remote_evtchn,
+			    "magic", NULL, &magic, NULL);
+	if (err) {
+		/* If configuration didn't get read correctly, wait longer */
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading configuration from frontend");
+		goto out;
+	}
+
+	if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
+		xenbus_dev_fatal(pdev->xdev, -EFAULT,
+				 "version mismatch (%s/%s) with pcifront - "
+				 "halting pciback",
+				 magic, XEN_PCI_MAGIC);
+		goto out;
+	}
+
+	err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
+	if (err)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "Connecting...\n");
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
+	if (err)
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error switching to connected state!");
+
+	dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
+      out:
+	spin_unlock(&pdev->dev_lock);
+
+	if (magic)
+		kfree(magic);
+
+	return err;
+}
+
+static void pciback_frontend_changed(struct xenbus_device *xdev,
+				     XenbusState fe_state)
+{
+	struct pciback_device *pdev = xdev->data;
+
+	dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
+
+	switch (fe_state) {
+	case XenbusStateInitialised:
+		pciback_attach(pdev);
+		break;
+
+	case XenbusStateClosing:
+		xenbus_switch_state(xdev, XBT_NULL, XenbusStateClosing);
+		break;
+
+	case XenbusStateClosed:
+		dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
+		device_unregister(&xdev->dev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pciback_publish_pci_root(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus)
+{
+	unsigned int d, b;
+	int i, root_num, len, err;
+	char str[64];
+
+	dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
+			   "root_num", "%d", &root_num);
+	if (err == 0 || err == -ENOENT)
+		root_num = 0;
+	else if (err < 0)
+		goto out;
+
+	/* Verify that we haven't already published this pci root */
+	for (i = 0; i < root_num; i++) {
+		len = snprintf(str, sizeof(str), "root-%d", i);
+		if (unlikely(len >= (sizeof(str) - 1))) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
+				   str, "%x:%x", &d, &b);
+		if (err < 0)
+			goto out;
+		if (err != 2) {
+			err = -EINVAL;
+			goto out;
+		}
+
+		if (d == domain && b == bus) {
+			err = 0;
+			goto out;
+		}
+	}
+
+	len = snprintf(str, sizeof(str), "root-%d", root_num);
+	if (unlikely(len >= (sizeof(str) - 1))) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
+		root_num, domain, bus);
+
+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename, str,
+			    "%04x:%02x", domain, bus);
+	if (err)
+		goto out;
+
+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename,
+			    "root_num", "%d", (root_num + 1));
+
+      out:
+	return err;
+}
+
+static int pciback_export_device(struct pciback_device *pdev,
+				 int domain, int bus, int slot, int func)
+{
+	struct pci_dev *dev;
+	int err = 0;
+
+	dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
+		domain, bus, slot, func);
+
+	dev = pcistub_get_pci_dev_by_slot(domain, bus, slot, func);
+	if (!dev) {
+		err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Couldn't locate PCI device "
+				 "(%04x:%02x:%02x.%01x)! "
+				 "perhaps already in-use?",
+				 domain, bus, slot, func);
+		goto out;
+	}
+
+	err = pciback_add_pci_dev(pdev, dev);
+	if (err)
+		goto out;
+
+	/* TODO: If this is a bridge, export all the children (this won't work
+	 * for children dynamically added to the bus later!) - This is
+	 * trivial in kernels >= 2.6.14 with pci_walk_bus(dev->subordinate)
+	 */
+      out:
+	return err;
+}
+
+static int pciback_setup_backend(struct pciback_device *pdev)
+{
+	/* Get configuration from xend (if available now) */
+	int domain, bus, slot, func;
+	int err = 0;
+	int i, num_devs;
+	char dev_str[64];
+
+	spin_lock(&pdev->dev_lock);
+
+	/* It's possible we could get the call to setup twice, so make sure
+	 * we're not already connected.
+	 */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitWait)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "getting be setup\n");
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, "num_devs", "%d",
+			   &num_devs);
+	if (err != 1) {
+		if (err >= 0)
+			err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading number of devices");
+		goto out;
+	}
+
+	for (i = 0; i < num_devs; i++) {
+		int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
+		if (unlikely(l >= (sizeof(dev_str) - 1))) {
+			err = -ENOMEM;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "String overflow while reading "
+					 "configuration");
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, dev_str,
+				   "%x:%x:%x.%x", &domain, &bus, &slot, &func);
+		if (err < 0) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error reading device configuration");
+			goto out;
+		}
+		if (err != 4) {
+			err = -EINVAL;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error parsing pci device "
+					 "configuration");
+			goto out;
+		}
+
+		err = pciback_export_device(pdev, domain, bus, slot, func);
+		if (err)
+			goto out;
+	}
+
+	err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error while publish PCI root buses "
+				 "for frontend");
+		goto out;
+	}
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateInitialised);
+	if (err)
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error switching to initialised state!");
+
+      out:
+	spin_unlock(&pdev->dev_lock);
+
+	if (!err)
+		/* see if pcifront is already configured (if not, we'll wait) */
+		pciback_attach(pdev);
+
+	return err;
+}
+
+static void pciback_be_watch(struct xenbus_watch *watch,
+			     const char **vec, unsigned int len)
+{
+	struct pciback_device *pdev =
+	    container_of(watch, struct pciback_device, be_watch);
+
+	switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
+	case XenbusStateInitWait:
+		pciback_setup_backend(pdev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pciback_xenbus_probe(struct xenbus_device *dev,
+				const struct xenbus_device_id *id)
+{
+	int err = 0;
+	struct pciback_device *pdev = alloc_pdev(dev);
+
+	if (pdev == NULL) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(dev, err,
+				 "Error allocating pciback_device struct");
+		goto out;
+	}
+
+	/* wait for xend to configure us */
+	err = xenbus_switch_state(dev, XBT_NULL, XenbusStateInitWait);
+	if (err)
+		goto out;
+
+	/* watch the backend node for backend configuration information */
+	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
+				pciback_be_watch);
+	if (err)
+		goto out;
+	pdev->be_watching = 1;
+
+	/* We need to force a call to our callback here in case
+	 * xend already configured us!
+	 */
+	pciback_be_watch(&pdev->be_watch, NULL, 0);
+
+      out:
+	return err;
+}
+
+static int pciback_xenbus_remove(struct xenbus_device *dev)
+{
+	struct pciback_device *pdev = dev->data;
+
+	if (pdev != NULL)
+		free_pdev(pdev);
+
+	return 0;
+}
+
+static struct xenbus_device_id xenpci_ids[] = {
+	{"pci"},
+	{{0}},
+};
+
+static struct xenbus_driver xenbus_pciback_driver = {
+	.name 			= "pciback",
+	.owner 			= THIS_MODULE,
+	.ids 			= xenpci_ids,
+	.probe 			= pciback_xenbus_probe,
+	.remove 		= pciback_xenbus_remove,
+	.otherend_changed 	= pciback_frontend_changed,
+};
+
+static __init int pciback_xenbus_register(void)
+{
+	return xenbus_register_backend(&xenbus_pciback_driver);
+}
+
+/* Must only initialize our xenbus driver after the pcistub driver */
+device_initcall(pciback_xenbus_register);
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,8 @@
+obj-y += pcifront.o
+
+pcifront-y := pci_op.o xenbus.o pci.o
+pcifront-$(CONFIG_XEN_PCI_FE_ARCH_REPLACE) += arch.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pcifront/arch.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/arch.c	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,98 @@
+/*
+ * PCI Frontend Arch Replacement Code - replaces an architecture's PCI access
+ *              code with a generic, Xen version (Experimental)
+ * - This file *should* be arch-independent (except for
+ *   pci_mmap_page_range) and should replace an arch's PCI implementation
+ * - You must prevent an architecture's PCI code from compiling into the kernel
+ *   when you use the code contained here.
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+/* More or less copied from other architectures */
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+	u16 cmd, oldcmd;
+	u8 irq;
+	int i;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	oldcmd = cmd;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		struct resource *r = &dev->resource[i];
+
+		if (!(mask & (1 << i)))
+			continue;
+
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+
+	if (cmd != oldcmd) {
+		printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n",
+		       pci_name(dev), cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	dev->irq = irq;
+
+	return 0;
+}
+
+#define CMD_DISABLE_BITS \
+	(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER)
+void pcibios_disable_device(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+	if (cmd & CMD_DISABLE_BITS) {
+		cmd &= ~CMD_DISABLE_BITS;
+
+		printk(KERN_DEBUG "PCI: Disabling device: (%s), cmd %x\n",
+		       pci_name(dev), cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+}
+
+char *pcibios_setup(char *str)
+{
+	/** Return NULL if we accept an option, str if we don't */
+	return str;
+}
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+	/* Handled by backend when we turn the master
+	 * bit on in the PCI_COMMAND register */
+}
+
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size, unsigned long align)
+{
+}
+
+void pcibios_fixup_bus(struct pci_bus *bus)
+{
+}
+
+unsigned int pcibios_assign_all_busses(void)
+{
+	return 0;
+}
+
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+			enum pci_mmap_state mmap_state, int write_combine)
+{
+	printk(KERN_ERR "%s: mmap_page_range not implemented!\n",
+	       pci_name(dev));
+	return -EINVAL;
+}
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,44 @@
+/*
+ * PCI Frontend Operations - ensure only one PCI frontend runs at a time
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include "pcifront.h"
+
+DEFINE_SPINLOCK(pcifront_dev_lock);
+static struct pcifront_device *pcifront_dev = NULL;
+
+int pcifront_connect(struct pcifront_device *pdev)
+{
+	int err = 0;
+
+	spin_lock(&pcifront_dev_lock);
+
+	if (!pcifront_dev)
+		dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
+	else {
+		dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
+		err = -EEXIST;
+	}
+
+	spin_unlock(&pcifront_dev_lock);
+
+	return err;
+}
+
+void pcifront_disconnect(struct pcifront_device *pdev)
+{
+	spin_lock(&pcifront_dev_lock);
+
+	if (pdev == pcifront_dev) {
+		dev_info(&pdev->xdev->dev,
+			 "Disconnecting PCI Frontend Buses\n");
+		pcifront_dev = NULL;
+	}
+
+	spin_unlock(&pcifront_dev_lock);
+}
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,224 @@
+/*
+ * PCI Frontend Operations - Communicates with frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <asm-xen/evtchn.h>
+#include "pcifront.h"
+
+int verbose_request = 0;
+module_param(verbose_request, int, 0644);
+
+static int errno_to_pcibios_err(int errno)
+{
+	switch (errno) {
+	case XEN_PCI_ERR_success:
+		return PCIBIOS_SUCCESSFUL;
+
+	case XEN_PCI_ERR_dev_not_found:
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	case XEN_PCI_ERR_invalid_offset:
+	case XEN_PCI_ERR_op_failed:
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	case XEN_PCI_ERR_not_implemented:
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+	case XEN_PCI_ERR_access_denied:
+		return PCIBIOS_SET_FAILED;
+	}
+	return errno;
+}
+
+static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
+{
+	int err = 0;
+	struct xen_pci_op *active_op = &pdev->sh_info->op;
+	unsigned long irq_flags;
+
+	unsigned int volatile ttl = (1U << 29);
+
+	spin_lock_irqsave(&pdev->sh_info_lock, irq_flags);
+
+	memcpy(active_op, op, sizeof(struct xen_pci_op));
+
+	/* Go */
+	wmb();
+	set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+	notify_remote_via_evtchn(pdev->evtchn);
+
+	/* IRQs are disabled for the pci config. space reads/writes,
+	 * which means no event channel to notify us that the backend
+	 * is done so spin while waiting for the answer */
+	while (test_bit
+	       (_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)) {
+		if (!ttl) {
+			dev_err(&pdev->xdev->dev,
+				"pciback not responding!!!\n");
+			clear_bit(_XEN_PCIF_active,
+				  (unsigned long *)&pdev->sh_info->flags);
+			err = XEN_PCI_ERR_dev_not_found;
+			goto out;
+		}
+		ttl--;
+	}
+
+	memcpy(op, active_op, sizeof(struct xen_pci_op));
+
+	err = op->err;
+      out:
+	spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags);
+	return err;
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
+			     int where, int size, u32 * val)
+{
+	int err = 0;
+	struct xen_pci_op op = {
+		.cmd    = XEN_PCI_OP_conf_read,
+		.domain = pci_domain_nr(bus),
+		.bus    = bus->number,
+		.devfn  = devfn,
+		.offset = where,
+		.size   = size,
+	};
+	struct pcifront_sd *sd = bus->sysdata;
+	struct pcifront_device *pdev = sd->pdev;
+
+	if (verbose_request)
+		dev_info(&pdev->xdev->dev,
+			 "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n",
+			 pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
+			 PCI_FUNC(devfn), where, size);
+
+	err = do_pci_op(pdev, &op);
+
+	if (likely(!err)) {
+		if (verbose_request)
+			dev_info(&pdev->xdev->dev, "read got back value %x\n",
+				 op.value);
+
+		*val = op.value;
+	} else if (err == -ENODEV) {
+		/* No device here, pretend that it just returned 0 */
+		err = 0;
+		*val = 0;
+	}
+
+	return errno_to_pcibios_err(err);
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
+			      int where, int size, u32 val)
+{
+	struct xen_pci_op op = {
+		.cmd    = XEN_PCI_OP_conf_write,
+		.domain = pci_domain_nr(bus),
+		.bus    = bus->number,
+		.devfn  = devfn,
+		.offset = where,
+		.size   = size,
+		.value  = val,
+	};
+	struct pcifront_sd *sd = bus->sysdata;
+	struct pcifront_device *pdev = sd->pdev;
+
+	if (verbose_request)
+		dev_info(&pdev->xdev->dev,
+			 "write dev=%04x:%02x:%02x.%01x - "
+			 "offset %x size %d val %x\n",
+			 pci_domain_nr(bus), bus->number,
+			 PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
+
+	return errno_to_pcibios_err(do_pci_op(pdev, &op));
+}
+
+struct pci_ops pcifront_bus_ops = {
+	.read = pcifront_bus_read,
+	.write = pcifront_bus_write,
+};
+
+int pcifront_scan_root(struct pcifront_device *pdev,
+		       unsigned int domain, unsigned int bus)
+{
+	struct pci_bus *b;
+	struct pcifront_sd *sd = NULL;
+	struct pci_bus_entry *bus_entry = NULL;
+	int err = 0;
+
+#ifndef CONFIG_PCI_DOMAINS
+	if (domain != 0) {
+		dev_err(&pdev->xdev->dev,
+			"PCI Root in non-zero PCI Domain! domain=%d\n", domain);
+		dev_err(&pdev->xdev->dev,
+			"Please compile with CONFIG_PCI_DOMAINS\n");
+		err = -EINVAL;
+		goto err_out;
+	}
+#endif
+
+	dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
+		 domain, bus);
+
+	bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
+	sd = kmalloc(sizeof(*sd), GFP_KERNEL);
+	if (!bus_entry || !sd) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+	sd->domain = domain;
+	sd->pdev = pdev;
+
+	b = pci_scan_bus_parented(&pdev->xdev->dev, bus, &pcifront_bus_ops, sd);
+	if (!b) {
+		dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+	bus_entry->bus = b;
+
+	list_add(&bus_entry->list, &pdev->root_buses);
+
+	/* In kernels >= 2.6.13, we need to:
+	   pci_bus_add_devices(b); */
+
+	return 0;
+
+      err_out:
+	kfree(bus_entry);
+	kfree(sd);
+
+	return err;
+}
+
+void pcifront_free_roots(struct pcifront_device *pdev)
+{
+	struct pci_bus_entry *bus_entry, *t;
+
+	list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
+		/* TODO: Removing a PCI Bus is untested (as it normally
+		 * just goes away on domain shutdown)
+		 */
+		list_del(&bus_entry->list);
+
+		spin_lock(&pci_bus_lock);
+		list_del(&bus_entry->bus->node);
+		spin_unlock(&pci_bus_lock);
+
+		kfree(bus_entry->bus->sysdata);
+
+		device_unregister(bus_entry->bus->bridge);
+
+		/* Do we need to free() the bus itself? */
+
+		kfree(bus_entry);
+	}
+}
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,40 @@
+/*
+ * PCI Frontend - Common data structures & function declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCIFRONT_H__
+#define __XEN_PCIFRONT_H__
+
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <asm-xen/xenbus.h>
+#include <asm-xen/xen-public/io/pciif.h>
+#include <asm-xen/pcifront.h>
+
+struct pci_bus_entry {
+	struct list_head list;
+	struct pci_bus *bus;
+};
+
+struct pcifront_device {
+	struct xenbus_device *xdev;
+	struct list_head root_buses;
+	spinlock_t dev_lock;
+
+	int evtchn;
+	int gnt_ref;
+
+	/* Lock this when doing any operations in sh_info */
+	spinlock_t sh_info_lock;
+	struct xen_pci_sharedinfo *sh_info;
+};
+
+int pcifront_connect(struct pcifront_device *pdev);
+void pcifront_disconnect(struct pcifront_device *pdev);
+
+int pcifront_scan_root(struct pcifront_device *pdev,
+		       unsigned int domain, unsigned int bus);
+void pcifront_free_roots(struct pcifront_device *pdev);
+
+#endif	/* __XEN_PCIFRONT_H__ */
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,295 @@
+/*
+ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn)
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <asm-xen/xenbus.h>
+#include "pcifront.h"
+
+#define INVALID_GRANT_REF (0)
+#define INVALID_EVTCHN    (-1)
+
+static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
+{
+	struct pcifront_device *pdev;
+
+	pdev = kmalloc(sizeof(struct pcifront_device), GFP_KERNEL);
+	if (pdev == NULL)
+		goto out;
+
+	pdev->sh_info =
+	    (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
+	if (pdev->sh_info == NULL) {
+		kfree(pdev);
+		pdev = NULL;
+		goto out;
+	}
+	pdev->sh_info->flags = 0;
+
+	xdev->data = pdev;
+	pdev->xdev = xdev;
+
+	INIT_LIST_HEAD(&pdev->root_buses);
+
+	spin_lock_init(&pdev->dev_lock);
+	spin_lock_init(&pdev->sh_info_lock);
+
+	pdev->evtchn = INVALID_EVTCHN;
+	pdev->gnt_ref = INVALID_GRANT_REF;
+
+	dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n",
+		pdev, pdev->sh_info);
+      out:
+	return pdev;
+}
+
+static void free_pdev(struct pcifront_device *pdev)
+{
+	dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev);
+
+	if (pdev->evtchn != INVALID_EVTCHN)
+		xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
+
+	if (pdev->gnt_ref != INVALID_GRANT_REF)
+		gnttab_end_foreign_access(pdev->gnt_ref, 0,
+					  (unsigned long)pdev->sh_info);
+
+	pdev->xdev->data = NULL;
+
+	kfree(pdev);
+}
+
+static int pcifront_publish_info(struct pcifront_device *pdev)
+{
+	int err = 0;
+	xenbus_transaction_t trans;
+
+	err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info));
+	if (err < 0)
+		goto out;
+
+	pdev->gnt_ref = err;
+
+	err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
+	if (err)
+		goto out;
+
+      do_publish:
+	err = xenbus_transaction_start(&trans);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error writing configuration for backend "
+				 "(start transaction)");
+		goto out;
+	}
+
+	err = xenbus_printf(trans, pdev->xdev->nodename,
+			    "pci-op-ref", "%u", pdev->gnt_ref);
+	if (!err)
+		err = xenbus_printf(trans, pdev->xdev->nodename,
+				    "event-channel", "%u", pdev->evtchn);
+	if (!err)
+		err = xenbus_printf(trans, pdev->xdev->nodename,
+				    "magic", XEN_PCI_MAGIC);
+	if (!err)
+		err =
+		    xenbus_switch_state(pdev->xdev, trans,
+					XenbusStateInitialised);
+
+	if (err) {
+		xenbus_transaction_end(trans, 1);
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error writing configuration for backend");
+		goto out;
+	} else {
+		err = xenbus_transaction_end(trans, 0);
+		if (err == -EAGAIN)
+			goto do_publish;
+		else if (err) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error completing transaction "
+					 "for backend");
+			goto out;
+		}
+	}
+
+	dev_dbg(&pdev->xdev->dev, "publishing successful!\n");
+
+      out:
+	return err;
+}
+
+static int pcifront_try_connect(struct pcifront_device *pdev)
+{
+	int err = -EFAULT;
+	int i, num_roots, len;
+	char str[64];
+	unsigned int domain, bus;
+
+	spin_lock(&pdev->dev_lock);
+
+	/* Only connect once */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	err = pcifront_connect(pdev);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error connecting PCI Frontend");
+		goto out;
+	}
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend,
+			   "root_num", "%d", &num_roots);
+	if (err == -ENOENT) {
+		xenbus_dev_error(pdev->xdev, err,
+				 "No PCI Roots found, trying 0000:00");
+		err = pcifront_scan_root(pdev, 0, 0);
+		num_roots = 0;
+	} else if (err != 1) {
+		if (err == 0)
+			err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading number of PCI roots");
+		goto out;
+	}
+
+	for (i = 0; i < num_roots; i++) {
+		len = snprintf(str, sizeof(str), "root-%d", i);
+		if (unlikely(len >= (sizeof(str) - 1))) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend, str,
+				   "%x:%x", &domain, &bus);
+		if (err != 2) {
+			if (err >= 0)
+				err = -EINVAL;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error reading PCI root %d", i);
+			goto out;
+		}
+
+		err = pcifront_scan_root(pdev, domain, bus);
+		if (err) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error scanning PCI root %04x:%02x",
+					 domain, bus);
+			goto out;
+		}
+	}
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
+	if (err)
+		goto out;
+
+      out:
+	spin_unlock(&pdev->dev_lock);
+	return err;
+}
+
+static int pcifront_try_disconnect(struct pcifront_device *pdev)
+{
+	int err = 0;
+	XenbusState prev_state;
+
+	spin_lock(&pdev->dev_lock);
+
+	prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
+
+	if (prev_state < XenbusStateClosing)
+		err = xenbus_switch_state(pdev->xdev, XBT_NULL,
+					XenbusStateClosing);
+
+	if (!err && prev_state == XenbusStateConnected)
+		pcifront_disconnect(pdev);
+
+	spin_unlock(&pdev->dev_lock);
+
+	return err;
+}
+
+static void pcifront_backend_changed(struct xenbus_device *xdev,
+				     XenbusState be_state)
+{
+	struct pcifront_device *pdev = xdev->data;
+
+	switch (be_state) {
+	case XenbusStateClosing:
+		dev_warn(&xdev->dev, "backend going away!\n");
+		pcifront_try_disconnect(pdev);
+		break;
+
+	case XenbusStateClosed:
+		dev_warn(&xdev->dev, "backend went away!\n");
+		pcifront_try_disconnect(pdev);
+
+		device_unregister(&pdev->xdev->dev);
+		break;
+
+	case XenbusStateConnected:
+		pcifront_try_connect(pdev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pcifront_xenbus_probe(struct xenbus_device *xdev,
+				 const struct xenbus_device_id *id)
+{
+	int err = 0;
+	struct pcifront_device *pdev = alloc_pdev(xdev);
+
+	if (pdev == NULL) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(xdev, err,
+				 "Error allocating pcifront_device struct");
+		goto out;
+	}
+
+	err = pcifront_publish_info(pdev);
+
+      out:
+	return err;
+}
+
+static int pcifront_xenbus_remove(struct xenbus_device *xdev)
+{
+	if (xdev->data)
+		free_pdev(xdev->data);
+
+	return 0;
+}
+
+static struct xenbus_device_id xenpci_ids[] = {
+	{"pci"},
+	{{0}},
+};
+
+static struct xenbus_driver xenbus_pcifront_driver = {
+	.name 			= "pcifront",
+	.owner 			= THIS_MODULE,
+	.ids 			= xenpci_ids,
+	.probe 			= pcifront_xenbus_probe,
+	.remove 		= pcifront_xenbus_remove,
+	.otherend_changed 	= pcifront_backend_changed,
+};
+
+static int __init pcifront_init(void)
+{
+	int err = 0;
+
+	err = xenbus_register_frontend(&xenbus_pcifront_driver);
+
+	return err;
+}
+
+/* Initialize after the Xen PCI Frontend Stub is initialized */
+subsys_initcall(pcifront_init);
diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/include/asm-xen/pcifront.h
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/include/asm-xen/pcifront.h	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,39 @@
+/*
+ * PCI Frontend - arch-dependendent declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_ASM_PCIFRONT_H__
+#define __XEN_ASM_PCIFRONT_H__
+
+#include <linux/config.h>
+#include <linux/spinlock.h>
+
+#ifdef __KERNEL__
+
+struct pcifront_device;
+
+struct pcifront_sd {
+	int domain;
+	struct pcifront_device *pdev;
+};
+
+struct pci_bus;
+
+#ifdef CONFIG_PCI_DOMAINS
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+	struct pcifront_sd *sd = bus->sysdata;
+	return sd->domain;
+}
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+	return pci_domain_nr(bus);
+}
+#endif /* CONFIG_PCI_DOMAINS */
+
+extern spinlock_t pci_bus_lock;
+
+#endif /* __KERNEL__ */
+
+#endif /* __XEN_ASM_PCIFRONT_H__ */
diff -r 2add7a262530 -r 4868d0f773ce xen/include/public/io/pciif.h
--- /dev/null	Fri Jan 27 15:17:38 2006
+++ b/xen/include/public/io/pciif.h	Mon Jan 30 18:32:09 2006
@@ -0,0 +1,55 @@
+/*
+ * PCI Backend/Frontend Common Data Structures & Macros
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCI_COMMON_H__
+#define __XEN_PCI_COMMON_H__
+
+/* Be sure to bump this number if you change this file */
+#define XEN_PCI_MAGIC		"7"
+
+/* xen_pci_sharedinfo flags */
+#define _XEN_PCIF_active     (0)
+#define XEN_PCIF_active      (1<<_XEN_PCI_active)
+
+/* xen_pci_op commands */
+#define XEN_PCI_OP_conf_read    (0)
+#define XEN_PCI_OP_conf_write   (1)
+
+/* xen_pci_op error numbers */
+#define XEN_PCI_ERR_success          (0)
+#define XEN_PCI_ERR_dev_not_found   (-1)
+#define XEN_PCI_ERR_invalid_offset  (-2)
+#define XEN_PCI_ERR_access_denied   (-3)
+#define XEN_PCI_ERR_not_implemented (-4)
+/* XEN_PCI_ERR_op_failed - backend failed to complete the operation */
+#define XEN_PCI_ERR_op_failed       (-5)
+
+struct xen_pci_op {
+	/* IN: what action to perform: XEN_PCI_OP_* */
+	uint32_t cmd;
+
+	/* OUT: will contain an error number (if any) from errno.h */
+	int32_t err;
+
+	/* IN: which device to touch */
+	uint32_t domain; /* PCI Domain/Segment */
+	uint32_t bus;
+	uint32_t devfn;
+
+	/* IN: which configuration registers to touch */
+	int32_t offset;
+	int32_t size;
+
+	/* IN/OUT: Contains the result after a READ or the value to WRITE */
+	uint32_t value;
+};
+
+struct xen_pci_sharedinfo {
+	/* flags - XEN_PCIF_* */
+	uint32_t flags;
+	struct xen_pci_op op;
+};
+
+#endif /* __XEN_PCI_COMMON_H__ */

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
  2006-01-30 18:43   ` Ryan
@ 2006-01-31  0:37     ` Anthony Liguori
  0 siblings, 0 replies; 15+ messages in thread
From: Anthony Liguori @ 2006-01-31  0:37 UTC (permalink / raw)
  To: Ryan; +Cc: xen-devel

Very much so, thanks!

Regards,

Anthony Liguori


Ryan wrote:

>On Mon, 2006-01-30 at 09:06 -0600, Anthony Liguori wrote:
>  
>
>>Hi Ryan,
>>
>>It would be nice if you could run your patches through lindent and 
>>resubmit.  You do a couple things that don't follow kernel style 
>>guidelines (lack of spaces around operators and else clauses on 
>>newlines).  Strictly adhering to the CodingStyle now will make upstream 
>>merge significantly easier in the future.
>>
>>Thanks,
>>
>>Anthony Liguori
>>
>>    
>>
><snip>
>
>Is the attached file better formatted? I used lindent. I also added a
>couple of macros to simplify readability and reduce code size (lindent
>changed some formatting that brought some code duplication to my
>attention).
>
>  
>
>------------------------------------------------------------------------
>
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/arch/xen/Kconfig
>--- a/linux-2.6-xen-sparse/arch/xen/Kconfig	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/arch/xen/Kconfig	Mon Jan 30 18:32:09 2006
>@@ -38,6 +38,85 @@
> 	  (e.g., hard drives, network cards). This allows you to configure
> 	  such devices and also includes some low-level support that is
> 	  otherwise not compiled into the kernel.
>+
>+config XEN_PCIDEV_BACKEND
>+	bool "PCI device backend driver"
>+	depends on XEN_PHYSDEV_ACCESS
>+	select PCI
>+	default y if XEN_PRIVILEGED_GUEST
>+	help
>+	  The PCI device backend driver allows the kernel to export arbitrary
>+	  PCI devices to other guests.
>+
>+choice
>+	prompt "PCI Backend Mode"
>+	depends on XEN_PCIDEV_BACKEND
>+	default XEN_PCIDEV_BACKEND_VPCI
>+
>+config XEN_PCIDEV_BACKEND_VPCI
>+	bool "Virtual PCI"
>+	---help---
>+	  This PCI Backend hides the true PCI topology and makes the frontend
>+	  think there is a single PCI bus with only the exported devices on it.
>+	  For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
>+	  second device at 02:1a.0 will be re-assigned to 00:01.0.
>+
>+config XEN_PCIDEV_BACKEND_PASS
>+	bool "Passthrough"
>+	---help---
>+	  This PCI Backend provides a real view of the PCI topology to the
>+	  frontend (for example, a device at 06:01.b will still appear at
>+	  06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
>+	  PCI devices to its driver domains. This may be required for drivers
>+	  which depend on finding their hardward in certain bus/slot
>+	  locations.
>+
>+endchoice
>+
>+config XEN_PCIDEV_BE_DEBUG
>+	bool "PCI Backend Debugging"
>+	depends on XEN_PCIDEV_BACKEND
>+	default n
>+
>+# This won't work in 2.6.12 due to what appears to be a kernel bug (related
>+# to reading the resources of transparent bridges in pci_read_bridge_bases).
>+# This bug appears to be fixed in 2.6.13:
>+# http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=90b54929b626c80056262d9d99b3f48522e404d0
>+#config XEN_PCIDEV_BACKEND_ALLOC
>+#	bool "Re-allocate PCI Resources (DANGEROUS)"
>+#	depends on XEN_PCIDEV_BACKEND
>+#	default n
>+#	---help---
>+#	  This forces the PCI Backend to try and re-allocate all of the resources
>+#	  on the PCI bus in an attempt to ensure that they fall entirely within
>+#	  boundaries that Xen can control.
>+
>+config XEN_PCIDEV_FRONTEND
>+	bool "PCI device frontend driver"
>+	depends on XEN_PHYSDEV_ACCESS
>+	select PCI
>+	default y if !XEN_PRIVILEGED_GUEST
>+	help
>+	  The PCI device frontend driver allows the kernel to import arbitrary
>+	  PCI devices from a PCI backend.
>+
>+config XEN_PCIDEV_FE_DEBUG
>+	bool "PCI Frontend Debugging"
>+	depends on XEN_PCIDEV_FRONTEND
>+	default n
>+
>+config XEN_PCI_FE_ARCH_REPLACE
>+	bool "PCI frontend driver - arch-independent (EXPERIMENTAL)"
>+	depends on XEN_PCIDEV_FRONTEND && EXPERIMENTAL
>+	default n
>+	help
>+	  This selects an implementation of the PCI frontend driver that is
>+	  architecture independent (i.e. it replaces the real architecture's
>+	  PCI code). The default is to use an implementation that works with
>+	  the architecture dependent PCI code (and you probably want the
>+	  default).
>+
>+	  If unsure, say N.
> 
> config XEN_BLKDEV_BACKEND
> 	bool "Block-device backend driver"
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/arch/xen/i386/Kconfig
>--- a/linux-2.6-xen-sparse/arch/xen/i386/Kconfig	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/arch/xen/i386/Kconfig	Mon Jan 30 18:32:09 2006
>@@ -788,9 +788,17 @@
> 	  information about which PCI hardware does work under Linux and which
> 	  doesn't.
> 
>+# need to enable this on other platforms to support XEN_PCI_FE_ARCH_REPLACE
>+config PCI_NATIVE
>+	bool
>+	depends on PCI
>+	default y if !XEN_PCI_FE_ARCH_REPLACE
>+    ---help---
>+	  Compile in Native PCI access (as opposed to Xen's PCI Frontend).
>+
> choice
> 	prompt "PCI access mode"
>-	depends on PCI && !X86_VISWS
>+	depends on PCI_NATIVE && !X86_VISWS
> 	default PCI_GOANY
> 	---help---
> 	  On PCI systems, the BIOS can be used to detect the PCI devices and
>@@ -810,6 +818,15 @@
> #config PCI_GOBIOS
> #	bool "BIOS"
> 
>+config PCI_GOXEN_PCI_FE_STUB
>+	bool "Xen PCI Frontend Stub"
>+	depends on XEN_PCIDEV_FRONTEND
>+	---help---
>+	  The Xen PCI Frontend stub replaces the architecture's means of talking
>+	  directly to the PCI host bridge with a "dummy" handler which will act
>+	  as somewhat of a placeholder until the real Xen PCI Frontend is
>+	  initialized.
>+
> config PCI_GOMMCONFIG
> 	bool "MMConfig"
> 
>@@ -835,6 +852,11 @@
> 	bool
> 	depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
> 	select ACPI_BOOT
>+	default y
>+
>+config XEN_PCI_FE_STUB
>+	bool
>+	depends on PCI && XEN_PCIDEV_FRONTEND && !XEN_PCI_FE_ARCH_REPLACE && (PCI_GOXEN_PCI_FE_STUB || PCI_GOANY)
> 	default y
> 
> source "drivers/pci/pcie/Kconfig"
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/arch/xen/i386/Makefile
>--- a/linux-2.6-xen-sparse/arch/xen/i386/Makefile	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/arch/xen/i386/Makefile	Mon Jan 30 18:32:09 2006
>@@ -82,7 +82,7 @@
> # \
> #					   arch/xen/$(mcore-y)/
> drivers-$(CONFIG_MATH_EMULATION)	+= arch/i386/math-emu/
>-drivers-$(CONFIG_PCI)			+= arch/xen/i386/pci/
>+drivers-$(CONFIG_PCI_NATIVE)		+= arch/xen/i386/pci/
> # must be linked after kernel/
> drivers-$(CONFIG_OPROFILE)		+= arch/i386/oprofile/
> drivers-$(CONFIG_PM)			+= arch/i386/power/
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile
>--- a/linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile	Mon Jan 30 18:32:09 2006
>@@ -7,6 +7,7 @@
> #c-obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
> c-obj-$(CONFIG_PCI_MMCONFIG)	+= mmconfig.o
> c-obj-$(CONFIG_PCI_DIRECT)	+= direct.o
>+c-obj-$(CONFIG_XEN_PCI_FE_STUB) += pcifront.o
> 
> c-pci-y				:= fixup.o
> c-pci-$(CONFIG_ACPI_PCI)	+= acpi.o
>@@ -30,4 +31,6 @@
> # Make sure irq.o gets linked in before common.o
> obj-y	+= $(patsubst common.o,$(l-pci-y) common.o,$(c-obj-y))
> 
>+obj-$(CONFIG_XEN_PCIDEV_BACKEND_ALLOC) += alloc.o
>+
> clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-) $(c-link))
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c
>--- a/linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c	Mon Jan 30 18:32:09 2006
>@@ -58,6 +58,13 @@
> 			res->start = start;
> 		}
> 	}
>+#ifdef CONFIG_XEN_PCIDEV_BACKEND_ALLOC
>+	/* Ensure i/o memory is allocated on page boundaries */
>+	else if (res->flags & IORESOURCE_MEM) {
>+		unsigned long alignto = max(align,PAGE_SIZE);
>+		res->start = ALIGN(res->start,alignto);
>+	}
>+#endif
> }
> 
> 
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/Makefile
>--- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Mon Jan 30 18:32:09 2006
>@@ -16,4 +16,6 @@
> obj-$(CONFIG_XEN_NETDEV_FRONTEND)	+= netfront/
> obj-$(CONFIG_XEN_BLKDEV_TAP)    	+= blktap/
> obj-$(CONFIG_XEN_TPMDEV_FRONTEND)	+= tpmfront/
>+obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= pciback/
>+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront/
> 
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h
>--- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h	Mon Jan 30 18:32:09 2006
>@@ -124,6 +124,10 @@
> 
> #endif /* __KERNEL__ */
> 
>+#ifdef CONFIG_XEN_PCIDEV_FRONTEND
>+#include <asm-xen/pcifront.h>
>+#endif /* CONFIG_XEN_PCIDEV_FRONTEND */
>+
> /* implement the pci_ DMA API in terms of the generic device dma_ one */
> #include <asm-generic/pci-dma-compat.h>
> 
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/arch/xen/i386/pci/alloc.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/alloc.c	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,16 @@
>+/*
>+ * PCI Backend - Try to force a re-assignment of resources so that all
>+ *               memory resources are allocated on page boundaries
>+ */
>+#include <linux/kernel.h>
>+#include <linux/pci.h>
>+#include <linux/list.h>
>+
>+static __init int pciback_alloc(void)
>+{
>+	printk(KERN_INFO "pciback: Attempt to re-allocate PCI resources\n");
>+	pci_assign_unassigned_resources();
>+	return 0;
>+}
>+
>+subsys_initcall(pciback_alloc);
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/arch/xen/i386/pci/pcifront.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/pcifront.c	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,48 @@
>+/*
>+ * PCI Frontend Stub - puts some "dummy" functions in to the Linux x86 PCI core
>+ *                     to support the Xen PCI Frontend's operation
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <linux/init.h>
>+#include <linux/pci.h>
>+#include "pci.h"
>+
>+static int pcifront_enable_irq(struct pci_dev *dev)
>+{
>+	u8 irq;
>+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
>+	dev->irq = irq;
>+
>+	return 0;
>+}
>+
>+extern u8 pci_cache_line_size;
>+
>+static int __init pcifront_x86_stub_init(void)
>+{
>+	struct cpuinfo_x86 *c = &boot_cpu_data;
>+
>+	/* Only install our method if we haven't found real hardware already */
>+	if (raw_pci_ops)
>+		return 0;
>+
>+	printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
>+
>+	/* Copied from arch/i386/pci/common.c */
>+	pci_cache_line_size = 32 >> 2;
>+	if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
>+		pci_cache_line_size = 64 >> 2;	/* K7 & K8 */
>+	else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL)
>+		pci_cache_line_size = 128 >> 2;	/* P4 */
>+
>+	/* On x86, we need to disable the normal IRQ routing table and
>+	 * just ask the backend
>+	 */
>+	pcibios_enable_irq = pcifront_enable_irq;
>+
>+	return 0;
>+}
>+
>+arch_initcall(pcifront_x86_stub_init);
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/Makefile
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,10 @@
>+obj-y += pciback.o
>+
>+pciback-y := pci_stub.o pciback_ops.o xenbus.o
>+pciback-y += conf_space.o conf_space_header.o
>+pciback-${CONFIG_XEN_PCIDEV_BACKEND_VPCI} += vpci.o
>+pciback-${CONFIG_XEN_PCIDEV_BACKEND_PASS} += passthrough.o
>+
>+ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
>+EXTRA_CFLAGS += -DDEBUG
>+endif
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,324 @@
>+/*
>+ * PCI Backend - Functions for creating a virtual configuration space for
>+ *               exported PCI Devices.
>+ *               It's dangerous to allow PCI Driver Domains to change their
>+ *               device's resources (memory, i/o ports, interrupts). We need to
>+ *               restrict changes to certain PCI Configuration registers:
>+ *               BARs, INTERRUPT_PIN, most registers in the header...
>+ *
>+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+
>+#include <linux/kernel.h>
>+#include <linux/pci.h>
>+#include "pciback.h"
>+#include "conf_space.h"
>+
>+#define DEFINE_PCI_CONFIG(op,size,type) 					\
>+int pciback_##op##_config_##size 							\
>+(struct pci_dev *dev, int offset, type value, void *data)	\
>+{															\
>+	return pci_##op##_config_##size (dev, offset, value);	\
>+}
>+
>+DEFINE_PCI_CONFIG(read, byte, u8 *)
>+DEFINE_PCI_CONFIG(read, word, u16 *)
>+DEFINE_PCI_CONFIG(read, dword, u32 *)
>+
>+DEFINE_PCI_CONFIG(write, byte, u8)
>+DEFINE_PCI_CONFIG(write, word, u16)
>+DEFINE_PCI_CONFIG(write, dword, u32)
>+
>+static int conf_space_read(struct pci_dev *dev,
>+			   struct config_field_entry *entry, int offset,
>+			   u32 * value)
>+{
>+	int ret = 0;
>+	struct config_field *field = entry->field;
>+
>+	*value = 0;
>+
>+	switch (field->size) {
>+	case 1:
>+		if (field->u.b.read)
>+			ret = field->u.b.read(dev, offset, (u8 *) value,
>+					      entry->data);
>+		break;
>+	case 2:
>+		if (field->u.w.read)
>+			ret = field->u.w.read(dev, offset, (u16 *) value,
>+					      entry->data);
>+		break;
>+	case 4:
>+		if (field->u.dw.read)
>+			ret = field->u.dw.read(dev, offset, value, entry->data);
>+		break;
>+	}
>+	return ret;
>+}
>+
>+static int conf_space_write(struct pci_dev *dev,
>+			    struct config_field_entry *entry, int offset,
>+			    u32 value)
>+{
>+	int ret = 0;
>+	struct config_field *field = entry->field;
>+
>+	switch (field->size) {
>+	case 1:
>+		if (field->u.b.write)
>+			ret = field->u.b.write(dev, offset, (u8) value,
>+					       entry->data);
>+		break;
>+	case 2:
>+		if (field->u.w.write)
>+			ret = field->u.w.write(dev, offset, (u16) value,
>+					       entry->data);
>+		break;
>+	case 4:
>+		if (field->u.dw.write)
>+			ret = field->u.dw.write(dev, offset, value,
>+					        entry->data);
>+		break;
>+	}
>+	return ret;
>+}
>+
>+static inline u32 get_mask(int size)
>+{
>+	if (size == 1)
>+		return 0xff;
>+	else if (size == 2)
>+		return 0xffff;
>+	else
>+		return 0xffffffff;
>+}
>+
>+static inline int valid_request(int offset, int size)
>+{
>+	/* Validate request (no un-aligned requests) */
>+	if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0)
>+		return 1;
>+	return 0;
>+}
>+
>+static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
>+			      u32 offset)
>+{
>+	if (offset >= 0) {
>+		new_val_mask <<= (offset * 8);
>+		new_val <<= (offset * 8);
>+	} else {
>+		new_val_mask >>= (offset * -8);
>+		new_val >>= (offset * -8);
>+	}
>+	val = (val & ~new_val_mask) | (new_val & new_val_mask);
>+
>+	return val;
>+}
>+
>+static int pcibios_err_to_errno(int err)
>+{
>+	switch (err) {
>+	case PCIBIOS_SUCCESSFUL:
>+		return XEN_PCI_ERR_success;
>+	case PCIBIOS_DEVICE_NOT_FOUND:
>+		return XEN_PCI_ERR_dev_not_found;
>+	case PCIBIOS_BAD_REGISTER_NUMBER:
>+		return XEN_PCI_ERR_invalid_offset;
>+	case PCIBIOS_FUNC_NOT_SUPPORTED:
>+		return XEN_PCI_ERR_not_implemented;
>+	case PCIBIOS_SET_FAILED:
>+		return XEN_PCI_ERR_access_denied;
>+	}
>+	return err;
>+}
>+
>+int pciback_config_read(struct pci_dev *dev, int offset, int size,
>+			u32 * ret_val)
>+{
>+	int err = 0;
>+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
>+	struct config_field_entry *cfg_entry;
>+	struct config_field *field;
>+	int req_start, req_end, field_start, field_end;
>+	/* if read fails for any reason, return 0 (as if device didn't respond) */
>+	u32 value = 0, tmp_val;
>+
>+	if (unlikely(verbose_request))
>+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n",
>+		       pci_name(dev), size, offset);
>+
>+	if (!valid_request(offset, size)) {
>+		err = XEN_PCI_ERR_invalid_offset;
>+		goto out;
>+	}
>+
>+	/* Get the real value first, then modify as appropriate */
>+	switch (size) {
>+	case 1:
>+		err = pci_read_config_byte(dev, offset, (u8 *) & value);
>+		break;
>+	case 2:
>+		err = pci_read_config_word(dev, offset, (u16 *) & value);
>+		break;
>+	case 4:
>+		err = pci_read_config_dword(dev, offset, &value);
>+		break;
>+	}
>+
>+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
>+		field = cfg_entry->field;
>+
>+		req_start = offset;
>+		req_end = offset + size;
>+		field_start = field->offset;
>+		field_end = field->offset + field->size;
>+
>+		if ((req_start >= field_start && req_start < field_end)
>+		    || (req_end > field_start && req_end <= field_end)) {
>+			err = conf_space_read(dev, cfg_entry, offset, &tmp_val);
>+			if (err)
>+				goto out;
>+
>+			value = merge_value(value, tmp_val,
>+					    get_mask(field->size),
>+					    field_start - req_start);
>+		}
>+	}
>+
>+      out:
>+	if (unlikely(verbose_request))
>+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
>+		       pci_name(dev), size, offset, value);
>+
>+	*ret_val = value;
>+	return pcibios_err_to_errno(err);
>+}
>+
>+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
>+{
>+	int err = 0;
>+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
>+	struct config_field_entry *cfg_entry;
>+	struct config_field *field;
>+	u32 tmp_val;
>+	int req_start, req_end, field_start, field_end;
>+
>+	if (unlikely(verbose_request))
>+		printk(KERN_DEBUG
>+		       "pciback: %s: write request %d bytes at 0x%x = %x\n",
>+		       pci_name(dev), size, offset, value);
>+
>+	if (!valid_request(offset, size))
>+		return XEN_PCI_ERR_invalid_offset;
>+
>+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
>+		field = cfg_entry->field;
>+
>+		req_start = offset;
>+		req_end = offset + size;
>+		field_start = field->offset;
>+		field_end = field->offset + field->size;
>+
>+		if ((req_start >= field_start && req_start < field_end)
>+		    || (req_end > field_start && req_end <= field_end)) {
>+			tmp_val = 0;
>+
>+			err = pciback_config_read(dev, offset, size, &tmp_val);
>+			if (err)
>+				break;
>+
>+			tmp_val = merge_value(tmp_val, value, get_mask(size),
>+					      field_start - req_start);
>+
>+			err = conf_space_write(dev, cfg_entry, offset, tmp_val);
>+		}
>+	}
>+
>+	return pcibios_err_to_errno(err);
>+}
>+
>+void pciback_config_reset(struct pci_dev *dev)
>+{
>+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
>+	struct config_field_entry *cfg_entry;
>+	struct config_field *field;
>+
>+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
>+		field = cfg_entry->field;
>+
>+		if (field->reset)
>+			field->reset(dev, field->offset, cfg_entry->data);
>+	}
>+}
>+
>+void pciback_config_free(struct pci_dev *dev)
>+{
>+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
>+	struct config_field_entry *cfg_entry, *t;
>+	struct config_field *field;
>+
>+	list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
>+		list_del(&cfg_entry->list);
>+
>+		field = cfg_entry->field;
>+
>+		if (field->release)
>+			field->release(dev, field->offset, cfg_entry->data);
>+
>+		kfree(cfg_entry);
>+	}
>+}
>+
>+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field)
>+{
>+	int err = 0;
>+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
>+	struct config_field_entry *cfg_entry;
>+	void *tmp;
>+
>+	cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
>+	if (!cfg_entry) {
>+		err = -ENOMEM;
>+		goto out;
>+	}
>+
>+	cfg_entry->data = NULL;
>+	cfg_entry->field = field;
>+
>+	if (field->init) {
>+		tmp = field->init(dev, field->offset);
>+
>+		if (IS_ERR(tmp)) {
>+			err = PTR_ERR(tmp);
>+			goto out;
>+		}
>+
>+		cfg_entry->data = tmp;
>+	}
>+
>+	list_add_tail(&cfg_entry->list, &dev_data->config_fields);
>+
>+      out:
>+	if (err)
>+		kfree(cfg_entry);
>+
>+	return err;
>+}
>+
>+/* This sets up the device's virtual configuration space to keep track of 
>+ * certain registers (like the base address registers (BARs) so that we can
>+ * keep the client from manipulating them directly.
>+ */
>+int pciback_config_init(struct pci_dev *dev)
>+{
>+	int err = 0;
>+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
>+
>+	INIT_LIST_HEAD(&dev_data->config_fields);
>+
>+	err = pciback_config_header_add_fields(dev);
>+
>+	return err;
>+}
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,97 @@
>+/*
>+ * PCI Backend - Common data structures for overriding the configuration space
>+ *
>+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+
>+#ifndef __XEN_PCIBACK_CONF_SPACE_H__
>+#define __XEN_PCIBACK_CONF_SPACE_H__
>+
>+#include <linux/list.h>
>+
>+typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
>+typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data);
>+typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
>+
>+typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value,
>+				 void *data);
>+typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value,
>+				void *data);
>+typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value,
>+				void *data);
>+typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value,
>+				void *data);
>+typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value,
>+			       void *data);
>+typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
>+			       void *data);
>+
>+/* These are the fields within the configuration space which we
>+ * are interested in intercepting reads/writes to and changing their
>+ * values.
>+ */
>+struct config_field {
>+	unsigned int     offset;
>+	unsigned int     size;
>+	conf_field_init  init;
>+	conf_field_reset reset;
>+	conf_field_free  release;
>+	union {
>+		struct {
>+			conf_dword_write write;
>+			conf_dword_read read;
>+		} dw;
>+		struct {
>+			conf_word_write write;
>+			conf_word_read read;
>+		} w;
>+		struct {
>+			conf_byte_write write;
>+			conf_byte_read read;
>+		} b;
>+	} u;
>+};
>+
>+struct config_field_entry {
>+	struct list_head list;
>+	struct config_field *field;
>+	void *data;
>+};
>+
>+/* Add fields to a device - the add_fields macro expects to get a pointer to
>+ * the first entry in an array (of which the ending is marked by size==0)
>+ */
>+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field);
>+static inline int pciback_config_add_fields(struct pci_dev *dev,
>+					    struct config_field *field)
>+{
>+	int i, err = 0;
>+	for (i = 0; field[i].size != 0; i++) {
>+		err = pciback_config_add_field(dev, &field[i]);
>+		if (err)
>+			break;
>+	}
>+	return err;
>+}
>+
>+/* Initializers which add fields to the virtual configuration space
>+ * ** We could add initializers to allow a guest domain to touch
>+ * the capability lists (for power management, the AGP bridge, etc.)
>+ */
>+int pciback_config_header_add_fields(struct pci_dev *dev);
>+
>+/* Read/Write the real configuration space */
>+int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
>+			     void *data);
>+int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value,
>+			     void *data);
>+int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value,
>+			      void *data);
>+int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
>+			      void *data);
>+int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value,
>+			      void *data);
>+int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
>+			       void *data);
>+
>+#endif				/* __XEN_PCIBACK_CONF_SPACE_H__ */
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,270 @@
>+/*
>+ * PCI Backend - Handles the virtual fields in the configuration space headers.
>+ *
>+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+
>+#include <linux/kernel.h>
>+#include <linux/pci.h>
>+#include "pciback.h"
>+#include "conf_space.h"
>+
>+struct pci_bar_info {
>+	u32 val;
>+	u32 len_val;
>+	int which;
>+};
>+
>+#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
>+#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
>+
>+static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
>+{
>+	if (!dev->is_enabled && is_enable_cmd(value)) {
>+		if (unlikely(verbose_request))
>+			printk(KERN_DEBUG "pciback: %s: enable\n",
>+			       pci_name(dev));
>+		dev->is_enabled = 1;
>+		pcibios_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
>+	} else if (dev->is_enabled && !is_enable_cmd(value)) {
>+		if (unlikely(verbose_request))
>+			printk(KERN_DEBUG "pciback: %s: disable\n",
>+			       pci_name(dev));
>+		pciback_disable_device(dev);
>+	}
>+
>+	if (!dev->is_busmaster && is_master_cmd(value)) {
>+		if (unlikely(verbose_request))
>+			printk(KERN_DEBUG "pciback: %s: set bus master\n",
>+			       pci_name(dev));
>+		dev->is_busmaster = 1;
>+		pcibios_set_master(dev);
>+	}
>+
>+	if (value & PCI_COMMAND_INVALIDATE) {
>+		if (unlikely(verbose_request))
>+			printk(KERN_DEBUG
>+			       "pciback: %s: enable memory-write-invalidate\n",
>+			       pci_name(dev));
>+		pci_set_mwi(dev);
>+	}
>+
>+	return pci_write_config_word(dev, offset, value);
>+}
>+
>+static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
>+{
>+	struct pci_bar_info *bar = data;
>+	int i;
>+
>+	if (unlikely(!bar)) {
>+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
>+		       pci_name(dev));
>+		return XEN_PCI_ERR_op_failed;
>+	}
>+
>+	bar->which = 0;
>+	/* Because writes *could* occur in bytes, if any byte is all 1s, switch */
>+	for (i = 0; i < 4; i++)
>+		if (((value >> (i * 8)) & 0xff) == 0xff)
>+			bar->which = 1;
>+
>+	/* Do we need to support enabling/disabling the rom address here? */
>+
>+	return 0;
>+}
>+
>+/* For the BARs, only allow writes which write ~0 or
>+ * the correct resource information
>+ * (Needed for when the driver probes the resource usage)
>+ */
>+static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
>+{
>+	int i;
>+	struct pci_bar_info *bar = data;
>+
>+	if (unlikely(!bar)) {
>+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
>+		       pci_name(dev));
>+		return XEN_PCI_ERR_op_failed;
>+	}
>+
>+	bar->which = 0;
>+
>+	/* Because writes *could* occur in bytes,
>+	 * if any byte is all 1s, switch
>+	 */
>+	for (i = 0; i < 4; i++)
>+		if (((value >> (i * 8)) & 0xff) == 0xff)
>+			bar->which = 1;
>+
>+	return 0;
>+}
>+
>+static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
>+{
>+	struct pci_bar_info *bar = data;
>+
>+	if (unlikely(!bar)) {
>+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
>+		       pci_name(dev));
>+		return XEN_PCI_ERR_op_failed;
>+	}
>+
>+	*value = bar->which ? bar->len_val : bar->val;
>+
>+	return 0;
>+}
>+
>+static inline void read_dev_bar(struct pci_dev *dev,
>+				struct pci_bar_info *bar_info, int offset,
>+				u32 len_mask)
>+{
>+	pci_read_config_dword(dev, offset, &bar_info->val);
>+	pci_write_config_dword(dev, offset, len_mask);
>+	pci_read_config_dword(dev, offset, &bar_info->len_val);
>+	pci_write_config_dword(dev, offset, bar_info->val);
>+}
>+
>+static void *bar_init(struct pci_dev *dev, int offset)
>+{
>+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
>+
>+	if (!bar)
>+		return ERR_PTR(-ENOMEM);
>+
>+	read_dev_bar(dev, bar, offset, ~0);
>+	bar->which = 0;
>+
>+	return bar;
>+}
>+
>+static void *rom_init(struct pci_dev *dev, int offset)
>+{
>+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
>+
>+	if (!bar)
>+		return ERR_PTR(-ENOMEM);
>+
>+	read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
>+	bar->which = 0;
>+
>+	return bar;
>+}
>+
>+static void bar_reset(struct pci_dev *dev, int offset, void *data)
>+{
>+	struct pci_bar_info *bar = data;
>+
>+	bar->which = 0;
>+}
>+
>+static void bar_release(struct pci_dev *dev, int offset, void *data)
>+{
>+	kfree(data);
>+}
>+
>+static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
>+			  void *data)
>+{
>+	*value = (u8) dev->irq;
>+
>+	return 0;
>+}
>+
>+struct config_field header_common[] = {
>+	{
>+	 .offset    = PCI_COMMAND,
>+	 .size      = 2,
>+	 .u.w.read  = pciback_read_config_word,
>+	 .u.w.write = command_write,
>+	 },
>+	{
>+	 .offset    = PCI_INTERRUPT_LINE,
>+	 .size      = 1,
>+	 .u.b.read  = interrupt_read,
>+	 .u.b.write = NULL,
>+	 },
>+	{
>+	 /* Any side effects of letting driver domain control cache line? */
>+	 .offset    = PCI_CACHE_LINE_SIZE,
>+	 .size      = 1,
>+	 .u.b.read  = pciback_read_config_byte,
>+	 .u.b.write = pciback_write_config_byte,
>+	 },
>+	{
>+	 .size = 0,
>+	 },
>+};
>+
>+#define CFG_FIELD_BAR(reg_offset) 			\
>+	{ 						\
>+	 .offset     = reg_offset, 			\
>+	 .size       = 4, 				\
>+	 .init       = bar_init, 			\
>+	 .reset      = bar_reset, 			\
>+	 .release    = bar_release, 			\
>+	 .u.dw.read  = bar_read, 			\
>+	 .u.dw.write = bar_write, 			\
>+	 }
>+
>+#define CFG_FIELD_ROM(reg_offset) 			\
>+	{ 						\
>+	 .offset     = reg_offset, 			\
>+	 .size       = 4, 				\
>+	 .init       = rom_init, 			\
>+	 .reset      = bar_reset, 			\
>+	 .release    = bar_release, 			\
>+	 .u.dw.read  = bar_read, 			\
>+	 .u.dw.write = rom_write, 			\
>+	 }
>+
>+struct config_field header_0[] = {
>+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
>+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
>+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
>+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
>+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
>+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
>+	CFG_FIELD_ROM(PCI_ROM_ADDRESS),
>+	{
>+	 .size = 0,
>+	 },
>+};
>+
>+struct config_field header_1[] = {
>+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
>+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
>+	CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
>+	{
>+	 .size = 0,
>+	 },
>+};
>+
>+int pciback_config_header_add_fields(struct pci_dev *dev)
>+{
>+	int err;
>+
>+	err = pciback_config_add_fields(dev, header_common);
>+	if (err)
>+		goto out;
>+
>+	switch (dev->hdr_type) {
>+	case PCI_HEADER_TYPE_NORMAL:
>+		err = pciback_config_add_fields(dev, header_0);
>+		break;
>+
>+	case PCI_HEADER_TYPE_BRIDGE:
>+		err = pciback_config_add_fields(dev, header_1);
>+		break;
>+
>+	default:
>+		err = -EINVAL;
>+		printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
>+		       pci_name(dev), dev->hdr_type);
>+		break;
>+	}
>+
>+      out:
>+	return err;
>+}
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,117 @@
>+/*
>+ * PCI Backend - Provides restricted access to the real PCI bus topology
>+ *               to the frontend
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+
>+#include <linux/list.h>
>+#include <linux/pci.h>
>+#include "pciback.h"
>+
>+struct passthrough_dev_data {
>+	struct list_head dev_list;
>+};
>+
>+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
>+				    unsigned int domain, unsigned int bus,
>+				    unsigned int devfn)
>+{
>+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
>+	struct pci_dev_entry *dev_entry;
>+
>+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
>+		if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
>+		    && bus == (unsigned int)dev_entry->dev->bus->number
>+		    && devfn == dev_entry->dev->devfn)
>+			return dev_entry->dev;
>+	}
>+
>+	return NULL;
>+}
>+
>+/* Must hold pciback_device->dev_lock when calling this */
>+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
>+{
>+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
>+	struct pci_dev_entry *dev_entry;
>+
>+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
>+	if (!dev_entry)
>+		return -ENOMEM;
>+	dev_entry->dev = dev;
>+
>+	list_add_tail(&dev_entry->list, &dev_data->dev_list);
>+
>+	return 0;
>+}
>+
>+int pciback_init_devices(struct pciback_device *pdev)
>+{
>+	struct passthrough_dev_data *dev_data;
>+
>+	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
>+	if (!dev_data)
>+		return -ENOMEM;
>+
>+	INIT_LIST_HEAD(&dev_data->dev_list);
>+
>+	pdev->pci_dev_data = dev_data;
>+
>+	return 0;
>+}
>+
>+int pciback_publish_pci_roots(struct pciback_device *pdev,
>+			      publish_pci_root_cb publish_root_cb)
>+{
>+	int err = 0;
>+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
>+	struct pci_dev_entry *dev_entry, *e;
>+	struct pci_dev *dev;
>+	int found;
>+	unsigned int domain, bus;
>+
>+	domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
>+	bus = (unsigned int)dev_entry->dev->bus->number;
>+
>+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
>+
>+		/* Only publish this device as a root if none of its
>+		 * parent bridges are exported
>+		 */
>+		found = 0;
>+		dev = dev_entry->dev->bus->self;
>+		for (; !found && dev != NULL; dev = dev->bus->self) {
>+			list_for_each_entry(e, &dev_data->dev_list, list) {
>+				if (dev == e->dev) {
>+					found = 1;
>+					break;
>+				}
>+			}
>+		}
>+
>+		if (!found) {
>+			err = publish_root_cb(pdev, domain, bus);
>+			if (err)
>+				break;
>+		}
>+	}
>+
>+	return err;
>+}
>+
>+/* Must hold pciback_device->dev_lock when calling this */
>+void pciback_release_devices(struct pciback_device *pdev)
>+{
>+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
>+	struct pci_dev_entry *dev_entry, *t;
>+
>+	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
>+		list_del(&dev_entry->list);
>+		pcistub_put_pci_dev(dev_entry->dev);
>+		kfree(dev_entry);
>+	}
>+
>+	kfree(dev_data);
>+	pdev->pci_dev_data = NULL;
>+}
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,377 @@
>+/*
>+ * PCI Stub Driver - Grabs devices in backend to be exported later
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <linux/init.h>
>+#include <linux/list.h>
>+#include <linux/spinlock.h>
>+#include <asm/atomic.h>
>+#include "pciback.h"
>+
>+static char *pci_devs_to_hide = NULL;
>+module_param_named(hide, pci_devs_to_hide, charp, 0444);
>+
>+struct pci_stub_device_id {
>+	struct list_head slot_list;
>+	int domain;
>+	unsigned char bus;
>+	unsigned int devfn;
>+};
>+LIST_HEAD(pci_stub_device_ids);
>+
>+struct pci_stub_device {
>+	struct list_head dev_list;
>+	struct pci_dev *dev;
>+	atomic_t in_use;
>+};
>+/* Access to pci_stub_devices & seized_devices lists and the initialize_devices
>+ * flag must be locked with pci_stub_devices_lock
>+ */
>+DEFINE_SPINLOCK(pci_stub_devices_lock);
>+LIST_HEAD(pci_stub_devices);
>+
>+/* wait for device_initcall before initializing our devices
>+ * (see pcistub_init_devices_late)
>+ */
>+static int initialize_devices = 0;
>+LIST_HEAD(seized_devices);
>+
>+static inline struct pci_dev *get_pci_dev(struct pci_stub_device *psdev)
>+{
>+	if (atomic_dec_and_test(&psdev->in_use))
>+		return psdev->dev;
>+	else {
>+		atomic_inc(&psdev->in_use);
>+		return NULL;
>+	}
>+}
>+
>+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
>+					    int slot, int func)
>+{
>+	struct pci_stub_device *psdev;
>+	struct pci_dev *found_dev = NULL;
>+
>+	spin_lock(&pci_stub_devices_lock);
>+
>+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
>+		if (psdev->dev != NULL
>+		    && domain == pci_domain_nr(psdev->dev->bus)
>+		    && bus == psdev->dev->bus->number
>+		    && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
>+			found_dev = get_pci_dev(psdev);
>+			break;
>+		}
>+	}
>+
>+	spin_unlock(&pci_stub_devices_lock);
>+	return found_dev;
>+}
>+
>+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev)
>+{
>+	struct pci_stub_device *psdev;
>+	struct pci_dev *found_dev = NULL;
>+
>+	spin_lock(&pci_stub_devices_lock);
>+
>+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
>+		if (psdev->dev == dev) {
>+			found_dev = get_pci_dev(psdev);
>+			break;
>+		}
>+	}
>+
>+	spin_unlock(&pci_stub_devices_lock);
>+	return found_dev;
>+}
>+
>+void pcistub_put_pci_dev(struct pci_dev *dev)
>+{
>+	struct pci_stub_device *psdev;
>+
>+	spin_lock(&pci_stub_devices_lock);
>+
>+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
>+		if (psdev->dev == dev) {
>+			/* Cleanup our device
>+			 * (so it's ready for the next domain)
>+			 */
>+			pciback_reset_device(psdev->dev);
>+
>+			atomic_inc(&psdev->in_use);
>+			break;
>+		}
>+	}
>+
>+	spin_unlock(&pci_stub_devices_lock);
>+}
>+
>+static int __devinit pcistub_match(struct pci_dev *dev,
>+				   struct pci_stub_device_id *pdev_id)
>+{
>+	/* Match the specified device by domain, bus, slot, func and also if
>+	 * any of the device's parent bridges match.
>+	 */
>+	for (; dev != NULL; dev = dev->bus->self) {
>+		if (pci_domain_nr(dev->bus) == pdev_id->domain
>+		    && dev->bus->number == pdev_id->bus
>+		    && dev->devfn == pdev_id->devfn)
>+			return 1;
>+	}
>+
>+	return 0;
>+}
>+
>+static int __devinit pcistub_init_device(struct pci_dev *dev)
>+{
>+	struct pciback_dev_data *dev_data;
>+	int err = 0;
>+
>+	/* The PCI backend is not intended to be a module (or to work with
>+	 * removable PCI devices (yet). If it were, pciback_config_free()
>+	 * would need to be called somewhere to free the memory allocated
>+	 * here and then to call kfree(pci_get_drvdata(psdev->dev)).
>+	 */
>+	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
>+	if (!dev_data) {
>+		err = -ENOMEM;
>+		goto out;
>+	}
>+	pci_set_drvdata(dev, dev_data);
>+
>+	err = pciback_config_init(dev);
>+	if (err)
>+		goto out;
>+
>+	/* HACK: Force device (& ACPI) to determine what IRQ it's on - we
>+	 * must do this here because pcibios_enable_device may specify
>+	 * the pci device's true irq (and possibly its other resources)
>+	 * if they differ from what's in the configuration space.
>+	 * This makes the assumption that the device's resources won't
>+	 * change after this point (otherwise this code may break!)
>+	 */
>+	err = pci_enable_device(dev);
>+	if (err)
>+		goto config_release;
>+
>+	/* Now disable the device (this also ensures some private device
>+	 * data is setup before we export)
>+	 * This calls pciback_config_reset(dev)
>+	 */
>+	pciback_reset_device(dev);
>+
>+	return 0;
>+
>+      config_release:
>+	pciback_config_free(dev);
>+
>+      out:
>+	pci_set_drvdata(dev, NULL);
>+	kfree(dev_data);
>+	return err;
>+}
>+
>+/*
>+ * Because some initialization still happens on
>+ * devices during fs_initcall, we need to defer
>+ * full initialization of our devices until
>+ * device_initcall.
>+ */
>+static int __init pcistub_init_devices_late(void)
>+{
>+	struct pci_stub_device *psdev, *t;
>+	int err = 0;
>+
>+	spin_lock(&pci_stub_devices_lock);
>+
>+	list_for_each_entry_safe(psdev, t, &seized_devices, dev_list) {
>+		list_del(&psdev->dev_list);
>+		err = pcistub_init_device(psdev->dev);
>+		if (err) {
>+			printk(KERN_ERR
>+			       "pciback: %s error %d initializing device\n",
>+			       pci_name(psdev->dev), err);
>+			kfree(psdev);
>+			continue;
>+		}
>+
>+		list_add_tail(&psdev->dev_list, &pci_stub_devices);
>+	}
>+
>+	initialize_devices = 1;
>+
>+	spin_unlock(&pci_stub_devices_lock);
>+
>+	return 0;
>+}
>+
>+device_initcall(pcistub_init_devices_late);
>+
>+static int __devinit pcistub_seize(struct pci_dev *dev)
>+{
>+	struct pci_stub_device *psdev;
>+	int err = 0;
>+
>+	psdev = kmalloc(sizeof(*psdev), GFP_KERNEL);
>+	if (!psdev)
>+		return -ENOMEM;
>+
>+	psdev->dev = dev;
>+	atomic_set(&psdev->in_use, 1);
>+
>+	spin_lock(&pci_stub_devices_lock);
>+
>+	if (initialize_devices) {
>+		err = pcistub_init_device(psdev->dev);
>+		if (err)
>+			goto out;
>+
>+		list_add(&psdev->dev_list, &pci_stub_devices);
>+	} else
>+		list_add(&psdev->dev_list, &seized_devices);
>+
>+      out:
>+	spin_unlock(&pci_stub_devices_lock);
>+
>+	if (err)
>+		kfree(psdev);
>+
>+	return err;
>+}
>+
>+static int __devinit pcistub_probe(struct pci_dev *dev,
>+				   const struct pci_device_id *id)
>+{
>+	struct pci_stub_device_id *pdev_id;
>+	struct pci_dev *seized_dev;
>+	int err = 0;
>+
>+	list_for_each_entry(pdev_id, &pci_stub_device_ids, slot_list) {
>+
>+		if (!pcistub_match(dev, pdev_id))
>+			continue;
>+
>+		if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
>+		    && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
>+			printk(KERN_ERR
>+			       "pciback: %s: can't export pci devices that "
>+			       "don't have a normal (0) or bridge (1) "
>+			       "header type!\n", pci_name(dev));
>+			break;
>+		}
>+
>+		pr_info("pciback: seizing PCI device %s\n", pci_name(dev));
>+		seized_dev = pci_dev_get(dev);
>+
>+		if (seized_dev) {
>+			err = pcistub_seize(seized_dev);
>+			if (err) {
>+				pci_dev_put(dev);
>+				goto out;
>+			}
>+
>+			/* Success! */
>+			goto out;
>+		}
>+	}
>+
>+	/* Didn't find the device */
>+	err = -ENODEV;
>+
>+      out:
>+	return err;
>+}
>+
>+struct pci_device_id pcistub_ids[] = {
>+	{
>+	 .vendor = PCI_ANY_ID,
>+	 .device = PCI_ANY_ID,
>+	 .subvendor = PCI_ANY_ID,
>+	 .subdevice = PCI_ANY_ID,
>+	 },
>+	{0,},
>+};
>+
>+/*
>+ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't
>+ * for a normal device. I don't want it to be loaded automatically.
>+ */
>+
>+struct pci_driver pciback_pci_driver = {
>+	.name = "pciback",
>+	.id_table = pcistub_ids,
>+	.probe = pcistub_probe,
>+};
>+
>+static int __init pcistub_init(void)
>+{
>+	int pos = 0;
>+	struct pci_stub_device_id *pci_dev_id;
>+	int err = 0;
>+	int domain, bus, slot, func;
>+	int parsed;
>+
>+	if (pci_devs_to_hide && *pci_devs_to_hide) {
>+		do {
>+			parsed = 0;
>+
>+			err = sscanf(pci_devs_to_hide + pos,
>+				     " (%x:%x:%x.%x) %n",
>+				     &domain, &bus, &slot, &func, &parsed);
>+			if (err != 4) {
>+				domain = 0;
>+				err = sscanf(pci_devs_to_hide + pos,
>+					     " (%x:%x.%x) %n",
>+					     &bus, &slot, &func, &parsed);
>+				if (err != 3)
>+					goto parse_error;
>+			}
>+
>+			pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
>+			if (!pci_dev_id) {
>+				err = -ENOMEM;
>+				goto out;
>+			}
>+
>+			pci_dev_id->domain = domain;
>+			pci_dev_id->bus = bus;
>+			pci_dev_id->devfn = PCI_DEVFN(slot, func);
>+
>+			pr_debug
>+			    ("pciback: wants to seize %04x:%02x:%02x.%01x\n",
>+			     domain, bus, slot, func);
>+
>+			list_add_tail(&pci_dev_id->slot_list,
>+				      &pci_stub_device_ids);
>+
>+			/* if parsed<=0, we've reached the end of the string */
>+			pos += parsed;
>+		} while (parsed > 0 && pci_devs_to_hide[pos]);
>+
>+		/* If we're the first PCI Device Driver to register, we're the
>+		 * first one to get offered PCI devices as they become
>+		 * available (and thus we can be the first to grab them)
>+		 */
>+		pci_register_driver(&pciback_pci_driver);
>+	}
>+
>+      out:
>+	return err;
>+
>+      parse_error:
>+	printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n",
>+	       pci_devs_to_hide + pos);
>+	return -EINVAL;
>+}
>+
>+/*
>+ * fs_initcall happens before device_initcall
>+ * so pciback *should* get called first (b/c we 
>+ * want to suck up any device before other drivers
>+ * get a chance by being the first pci device
>+ * driver to register)
>+ */
>+fs_initcall(pcistub_init);
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,73 @@
>+/*
>+ * PCI Backend Common Data Structures & Function Declarations
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#ifndef __XEN_PCIBACK_H__
>+#define __XEN_PCIBACK_H__
>+
>+#include <linux/pci.h>
>+#include <linux/interrupt.h>
>+#include <asm-xen/xenbus.h>
>+#include <linux/list.h>
>+#include <linux/spinlock.h>
>+#include <asm-xen/xen-public/io/pciif.h>
>+
>+struct pci_dev_entry {
>+	struct list_head list;
>+	struct pci_dev *dev;
>+};
>+
>+struct pciback_device {
>+	void *pci_dev_data;
>+	spinlock_t dev_lock;
>+
>+	struct xenbus_device *xdev;
>+
>+	struct xenbus_watch be_watch;
>+	u8 be_watching;
>+
>+	int evtchn_irq;
>+
>+	struct xen_pci_sharedinfo *sh_info;
>+};
>+
>+struct pciback_dev_data {
>+	struct list_head config_fields;
>+};
>+
>+/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
>+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
>+					    int slot, int func);
>+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev);
>+void pcistub_put_pci_dev(struct pci_dev *dev);
>+
>+/* Ensure a device is turned off or reset */
>+void pciback_disable_device(struct pci_dev *dev);
>+void pciback_reset_device(struct pci_dev *pdev);
>+
>+/* Access a virtual configuration space for a PCI device */
>+int pciback_config_init(struct pci_dev *dev);
>+void pciback_config_reset(struct pci_dev *dev);
>+void pciback_config_free(struct pci_dev *dev);
>+int pciback_config_read(struct pci_dev *dev, int offset, int size,
>+			u32 * ret_val);
>+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
>+
>+/* Handle requests for specific devices from the frontend */
>+typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
>+				    unsigned int domain, unsigned int bus);
>+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
>+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
>+				    unsigned int domain, unsigned int bus,
>+				    unsigned int devfn);
>+int pciback_init_devices(struct pciback_device *pdev);
>+int pciback_publish_pci_roots(struct pciback_device *pdev,
>+			      publish_pci_root_cb cb);
>+void pciback_release_devices(struct pciback_device *pdev);
>+
>+/* Handles events from front-end */
>+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
>+
>+extern int verbose_request;
>+#endif
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,84 @@
>+/*
>+ * PCI Backend Operations - respond to PCI requests from Frontend
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <asm/bitops.h>
>+#include "pciback.h"
>+
>+int verbose_request = 0;
>+module_param(verbose_request, int, 0644);
>+
>+/* For those architectures without a pcibios_disable_device */
>+void __attribute__ ((weak)) pcibios_disable_device(struct pci_dev *dev) { }
>+
>+void pciback_disable_device(struct pci_dev *dev)
>+{
>+	if (dev->is_enabled) {
>+		dev->is_enabled = 0;
>+		pcibios_disable_device(dev);
>+	}
>+}
>+
>+/* Ensure a device is "turned off" and ready to be exported.
>+ * This also sets up the device's private data to keep track of what should
>+ * be in the base address registers (BARs) so that we can keep the
>+ * client from manipulating them directly.
>+ */
>+void pciback_reset_device(struct pci_dev *dev)
>+{
>+	u16 cmd;
>+
>+	/* Disable devices (but not bridges) */
>+	if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
>+		pciback_disable_device(dev);
>+
>+		pci_write_config_word(dev, PCI_COMMAND, 0);
>+
>+		dev->is_enabled = 0;
>+		dev->is_busmaster = 0;
>+	} else {
>+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
>+		if (cmd & (PCI_COMMAND_INVALIDATE)) {
>+			cmd &= ~(PCI_COMMAND_INVALIDATE);
>+			pci_write_config_word(dev, PCI_COMMAND, cmd);
>+
>+			dev->is_busmaster = 0;
>+		}
>+	}
>+
>+	pciback_config_reset(dev);
>+}
>+
>+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
>+{
>+	struct pciback_device *pdev = dev_id;
>+	struct pci_dev *dev;
>+	struct xen_pci_op *op = &pdev->sh_info->op;
>+
>+	if (unlikely(!test_bit(_XEN_PCIF_active,
>+			       (unsigned long *)&pdev->sh_info->flags))) {
>+		pr_debug("pciback: interrupt, but no active operation\n");
>+		goto out;
>+	}
>+
>+	dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
>+
>+	if (dev == NULL)
>+		op->err = XEN_PCI_ERR_dev_not_found;
>+	else if (op->cmd == XEN_PCI_OP_conf_read)
>+		op->err = pciback_config_read(dev, op->offset, op->size,
>+					      &op->value);
>+	else if (op->cmd == XEN_PCI_OP_conf_write)
>+		op->err = pciback_config_write(dev, op->offset, op->size,
>+					       op->value);
>+	else
>+		op->err = XEN_PCI_ERR_not_implemented;
>+
>+	wmb();
>+	clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
>+
>+      out:
>+	return IRQ_HANDLED;
>+}
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,163 @@
>+/*
>+ * PCI Backend - Provides a Virtual PCI bus (with real devices)
>+ *               to the frontend
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+
>+#include <linux/list.h>
>+#include <linux/slab.h>
>+#include <linux/pci.h>
>+#include "pciback.h"
>+
>+#define PCI_SLOT_MAX 32
>+
>+struct vpci_dev_data {
>+	struct list_head dev_list[PCI_SLOT_MAX];
>+};
>+
>+static inline struct list_head *list_first(struct list_head *head)
>+{
>+	return head->next;
>+}
>+
>+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
>+				    unsigned int domain, unsigned int bus,
>+				    unsigned int devfn)
>+{
>+	struct pci_dev_entry *dev_entry;
>+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
>+
>+	if (domain != 0 || bus != 0)
>+		return NULL;
>+
>+	if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
>+		/* we don't need to lock the list here because once the backend
>+		 * is in operation, it won't have any more devices addeded
>+		 * (or removed).
>+		 */
>+		list_for_each_entry(dev_entry,
>+				    &vpci_dev->dev_list[PCI_SLOT(devfn)],
>+				    list) {
>+			if (PCI_FUNC(dev_entry->dev->devfn) == PCI_FUNC(devfn))
>+				return dev_entry->dev;
>+		}
>+	}
>+	return NULL;
>+}
>+
>+static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
>+{
>+	if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
>+	    && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn))
>+		return 1;
>+
>+	return 0;
>+}
>+
>+/* Must hold pciback_device->dev_lock when calling this */
>+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
>+{
>+	int err = 0, slot;
>+	struct pci_dev_entry *t, *dev_entry;
>+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
>+
>+	if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
>+		err = -EFAULT;
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				 "Can't export bridges on the virtual PCI bus");
>+		goto out;
>+	}
>+
>+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
>+	if (!dev_entry) {
>+		err = -ENOMEM;
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				 "Error adding entry to virtual PCI bus");
>+		goto out;
>+	}
>+
>+	dev_entry->dev = dev;
>+
>+	/* Keep multi-function devices together on the virtual PCI bus */
>+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
>+		if (!list_empty(&vpci_dev->dev_list[slot])) {
>+			t = list_entry(list_first(&vpci_dev->dev_list[slot]),
>+				       struct pci_dev_entry, list);
>+
>+			if (match_slot(dev, t->dev)) {
>+				pr_info("pciback: vpci: %s: "
>+					"assign to virtual slot %d func %d\n",
>+					pci_name(dev), slot,
>+					PCI_FUNC(dev->devfn));
>+				list_add_tail(&dev_entry->list,
>+					      &vpci_dev->dev_list[slot]);
>+				goto out;
>+			}
>+		}
>+	}
>+
>+	/* Assign to a new slot on the virtual PCI bus */
>+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
>+		if (list_empty(&vpci_dev->dev_list[slot])) {
>+			printk(KERN_INFO
>+			       "pciback: vpci: %s: assign to virtual slot %d\n",
>+			       pci_name(dev), slot);
>+			list_add_tail(&dev_entry->list,
>+				      &vpci_dev->dev_list[slot]);
>+			goto out;
>+		}
>+	}
>+
>+	err = -ENOMEM;
>+	xenbus_dev_fatal(pdev->xdev, err,
>+			 "No more space on root virtual PCI bus");
>+
>+      out:
>+	return err;
>+}
>+
>+int pciback_init_devices(struct pciback_device *pdev)
>+{
>+	int slot;
>+	struct vpci_dev_data *vpci_dev;
>+
>+	vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
>+	if (!vpci_dev)
>+		return -ENOMEM;
>+
>+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
>+		INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
>+	}
>+
>+	pdev->pci_dev_data = vpci_dev;
>+
>+	return 0;
>+}
>+
>+int pciback_publish_pci_roots(struct pciback_device *pdev,
>+			      publish_pci_root_cb publish_cb)
>+{
>+	/* The Virtual PCI bus has only one root */
>+	return publish_cb(pdev, 0, 0);
>+}
>+
>+/* Must hold pciback_device->dev_lock when calling this */
>+void pciback_release_devices(struct pciback_device *pdev)
>+{
>+	int slot;
>+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
>+
>+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
>+		struct pci_dev_entry *e, *tmp;
>+		list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
>+					 list) {
>+			list_del(&e->list);
>+			pcistub_put_pci_dev(e->dev);
>+			kfree(e);
>+		}
>+	}
>+
>+	kfree(vpci_dev);
>+	pdev->pci_dev_data = NULL;
>+}
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,435 @@
>+/*
>+ * PCI Backend Xenbus Setup - handles setup with frontend and xend
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <linux/init.h>
>+#include <linux/list.h>
>+#include <asm-xen/xenbus.h>
>+#include <asm-xen/evtchn.h>
>+#include "pciback.h"
>+
>+#define INVALID_EVTCHN_IRQ  (-1)
>+
>+struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
>+{
>+	struct pciback_device *pdev;
>+
>+	pdev = kmalloc(sizeof(struct pciback_device), GFP_KERNEL);
>+	if (pdev == NULL)
>+		goto out;
>+	dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
>+
>+	pdev->xdev = xdev;
>+	xdev->data = pdev;
>+
>+	spin_lock_init(&pdev->dev_lock);
>+
>+	pdev->sh_info = NULL;
>+	pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
>+	pdev->be_watching = 0;
>+
>+	if (pciback_init_devices(pdev)) {
>+		kfree(pdev);
>+		pdev = NULL;
>+	}
>+      out:
>+	return pdev;
>+}
>+
>+void free_pdev(struct pciback_device *pdev)
>+{
>+	if (pdev->be_watching)
>+		unregister_xenbus_watch(&pdev->be_watch);
>+
>+	/* Ensure the guest can't trigger our handler before removing devices */
>+	if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ)
>+		unbind_from_irqhandler(pdev->evtchn_irq, pdev);
>+
>+	if (pdev->sh_info)
>+		xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
>+
>+	pciback_release_devices(pdev);
>+
>+	pdev->xdev->data = NULL;
>+	pdev->xdev = NULL;
>+
>+	kfree(pdev);
>+}
>+
>+static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
>+			     int remote_evtchn)
>+{
>+	int err = 0;
>+	int evtchn;
>+	dev_dbg(&pdev->xdev->dev,
>+		"Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
>+		gnt_ref, remote_evtchn);
>+
>+	err =
>+	    xenbus_map_ring_valloc(pdev->xdev, gnt_ref,
>+				   (void **)&pdev->sh_info);
>+	if (err)
>+		goto out;
>+
>+	err = xenbus_bind_evtchn(pdev->xdev, remote_evtchn, &evtchn);
>+	if (err)
>+		goto out;
>+
>+	err = bind_evtchn_to_irqhandler(evtchn, pciback_handle_event,
>+					SA_SAMPLE_RANDOM, "pciback", pdev);
>+	if (err < 0) {
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				 "Error binding event channel to IRQ");
>+		goto out;
>+	}
>+	pdev->evtchn_irq = err;
>+	err = 0;
>+
>+	dev_dbg(&pdev->xdev->dev, "Attached!\n");
>+      out:
>+	return err;
>+}
>+
>+static int pciback_attach(struct pciback_device *pdev)
>+{
>+	int err = 0;
>+	int gnt_ref, remote_evtchn;
>+	char *magic = NULL;
>+
>+	spin_lock(&pdev->dev_lock);
>+
>+	/* Make sure we only do this setup once */
>+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
>+	    XenbusStateInitialised)
>+		goto out;
>+
>+	/* Wait for frontend to state that it has published the configuration */
>+	if (xenbus_read_driver_state(pdev->xdev->otherend) !=
>+	    XenbusStateInitialised)
>+		goto out;
>+
>+	dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
>+
>+	err = xenbus_gather(XBT_NULL, pdev->xdev->otherend,
>+			    "pci-op-ref", "%u", &gnt_ref,
>+			    "event-channel", "%u", &remote_evtchn,
>+			    "magic", NULL, &magic, NULL);
>+	if (err) {
>+		/* If configuration didn't get read correctly, wait longer */
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				 "Error reading configuration from frontend");
>+		goto out;
>+	}
>+
>+	if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
>+		xenbus_dev_fatal(pdev->xdev, -EFAULT,
>+				 "version mismatch (%s/%s) with pcifront - "
>+				 "halting pciback",
>+				 magic, XEN_PCI_MAGIC);
>+		goto out;
>+	}
>+
>+	err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
>+	if (err)
>+		goto out;
>+
>+	dev_dbg(&pdev->xdev->dev, "Connecting...\n");
>+
>+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
>+	if (err)
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				 "Error switching to connected state!");
>+
>+	dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
>+      out:
>+	spin_unlock(&pdev->dev_lock);
>+
>+	if (magic)
>+		kfree(magic);
>+
>+	return err;
>+}
>+
>+static void pciback_frontend_changed(struct xenbus_device *xdev,
>+				     XenbusState fe_state)
>+{
>+	struct pciback_device *pdev = xdev->data;
>+
>+	dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
>+
>+	switch (fe_state) {
>+	case XenbusStateInitialised:
>+		pciback_attach(pdev);
>+		break;
>+
>+	case XenbusStateClosing:
>+		xenbus_switch_state(xdev, XBT_NULL, XenbusStateClosing);
>+		break;
>+
>+	case XenbusStateClosed:
>+		dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
>+		device_unregister(&xdev->dev);
>+		break;
>+
>+	default:
>+		break;
>+	}
>+}
>+
>+static int pciback_publish_pci_root(struct pciback_device *pdev,
>+				    unsigned int domain, unsigned int bus)
>+{
>+	unsigned int d, b;
>+	int i, root_num, len, err;
>+	char str[64];
>+
>+	dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
>+
>+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
>+			   "root_num", "%d", &root_num);
>+	if (err == 0 || err == -ENOENT)
>+		root_num = 0;
>+	else if (err < 0)
>+		goto out;
>+
>+	/* Verify that we haven't already published this pci root */
>+	for (i = 0; i < root_num; i++) {
>+		len = snprintf(str, sizeof(str), "root-%d", i);
>+		if (unlikely(len >= (sizeof(str) - 1))) {
>+			err = -ENOMEM;
>+			goto out;
>+		}
>+
>+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
>+				   str, "%x:%x", &d, &b);
>+		if (err < 0)
>+			goto out;
>+		if (err != 2) {
>+			err = -EINVAL;
>+			goto out;
>+		}
>+
>+		if (d == domain && b == bus) {
>+			err = 0;
>+			goto out;
>+		}
>+	}
>+
>+	len = snprintf(str, sizeof(str), "root-%d", root_num);
>+	if (unlikely(len >= (sizeof(str) - 1))) {
>+		err = -ENOMEM;
>+		goto out;
>+	}
>+
>+	dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
>+		root_num, domain, bus);
>+
>+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename, str,
>+			    "%04x:%02x", domain, bus);
>+	if (err)
>+		goto out;
>+
>+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename,
>+			    "root_num", "%d", (root_num + 1));
>+
>+      out:
>+	return err;
>+}
>+
>+static int pciback_export_device(struct pciback_device *pdev,
>+				 int domain, int bus, int slot, int func)
>+{
>+	struct pci_dev *dev;
>+	int err = 0;
>+
>+	dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
>+		domain, bus, slot, func);
>+
>+	dev = pcistub_get_pci_dev_by_slot(domain, bus, slot, func);
>+	if (!dev) {
>+		err = -EINVAL;
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				 "Couldn't locate PCI device "
>+				 "(%04x:%02x:%02x.%01x)! "
>+				 "perhaps already in-use?",
>+				 domain, bus, slot, func);
>+		goto out;
>+	}
>+
>+	err = pciback_add_pci_dev(pdev, dev);
>+	if (err)
>+		goto out;
>+
>+	/* TODO: If this is a bridge, export all the children (this won't work
>+	 * for children dynamically added to the bus later!) - This is
>+	 * trivial in kernels >= 2.6.14 with pci_walk_bus(dev->subordinate)
>+	 */
>+      out:
>+	return err;
>+}
>+
>+static int pciback_setup_backend(struct pciback_device *pdev)
>+{
>+	/* Get configuration from xend (if available now) */
>+	int domain, bus, slot, func;
>+	int err = 0;
>+	int i, num_devs;
>+	char dev_str[64];
>+
>+	spin_lock(&pdev->dev_lock);
>+
>+	/* It's possible we could get the call to setup twice, so make sure
>+	 * we're not already connected.
>+	 */
>+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
>+	    XenbusStateInitWait)
>+		goto out;
>+
>+	dev_dbg(&pdev->xdev->dev, "getting be setup\n");
>+
>+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, "num_devs", "%d",
>+			   &num_devs);
>+	if (err != 1) {
>+		if (err >= 0)
>+			err = -EINVAL;
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				 "Error reading number of devices");
>+		goto out;
>+	}
>+
>+	for (i = 0; i < num_devs; i++) {
>+		int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
>+		if (unlikely(l >= (sizeof(dev_str) - 1))) {
>+			err = -ENOMEM;
>+			xenbus_dev_fatal(pdev->xdev, err,
>+					 "String overflow while reading "
>+					 "configuration");
>+			goto out;
>+		}
>+
>+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, dev_str,
>+				   "%x:%x:%x.%x", &domain, &bus, &slot, &func);
>+		if (err < 0) {
>+			xenbus_dev_fatal(pdev->xdev, err,
>+					 "Error reading device configuration");
>+			goto out;
>+		}
>+		if (err != 4) {
>+			err = -EINVAL;
>+			xenbus_dev_fatal(pdev->xdev, err,
>+					 "Error parsing pci device "
>+					 "configuration");
>+			goto out;
>+		}
>+
>+		err = pciback_export_device(pdev, domain, bus, slot, func);
>+		if (err)
>+			goto out;
>+	}
>+
>+	err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
>+	if (err) {
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				 "Error while publish PCI root buses "
>+				 "for frontend");
>+		goto out;
>+	}
>+
>+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateInitialised);
>+	if (err)
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				 "Error switching to initialised state!");
>+
>+      out:
>+	spin_unlock(&pdev->dev_lock);
>+
>+	if (!err)
>+		/* see if pcifront is already configured (if not, we'll wait) */
>+		pciback_attach(pdev);
>+
>+	return err;
>+}
>+
>+static void pciback_be_watch(struct xenbus_watch *watch,
>+			     const char **vec, unsigned int len)
>+{
>+	struct pciback_device *pdev =
>+	    container_of(watch, struct pciback_device, be_watch);
>+
>+	switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
>+	case XenbusStateInitWait:
>+		pciback_setup_backend(pdev);
>+		break;
>+
>+	default:
>+		break;
>+	}
>+}
>+
>+static int pciback_xenbus_probe(struct xenbus_device *dev,
>+				const struct xenbus_device_id *id)
>+{
>+	int err = 0;
>+	struct pciback_device *pdev = alloc_pdev(dev);
>+
>+	if (pdev == NULL) {
>+		err = -ENOMEM;
>+		xenbus_dev_fatal(dev, err,
>+				 "Error allocating pciback_device struct");
>+		goto out;
>+	}
>+
>+	/* wait for xend to configure us */
>+	err = xenbus_switch_state(dev, XBT_NULL, XenbusStateInitWait);
>+	if (err)
>+		goto out;
>+
>+	/* watch the backend node for backend configuration information */
>+	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
>+				pciback_be_watch);
>+	if (err)
>+		goto out;
>+	pdev->be_watching = 1;
>+
>+	/* We need to force a call to our callback here in case
>+	 * xend already configured us!
>+	 */
>+	pciback_be_watch(&pdev->be_watch, NULL, 0);
>+
>+      out:
>+	return err;
>+}
>+
>+static int pciback_xenbus_remove(struct xenbus_device *dev)
>+{
>+	struct pciback_device *pdev = dev->data;
>+
>+	if (pdev != NULL)
>+		free_pdev(pdev);
>+
>+	return 0;
>+}
>+
>+static struct xenbus_device_id xenpci_ids[] = {
>+	{"pci"},
>+	{{0}},
>+};
>+
>+static struct xenbus_driver xenbus_pciback_driver = {
>+	.name 			= "pciback",
>+	.owner 			= THIS_MODULE,
>+	.ids 			= xenpci_ids,
>+	.probe 			= pciback_xenbus_probe,
>+	.remove 		= pciback_xenbus_remove,
>+	.otherend_changed 	= pciback_frontend_changed,
>+};
>+
>+static __init int pciback_xenbus_register(void)
>+{
>+	return xenbus_register_backend(&xenbus_pciback_driver);
>+}
>+
>+/* Must only initialize our xenbus driver after the pcistub driver */
>+device_initcall(pciback_xenbus_register);
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,8 @@
>+obj-y += pcifront.o
>+
>+pcifront-y := pci_op.o xenbus.o pci.o
>+pcifront-$(CONFIG_XEN_PCI_FE_ARCH_REPLACE) += arch.o
>+
>+ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y)
>+EXTRA_CFLAGS += -DDEBUG
>+endif
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pcifront/arch.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/arch.c	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,98 @@
>+/*
>+ * PCI Frontend Arch Replacement Code - replaces an architecture's PCI access
>+ *              code with a generic, Xen version (Experimental)
>+ * - This file *should* be arch-independent (except for
>+ *   pci_mmap_page_range) and should replace an arch's PCI implementation
>+ * - You must prevent an architecture's PCI code from compiling into the kernel
>+ *   when you use the code contained here.
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <linux/init.h>
>+#include <linux/pci.h>
>+
>+/* More or less copied from other architectures */
>+int pcibios_enable_device(struct pci_dev *dev, int mask)
>+{
>+	u16 cmd, oldcmd;
>+	u8 irq;
>+	int i;
>+
>+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
>+	oldcmd = cmd;
>+
>+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
>+		struct resource *r = &dev->resource[i];
>+
>+		if (!(mask & (1 << i)))
>+			continue;
>+
>+		if (r->flags & IORESOURCE_IO)
>+			cmd |= PCI_COMMAND_IO;
>+		if (r->flags & IORESOURCE_MEM)
>+			cmd |= PCI_COMMAND_MEMORY;
>+	}
>+
>+	if (cmd != oldcmd) {
>+		printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n",
>+		       pci_name(dev), cmd);
>+		pci_write_config_word(dev, PCI_COMMAND, cmd);
>+	}
>+
>+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
>+	dev->irq = irq;
>+
>+	return 0;
>+}
>+
>+#define CMD_DISABLE_BITS \
>+	(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER)
>+void pcibios_disable_device(struct pci_dev *dev)
>+{
>+	u16 cmd;
>+
>+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
>+
>+	if (cmd & CMD_DISABLE_BITS) {
>+		cmd &= ~CMD_DISABLE_BITS;
>+
>+		printk(KERN_DEBUG "PCI: Disabling device: (%s), cmd %x\n",
>+		       pci_name(dev), cmd);
>+		pci_write_config_word(dev, PCI_COMMAND, cmd);
>+	}
>+}
>+
>+char *pcibios_setup(char *str)
>+{
>+	/** Return NULL if we accept an option, str if we don't */
>+	return str;
>+}
>+
>+void pcibios_set_master(struct pci_dev *dev)
>+{
>+	/* Handled by backend when we turn the master
>+	 * bit on in the PCI_COMMAND register */
>+}
>+
>+void pcibios_align_resource(void *data, struct resource *res,
>+			    unsigned long size, unsigned long align)
>+{
>+}
>+
>+void pcibios_fixup_bus(struct pci_bus *bus)
>+{
>+}
>+
>+unsigned int pcibios_assign_all_busses(void)
>+{
>+	return 0;
>+}
>+
>+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
>+			enum pci_mmap_state mmap_state, int write_combine)
>+{
>+	printk(KERN_ERR "%s: mmap_page_range not implemented!\n",
>+	       pci_name(dev));
>+	return -EINVAL;
>+}
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,44 @@
>+/*
>+ * PCI Frontend Operations - ensure only one PCI frontend runs at a time
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <linux/init.h>
>+#include <linux/pci.h>
>+#include <linux/spinlock.h>
>+#include "pcifront.h"
>+
>+DEFINE_SPINLOCK(pcifront_dev_lock);
>+static struct pcifront_device *pcifront_dev = NULL;
>+
>+int pcifront_connect(struct pcifront_device *pdev)
>+{
>+	int err = 0;
>+
>+	spin_lock(&pcifront_dev_lock);
>+
>+	if (!pcifront_dev)
>+		dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
>+	else {
>+		dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
>+		err = -EEXIST;
>+	}
>+
>+	spin_unlock(&pcifront_dev_lock);
>+
>+	return err;
>+}
>+
>+void pcifront_disconnect(struct pcifront_device *pdev)
>+{
>+	spin_lock(&pcifront_dev_lock);
>+
>+	if (pdev == pcifront_dev) {
>+		dev_info(&pdev->xdev->dev,
>+			 "Disconnecting PCI Frontend Buses\n");
>+		pcifront_dev = NULL;
>+	}
>+
>+	spin_unlock(&pcifront_dev_lock);
>+}
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,224 @@
>+/*
>+ * PCI Frontend Operations - Communicates with frontend
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <linux/init.h>
>+#include <linux/pci.h>
>+#include <linux/spinlock.h>
>+#include <asm-xen/evtchn.h>
>+#include "pcifront.h"
>+
>+int verbose_request = 0;
>+module_param(verbose_request, int, 0644);
>+
>+static int errno_to_pcibios_err(int errno)
>+{
>+	switch (errno) {
>+	case XEN_PCI_ERR_success:
>+		return PCIBIOS_SUCCESSFUL;
>+
>+	case XEN_PCI_ERR_dev_not_found:
>+		return PCIBIOS_DEVICE_NOT_FOUND;
>+
>+	case XEN_PCI_ERR_invalid_offset:
>+	case XEN_PCI_ERR_op_failed:
>+		return PCIBIOS_BAD_REGISTER_NUMBER;
>+
>+	case XEN_PCI_ERR_not_implemented:
>+		return PCIBIOS_FUNC_NOT_SUPPORTED;
>+
>+	case XEN_PCI_ERR_access_denied:
>+		return PCIBIOS_SET_FAILED;
>+	}
>+	return errno;
>+}
>+
>+static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
>+{
>+	int err = 0;
>+	struct xen_pci_op *active_op = &pdev->sh_info->op;
>+	unsigned long irq_flags;
>+
>+	unsigned int volatile ttl = (1U << 29);
>+
>+	spin_lock_irqsave(&pdev->sh_info_lock, irq_flags);
>+
>+	memcpy(active_op, op, sizeof(struct xen_pci_op));
>+
>+	/* Go */
>+	wmb();
>+	set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
>+	notify_remote_via_evtchn(pdev->evtchn);
>+
>+	/* IRQs are disabled for the pci config. space reads/writes,
>+	 * which means no event channel to notify us that the backend
>+	 * is done so spin while waiting for the answer */
>+	while (test_bit
>+	       (_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)) {
>+		if (!ttl) {
>+			dev_err(&pdev->xdev->dev,
>+				"pciback not responding!!!\n");
>+			clear_bit(_XEN_PCIF_active,
>+				  (unsigned long *)&pdev->sh_info->flags);
>+			err = XEN_PCI_ERR_dev_not_found;
>+			goto out;
>+		}
>+		ttl--;
>+	}
>+
>+	memcpy(op, active_op, sizeof(struct xen_pci_op));
>+
>+	err = op->err;
>+      out:
>+	spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags);
>+	return err;
>+}
>+
>+/* Access to this function is spinlocked in drivers/pci/access.c */
>+static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
>+			     int where, int size, u32 * val)
>+{
>+	int err = 0;
>+	struct xen_pci_op op = {
>+		.cmd    = XEN_PCI_OP_conf_read,
>+		.domain = pci_domain_nr(bus),
>+		.bus    = bus->number,
>+		.devfn  = devfn,
>+		.offset = where,
>+		.size   = size,
>+	};
>+	struct pcifront_sd *sd = bus->sysdata;
>+	struct pcifront_device *pdev = sd->pdev;
>+
>+	if (verbose_request)
>+		dev_info(&pdev->xdev->dev,
>+			 "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n",
>+			 pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
>+			 PCI_FUNC(devfn), where, size);
>+
>+	err = do_pci_op(pdev, &op);
>+
>+	if (likely(!err)) {
>+		if (verbose_request)
>+			dev_info(&pdev->xdev->dev, "read got back value %x\n",
>+				 op.value);
>+
>+		*val = op.value;
>+	} else if (err == -ENODEV) {
>+		/* No device here, pretend that it just returned 0 */
>+		err = 0;
>+		*val = 0;
>+	}
>+
>+	return errno_to_pcibios_err(err);
>+}
>+
>+/* Access to this function is spinlocked in drivers/pci/access.c */
>+static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
>+			      int where, int size, u32 val)
>+{
>+	struct xen_pci_op op = {
>+		.cmd    = XEN_PCI_OP_conf_write,
>+		.domain = pci_domain_nr(bus),
>+		.bus    = bus->number,
>+		.devfn  = devfn,
>+		.offset = where,
>+		.size   = size,
>+		.value  = val,
>+	};
>+	struct pcifront_sd *sd = bus->sysdata;
>+	struct pcifront_device *pdev = sd->pdev;
>+
>+	if (verbose_request)
>+		dev_info(&pdev->xdev->dev,
>+			 "write dev=%04x:%02x:%02x.%01x - "
>+			 "offset %x size %d val %x\n",
>+			 pci_domain_nr(bus), bus->number,
>+			 PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
>+
>+	return errno_to_pcibios_err(do_pci_op(pdev, &op));
>+}
>+
>+struct pci_ops pcifront_bus_ops = {
>+	.read = pcifront_bus_read,
>+	.write = pcifront_bus_write,
>+};
>+
>+int pcifront_scan_root(struct pcifront_device *pdev,
>+		       unsigned int domain, unsigned int bus)
>+{
>+	struct pci_bus *b;
>+	struct pcifront_sd *sd = NULL;
>+	struct pci_bus_entry *bus_entry = NULL;
>+	int err = 0;
>+
>+#ifndef CONFIG_PCI_DOMAINS
>+	if (domain != 0) {
>+		dev_err(&pdev->xdev->dev,
>+			"PCI Root in non-zero PCI Domain! domain=%d\n", domain);
>+		dev_err(&pdev->xdev->dev,
>+			"Please compile with CONFIG_PCI_DOMAINS\n");
>+		err = -EINVAL;
>+		goto err_out;
>+	}
>+#endif
>+
>+	dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
>+		 domain, bus);
>+
>+	bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
>+	sd = kmalloc(sizeof(*sd), GFP_KERNEL);
>+	if (!bus_entry || !sd) {
>+		err = -ENOMEM;
>+		goto err_out;
>+	}
>+	sd->domain = domain;
>+	sd->pdev = pdev;
>+
>+	b = pci_scan_bus_parented(&pdev->xdev->dev, bus, &pcifront_bus_ops, sd);
>+	if (!b) {
>+		dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n");
>+		err = -ENOMEM;
>+		goto err_out;
>+	}
>+	bus_entry->bus = b;
>+
>+	list_add(&bus_entry->list, &pdev->root_buses);
>+
>+	/* In kernels >= 2.6.13, we need to:
>+	   pci_bus_add_devices(b); */
>+
>+	return 0;
>+
>+      err_out:
>+	kfree(bus_entry);
>+	kfree(sd);
>+
>+	return err;
>+}
>+
>+void pcifront_free_roots(struct pcifront_device *pdev)
>+{
>+	struct pci_bus_entry *bus_entry, *t;
>+
>+	list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
>+		/* TODO: Removing a PCI Bus is untested (as it normally
>+		 * just goes away on domain shutdown)
>+		 */
>+		list_del(&bus_entry->list);
>+
>+		spin_lock(&pci_bus_lock);
>+		list_del(&bus_entry->bus->node);
>+		spin_unlock(&pci_bus_lock);
>+
>+		kfree(bus_entry->bus->sysdata);
>+
>+		device_unregister(bus_entry->bus->bridge);
>+
>+		/* Do we need to free() the bus itself? */
>+
>+		kfree(bus_entry);
>+	}
>+}
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,40 @@
>+/*
>+ * PCI Frontend - Common data structures & function declarations
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#ifndef __XEN_PCIFRONT_H__
>+#define __XEN_PCIFRONT_H__
>+
>+#include <linux/spinlock.h>
>+#include <linux/pci.h>
>+#include <asm-xen/xenbus.h>
>+#include <asm-xen/xen-public/io/pciif.h>
>+#include <asm-xen/pcifront.h>
>+
>+struct pci_bus_entry {
>+	struct list_head list;
>+	struct pci_bus *bus;
>+};
>+
>+struct pcifront_device {
>+	struct xenbus_device *xdev;
>+	struct list_head root_buses;
>+	spinlock_t dev_lock;
>+
>+	int evtchn;
>+	int gnt_ref;
>+
>+	/* Lock this when doing any operations in sh_info */
>+	spinlock_t sh_info_lock;
>+	struct xen_pci_sharedinfo *sh_info;
>+};
>+
>+int pcifront_connect(struct pcifront_device *pdev);
>+void pcifront_disconnect(struct pcifront_device *pdev);
>+
>+int pcifront_scan_root(struct pcifront_device *pdev,
>+		       unsigned int domain, unsigned int bus);
>+void pcifront_free_roots(struct pcifront_device *pdev);
>+
>+#endif	/* __XEN_PCIFRONT_H__ */
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,295 @@
>+/*
>+ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn)
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#include <linux/module.h>
>+#include <linux/init.h>
>+#include <linux/mm.h>
>+#include <asm-xen/xenbus.h>
>+#include "pcifront.h"
>+
>+#define INVALID_GRANT_REF (0)
>+#define INVALID_EVTCHN    (-1)
>+
>+static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
>+{
>+	struct pcifront_device *pdev;
>+
>+	pdev = kmalloc(sizeof(struct pcifront_device), GFP_KERNEL);
>+	if (pdev == NULL)
>+		goto out;
>+
>+	pdev->sh_info =
>+	    (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
>+	if (pdev->sh_info == NULL) {
>+		kfree(pdev);
>+		pdev = NULL;
>+		goto out;
>+	}
>+	pdev->sh_info->flags = 0;
>+
>+	xdev->data = pdev;
>+	pdev->xdev = xdev;
>+
>+	INIT_LIST_HEAD(&pdev->root_buses);
>+
>+	spin_lock_init(&pdev->dev_lock);
>+	spin_lock_init(&pdev->sh_info_lock);
>+
>+	pdev->evtchn = INVALID_EVTCHN;
>+	pdev->gnt_ref = INVALID_GRANT_REF;
>+
>+	dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n",
>+		pdev, pdev->sh_info);
>+      out:
>+	return pdev;
>+}
>+
>+static void free_pdev(struct pcifront_device *pdev)
>+{
>+	dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev);
>+
>+	if (pdev->evtchn != INVALID_EVTCHN)
>+		xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
>+
>+	if (pdev->gnt_ref != INVALID_GRANT_REF)
>+		gnttab_end_foreign_access(pdev->gnt_ref, 0,
>+					  (unsigned long)pdev->sh_info);
>+
>+	pdev->xdev->data = NULL;
>+
>+	kfree(pdev);
>+}
>+
>+static int pcifront_publish_info(struct pcifront_device *pdev)
>+{
>+	int err = 0;
>+	xenbus_transaction_t trans;
>+
>+	err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info));
>+	if (err < 0)
>+		goto out;
>+
>+	pdev->gnt_ref = err;
>+
>+	err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
>+	if (err)
>+		goto out;
>+
>+      do_publish:
>+	err = xenbus_transaction_start(&trans);
>+	if (err) {
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				 "Error writing configuration for backend "
>+				 "(start transaction)");
>+		goto out;
>+	}
>+
>+	err = xenbus_printf(trans, pdev->xdev->nodename,
>+			    "pci-op-ref", "%u", pdev->gnt_ref);
>+	if (!err)
>+		err = xenbus_printf(trans, pdev->xdev->nodename,
>+				    "event-channel", "%u", pdev->evtchn);
>+	if (!err)
>+		err = xenbus_printf(trans, pdev->xdev->nodename,
>+				    "magic", XEN_PCI_MAGIC);
>+	if (!err)
>+		err =
>+		    xenbus_switch_state(pdev->xdev, trans,
>+					XenbusStateInitialised);
>+
>+	if (err) {
>+		xenbus_transaction_end(trans, 1);
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				 "Error writing configuration for backend");
>+		goto out;
>+	} else {
>+		err = xenbus_transaction_end(trans, 0);
>+		if (err == -EAGAIN)
>+			goto do_publish;
>+		else if (err) {
>+			xenbus_dev_fatal(pdev->xdev, err,
>+					 "Error completing transaction "
>+					 "for backend");
>+			goto out;
>+		}
>+	}
>+
>+	dev_dbg(&pdev->xdev->dev, "publishing successful!\n");
>+
>+      out:
>+	return err;
>+}
>+
>+static int pcifront_try_connect(struct pcifront_device *pdev)
>+{
>+	int err = -EFAULT;
>+	int i, num_roots, len;
>+	char str[64];
>+	unsigned int domain, bus;
>+
>+	spin_lock(&pdev->dev_lock);
>+
>+	/* Only connect once */
>+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
>+	    XenbusStateInitialised)
>+		goto out;
>+
>+	err = pcifront_connect(pdev);
>+	if (err) {
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				 "Error connecting PCI Frontend");
>+		goto out;
>+	}
>+
>+	err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend,
>+			   "root_num", "%d", &num_roots);
>+	if (err == -ENOENT) {
>+		xenbus_dev_error(pdev->xdev, err,
>+				 "No PCI Roots found, trying 0000:00");
>+		err = pcifront_scan_root(pdev, 0, 0);
>+		num_roots = 0;
>+	} else if (err != 1) {
>+		if (err == 0)
>+			err = -EINVAL;
>+		xenbus_dev_fatal(pdev->xdev, err,
>+				 "Error reading number of PCI roots");
>+		goto out;
>+	}
>+
>+	for (i = 0; i < num_roots; i++) {
>+		len = snprintf(str, sizeof(str), "root-%d", i);
>+		if (unlikely(len >= (sizeof(str) - 1))) {
>+			err = -ENOMEM;
>+			goto out;
>+		}
>+
>+		err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend, str,
>+				   "%x:%x", &domain, &bus);
>+		if (err != 2) {
>+			if (err >= 0)
>+				err = -EINVAL;
>+			xenbus_dev_fatal(pdev->xdev, err,
>+					 "Error reading PCI root %d", i);
>+			goto out;
>+		}
>+
>+		err = pcifront_scan_root(pdev, domain, bus);
>+		if (err) {
>+			xenbus_dev_fatal(pdev->xdev, err,
>+					 "Error scanning PCI root %04x:%02x",
>+					 domain, bus);
>+			goto out;
>+		}
>+	}
>+
>+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
>+	if (err)
>+		goto out;
>+
>+      out:
>+	spin_unlock(&pdev->dev_lock);
>+	return err;
>+}
>+
>+static int pcifront_try_disconnect(struct pcifront_device *pdev)
>+{
>+	int err = 0;
>+	XenbusState prev_state;
>+
>+	spin_lock(&pdev->dev_lock);
>+
>+	prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
>+
>+	if (prev_state < XenbusStateClosing)
>+		err = xenbus_switch_state(pdev->xdev, XBT_NULL,
>+					XenbusStateClosing);
>+
>+	if (!err && prev_state == XenbusStateConnected)
>+		pcifront_disconnect(pdev);
>+
>+	spin_unlock(&pdev->dev_lock);
>+
>+	return err;
>+}
>+
>+static void pcifront_backend_changed(struct xenbus_device *xdev,
>+				     XenbusState be_state)
>+{
>+	struct pcifront_device *pdev = xdev->data;
>+
>+	switch (be_state) {
>+	case XenbusStateClosing:
>+		dev_warn(&xdev->dev, "backend going away!\n");
>+		pcifront_try_disconnect(pdev);
>+		break;
>+
>+	case XenbusStateClosed:
>+		dev_warn(&xdev->dev, "backend went away!\n");
>+		pcifront_try_disconnect(pdev);
>+
>+		device_unregister(&pdev->xdev->dev);
>+		break;
>+
>+	case XenbusStateConnected:
>+		pcifront_try_connect(pdev);
>+		break;
>+
>+	default:
>+		break;
>+	}
>+}
>+
>+static int pcifront_xenbus_probe(struct xenbus_device *xdev,
>+				 const struct xenbus_device_id *id)
>+{
>+	int err = 0;
>+	struct pcifront_device *pdev = alloc_pdev(xdev);
>+
>+	if (pdev == NULL) {
>+		err = -ENOMEM;
>+		xenbus_dev_fatal(xdev, err,
>+				 "Error allocating pcifront_device struct");
>+		goto out;
>+	}
>+
>+	err = pcifront_publish_info(pdev);
>+
>+      out:
>+	return err;
>+}
>+
>+static int pcifront_xenbus_remove(struct xenbus_device *xdev)
>+{
>+	if (xdev->data)
>+		free_pdev(xdev->data);
>+
>+	return 0;
>+}
>+
>+static struct xenbus_device_id xenpci_ids[] = {
>+	{"pci"},
>+	{{0}},
>+};
>+
>+static struct xenbus_driver xenbus_pcifront_driver = {
>+	.name 			= "pcifront",
>+	.owner 			= THIS_MODULE,
>+	.ids 			= xenpci_ids,
>+	.probe 			= pcifront_xenbus_probe,
>+	.remove 		= pcifront_xenbus_remove,
>+	.otherend_changed 	= pcifront_backend_changed,
>+};
>+
>+static int __init pcifront_init(void)
>+{
>+	int err = 0;
>+
>+	err = xenbus_register_frontend(&xenbus_pcifront_driver);
>+
>+	return err;
>+}
>+
>+/* Initialize after the Xen PCI Frontend Stub is initialized */
>+subsys_initcall(pcifront_init);
>diff -r 2add7a262530 -r 4868d0f773ce linux-2.6-xen-sparse/include/asm-xen/pcifront.h
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/linux-2.6-xen-sparse/include/asm-xen/pcifront.h	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,39 @@
>+/*
>+ * PCI Frontend - arch-dependendent declarations
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#ifndef __XEN_ASM_PCIFRONT_H__
>+#define __XEN_ASM_PCIFRONT_H__
>+
>+#include <linux/config.h>
>+#include <linux/spinlock.h>
>+
>+#ifdef __KERNEL__
>+
>+struct pcifront_device;
>+
>+struct pcifront_sd {
>+	int domain;
>+	struct pcifront_device *pdev;
>+};
>+
>+struct pci_bus;
>+
>+#ifdef CONFIG_PCI_DOMAINS
>+static inline int pci_domain_nr(struct pci_bus *bus)
>+{
>+	struct pcifront_sd *sd = bus->sysdata;
>+	return sd->domain;
>+}
>+static inline int pci_proc_domain(struct pci_bus *bus)
>+{
>+	return pci_domain_nr(bus);
>+}
>+#endif /* CONFIG_PCI_DOMAINS */
>+
>+extern spinlock_t pci_bus_lock;
>+
>+#endif /* __KERNEL__ */
>+
>+#endif /* __XEN_ASM_PCIFRONT_H__ */
>diff -r 2add7a262530 -r 4868d0f773ce xen/include/public/io/pciif.h
>--- /dev/null	Fri Jan 27 15:17:38 2006
>+++ b/xen/include/public/io/pciif.h	Mon Jan 30 18:32:09 2006
>@@ -0,0 +1,55 @@
>+/*
>+ * PCI Backend/Frontend Common Data Structures & Macros
>+ *
>+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
>+ */
>+#ifndef __XEN_PCI_COMMON_H__
>+#define __XEN_PCI_COMMON_H__
>+
>+/* Be sure to bump this number if you change this file */
>+#define XEN_PCI_MAGIC		"7"
>+
>+/* xen_pci_sharedinfo flags */
>+#define _XEN_PCIF_active     (0)
>+#define XEN_PCIF_active      (1<<_XEN_PCI_active)
>+
>+/* xen_pci_op commands */
>+#define XEN_PCI_OP_conf_read    (0)
>+#define XEN_PCI_OP_conf_write   (1)
>+
>+/* xen_pci_op error numbers */
>+#define XEN_PCI_ERR_success          (0)
>+#define XEN_PCI_ERR_dev_not_found   (-1)
>+#define XEN_PCI_ERR_invalid_offset  (-2)
>+#define XEN_PCI_ERR_access_denied   (-3)
>+#define XEN_PCI_ERR_not_implemented (-4)
>+/* XEN_PCI_ERR_op_failed - backend failed to complete the operation */
>+#define XEN_PCI_ERR_op_failed       (-5)
>+
>+struct xen_pci_op {
>+	/* IN: what action to perform: XEN_PCI_OP_* */
>+	uint32_t cmd;
>+
>+	/* OUT: will contain an error number (if any) from errno.h */
>+	int32_t err;
>+
>+	/* IN: which device to touch */
>+	uint32_t domain; /* PCI Domain/Segment */
>+	uint32_t bus;
>+	uint32_t devfn;
>+
>+	/* IN: which configuration registers to touch */
>+	int32_t offset;
>+	int32_t size;
>+
>+	/* IN/OUT: Contains the result after a READ or the value to WRITE */
>+	uint32_t value;
>+};
>+
>+struct xen_pci_sharedinfo {
>+	/* flags - XEN_PCIF_* */
>+	uint32_t flags;
>+	struct xen_pci_op op;
>+};
>+
>+#endif /* __XEN_PCI_COMMON_H__ */
>  
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
@ 2006-02-06 18:45 Dave Thompson (davetho)
  2006-02-06 20:08 ` Ryan
  0 siblings, 1 reply; 15+ messages in thread
From: Dave Thompson (davetho) @ 2006-02-06 18:45 UTC (permalink / raw)
  To: Ryan; +Cc: xen-devel

Ryan,

I found a bug in this patch.  The function pciback_publish_pci_roots()
added in the file linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c
sets the local variables domain and bus using the dev_entry pointer
which is uninitialized at this point.  The two lines which set these
variables should be moved down so that they are within the
list_for_each_entry loop.

FYI,
Dave Thompson

> -----Original Message-----
> From: xen-devel-bounces@lists.xensource.com 
> [mailto:xen-devel-bounces@lists.xensource.com] On Behalf Of Ryan
> Sent: Monday, January 30, 2006 7:24 AM
> To: xen-devel
> Subject: [Xen-devel] [PATCH][2/4] PCI Driver Domains: PCI 
> Backend/Frontend
> 
> This patch contains the PCI backend and frontend drivers for Linux
> 2.6.12. There are a couple of compile-time options in the backend and
> frontend although the defaults should be sufficient to get you up and
> running.
> 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
  2006-02-06 18:45 Dave Thompson (davetho)
@ 2006-02-06 20:08 ` Ryan
  0 siblings, 0 replies; 15+ messages in thread
From: Ryan @ 2006-02-06 20:08 UTC (permalink / raw)
  To: Dave Thompson (davetho); +Cc: xen-devel

Dave,

Thanks for spotting that. I believe those were incorrectly moved when I
was correcting some coding style issues. I'm preparing a new patch
against xen-unstable (to include the recent Linux 2.6.16-rc2 import into
the tree) which I hope to post in the next few days. I'll include this
fix in that patch.

Ryan

On Mon, 2006-02-06 at 13:45 -0500, Dave Thompson (davetho) wrote:
> Ryan,
> 
> I found a bug in this patch.  The function pciback_publish_pci_roots()
> added in the file linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c
> sets the local variables domain and bus using the dev_entry pointer
> which is uninitialized at this point.  The two lines which set these
> variables should be moved down so that they are within the
> list_for_each_entry loop.
> 
> FYI,
> Dave Thompson
> 
> > -----Original Message-----
> > From: xen-devel-bounces@lists.xensource.com 
> > [mailto:xen-devel-bounces@lists.xensource.com] On Behalf Of Ryan
> > Sent: Monday, January 30, 2006 7:24 AM
> > To: xen-devel
> > Subject: [Xen-devel] [PATCH][2/4] PCI Driver Domains: PCI 
> > Backend/Frontend
> > 
> > This patch contains the PCI backend and frontend drivers for Linux
> > 2.6.12. There are a couple of compile-time options in the backend and
> > frontend although the defaults should be sufficient to get you up and
> > running.
> > 
> 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
@ 2006-02-07 14:37 Ryan
  2006-02-07 15:19 ` Keir Fraser
  0 siblings, 1 reply; 15+ messages in thread
From: Ryan @ 2006-02-07 14:37 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: Type: text/plain, Size: 1400 bytes --]

Resubmitting the driver domain patches against the latest xen-unstable.
These should apply cleanly to 8772:55268b90a519.

Thanks to Dave Thompson for pointing out a bug in the PCI backend. His
fix is now included.

Other than changing the location of some files to reflect the new
sub-arch directory layout, the two significant changes for PCI driver
domains and 2.6.16-rc2 are:

1) Need to call pci_bus_add_devices after creating the bus (previously,
this used to be done for you as part of pci_scan_bus_parented).

2) arch/i386/pci/i386-xen.c needed to return. Calling
pci_assign_unassigned_resources in a driver domain with the PCI frontend
fails. The PCI backend restricts writing to the configuration space (it
would be dangerous if we let the driver domain change the resource
allocations in the BARs, see drivers/xen/pciback/conf_space_header.c for
how this is done). When pci_assign_unassigned_resources tries to update
the BARs, it will fail (and then the struct pci_dev's resources will not
reflect the real resources of the devices and things just won't work).
To fix this problem, I added a #ifdef around the call to
pci_assign_unassigned_resources in i386-xen.c so that it only works if
the PCI frontend is not compiled in. However, I'm not certain that this
is the best solution so please let me know if you can think of a better
way.

Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>


[-- Attachment #2: pci-ddi.patch --]
[-- Type: text/x-patch, Size: 89155 bytes --]

diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/arch/i386/Kconfig
--- a/linux-2.6-xen-sparse/arch/i386/Kconfig	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/arch/i386/Kconfig	Tue Feb  7 15:04:25 2006
@@ -967,9 +967,19 @@
 	  information about which PCI hardware does work under Linux and which
 	  doesn't.
 
+# need to enable this on other platforms to support XEN_PCI_FE_ARCH_REPLACE
+# if XEN_PCI_FE_ARCH_REPLACE support is desired
+config PCI_NATIVE
+	bool
+	depends on PCI
+	default y if !XEN_PCI_FE_ARCH_REPLACE
+	---help---
+	  Compile in Native PCI access (as opposed to Xen's PCI Frontend).
+
 choice
 	prompt "PCI access mode"
-	depends on PCI && !X86_VISWS
+	depends on PCI_NATIVE && !X86_VISWS
+	default PCI_GOXEN_PCI_FE_STUB if XEN_PCIDEV_FRONTEND
 	default PCI_GOANY
 	---help---
 	  On PCI systems, the BIOS can be used to detect the PCI devices and
@@ -990,6 +1000,15 @@
 	bool "BIOS"
 	depends on !X86_XEN
 
+config PCI_GOXEN_PCI_FE_STUB
+	bool "Xen PCI Frontend Stub"
+	depends on XEN_PCIDEV_FRONTEND
+	---help---
+	  The Xen PCI Frontend stub replaces the architecture's means of talking
+	  directly to the PCI host bridge with a "dummy" handler which will act
+	  as somewhat of a placeholder until the real Xen PCI Frontend is
+	  initialized.
+
 config PCI_GOMMCONFIG
 	bool "MMConfig"
 
@@ -1014,6 +1033,11 @@
 config PCI_MMCONFIG
 	bool
 	depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
+	default y
+
+config XEN_PCI_FE_STUB
+	bool
+	depends on PCI && XEN_PCIDEV_FRONTEND && !XEN_PCI_FE_ARCH_REPLACE && (PCI_GOXEN_PCI_FE_STUB || PCI_GOANY)
 	default y
 
 source "drivers/pci/pcie/Kconfig"
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/arch/i386/Makefile
--- a/linux-2.6-xen-sparse/arch/i386/Makefile	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/arch/i386/Makefile	Tue Feb  7 15:04:25 2006
@@ -93,7 +93,7 @@
 					   arch/i386/$(mcore-y)/ \
 					   arch/i386/crypto/
 drivers-$(CONFIG_MATH_EMULATION)	+= arch/i386/math-emu/
-drivers-$(CONFIG_PCI)			+= arch/i386/pci/
+drivers-$(CONFIG_PCI_NATIVE)			+= arch/i386/pci/
 # must be linked after kernel/
 drivers-$(CONFIG_OPROFILE)		+= arch/i386/oprofile/
 drivers-$(CONFIG_PM)			+= arch/i386/power/
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/arch/i386/pci/Makefile
--- a/linux-2.6-xen-sparse/arch/i386/pci/Makefile	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/arch/i386/pci/Makefile	Tue Feb  7 15:04:25 2006
@@ -3,6 +3,7 @@
 obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
 obj-$(CONFIG_PCI_MMCONFIG)	+= mmconfig.o direct.o
 obj-$(CONFIG_PCI_DIRECT)	+= direct.o
+obj-$(CONFIG_XEN_PCI_FE_STUB)	+= pcifront.o
 
 pci-y				:= fixup.o
 pci-$(CONFIG_ACPI)		+= acpi.o
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/Kconfig
--- a/linux-2.6-xen-sparse/drivers/xen/Kconfig	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig	Tue Feb  7 15:04:25 2006
@@ -28,6 +28,70 @@
 config XEN_UNPRIVILEGED_GUEST
 	bool
 	default !XEN_PRIVILEGED_GUEST
+
+config XEN_PCIDEV_BACKEND
+	bool "PCI device backend driver"
+	select PCI
+	default y if XEN_PRIVILEGED_GUEST
+	help
+	  The PCI device backend driver allows the kernel to export arbitrary
+	  PCI devices to other guests.
+
+choice
+	prompt "PCI Backend Mode"
+	depends on XEN_PCIDEV_BACKEND
+	default XEN_PCIDEV_BACKEND_VPCI
+
+config XEN_PCIDEV_BACKEND_VPCI
+	bool "Virtual PCI"
+	---help---
+	  This PCI Backend hides the true PCI topology and makes the frontend
+	  think there is a single PCI bus with only the exported devices on it.
+	  For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
+	  second device at 02:1a.0 will be re-assigned to 00:01.0.
+
+config XEN_PCIDEV_BACKEND_PASS
+	bool "Passthrough"
+	---help---
+	  This PCI Backend provides a real view of the PCI topology to the
+	  frontend (for example, a device at 06:01.b will still appear at
+	  06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
+	  PCI devices to its driver domains. This may be required for drivers
+	  which depend on finding their hardward in certain bus/slot
+	  locations.
+
+endchoice
+
+config XEN_PCIDEV_BE_DEBUG
+	bool "PCI Backend Debugging"
+	depends on XEN_PCIDEV_BACKEND
+	default n
+
+config XEN_PCIDEV_FRONTEND
+	bool "PCI device frontend driver"
+	select PCI
+	default y if !XEN_PRIVILEGED_GUEST
+	help
+	  The PCI device frontend driver allows the kernel to import arbitrary
+	  PCI devices from a PCI backend.
+
+config XEN_PCIDEV_FE_DEBUG
+	bool "PCI Frontend Debugging"
+	depends on XEN_PCIDEV_FRONTEND
+	default n
+
+config XEN_PCI_FE_ARCH_REPLACE
+	bool "PCI frontend driver - arch-independent (EXPERIMENTAL)"
+	depends on XEN_PCIDEV_FRONTEND && EXPERIMENTAL
+	default n
+	help
+	  This selects an implementation of the PCI frontend driver that is
+	  architecture independent (i.e. it replaces the real architecture's
+	  PCI code). The default is to use an implementation that works with
+	  the architecture dependent PCI code (and you probably want the
+	  default).
+
+	  If unsure, say N.
 
 config XEN_BLKDEV_BACKEND
 	bool "Block-device backend driver"
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Tue Feb  7 15:04:25 2006
@@ -17,4 +17,6 @@
 obj-$(CONFIG_XEN_NETDEV_FRONTEND)	+= netfront/
 obj-$(CONFIG_XEN_BLKDEV_TAP)    	+= blktap/
 obj-$(CONFIG_XEN_TPMDEV_FRONTEND)	+= tpmfront/
+obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= pciback/
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront/
 
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h	Tue Feb  7 15:04:25 2006
@@ -134,6 +134,10 @@
 
 #endif /* __KERNEL__ */
 
+#ifdef CONFIG_XEN_PCIDEV_FRONTEND
+#include <xen/pcifront.h>
+#endif /* CONFIG_XEN_PCIDEV_FRONTEND */
+
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
 #include <asm-generic/pci-dma-compat.h>
 
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/arch/i386/pci/i386-xen.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/arch/i386/pci/i386-xen.c	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,297 @@
+/*
+ *	Low-Level PCI Access for i386 machines
+ *
+ * Copyright 1993, 1994 Drew Eckhardt
+ *      Visionary Computing
+ *      (Unix and Linux consulting and custom programming)
+ *      Drew@Colorado.EDU
+ *      +1 (303) 786-7975
+ *
+ * Drew's work was sponsored by:
+ *	iX Multiuser Multitasking Magazine
+ *	Hannover, Germany
+ *	hm@ix.de
+ *
+ * Copyright 1997--2000 Martin Mares <mj@ucw.cz>
+ *
+ * For more information, please consult the following manuals (look at
+ * http://www.pcisig.com/ for how to get them):
+ *
+ * PCI BIOS Specification
+ * PCI Local Bus Specification
+ * PCI to PCI Bridge Specification
+ * PCI System Design Guide
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+
+#include "pci.h"
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ *
+ * Why? Because some silly external IO cards only decode
+ * the low 10 bits of the IO address. The 0x00-0xff region
+ * is reserved for motherboard devices that decode all 16
+ * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
+ * but we want to try to avoid allocating at 0x2900-0x2bff
+ * which might have be mirrored at 0x0100-0x03ff..
+ */
+void
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long align)
+{
+	if (res->flags & IORESOURCE_IO) {
+		unsigned long start = res->start;
+
+		if (start & 0x300) {
+			start = (start + 0x3ff) & ~0x3ff;
+			res->start = start;
+		}
+	}
+}
+
+
+/*
+ *  Handle resources of PCI devices.  If the world were perfect, we could
+ *  just allocate all the resource regions and do nothing more.  It isn't.
+ *  On the other hand, we cannot just re-allocate all devices, as it would
+ *  require us to know lots of host bridge internals.  So we attempt to
+ *  keep as much of the original configuration as possible, but tweak it
+ *  when it's found to be wrong.
+ *
+ *  Known BIOS problems we have to work around:
+ *	- I/O or memory regions not configured
+ *	- regions configured, but not enabled in the command register
+ *	- bogus I/O addresses above 64K used
+ *	- expansion ROMs left enabled (this may sound harmless, but given
+ *	  the fact the PCI specs explicitly allow address decoders to be
+ *	  shared between expansion ROMs and other resource regions, it's
+ *	  at least dangerous)
+ *
+ *  Our solution:
+ *	(1) Allocate resources for all buses behind PCI-to-PCI bridges.
+ *	    This gives us fixed barriers on where we can allocate.
+ *	(2) Allocate resources for all enabled devices.  If there is
+ *	    a collision, just mark the resource as unallocated. Also
+ *	    disable expansion ROMs during this step.
+ *	(3) Try to allocate resources for disabled devices.  If the
+ *	    resources were assigned correctly, everything goes well,
+ *	    if they weren't, they won't disturb allocation of other
+ *	    resources.
+ *	(4) Assign new addresses to resources which were either
+ *	    not configured at all or misconfigured.  If explicitly
+ *	    requested by the user, configure expansion ROM address
+ *	    as well.
+ */
+
+static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
+{
+	struct pci_bus *bus;
+	struct pci_dev *dev;
+	int idx;
+	struct resource *r, *pr;
+
+	/* Depth-First Search on bus tree */
+	list_for_each_entry(bus, bus_list, node) {
+		if ((dev = bus->self)) {
+			for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
+				r = &dev->resource[idx];
+				if (!r->flags)
+					continue;
+				pr = pci_find_parent_resource(dev, r);
+				if (!r->start || !pr || request_resource(pr, r) < 0) {
+					printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, pci_name(dev));
+					/* Something is wrong with the region.
+					   Invalidate the resource to prevent child
+					   resource allocations in this range. */
+					r->flags = 0;
+				}
+			}
+		}
+		pcibios_allocate_bus_resources(&bus->children);
+	}
+}
+
+static void __init pcibios_allocate_resources(int pass)
+{
+	struct pci_dev *dev = NULL;
+	int idx, disabled;
+	u16 command;
+	struct resource *r, *pr;
+
+	for_each_pci_dev(dev) {
+		pci_read_config_word(dev, PCI_COMMAND, &command);
+		for(idx = 0; idx < 6; idx++) {
+			r = &dev->resource[idx];
+			if (r->parent)		/* Already allocated */
+				continue;
+			if (!r->start)		/* Address not assigned at all */
+				continue;
+			if (r->flags & IORESOURCE_IO)
+				disabled = !(command & PCI_COMMAND_IO);
+			else
+				disabled = !(command & PCI_COMMAND_MEMORY);
+			if (pass == disabled) {
+				DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
+				    r->start, r->end, r->flags, disabled, pass);
+				pr = pci_find_parent_resource(dev, r);
+				if (!pr || request_resource(pr, r) < 0) {
+					printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, pci_name(dev));
+					/* We'll assign a new address later */
+					r->end -= r->start;
+					r->start = 0;
+				}
+			}
+		}
+		if (!pass) {
+			r = &dev->resource[PCI_ROM_RESOURCE];
+			if (r->flags & IORESOURCE_ROM_ENABLE) {
+				/* Turn the ROM off, leave the resource region, but keep it unregistered. */
+				u32 reg;
+				DBG("PCI: Switching off ROM of %s\n", pci_name(dev));
+				r->flags &= ~IORESOURCE_ROM_ENABLE;
+				pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+				pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
+			}
+		}
+	}
+}
+
+static int __init pcibios_assign_resources(void)
+{
+	struct pci_dev *dev = NULL;
+	struct resource *r, *pr;
+
+	if (!(pci_probe & PCI_ASSIGN_ROMS)) {
+		/* Try to use BIOS settings for ROMs, otherwise let
+		   pci_assign_unassigned_resources() allocate the new
+		   addresses. */
+		for_each_pci_dev(dev) {
+			r = &dev->resource[PCI_ROM_RESOURCE];
+			if (!r->flags || !r->start)
+				continue;
+			pr = pci_find_parent_resource(dev, r);
+			if (!pr || request_resource(pr, r) < 0) {
+				r->end -= r->start;
+				r->start = 0;
+			}
+		}
+	}
+
+#ifndef CONFIG_XEN_PCIDEV_FRONTEND
+	pci_assign_unassigned_resources();
+#endif
+
+	return 0;
+}
+
+void __init pcibios_resource_survey(void)
+{
+	DBG("PCI: Allocating resources\n");
+	pcibios_allocate_bus_resources(&pci_root_buses);
+	pcibios_allocate_resources(0);
+	pcibios_allocate_resources(1);
+}
+
+/**
+ * called in fs_initcall (one below subsys_initcall),
+ * give a chance for motherboard reserve resources
+ */
+fs_initcall(pcibios_assign_resources);
+
+int pcibios_enable_resources(struct pci_dev *dev, int mask)
+{
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for(idx = 0; idx < PCI_NUM_RESOURCES; idx++) {
+		/* Only set up the requested stuff */
+		if (!(mask & (1<<idx)))
+			continue;
+
+		r = &dev->resource[idx];
+		if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
+			continue;
+		if ((idx == PCI_ROM_RESOURCE) &&
+				(!(r->flags & IORESOURCE_ROM_ENABLE)))
+			continue;
+		if (!r->start && r->end) {
+			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev));
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (cmd != old_cmd) {
+		printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+}
+
+/*
+ *  If we set up a device for bus mastering, we need to check the latency
+ *  timer as certain crappy BIOSes forget to set it properly.
+ */
+unsigned int pcibios_max_latency = 255;
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+	u8 lat;
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+	if (lat < 16)
+		lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+	else if (lat > pcibios_max_latency)
+		lat = pcibios_max_latency;
+	else
+		return;
+	printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
+
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+			enum pci_mmap_state mmap_state, int write_combine)
+{
+	unsigned long prot;
+
+	/* I/O space cannot be accessed via normal processor loads and
+	 * stores on this platform.
+	 */
+	if (mmap_state == pci_mmap_io)
+		return -EINVAL;
+
+	/* Leave vm_pgoff as-is, the PCI space address is the physical
+	 * address on this platform.
+	 */
+	vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
+
+	prot = pgprot_val(vma->vm_page_prot);
+	if (boot_cpu_data.x86 > 3)
+		prot |= _PAGE_PCD | _PAGE_PWT;
+	vma->vm_page_prot = __pgprot(prot);
+
+	/* Write-combine setting is ignored, it is changed via the mtrr
+	 * interfaces on this platform.
+	 */
+	if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot))
+		return -EAGAIN;
+
+	return 0;
+}
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/arch/i386/pci/pcifront.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/arch/i386/pci/pcifront.c	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,48 @@
+/*
+ * PCI Frontend Stub - puts some "dummy" functions in to the Linux x86 PCI core
+ *                     to support the Xen PCI Frontend's operation
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include "pci.h"
+
+static int pcifront_enable_irq(struct pci_dev *dev)
+{
+	u8 irq;
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	dev->irq = irq;
+
+	return 0;
+}
+
+extern u8 pci_cache_line_size;
+
+static int __init pcifront_x86_stub_init(void)
+{
+	struct cpuinfo_x86 *c = &boot_cpu_data;
+
+	/* Only install our method if we haven't found real hardware already */
+	if (raw_pci_ops)
+		return 0;
+
+	printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
+
+	/* Copied from arch/i386/pci/common.c */
+	pci_cache_line_size = 32 >> 2;
+	if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
+		pci_cache_line_size = 64 >> 2;	/* K7 & K8 */
+	else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL)
+		pci_cache_line_size = 128 >> 2;	/* P4 */
+
+	/* On x86, we need to disable the normal IRQ routing table and
+	 * just ask the backend
+	 */
+	pcibios_enable_irq = pcifront_enable_irq;
+
+	return 0;
+}
+
+arch_initcall(pcifront_x86_stub_init);
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pciback/Makefile
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,10 @@
+obj-y += pciback.o
+
+pciback-y := pci_stub.o pciback_ops.o xenbus.o
+pciback-y += conf_space.o conf_space_header.o
+pciback-${CONFIG_XEN_PCIDEV_BACKEND_VPCI} += vpci.o
+pciback-${CONFIG_XEN_PCIDEV_BACKEND_PASS} += passthrough.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,324 @@
+/*
+ * PCI Backend - Functions for creating a virtual configuration space for
+ *               exported PCI Devices.
+ *               It's dangerous to allow PCI Driver Domains to change their
+ *               device's resources (memory, i/o ports, interrupts). We need to
+ *               restrict changes to certain PCI Configuration registers:
+ *               BARs, INTERRUPT_PIN, most registers in the header...
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+
+#define DEFINE_PCI_CONFIG(op,size,type) 					\
+int pciback_##op##_config_##size 							\
+(struct pci_dev *dev, int offset, type value, void *data)	\
+{															\
+	return pci_##op##_config_##size (dev, offset, value);	\
+}
+
+DEFINE_PCI_CONFIG(read, byte, u8 *)
+DEFINE_PCI_CONFIG(read, word, u16 *)
+DEFINE_PCI_CONFIG(read, dword, u32 *)
+
+DEFINE_PCI_CONFIG(write, byte, u8)
+DEFINE_PCI_CONFIG(write, word, u16)
+DEFINE_PCI_CONFIG(write, dword, u32)
+
+static int conf_space_read(struct pci_dev *dev,
+			   struct config_field_entry *entry, int offset,
+			   u32 * value)
+{
+	int ret = 0;
+	struct config_field *field = entry->field;
+
+	*value = 0;
+
+	switch (field->size) {
+	case 1:
+		if (field->u.b.read)
+			ret = field->u.b.read(dev, offset, (u8 *) value,
+					      entry->data);
+		break;
+	case 2:
+		if (field->u.w.read)
+			ret = field->u.w.read(dev, offset, (u16 *) value,
+					      entry->data);
+		break;
+	case 4:
+		if (field->u.dw.read)
+			ret = field->u.dw.read(dev, offset, value, entry->data);
+		break;
+	}
+	return ret;
+}
+
+static int conf_space_write(struct pci_dev *dev,
+			    struct config_field_entry *entry, int offset,
+			    u32 value)
+{
+	int ret = 0;
+	struct config_field *field = entry->field;
+
+	switch (field->size) {
+	case 1:
+		if (field->u.b.write)
+			ret = field->u.b.write(dev, offset, (u8) value,
+					       entry->data);
+		break;
+	case 2:
+		if (field->u.w.write)
+			ret = field->u.w.write(dev, offset, (u16) value,
+					       entry->data);
+		break;
+	case 4:
+		if (field->u.dw.write)
+			ret = field->u.dw.write(dev, offset, value,
+					        entry->data);
+		break;
+	}
+	return ret;
+}
+
+static inline u32 get_mask(int size)
+{
+	if (size == 1)
+		return 0xff;
+	else if (size == 2)
+		return 0xffff;
+	else
+		return 0xffffffff;
+}
+
+static inline int valid_request(int offset, int size)
+{
+	/* Validate request (no un-aligned requests) */
+	if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0)
+		return 1;
+	return 0;
+}
+
+static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
+			      u32 offset)
+{
+	if (offset >= 0) {
+		new_val_mask <<= (offset * 8);
+		new_val <<= (offset * 8);
+	} else {
+		new_val_mask >>= (offset * -8);
+		new_val >>= (offset * -8);
+	}
+	val = (val & ~new_val_mask) | (new_val & new_val_mask);
+
+	return val;
+}
+
+static int pcibios_err_to_errno(int err)
+{
+	switch (err) {
+	case PCIBIOS_SUCCESSFUL:
+		return XEN_PCI_ERR_success;
+	case PCIBIOS_DEVICE_NOT_FOUND:
+		return XEN_PCI_ERR_dev_not_found;
+	case PCIBIOS_BAD_REGISTER_NUMBER:
+		return XEN_PCI_ERR_invalid_offset;
+	case PCIBIOS_FUNC_NOT_SUPPORTED:
+		return XEN_PCI_ERR_not_implemented;
+	case PCIBIOS_SET_FAILED:
+		return XEN_PCI_ERR_access_denied;
+	}
+	return err;
+}
+
+int pciback_config_read(struct pci_dev *dev, int offset, int size,
+			u32 * ret_val)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+	int req_start, req_end, field_start, field_end;
+	/* if read fails for any reason, return 0 (as if device didn't respond) */
+	u32 value = 0, tmp_val;
+
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n",
+		       pci_name(dev), size, offset);
+
+	if (!valid_request(offset, size)) {
+		err = XEN_PCI_ERR_invalid_offset;
+		goto out;
+	}
+
+	/* Get the real value first, then modify as appropriate */
+	switch (size) {
+	case 1:
+		err = pci_read_config_byte(dev, offset, (u8 *) & value);
+		break;
+	case 2:
+		err = pci_read_config_word(dev, offset, (u16 *) & value);
+		break;
+	case 4:
+		err = pci_read_config_dword(dev, offset, &value);
+		break;
+	}
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		req_start = offset;
+		req_end = offset + size;
+		field_start = field->offset;
+		field_end = field->offset + field->size;
+
+		if ((req_start >= field_start && req_start < field_end)
+		    || (req_end > field_start && req_end <= field_end)) {
+			err = conf_space_read(dev, cfg_entry, offset, &tmp_val);
+			if (err)
+				goto out;
+
+			value = merge_value(value, tmp_val,
+					    get_mask(field->size),
+					    field_start - req_start);
+		}
+	}
+
+      out:
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
+		       pci_name(dev), size, offset, value);
+
+	*ret_val = value;
+	return pcibios_err_to_errno(err);
+}
+
+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+	u32 tmp_val;
+	int req_start, req_end, field_start, field_end;
+
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG
+		       "pciback: %s: write request %d bytes at 0x%x = %x\n",
+		       pci_name(dev), size, offset, value);
+
+	if (!valid_request(offset, size))
+		return XEN_PCI_ERR_invalid_offset;
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		req_start = offset;
+		req_end = offset + size;
+		field_start = field->offset;
+		field_end = field->offset + field->size;
+
+		if ((req_start >= field_start && req_start < field_end)
+		    || (req_end > field_start && req_end <= field_end)) {
+			tmp_val = 0;
+
+			err = pciback_config_read(dev, offset, size, &tmp_val);
+			if (err)
+				break;
+
+			tmp_val = merge_value(tmp_val, value, get_mask(size),
+					      field_start - req_start);
+
+			err = conf_space_write(dev, cfg_entry, offset, tmp_val);
+		}
+	}
+
+	return pcibios_err_to_errno(err);
+}
+
+void pciback_config_reset(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		if (field->reset)
+			field->reset(dev, field->offset, cfg_entry->data);
+	}
+}
+
+void pciback_config_free(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry, *t;
+	struct config_field *field;
+
+	list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
+		list_del(&cfg_entry->list);
+
+		field = cfg_entry->field;
+
+		if (field->release)
+			field->release(dev, field->offset, cfg_entry->data);
+
+		kfree(cfg_entry);
+	}
+}
+
+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	void *tmp;
+
+	cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
+	if (!cfg_entry) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	cfg_entry->data = NULL;
+	cfg_entry->field = field;
+
+	if (field->init) {
+		tmp = field->init(dev, field->offset);
+
+		if (IS_ERR(tmp)) {
+			err = PTR_ERR(tmp);
+			goto out;
+		}
+
+		cfg_entry->data = tmp;
+	}
+
+	list_add_tail(&cfg_entry->list, &dev_data->config_fields);
+
+      out:
+	if (err)
+		kfree(cfg_entry);
+
+	return err;
+}
+
+/* This sets up the device's virtual configuration space to keep track of 
+ * certain registers (like the base address registers (BARs) so that we can
+ * keep the client from manipulating them directly.
+ */
+int pciback_config_init(struct pci_dev *dev)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+
+	INIT_LIST_HEAD(&dev_data->config_fields);
+
+	err = pciback_config_header_add_fields(dev);
+
+	return err;
+}
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,97 @@
+/*
+ * PCI Backend - Common data structures for overriding the configuration space
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#ifndef __XEN_PCIBACK_CONF_SPACE_H__
+#define __XEN_PCIBACK_CONF_SPACE_H__
+
+#include <linux/list.h>
+
+typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
+typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data);
+typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
+
+typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value,
+				 void *data);
+typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value,
+				void *data);
+typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value,
+				void *data);
+typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value,
+				void *data);
+typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value,
+			       void *data);
+typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
+			       void *data);
+
+/* These are the fields within the configuration space which we
+ * are interested in intercepting reads/writes to and changing their
+ * values.
+ */
+struct config_field {
+	unsigned int     offset;
+	unsigned int     size;
+	conf_field_init  init;
+	conf_field_reset reset;
+	conf_field_free  release;
+	union {
+		struct {
+			conf_dword_write write;
+			conf_dword_read read;
+		} dw;
+		struct {
+			conf_word_write write;
+			conf_word_read read;
+		} w;
+		struct {
+			conf_byte_write write;
+			conf_byte_read read;
+		} b;
+	} u;
+};
+
+struct config_field_entry {
+	struct list_head list;
+	struct config_field *field;
+	void *data;
+};
+
+/* Add fields to a device - the add_fields macro expects to get a pointer to
+ * the first entry in an array (of which the ending is marked by size==0)
+ */
+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field);
+static inline int pciback_config_add_fields(struct pci_dev *dev,
+					    struct config_field *field)
+{
+	int i, err = 0;
+	for (i = 0; field[i].size != 0; i++) {
+		err = pciback_config_add_field(dev, &field[i]);
+		if (err)
+			break;
+	}
+	return err;
+}
+
+/* Initializers which add fields to the virtual configuration space
+ * ** We could add initializers to allow a guest domain to touch
+ * the capability lists (for power management, the AGP bridge, etc.)
+ */
+int pciback_config_header_add_fields(struct pci_dev *dev);
+
+/* Read/Write the real configuration space */
+int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
+			     void *data);
+int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value,
+			     void *data);
+int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value,
+			      void *data);
+int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
+			      void *data);
+int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value,
+			      void *data);
+int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
+			       void *data);
+
+#endif				/* __XEN_PCIBACK_CONF_SPACE_H__ */
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,269 @@
+/*
+ * PCI Backend - Handles the virtual fields in the configuration space headers.
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+
+struct pci_bar_info {
+	u32 val;
+	u32 len_val;
+	int which;
+};
+
+#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
+#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
+
+static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
+{
+	if (!dev->is_enabled && is_enable_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: enable\n",
+			       pci_name(dev));
+		dev->is_enabled = 1;
+		pcibios_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
+	} else if (dev->is_enabled && !is_enable_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: disable\n",
+			       pci_name(dev));
+		pciback_disable_device(dev);
+	}
+
+	if (!dev->is_busmaster && is_master_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: set bus master\n",
+			       pci_name(dev));
+		dev->is_busmaster = 1;
+		pcibios_set_master(dev);
+	}
+
+	if (value & PCI_COMMAND_INVALIDATE) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG
+			       "pciback: %s: enable memory-write-invalidate\n",
+			       pci_name(dev));
+		pci_set_mwi(dev);
+	}
+
+	return pci_write_config_word(dev, offset, value);
+}
+
+static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	/* A write to obtain the length must happen as a 32-bit write.
+	 * This does not (yet) support writing individual bytes
+	 */
+	if (value == ~PCI_ROM_ADDRESS_ENABLE)
+		bar->which = 1;
+	else
+		bar->which = 0;
+
+	/* Do we need to support enabling/disabling the rom address here? */
+
+	return 0;
+}
+
+/* For the BARs, only allow writes which write ~0 or
+ * the correct resource information
+ * (Needed for when the driver probes the resource usage)
+ */
+static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	/* A write to obtain the length must happen as a 32-bit write.
+	 * This does not (yet) support writing individual bytes
+	 */
+	if (value == ~0)
+		bar->which = 1;
+	else
+		bar->which = 0;
+
+	return 0;
+}
+
+static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	*value = bar->which ? bar->len_val : bar->val;
+
+	return 0;
+}
+
+static inline void read_dev_bar(struct pci_dev *dev,
+				struct pci_bar_info *bar_info, int offset,
+				u32 len_mask)
+{
+	pci_read_config_dword(dev, offset, &bar_info->val);
+	pci_write_config_dword(dev, offset, len_mask);
+	pci_read_config_dword(dev, offset, &bar_info->len_val);
+	pci_write_config_dword(dev, offset, bar_info->val);
+}
+
+static void *bar_init(struct pci_dev *dev, int offset)
+{
+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
+
+	if (!bar)
+		return ERR_PTR(-ENOMEM);
+
+	read_dev_bar(dev, bar, offset, ~0);
+	bar->which = 0;
+
+	return bar;
+}
+
+static void *rom_init(struct pci_dev *dev, int offset)
+{
+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
+
+	if (!bar)
+		return ERR_PTR(-ENOMEM);
+
+	read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
+	bar->which = 0;
+
+	return bar;
+}
+
+static void bar_reset(struct pci_dev *dev, int offset, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	bar->which = 0;
+}
+
+static void bar_release(struct pci_dev *dev, int offset, void *data)
+{
+	kfree(data);
+}
+
+static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
+			  void *data)
+{
+	*value = (u8) dev->irq;
+
+	return 0;
+}
+
+struct config_field header_common[] = {
+	{
+	 .offset    = PCI_COMMAND,
+	 .size      = 2,
+	 .u.w.read  = pciback_read_config_word,
+	 .u.w.write = command_write,
+	 },
+	{
+	 .offset    = PCI_INTERRUPT_LINE,
+	 .size      = 1,
+	 .u.b.read  = interrupt_read,
+	 .u.b.write = NULL,
+	 },
+	{
+	 /* Any side effects of letting driver domain control cache line? */
+	 .offset    = PCI_CACHE_LINE_SIZE,
+	 .size      = 1,
+	 .u.b.read  = pciback_read_config_byte,
+	 .u.b.write = pciback_write_config_byte,
+	 },
+	{
+	 .size = 0,
+	 },
+};
+
+#define CFG_FIELD_BAR(reg_offset) 			\
+	{ 						\
+	 .offset     = reg_offset, 			\
+	 .size       = 4, 				\
+	 .init       = bar_init, 			\
+	 .reset      = bar_reset, 			\
+	 .release    = bar_release, 			\
+	 .u.dw.read  = bar_read, 			\
+	 .u.dw.write = bar_write, 			\
+	 }
+
+#define CFG_FIELD_ROM(reg_offset) 			\
+	{ 						\
+	 .offset     = reg_offset, 			\
+	 .size       = 4, 				\
+	 .init       = rom_init, 			\
+	 .reset      = bar_reset, 			\
+	 .release    = bar_release, 			\
+	 .u.dw.read  = bar_read, 			\
+	 .u.dw.write = rom_write, 			\
+	 }
+
+struct config_field header_0[] = {
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
+	CFG_FIELD_ROM(PCI_ROM_ADDRESS),
+	{
+	 .size = 0,
+	 },
+};
+
+struct config_field header_1[] = {
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
+	CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
+	{
+	 .size = 0,
+	 },
+};
+
+int pciback_config_header_add_fields(struct pci_dev *dev)
+{
+	int err;
+
+	err = pciback_config_add_fields(dev, header_common);
+	if (err)
+		goto out;
+
+	switch (dev->hdr_type) {
+	case PCI_HEADER_TYPE_NORMAL:
+		err = pciback_config_add_fields(dev, header_0);
+		break;
+
+	case PCI_HEADER_TYPE_BRIDGE:
+		err = pciback_config_add_fields(dev, header_1);
+		break;
+
+	default:
+		err = -EINVAL;
+		printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
+		       pci_name(dev), dev->hdr_type);
+		break;
+	}
+
+      out:
+	return err;
+}
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,116 @@
+/*
+ * PCI Backend - Provides restricted access to the real PCI bus topology
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/list.h>
+#include <linux/pci.h>
+#include "pciback.h"
+
+struct passthrough_dev_data {
+	struct list_head dev_list;
+};
+
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry;
+
+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
+		if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
+		    && bus == (unsigned int)dev_entry->dev->bus->number
+		    && devfn == dev_entry->dev->devfn)
+			return dev_entry->dev;
+	}
+
+	return NULL;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry;
+
+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
+	if (!dev_entry)
+		return -ENOMEM;
+	dev_entry->dev = dev;
+
+	list_add_tail(&dev_entry->list, &dev_data->dev_list);
+
+	return 0;
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+	struct passthrough_dev_data *dev_data;
+
+	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
+	if (!dev_data)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&dev_data->dev_list);
+
+	pdev->pci_dev_data = dev_data;
+
+	return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb publish_root_cb)
+{
+	int err = 0;
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry, *e;
+	struct pci_dev *dev;
+	int found;
+	unsigned int domain, bus;
+
+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
+		/* Only publish this device as a root if none of its
+		 * parent bridges are exported
+		 */
+		found = 0;
+		dev = dev_entry->dev->bus->self;
+		for (; !found && dev != NULL; dev = dev->bus->self) {
+			list_for_each_entry(e, &dev_data->dev_list, list) {
+				if (dev == e->dev) {
+					found = 1;
+					break;
+				}
+			}
+		}
+
+		domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
+		bus = (unsigned int)dev_entry->dev->bus->number;
+
+		if (!found) {
+			err = publish_root_cb(pdev, domain, bus);
+			if (err)
+				break;
+		}
+	}
+
+	return err;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry, *t;
+
+	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
+		list_del(&dev_entry->list);
+		pcistub_put_pci_dev(dev_entry->dev);
+		kfree(dev_entry);
+	}
+
+	kfree(dev_data);
+	pdev->pci_dev_data = NULL;
+}
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,377 @@
+/*
+ * PCI Stub Driver - Grabs devices in backend to be exported later
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include "pciback.h"
+
+static char *pci_devs_to_hide = NULL;
+module_param_named(hide, pci_devs_to_hide, charp, 0444);
+
+struct pci_stub_device_id {
+	struct list_head slot_list;
+	int domain;
+	unsigned char bus;
+	unsigned int devfn;
+};
+LIST_HEAD(pci_stub_device_ids);
+
+struct pci_stub_device {
+	struct list_head dev_list;
+	struct pci_dev *dev;
+	atomic_t in_use;
+};
+/* Access to pci_stub_devices & seized_devices lists and the initialize_devices
+ * flag must be locked with pci_stub_devices_lock
+ */
+DEFINE_SPINLOCK(pci_stub_devices_lock);
+LIST_HEAD(pci_stub_devices);
+
+/* wait for device_initcall before initializing our devices
+ * (see pcistub_init_devices_late)
+ */
+static int initialize_devices = 0;
+LIST_HEAD(seized_devices);
+
+static inline struct pci_dev *get_pci_dev(struct pci_stub_device *psdev)
+{
+	if (atomic_dec_and_test(&psdev->in_use))
+		return psdev->dev;
+	else {
+		atomic_inc(&psdev->in_use);
+		return NULL;
+	}
+}
+
+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
+					    int slot, int func)
+{
+	struct pci_stub_device *psdev;
+	struct pci_dev *found_dev = NULL;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev != NULL
+		    && domain == pci_domain_nr(psdev->dev->bus)
+		    && bus == psdev->dev->bus->number
+		    && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
+			found_dev = get_pci_dev(psdev);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+	return found_dev;
+}
+
+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+	struct pci_dev *found_dev = NULL;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev == dev) {
+			found_dev = get_pci_dev(psdev);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+	return found_dev;
+}
+
+void pcistub_put_pci_dev(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev == dev) {
+			/* Cleanup our device
+			 * (so it's ready for the next domain)
+			 */
+			pciback_reset_device(psdev->dev);
+
+			atomic_inc(&psdev->in_use);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+}
+
+static int __devinit pcistub_match(struct pci_dev *dev,
+				   struct pci_stub_device_id *pdev_id)
+{
+	/* Match the specified device by domain, bus, slot, func and also if
+	 * any of the device's parent bridges match.
+	 */
+	for (; dev != NULL; dev = dev->bus->self) {
+		if (pci_domain_nr(dev->bus) == pdev_id->domain
+		    && dev->bus->number == pdev_id->bus
+		    && dev->devfn == pdev_id->devfn)
+			return 1;
+	}
+
+	return 0;
+}
+
+static int __devinit pcistub_init_device(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data;
+	int err = 0;
+
+	/* The PCI backend is not intended to be a module (or to work with
+	 * removable PCI devices (yet). If it were, pciback_config_free()
+	 * would need to be called somewhere to free the memory allocated
+	 * here and then to call kfree(pci_get_drvdata(psdev->dev)).
+	 */
+	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
+	if (!dev_data) {
+		err = -ENOMEM;
+		goto out;
+	}
+	pci_set_drvdata(dev, dev_data);
+
+	err = pciback_config_init(dev);
+	if (err)
+		goto out;
+
+	/* HACK: Force device (& ACPI) to determine what IRQ it's on - we
+	 * must do this here because pcibios_enable_device may specify
+	 * the pci device's true irq (and possibly its other resources)
+	 * if they differ from what's in the configuration space.
+	 * This makes the assumption that the device's resources won't
+	 * change after this point (otherwise this code may break!)
+	 */
+	err = pci_enable_device(dev);
+	if (err)
+		goto config_release;
+
+	/* Now disable the device (this also ensures some private device
+	 * data is setup before we export)
+	 * This calls pciback_config_reset(dev)
+	 */
+	pciback_reset_device(dev);
+
+	return 0;
+
+      config_release:
+	pciback_config_free(dev);
+
+      out:
+	pci_set_drvdata(dev, NULL);
+	kfree(dev_data);
+	return err;
+}
+
+/*
+ * Because some initialization still happens on
+ * devices during fs_initcall, we need to defer
+ * full initialization of our devices until
+ * device_initcall.
+ */
+static int __init pcistub_init_devices_late(void)
+{
+	struct pci_stub_device *psdev, *t;
+	int err = 0;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry_safe(psdev, t, &seized_devices, dev_list) {
+		list_del(&psdev->dev_list);
+		err = pcistub_init_device(psdev->dev);
+		if (err) {
+			printk(KERN_ERR
+			       "pciback: %s error %d initializing device\n",
+			       pci_name(psdev->dev), err);
+			kfree(psdev);
+			continue;
+		}
+
+		list_add_tail(&psdev->dev_list, &pci_stub_devices);
+	}
+
+	initialize_devices = 1;
+
+	spin_unlock(&pci_stub_devices_lock);
+
+	return 0;
+}
+
+device_initcall(pcistub_init_devices_late);
+
+static int __devinit pcistub_seize(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+	int err = 0;
+
+	psdev = kmalloc(sizeof(*psdev), GFP_KERNEL);
+	if (!psdev)
+		return -ENOMEM;
+
+	psdev->dev = dev;
+	atomic_set(&psdev->in_use, 1);
+
+	spin_lock(&pci_stub_devices_lock);
+
+	if (initialize_devices) {
+		err = pcistub_init_device(psdev->dev);
+		if (err)
+			goto out;
+
+		list_add(&psdev->dev_list, &pci_stub_devices);
+	} else
+		list_add(&psdev->dev_list, &seized_devices);
+
+      out:
+	spin_unlock(&pci_stub_devices_lock);
+
+	if (err)
+		kfree(psdev);
+
+	return err;
+}
+
+static int __devinit pcistub_probe(struct pci_dev *dev,
+				   const struct pci_device_id *id)
+{
+	struct pci_stub_device_id *pdev_id;
+	struct pci_dev *seized_dev;
+	int err = 0;
+
+	list_for_each_entry(pdev_id, &pci_stub_device_ids, slot_list) {
+
+		if (!pcistub_match(dev, pdev_id))
+			continue;
+
+		if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
+		    && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
+			printk(KERN_ERR
+			       "pciback: %s: can't export pci devices that "
+			       "don't have a normal (0) or bridge (1) "
+			       "header type!\n", pci_name(dev));
+			break;
+		}
+
+		pr_info("pciback: seizing PCI device %s\n", pci_name(dev));
+		seized_dev = pci_dev_get(dev);
+
+		if (seized_dev) {
+			err = pcistub_seize(seized_dev);
+			if (err) {
+				pci_dev_put(dev);
+				goto out;
+			}
+
+			/* Success! */
+			goto out;
+		}
+	}
+
+	/* Didn't find the device */
+	err = -ENODEV;
+
+      out:
+	return err;
+}
+
+struct pci_device_id pcistub_ids[] = {
+	{
+	 .vendor = PCI_ANY_ID,
+	 .device = PCI_ANY_ID,
+	 .subvendor = PCI_ANY_ID,
+	 .subdevice = PCI_ANY_ID,
+	 },
+	{0,},
+};
+
+/*
+ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't
+ * for a normal device. I don't want it to be loaded automatically.
+ */
+
+struct pci_driver pciback_pci_driver = {
+	.name = "pciback",
+	.id_table = pcistub_ids,
+	.probe = pcistub_probe,
+};
+
+static int __init pcistub_init(void)
+{
+	int pos = 0;
+	struct pci_stub_device_id *pci_dev_id;
+	int err = 0;
+	int domain, bus, slot, func;
+	int parsed;
+
+	if (pci_devs_to_hide && *pci_devs_to_hide) {
+		do {
+			parsed = 0;
+
+			err = sscanf(pci_devs_to_hide + pos,
+				     " (%x:%x:%x.%x) %n",
+				     &domain, &bus, &slot, &func, &parsed);
+			if (err != 4) {
+				domain = 0;
+				err = sscanf(pci_devs_to_hide + pos,
+					     " (%x:%x.%x) %n",
+					     &bus, &slot, &func, &parsed);
+				if (err != 3)
+					goto parse_error;
+			}
+
+			pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
+			if (!pci_dev_id) {
+				err = -ENOMEM;
+				goto out;
+			}
+
+			pci_dev_id->domain = domain;
+			pci_dev_id->bus = bus;
+			pci_dev_id->devfn = PCI_DEVFN(slot, func);
+
+			pr_debug
+			    ("pciback: wants to seize %04x:%02x:%02x.%01x\n",
+			     domain, bus, slot, func);
+
+			list_add_tail(&pci_dev_id->slot_list,
+				      &pci_stub_device_ids);
+
+			/* if parsed<=0, we've reached the end of the string */
+			pos += parsed;
+		} while (parsed > 0 && pci_devs_to_hide[pos]);
+
+		/* If we're the first PCI Device Driver to register, we're the
+		 * first one to get offered PCI devices as they become
+		 * available (and thus we can be the first to grab them)
+		 */
+		pci_register_driver(&pciback_pci_driver);
+	}
+
+      out:
+	return err;
+
+      parse_error:
+	printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n",
+	       pci_devs_to_hide + pos);
+	return -EINVAL;
+}
+
+/*
+ * fs_initcall happens before device_initcall
+ * so pciback *should* get called first (b/c we 
+ * want to suck up any device before other drivers
+ * get a chance by being the first pci device
+ * driver to register)
+ */
+fs_initcall(pcistub_init);
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,73 @@
+/*
+ * PCI Backend Common Data Structures & Function Declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCIBACK_H__
+#define __XEN_PCIBACK_H__
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <xen/xenbus.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <xen/interface/io/pciif.h>
+
+struct pci_dev_entry {
+	struct list_head list;
+	struct pci_dev *dev;
+};
+
+struct pciback_device {
+	void *pci_dev_data;
+	spinlock_t dev_lock;
+
+	struct xenbus_device *xdev;
+
+	struct xenbus_watch be_watch;
+	u8 be_watching;
+
+	int evtchn_irq;
+
+	struct xen_pci_sharedinfo *sh_info;
+};
+
+struct pciback_dev_data {
+	struct list_head config_fields;
+};
+
+/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
+					    int slot, int func);
+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev);
+void pcistub_put_pci_dev(struct pci_dev *dev);
+
+/* Ensure a device is turned off or reset */
+void pciback_disable_device(struct pci_dev *dev);
+void pciback_reset_device(struct pci_dev *pdev);
+
+/* Access a virtual configuration space for a PCI device */
+int pciback_config_init(struct pci_dev *dev);
+void pciback_config_reset(struct pci_dev *dev);
+void pciback_config_free(struct pci_dev *dev);
+int pciback_config_read(struct pci_dev *dev, int offset, int size,
+			u32 * ret_val);
+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
+
+/* Handle requests for specific devices from the frontend */
+typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
+				    unsigned int domain, unsigned int bus);
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn);
+int pciback_init_devices(struct pciback_device *pdev);
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb cb);
+void pciback_release_devices(struct pciback_device *pdev);
+
+/* Handles events from front-end */
+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
+
+extern int verbose_request;
+#endif
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,84 @@
+/*
+ * PCI Backend Operations - respond to PCI requests from Frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <asm/bitops.h>
+#include "pciback.h"
+
+int verbose_request = 0;
+module_param(verbose_request, int, 0644);
+
+/* For those architectures without a pcibios_disable_device */
+void __attribute__ ((weak)) pcibios_disable_device(struct pci_dev *dev) { }
+
+void pciback_disable_device(struct pci_dev *dev)
+{
+	if (dev->is_enabled) {
+		dev->is_enabled = 0;
+		pcibios_disable_device(dev);
+	}
+}
+
+/* Ensure a device is "turned off" and ready to be exported.
+ * This also sets up the device's private data to keep track of what should
+ * be in the base address registers (BARs) so that we can keep the
+ * client from manipulating them directly.
+ */
+void pciback_reset_device(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	/* Disable devices (but not bridges) */
+	if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
+		pciback_disable_device(dev);
+
+		pci_write_config_word(dev, PCI_COMMAND, 0);
+
+		dev->is_enabled = 0;
+		dev->is_busmaster = 0;
+	} else {
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		if (cmd & (PCI_COMMAND_INVALIDATE)) {
+			cmd &= ~(PCI_COMMAND_INVALIDATE);
+			pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+			dev->is_busmaster = 0;
+		}
+	}
+
+	pciback_config_reset(dev);
+}
+
+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pciback_device *pdev = dev_id;
+	struct pci_dev *dev;
+	struct xen_pci_op *op = &pdev->sh_info->op;
+
+	if (unlikely(!test_bit(_XEN_PCIF_active,
+			       (unsigned long *)&pdev->sh_info->flags))) {
+		pr_debug("pciback: interrupt, but no active operation\n");
+		goto out;
+	}
+
+	dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
+
+	if (dev == NULL)
+		op->err = XEN_PCI_ERR_dev_not_found;
+	else if (op->cmd == XEN_PCI_OP_conf_read)
+		op->err = pciback_config_read(dev, op->offset, op->size,
+					      &op->value);
+	else if (op->cmd == XEN_PCI_OP_conf_write)
+		op->err = pciback_config_write(dev, op->offset, op->size,
+					       op->value);
+	else
+		op->err = XEN_PCI_ERR_not_implemented;
+
+	wmb();
+	clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+
+      out:
+	return IRQ_HANDLED;
+}
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,163 @@
+/*
+ * PCI Backend - Provides a Virtual PCI bus (with real devices)
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include "pciback.h"
+
+#define PCI_SLOT_MAX 32
+
+struct vpci_dev_data {
+	struct list_head dev_list[PCI_SLOT_MAX];
+};
+
+static inline struct list_head *list_first(struct list_head *head)
+{
+	return head->next;
+}
+
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn)
+{
+	struct pci_dev_entry *dev_entry;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	if (domain != 0 || bus != 0)
+		return NULL;
+
+	if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
+		/* we don't need to lock the list here because once the backend
+		 * is in operation, it won't have any more devices addeded
+		 * (or removed).
+		 */
+		list_for_each_entry(dev_entry,
+				    &vpci_dev->dev_list[PCI_SLOT(devfn)],
+				    list) {
+			if (PCI_FUNC(dev_entry->dev->devfn) == PCI_FUNC(devfn))
+				return dev_entry->dev;
+		}
+	}
+	return NULL;
+}
+
+static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
+{
+	if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
+	    && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn))
+		return 1;
+
+	return 0;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+	int err = 0, slot;
+	struct pci_dev_entry *t, *dev_entry;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
+		err = -EFAULT;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Can't export bridges on the virtual PCI bus");
+		goto out;
+	}
+
+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
+	if (!dev_entry) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error adding entry to virtual PCI bus");
+		goto out;
+	}
+
+	dev_entry->dev = dev;
+
+	/* Keep multi-function devices together on the virtual PCI bus */
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		if (!list_empty(&vpci_dev->dev_list[slot])) {
+			t = list_entry(list_first(&vpci_dev->dev_list[slot]),
+				       struct pci_dev_entry, list);
+
+			if (match_slot(dev, t->dev)) {
+				pr_info("pciback: vpci: %s: "
+					"assign to virtual slot %d func %d\n",
+					pci_name(dev), slot,
+					PCI_FUNC(dev->devfn));
+				list_add_tail(&dev_entry->list,
+					      &vpci_dev->dev_list[slot]);
+				goto out;
+			}
+		}
+	}
+
+	/* Assign to a new slot on the virtual PCI bus */
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		if (list_empty(&vpci_dev->dev_list[slot])) {
+			printk(KERN_INFO
+			       "pciback: vpci: %s: assign to virtual slot %d\n",
+			       pci_name(dev), slot);
+			list_add_tail(&dev_entry->list,
+				      &vpci_dev->dev_list[slot]);
+			goto out;
+		}
+	}
+
+	err = -ENOMEM;
+	xenbus_dev_fatal(pdev->xdev, err,
+			 "No more space on root virtual PCI bus");
+
+      out:
+	return err;
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+	int slot;
+	struct vpci_dev_data *vpci_dev;
+
+	vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
+	if (!vpci_dev)
+		return -ENOMEM;
+
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
+	}
+
+	pdev->pci_dev_data = vpci_dev;
+
+	return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb publish_cb)
+{
+	/* The Virtual PCI bus has only one root */
+	return publish_cb(pdev, 0, 0);
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+	int slot;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		struct pci_dev_entry *e, *tmp;
+		list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
+					 list) {
+			list_del(&e->list);
+			pcistub_put_pci_dev(e->dev);
+			kfree(e);
+		}
+	}
+
+	kfree(vpci_dev);
+	pdev->pci_dev_data = NULL;
+}
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,435 @@
+/*
+ * PCI Backend Xenbus Setup - handles setup with frontend and xend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <xen/xenbus.h>
+#include <xen/evtchn.h>
+#include "pciback.h"
+
+#define INVALID_EVTCHN_IRQ  (-1)
+
+struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
+{
+	struct pciback_device *pdev;
+
+	pdev = kmalloc(sizeof(struct pciback_device), GFP_KERNEL);
+	if (pdev == NULL)
+		goto out;
+	dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
+
+	pdev->xdev = xdev;
+	xdev->data = pdev;
+
+	spin_lock_init(&pdev->dev_lock);
+
+	pdev->sh_info = NULL;
+	pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
+	pdev->be_watching = 0;
+
+	if (pciback_init_devices(pdev)) {
+		kfree(pdev);
+		pdev = NULL;
+	}
+      out:
+	return pdev;
+}
+
+void free_pdev(struct pciback_device *pdev)
+{
+	if (pdev->be_watching)
+		unregister_xenbus_watch(&pdev->be_watch);
+
+	/* Ensure the guest can't trigger our handler before removing devices */
+	if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ)
+		unbind_from_irqhandler(pdev->evtchn_irq, pdev);
+
+	if (pdev->sh_info)
+		xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
+
+	pciback_release_devices(pdev);
+
+	pdev->xdev->data = NULL;
+	pdev->xdev = NULL;
+
+	kfree(pdev);
+}
+
+static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
+			     int remote_evtchn)
+{
+	int err = 0;
+	int evtchn;
+	dev_dbg(&pdev->xdev->dev,
+		"Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
+		gnt_ref, remote_evtchn);
+
+	err =
+	    xenbus_map_ring_valloc(pdev->xdev, gnt_ref,
+				   (void **)&pdev->sh_info);
+	if (err)
+		goto out;
+
+	err = xenbus_bind_evtchn(pdev->xdev, remote_evtchn, &evtchn);
+	if (err)
+		goto out;
+
+	err = bind_evtchn_to_irqhandler(evtchn, pciback_handle_event,
+					SA_SAMPLE_RANDOM, "pciback", pdev);
+	if (err < 0) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error binding event channel to IRQ");
+		goto out;
+	}
+	pdev->evtchn_irq = err;
+	err = 0;
+
+	dev_dbg(&pdev->xdev->dev, "Attached!\n");
+      out:
+	return err;
+}
+
+static int pciback_attach(struct pciback_device *pdev)
+{
+	int err = 0;
+	int gnt_ref, remote_evtchn;
+	char *magic = NULL;
+
+	spin_lock(&pdev->dev_lock);
+
+	/* Make sure we only do this setup once */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	/* Wait for frontend to state that it has published the configuration */
+	if (xenbus_read_driver_state(pdev->xdev->otherend) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
+
+	err = xenbus_gather(XBT_NULL, pdev->xdev->otherend,
+			    "pci-op-ref", "%u", &gnt_ref,
+			    "event-channel", "%u", &remote_evtchn,
+			    "magic", NULL, &magic, NULL);
+	if (err) {
+		/* If configuration didn't get read correctly, wait longer */
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading configuration from frontend");
+		goto out;
+	}
+
+	if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
+		xenbus_dev_fatal(pdev->xdev, -EFAULT,
+				 "version mismatch (%s/%s) with pcifront - "
+				 "halting pciback",
+				 magic, XEN_PCI_MAGIC);
+		goto out;
+	}
+
+	err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
+	if (err)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "Connecting...\n");
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
+	if (err)
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error switching to connected state!");
+
+	dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
+      out:
+	spin_unlock(&pdev->dev_lock);
+
+	if (magic)
+		kfree(magic);
+
+	return err;
+}
+
+static void pciback_frontend_changed(struct xenbus_device *xdev,
+				     XenbusState fe_state)
+{
+	struct pciback_device *pdev = xdev->data;
+
+	dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
+
+	switch (fe_state) {
+	case XenbusStateInitialised:
+		pciback_attach(pdev);
+		break;
+
+	case XenbusStateClosing:
+		xenbus_switch_state(xdev, XBT_NULL, XenbusStateClosing);
+		break;
+
+	case XenbusStateClosed:
+		dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
+		device_unregister(&xdev->dev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pciback_publish_pci_root(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus)
+{
+	unsigned int d, b;
+	int i, root_num, len, err;
+	char str[64];
+
+	dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
+			   "root_num", "%d", &root_num);
+	if (err == 0 || err == -ENOENT)
+		root_num = 0;
+	else if (err < 0)
+		goto out;
+
+	/* Verify that we haven't already published this pci root */
+	for (i = 0; i < root_num; i++) {
+		len = snprintf(str, sizeof(str), "root-%d", i);
+		if (unlikely(len >= (sizeof(str) - 1))) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
+				   str, "%x:%x", &d, &b);
+		if (err < 0)
+			goto out;
+		if (err != 2) {
+			err = -EINVAL;
+			goto out;
+		}
+
+		if (d == domain && b == bus) {
+			err = 0;
+			goto out;
+		}
+	}
+
+	len = snprintf(str, sizeof(str), "root-%d", root_num);
+	if (unlikely(len >= (sizeof(str) - 1))) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
+		root_num, domain, bus);
+
+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename, str,
+			    "%04x:%02x", domain, bus);
+	if (err)
+		goto out;
+
+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename,
+			    "root_num", "%d", (root_num + 1));
+
+      out:
+	return err;
+}
+
+static int pciback_export_device(struct pciback_device *pdev,
+				 int domain, int bus, int slot, int func)
+{
+	struct pci_dev *dev;
+	int err = 0;
+
+	dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
+		domain, bus, slot, func);
+
+	dev = pcistub_get_pci_dev_by_slot(domain, bus, slot, func);
+	if (!dev) {
+		err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Couldn't locate PCI device "
+				 "(%04x:%02x:%02x.%01x)! "
+				 "perhaps already in-use?",
+				 domain, bus, slot, func);
+		goto out;
+	}
+
+	err = pciback_add_pci_dev(pdev, dev);
+	if (err)
+		goto out;
+
+	/* TODO: If this is a bridge, export all the children (this won't work
+	 * for children dynamically added to the bus later!) - This is
+	 * trivial in kernels >= 2.6.14 with pci_walk_bus(dev->subordinate)
+	 */
+      out:
+	return err;
+}
+
+static int pciback_setup_backend(struct pciback_device *pdev)
+{
+	/* Get configuration from xend (if available now) */
+	int domain, bus, slot, func;
+	int err = 0;
+	int i, num_devs;
+	char dev_str[64];
+
+	spin_lock(&pdev->dev_lock);
+
+	/* It's possible we could get the call to setup twice, so make sure
+	 * we're not already connected.
+	 */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitWait)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "getting be setup\n");
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, "num_devs", "%d",
+			   &num_devs);
+	if (err != 1) {
+		if (err >= 0)
+			err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading number of devices");
+		goto out;
+	}
+
+	for (i = 0; i < num_devs; i++) {
+		int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
+		if (unlikely(l >= (sizeof(dev_str) - 1))) {
+			err = -ENOMEM;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "String overflow while reading "
+					 "configuration");
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, dev_str,
+				   "%x:%x:%x.%x", &domain, &bus, &slot, &func);
+		if (err < 0) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error reading device configuration");
+			goto out;
+		}
+		if (err != 4) {
+			err = -EINVAL;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error parsing pci device "
+					 "configuration");
+			goto out;
+		}
+
+		err = pciback_export_device(pdev, domain, bus, slot, func);
+		if (err)
+			goto out;
+	}
+
+	err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error while publish PCI root buses "
+				 "for frontend");
+		goto out;
+	}
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateInitialised);
+	if (err)
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error switching to initialised state!");
+
+      out:
+	spin_unlock(&pdev->dev_lock);
+
+	if (!err)
+		/* see if pcifront is already configured (if not, we'll wait) */
+		pciback_attach(pdev);
+
+	return err;
+}
+
+static void pciback_be_watch(struct xenbus_watch *watch,
+			     const char **vec, unsigned int len)
+{
+	struct pciback_device *pdev =
+	    container_of(watch, struct pciback_device, be_watch);
+
+	switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
+	case XenbusStateInitWait:
+		pciback_setup_backend(pdev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pciback_xenbus_probe(struct xenbus_device *dev,
+				const struct xenbus_device_id *id)
+{
+	int err = 0;
+	struct pciback_device *pdev = alloc_pdev(dev);
+
+	if (pdev == NULL) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(dev, err,
+				 "Error allocating pciback_device struct");
+		goto out;
+	}
+
+	/* wait for xend to configure us */
+	err = xenbus_switch_state(dev, XBT_NULL, XenbusStateInitWait);
+	if (err)
+		goto out;
+
+	/* watch the backend node for backend configuration information */
+	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
+				pciback_be_watch);
+	if (err)
+		goto out;
+	pdev->be_watching = 1;
+
+	/* We need to force a call to our callback here in case
+	 * xend already configured us!
+	 */
+	pciback_be_watch(&pdev->be_watch, NULL, 0);
+
+      out:
+	return err;
+}
+
+static int pciback_xenbus_remove(struct xenbus_device *dev)
+{
+	struct pciback_device *pdev = dev->data;
+
+	if (pdev != NULL)
+		free_pdev(pdev);
+
+	return 0;
+}
+
+static struct xenbus_device_id xenpci_ids[] = {
+	{"pci"},
+	{{0}},
+};
+
+static struct xenbus_driver xenbus_pciback_driver = {
+	.name 			= "pciback",
+	.owner 			= THIS_MODULE,
+	.ids 			= xenpci_ids,
+	.probe 			= pciback_xenbus_probe,
+	.remove 		= pciback_xenbus_remove,
+	.otherend_changed 	= pciback_frontend_changed,
+};
+
+static __init int pciback_xenbus_register(void)
+{
+	return xenbus_register_backend(&xenbus_pciback_driver);
+}
+
+/* Must only initialize our xenbus driver after the pcistub driver */
+device_initcall(pciback_xenbus_register);
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,8 @@
+obj-y += pcifront.o
+
+pcifront-y := pci_op.o xenbus.o pci.o
+pcifront-$(CONFIG_XEN_PCI_FE_ARCH_REPLACE) += arch.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pcifront/arch.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/arch.c	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,98 @@
+/*
+ * PCI Frontend Arch Replacement Code - replaces an architecture's PCI access
+ *              code with a generic, Xen version (Experimental)
+ * - This file *should* be arch-independent (except for
+ *   pci_mmap_page_range) and should replace an arch's PCI implementation
+ * - You must prevent an architecture's PCI code from compiling into the kernel
+ *   when you use the code contained here.
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+/* More or less copied from other architectures */
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+	u16 cmd, oldcmd;
+	u8 irq;
+	int i;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	oldcmd = cmd;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		struct resource *r = &dev->resource[i];
+
+		if (!(mask & (1 << i)))
+			continue;
+
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+
+	if (cmd != oldcmd) {
+		printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n",
+		       pci_name(dev), cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	dev->irq = irq;
+
+	return 0;
+}
+
+#define CMD_DISABLE_BITS \
+	(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER)
+void pcibios_disable_device(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+	if (cmd & CMD_DISABLE_BITS) {
+		cmd &= ~CMD_DISABLE_BITS;
+
+		printk(KERN_DEBUG "PCI: Disabling device: (%s), cmd %x\n",
+		       pci_name(dev), cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+}
+
+char *pcibios_setup(char *str)
+{
+	/** Return NULL if we accept an option, str if we don't */
+	return str;
+}
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+	/* Handled by backend when we turn the master
+	 * bit on in the PCI_COMMAND register */
+}
+
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size, unsigned long align)
+{
+}
+
+void pcibios_fixup_bus(struct pci_bus *bus)
+{
+}
+
+unsigned int pcibios_assign_all_busses(void)
+{
+	return 0;
+}
+
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+			enum pci_mmap_state mmap_state, int write_combine)
+{
+	printk(KERN_ERR "%s: mmap_page_range not implemented!\n",
+	       pci_name(dev));
+	return -EINVAL;
+}
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,44 @@
+/*
+ * PCI Frontend Operations - ensure only one PCI frontend runs at a time
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include "pcifront.h"
+
+DEFINE_SPINLOCK(pcifront_dev_lock);
+static struct pcifront_device *pcifront_dev = NULL;
+
+int pcifront_connect(struct pcifront_device *pdev)
+{
+	int err = 0;
+
+	spin_lock(&pcifront_dev_lock);
+
+	if (!pcifront_dev)
+		dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
+	else {
+		dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
+		err = -EEXIST;
+	}
+
+	spin_unlock(&pcifront_dev_lock);
+
+	return err;
+}
+
+void pcifront_disconnect(struct pcifront_device *pdev)
+{
+	spin_lock(&pcifront_dev_lock);
+
+	if (pdev == pcifront_dev) {
+		dev_info(&pdev->xdev->dev,
+			 "Disconnecting PCI Frontend Buses\n");
+		pcifront_dev = NULL;
+	}
+
+	spin_unlock(&pcifront_dev_lock);
+}
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,224 @@
+/*
+ * PCI Frontend Operations - Communicates with frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <xen/evtchn.h>
+#include "pcifront.h"
+
+int verbose_request = 0;
+module_param(verbose_request, int, 0644);
+
+static int errno_to_pcibios_err(int errno)
+{
+	switch (errno) {
+	case XEN_PCI_ERR_success:
+		return PCIBIOS_SUCCESSFUL;
+
+	case XEN_PCI_ERR_dev_not_found:
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	case XEN_PCI_ERR_invalid_offset:
+	case XEN_PCI_ERR_op_failed:
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	case XEN_PCI_ERR_not_implemented:
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+	case XEN_PCI_ERR_access_denied:
+		return PCIBIOS_SET_FAILED;
+	}
+	return errno;
+}
+
+static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
+{
+	int err = 0;
+	struct xen_pci_op *active_op = &pdev->sh_info->op;
+	unsigned long irq_flags;
+
+	unsigned int volatile ttl = (1U << 29);
+
+	spin_lock_irqsave(&pdev->sh_info_lock, irq_flags);
+
+	memcpy(active_op, op, sizeof(struct xen_pci_op));
+
+	/* Go */
+	wmb();
+	set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+	notify_remote_via_evtchn(pdev->evtchn);
+
+	/* IRQs are disabled for the pci config. space reads/writes,
+	 * which means no event channel to notify us that the backend
+	 * is done so spin while waiting for the answer */
+	while (test_bit
+	       (_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)) {
+		if (!ttl) {
+			dev_err(&pdev->xdev->dev,
+				"pciback not responding!!!\n");
+			clear_bit(_XEN_PCIF_active,
+				  (unsigned long *)&pdev->sh_info->flags);
+			err = XEN_PCI_ERR_dev_not_found;
+			goto out;
+		}
+		ttl--;
+	}
+
+	memcpy(op, active_op, sizeof(struct xen_pci_op));
+
+	err = op->err;
+      out:
+	spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags);
+	return err;
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
+			     int where, int size, u32 * val)
+{
+	int err = 0;
+	struct xen_pci_op op = {
+		.cmd    = XEN_PCI_OP_conf_read,
+		.domain = pci_domain_nr(bus),
+		.bus    = bus->number,
+		.devfn  = devfn,
+		.offset = where,
+		.size   = size,
+	};
+	struct pcifront_sd *sd = bus->sysdata;
+	struct pcifront_device *pdev = sd->pdev;
+
+	if (verbose_request)
+		dev_info(&pdev->xdev->dev,
+			 "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n",
+			 pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
+			 PCI_FUNC(devfn), where, size);
+
+	err = do_pci_op(pdev, &op);
+
+	if (likely(!err)) {
+		if (verbose_request)
+			dev_info(&pdev->xdev->dev, "read got back value %x\n",
+				 op.value);
+
+		*val = op.value;
+	} else if (err == -ENODEV) {
+		/* No device here, pretend that it just returned 0 */
+		err = 0;
+		*val = 0;
+	}
+
+	return errno_to_pcibios_err(err);
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
+			      int where, int size, u32 val)
+{
+	struct xen_pci_op op = {
+		.cmd    = XEN_PCI_OP_conf_write,
+		.domain = pci_domain_nr(bus),
+		.bus    = bus->number,
+		.devfn  = devfn,
+		.offset = where,
+		.size   = size,
+		.value  = val,
+	};
+	struct pcifront_sd *sd = bus->sysdata;
+	struct pcifront_device *pdev = sd->pdev;
+
+	if (verbose_request)
+		dev_info(&pdev->xdev->dev,
+			 "write dev=%04x:%02x:%02x.%01x - "
+			 "offset %x size %d val %x\n",
+			 pci_domain_nr(bus), bus->number,
+			 PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
+
+	return errno_to_pcibios_err(do_pci_op(pdev, &op));
+}
+
+struct pci_ops pcifront_bus_ops = {
+	.read = pcifront_bus_read,
+	.write = pcifront_bus_write,
+};
+
+int pcifront_scan_root(struct pcifront_device *pdev,
+		       unsigned int domain, unsigned int bus)
+{
+	struct pci_bus *b;
+	struct pcifront_sd *sd = NULL;
+	struct pci_bus_entry *bus_entry = NULL;
+	int err = 0;
+
+#ifndef CONFIG_PCI_DOMAINS
+	if (domain != 0) {
+		dev_err(&pdev->xdev->dev,
+			"PCI Root in non-zero PCI Domain! domain=%d\n", domain);
+		dev_err(&pdev->xdev->dev,
+			"Please compile with CONFIG_PCI_DOMAINS\n");
+		err = -EINVAL;
+		goto err_out;
+	}
+#endif
+
+	dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
+		 domain, bus);
+
+	bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
+	sd = kmalloc(sizeof(*sd), GFP_KERNEL);
+	if (!bus_entry || !sd) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+	sd->domain = domain;
+	sd->pdev = pdev;
+
+	b = pci_scan_bus_parented(&pdev->xdev->dev, bus, &pcifront_bus_ops, sd);
+	if (!b) {
+		dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+	bus_entry->bus = b;
+
+	list_add(&bus_entry->list, &pdev->root_buses);
+
+	pci_bus_add_devices(b);
+
+	return 0;
+
+      err_out:
+	kfree(bus_entry);
+	kfree(sd);
+
+	return err;
+}
+
+void pcifront_free_roots(struct pcifront_device *pdev)
+{
+	struct pci_bus_entry *bus_entry, *t;
+
+	list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
+		/* TODO: Removing a PCI Bus is untested (as it normally
+		 * just goes away on domain shutdown)
+		 */
+		list_del(&bus_entry->list);
+
+		spin_lock(&pci_bus_lock);
+		list_del(&bus_entry->bus->node);
+		spin_unlock(&pci_bus_lock);
+
+		kfree(bus_entry->bus->sysdata);
+
+		device_unregister(bus_entry->bus->bridge);
+
+		/* Do we need to free() the bus itself? */
+
+		kfree(bus_entry);
+	}
+}
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,40 @@
+/*
+ * PCI Frontend - Common data structures & function declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCIFRONT_H__
+#define __XEN_PCIFRONT_H__
+
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <xen/xenbus.h>
+#include <xen/interface/io/pciif.h>
+#include <xen/pcifront.h>
+
+struct pci_bus_entry {
+	struct list_head list;
+	struct pci_bus *bus;
+};
+
+struct pcifront_device {
+	struct xenbus_device *xdev;
+	struct list_head root_buses;
+	spinlock_t dev_lock;
+
+	int evtchn;
+	int gnt_ref;
+
+	/* Lock this when doing any operations in sh_info */
+	spinlock_t sh_info_lock;
+	struct xen_pci_sharedinfo *sh_info;
+};
+
+int pcifront_connect(struct pcifront_device *pdev);
+void pcifront_disconnect(struct pcifront_device *pdev);
+
+int pcifront_scan_root(struct pcifront_device *pdev,
+		       unsigned int domain, unsigned int bus);
+void pcifront_free_roots(struct pcifront_device *pdev);
+
+#endif	/* __XEN_PCIFRONT_H__ */
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,295 @@
+/*
+ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn)
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <xen/xenbus.h>
+#include "pcifront.h"
+
+#define INVALID_GRANT_REF (0)
+#define INVALID_EVTCHN    (-1)
+
+static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
+{
+	struct pcifront_device *pdev;
+
+	pdev = kmalloc(sizeof(struct pcifront_device), GFP_KERNEL);
+	if (pdev == NULL)
+		goto out;
+
+	pdev->sh_info =
+	    (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
+	if (pdev->sh_info == NULL) {
+		kfree(pdev);
+		pdev = NULL;
+		goto out;
+	}
+	pdev->sh_info->flags = 0;
+
+	xdev->data = pdev;
+	pdev->xdev = xdev;
+
+	INIT_LIST_HEAD(&pdev->root_buses);
+
+	spin_lock_init(&pdev->dev_lock);
+	spin_lock_init(&pdev->sh_info_lock);
+
+	pdev->evtchn = INVALID_EVTCHN;
+	pdev->gnt_ref = INVALID_GRANT_REF;
+
+	dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n",
+		pdev, pdev->sh_info);
+      out:
+	return pdev;
+}
+
+static void free_pdev(struct pcifront_device *pdev)
+{
+	dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev);
+
+	if (pdev->evtchn != INVALID_EVTCHN)
+		xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
+
+	if (pdev->gnt_ref != INVALID_GRANT_REF)
+		gnttab_end_foreign_access(pdev->gnt_ref, 0,
+					  (unsigned long)pdev->sh_info);
+
+	pdev->xdev->data = NULL;
+
+	kfree(pdev);
+}
+
+static int pcifront_publish_info(struct pcifront_device *pdev)
+{
+	int err = 0;
+	xenbus_transaction_t trans;
+
+	err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info));
+	if (err < 0)
+		goto out;
+
+	pdev->gnt_ref = err;
+
+	err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
+	if (err)
+		goto out;
+
+      do_publish:
+	err = xenbus_transaction_start(&trans);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error writing configuration for backend "
+				 "(start transaction)");
+		goto out;
+	}
+
+	err = xenbus_printf(trans, pdev->xdev->nodename,
+			    "pci-op-ref", "%u", pdev->gnt_ref);
+	if (!err)
+		err = xenbus_printf(trans, pdev->xdev->nodename,
+				    "event-channel", "%u", pdev->evtchn);
+	if (!err)
+		err = xenbus_printf(trans, pdev->xdev->nodename,
+				    "magic", XEN_PCI_MAGIC);
+	if (!err)
+		err =
+		    xenbus_switch_state(pdev->xdev, trans,
+					XenbusStateInitialised);
+
+	if (err) {
+		xenbus_transaction_end(trans, 1);
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error writing configuration for backend");
+		goto out;
+	} else {
+		err = xenbus_transaction_end(trans, 0);
+		if (err == -EAGAIN)
+			goto do_publish;
+		else if (err) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error completing transaction "
+					 "for backend");
+			goto out;
+		}
+	}
+
+	dev_dbg(&pdev->xdev->dev, "publishing successful!\n");
+
+      out:
+	return err;
+}
+
+static int pcifront_try_connect(struct pcifront_device *pdev)
+{
+	int err = -EFAULT;
+	int i, num_roots, len;
+	char str[64];
+	unsigned int domain, bus;
+
+	spin_lock(&pdev->dev_lock);
+
+	/* Only connect once */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	err = pcifront_connect(pdev);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error connecting PCI Frontend");
+		goto out;
+	}
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend,
+			   "root_num", "%d", &num_roots);
+	if (err == -ENOENT) {
+		xenbus_dev_error(pdev->xdev, err,
+				 "No PCI Roots found, trying 0000:00");
+		err = pcifront_scan_root(pdev, 0, 0);
+		num_roots = 0;
+	} else if (err != 1) {
+		if (err == 0)
+			err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading number of PCI roots");
+		goto out;
+	}
+
+	for (i = 0; i < num_roots; i++) {
+		len = snprintf(str, sizeof(str), "root-%d", i);
+		if (unlikely(len >= (sizeof(str) - 1))) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend, str,
+				   "%x:%x", &domain, &bus);
+		if (err != 2) {
+			if (err >= 0)
+				err = -EINVAL;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error reading PCI root %d", i);
+			goto out;
+		}
+
+		err = pcifront_scan_root(pdev, domain, bus);
+		if (err) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error scanning PCI root %04x:%02x",
+					 domain, bus);
+			goto out;
+		}
+	}
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
+	if (err)
+		goto out;
+
+      out:
+	spin_unlock(&pdev->dev_lock);
+	return err;
+}
+
+static int pcifront_try_disconnect(struct pcifront_device *pdev)
+{
+	int err = 0;
+	XenbusState prev_state;
+
+	spin_lock(&pdev->dev_lock);
+
+	prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
+
+	if (prev_state < XenbusStateClosing)
+		err = xenbus_switch_state(pdev->xdev, XBT_NULL,
+					XenbusStateClosing);
+
+	if (!err && prev_state == XenbusStateConnected)
+		pcifront_disconnect(pdev);
+
+	spin_unlock(&pdev->dev_lock);
+
+	return err;
+}
+
+static void pcifront_backend_changed(struct xenbus_device *xdev,
+				     XenbusState be_state)
+{
+	struct pcifront_device *pdev = xdev->data;
+
+	switch (be_state) {
+	case XenbusStateClosing:
+		dev_warn(&xdev->dev, "backend going away!\n");
+		pcifront_try_disconnect(pdev);
+		break;
+
+	case XenbusStateClosed:
+		dev_warn(&xdev->dev, "backend went away!\n");
+		pcifront_try_disconnect(pdev);
+
+		device_unregister(&pdev->xdev->dev);
+		break;
+
+	case XenbusStateConnected:
+		pcifront_try_connect(pdev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pcifront_xenbus_probe(struct xenbus_device *xdev,
+				 const struct xenbus_device_id *id)
+{
+	int err = 0;
+	struct pcifront_device *pdev = alloc_pdev(xdev);
+
+	if (pdev == NULL) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(xdev, err,
+				 "Error allocating pcifront_device struct");
+		goto out;
+	}
+
+	err = pcifront_publish_info(pdev);
+
+      out:
+	return err;
+}
+
+static int pcifront_xenbus_remove(struct xenbus_device *xdev)
+{
+	if (xdev->data)
+		free_pdev(xdev->data);
+
+	return 0;
+}
+
+static struct xenbus_device_id xenpci_ids[] = {
+	{"pci"},
+	{{0}},
+};
+
+static struct xenbus_driver xenbus_pcifront_driver = {
+	.name 			= "pcifront",
+	.owner 			= THIS_MODULE,
+	.ids 			= xenpci_ids,
+	.probe 			= pcifront_xenbus_probe,
+	.remove 		= pcifront_xenbus_remove,
+	.otherend_changed 	= pcifront_backend_changed,
+};
+
+static int __init pcifront_init(void)
+{
+	int err = 0;
+
+	err = xenbus_register_frontend(&xenbus_pcifront_driver);
+
+	return err;
+}
+
+/* Initialize after the Xen PCI Frontend Stub is initialized */
+subsys_initcall(pcifront_init);
diff -r 55268b90a519 -r 289ab24e70db linux-2.6-xen-sparse/include/xen/pcifront.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/include/xen/pcifront.h	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,39 @@
+/*
+ * PCI Frontend - arch-dependendent declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_ASM_PCIFRONT_H__
+#define __XEN_ASM_PCIFRONT_H__
+
+#include <linux/config.h>
+#include <linux/spinlock.h>
+
+#ifdef __KERNEL__
+
+struct pcifront_device;
+
+struct pcifront_sd {
+	int domain;
+	struct pcifront_device *pdev;
+};
+
+struct pci_bus;
+
+#ifdef CONFIG_PCI_DOMAINS
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+	struct pcifront_sd *sd = bus->sysdata;
+	return sd->domain;
+}
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+	return pci_domain_nr(bus);
+}
+#endif /* CONFIG_PCI_DOMAINS */
+
+extern spinlock_t pci_bus_lock;
+
+#endif /* __KERNEL__ */
+
+#endif /* __XEN_ASM_PCIFRONT_H__ */
diff -r 55268b90a519 -r 289ab24e70db xen/include/public/io/pciif.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/xen/include/public/io/pciif.h	Tue Feb  7 15:04:25 2006
@@ -0,0 +1,55 @@
+/*
+ * PCI Backend/Frontend Common Data Structures & Macros
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCI_COMMON_H__
+#define __XEN_PCI_COMMON_H__
+
+/* Be sure to bump this number if you change this file */
+#define XEN_PCI_MAGIC		"7"
+
+/* xen_pci_sharedinfo flags */
+#define _XEN_PCIF_active     (0)
+#define XEN_PCIF_active      (1<<_XEN_PCI_active)
+
+/* xen_pci_op commands */
+#define XEN_PCI_OP_conf_read    (0)
+#define XEN_PCI_OP_conf_write   (1)
+
+/* xen_pci_op error numbers */
+#define XEN_PCI_ERR_success          (0)
+#define XEN_PCI_ERR_dev_not_found   (-1)
+#define XEN_PCI_ERR_invalid_offset  (-2)
+#define XEN_PCI_ERR_access_denied   (-3)
+#define XEN_PCI_ERR_not_implemented (-4)
+/* XEN_PCI_ERR_op_failed - backend failed to complete the operation */
+#define XEN_PCI_ERR_op_failed       (-5)
+
+struct xen_pci_op {
+	/* IN: what action to perform: XEN_PCI_OP_* */
+	uint32_t cmd;
+
+	/* OUT: will contain an error number (if any) from errno.h */
+	int32_t err;
+
+	/* IN: which device to touch */
+	uint32_t domain; /* PCI Domain/Segment */
+	uint32_t bus;
+	uint32_t devfn;
+
+	/* IN: which configuration registers to touch */
+	int32_t offset;
+	int32_t size;
+
+	/* IN/OUT: Contains the result after a READ or the value to WRITE */
+	uint32_t value;
+};
+
+struct xen_pci_sharedinfo {
+	/* flags - XEN_PCIF_* */
+	uint32_t flags;
+	struct xen_pci_op op;
+};
+
+#endif /* __XEN_PCI_COMMON_H__ */

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
  2006-02-07 14:37 Ryan
@ 2006-02-07 15:19 ` Keir Fraser
  2006-02-07 15:50   ` Ryan
  0 siblings, 1 reply; 15+ messages in thread
From: Keir Fraser @ 2006-02-07 15:19 UTC (permalink / raw)
  To: Ryan; +Cc: xen-devel


On 7 Feb 2006, at 14:37, Ryan wrote:

> 2) arch/i386/pci/i386-xen.c needed to return. Calling
> pci_assign_unassigned_resources in a driver domain with the PCI 
> frontend
> fails. The PCI backend restricts writing to the configuration space (it
> would be dangerous if we let the driver domain change the resource
> allocations in the BARs, see drivers/xen/pciback/conf_space_header.c 
> for
> how this is done). When pci_assign_unassigned_resources tries to update
> the BARs, it will fail (and then the struct pci_dev's resources will 
> not
> reflect the real resources of the devices and things just won't work).
> To fix this problem, I added a #ifdef around the call to
> pci_assign_unassigned_resources in i386-xen.c so that it only works if
> the PCI frontend is not compiled in. However, I'm not certain that this
> is the best solution so please let me know if you can think of a better
> way.

Isn't absence of PCI_ASSIGN_ROMS supposed to mean that the OS tries to 
use the existing resource allocations? So, unless someone says 
'pci=rom' as a boot parameter I would have hoped that things would just 
work and the OS would not try shuffling resources around. If it is 
shuffling things, that's a bit worrying.

In any case, it is important that we continue to be able to build a 
single kernel image that works as both dom0 and domU. This means that 
you need to support both direct PCI access and virtualised PCI access 
*in the same kernel build*. Compile-time ifdef's are right out: worst 
case you'll have to test at runtime whether or not you are dom0.

Perhaps this restriction will make it easier to pick between the raw-op 
and non-raw-op virtualised pci access methods? :-)

  -- Keir

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
  2006-02-07 15:19 ` Keir Fraser
@ 2006-02-07 15:50   ` Ryan
  2006-02-07 15:59     ` Ryan
  0 siblings, 1 reply; 15+ messages in thread
From: Ryan @ 2006-02-07 15:50 UTC (permalink / raw)
  To: Keir Fraser; +Cc: xen-devel

On Tue, 2006-02-07 at 15:19 +0000, Keir Fraser wrote:
> Isn't absence of PCI_ASSIGN_ROMS supposed to mean that the OS tries to 
> use the existing resource allocations? So, unless someone says 
> 'pci=rom' as a boot parameter I would have hoped that things would just 
> work and the OS would not try shuffling resources around. If it is 
> shuffling things, that's a bit worrying.

There was a change somewhere between 2.6.12 and 2.6.15 (I can't remember
exactly where now) where Linux now tries to reassign resources that it
detects as unassigned. I think the behavior that you reference used to
be true, but is different now. See pcibios_assign_resources in
arch/i386/pci/i386.c.

It is strange that it tries to shuffle things... I can't seem to track
down in the source the exact conditions under which Linux tries to
reassign the BARs and doesn't just use what the BIOS/Backend provided.
pci_assign_unassigned_resources was never called in 2.6.12 (at least not
on x86) so it was not an issue before. If someone else is more familiar
with that code, please let me know, perhaps there's a better workaround.

> 
> In any case, it is important that we continue to be able to build a 
> single kernel image that works as both dom0 and domU. This means that 
> you need to support both direct PCI access and virtualised PCI access 
> *in the same kernel build*. Compile-time ifdef's are right out: worst 
> case you'll have to test at runtime whether or not you are dom0.

I thought about testing at run-time for whether or not the PCI frontend
was active, but I decided against it because I suspected that would
involve creating some kind of global variable or globally-visible
function. I don't want to create a test for dom0 because that rules out
putting the PCI backend in it's own driver domain. Perhaps a global
variable is a better workaround for now than a compile-time ifdef.

> 
> Perhaps this restriction will make it easier to pick between the raw-op 
> and non-raw-op virtualised pci access methods? :-)
> 

Perhaps if I understood why the -domU was trying to reallocate the PCI
resources, maybe it would help make the decision for us. But I'm not
sure that the choice between the two methods of operation for the PCI
frontend is related to this problem with
pci_assign_unassigned_resources.

Ryan

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
  2006-02-07 15:50   ` Ryan
@ 2006-02-07 15:59     ` Ryan
  2006-02-07 17:57       ` Keir Fraser
  0 siblings, 1 reply; 15+ messages in thread
From: Ryan @ 2006-02-07 15:59 UTC (permalink / raw)
  To: Keir Fraser; +Cc: xen-devel

> > 
> > Perhaps this restriction will make it easier to pick between the raw-op 
> > and non-raw-op virtualised pci access methods? :-)
> > 
> 

Sorry, I misunderstood you the first time I read your statement above.
Yes, I think the restriction of having one domain compile for both -dom0
and -domU will make the decision for us as the non-raw-op version (the
arch-independent version) actually replaces the native PCI code.

Ryan

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
  2006-02-07 15:59     ` Ryan
@ 2006-02-07 17:57       ` Keir Fraser
  2006-02-07 19:58         ` Ryan
  0 siblings, 1 reply; 15+ messages in thread
From: Keir Fraser @ 2006-02-07 17:57 UTC (permalink / raw)
  To: Ryan; +Cc: xen-devel


On 7 Feb 2006, at 15:59, Ryan wrote:

>>>
>>> Perhaps this restriction will make it easier to pick between the 
>>> raw-op
>>> and non-raw-op virtualised pci access methods? :-)
>>>
>>
>
> Sorry, I misunderstood you the first time I read your statement above.
> Yes, I think the restriction of having one domain compile for both 
> -dom0
> and -domU will make the decision for us as the non-raw-op version (the
> arch-independent version) actually replaces the native PCI code.

If we have to get 'grubby' and do the raw-op version and modify 
arch-dep pci code, perhaps it makes sense to gate 
pci_assign_unassigned_resources on a global am-i-virtual flag.

I expect we would add the virtual access ops as a fall-back pci access 
method (preferring direct hardware access if possible 
CONF1/CONF2/MMCONF etc). If we do fall back then we set the global flag 
and gate certain things.

It certainly would be better to not need to gate things at all -- but 
clearly calling pci_assign_unassigned_resources can never help things 
in a virtualized-pci guest. :-)

Will you be working support for dual-mode pci access support into your 
patches? I'd probably check them in now except for this current 
limitation.

  -- Keir

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
  2006-02-07 17:57       ` Keir Fraser
@ 2006-02-07 19:58         ` Ryan
  2006-02-07 23:17           ` Keir Fraser
  0 siblings, 1 reply; 15+ messages in thread
From: Ryan @ 2006-02-07 19:58 UTC (permalink / raw)
  To: Keir Fraser; +Cc: xen-devel

[-- Attachment #1: Type: text/plain, Size: 2635 bytes --]

On Tue, 2006-02-07 at 17:57 +0000, Keir Fraser wrote:
> 
> If we have to get 'grubby' and do the raw-op version and modify 
> arch-dep pci code, perhaps it makes sense to gate 
> pci_assign_unassigned_resources on a global am-i-virtual flag.
> 
> I expect we would add the virtual access ops as a fall-back pci access 
> method (preferring direct hardware access if possible 
> CONF1/CONF2/MMCONF etc). If we do fall back then we set the global flag 
> and gate certain things.
> 
> It certainly would be better to not need to gate things at all -- but 
> clearly calling pci_assign_unassigned_resources can never help things 
> in a virtualized-pci guest. :-)

I believe that I've found the correct solution to the resource issue
with pci_assign_unassigned_resources and it doesn't involve any kind of
global variables. It turns out that pci_assign_unassigned_resources (and
the functions it calls) iterate over all of the resources in a struct
pci_dev and if they don't have a parent resource, it considers them
"unassigned". By forcibly claiming resources (using pci_claim_resource),
the PCI frontend can mark all of those resources as assigned so the
kernel doesn't try to change them later in
pci_assign_unassigned_resources.

> 
> Will you be working support for dual-mode pci access support into your 
> patches? I'd probably check them in now except for this current 
> limitation.

When you say "dual-mode", to you mean having the PCI frontend and
backend in the same kernel? If so, yes. I tested it out with this patch
and my dom0 kernel works fine in domU and dom0 with both the PCI
frontend and the PCI backend compiled in. It prefers direct access to
the PCI bus and falls back on the Xen pcifront stub if that fails.


I've attached a new patch for the PCI frontend/backend that replaces
patch 2 of 4 that I sent earlier today. The other patches sent today
remain unchanged.

One issue with this patch (at least the frontend part of it) is that it
will probably only work correctly with x86 (I don't have access to other
architectures to test on) and the kconfig menu entries will appear
regardless of the architecture (they don't list x86 as a dependency).
Should they list x86 as a dependency? Right now, they're under the "Xen"
menu with the other backends and frontends. Should I move the PCI
frontend configuration option into the "Bus options/PCI Access" menu
next to the mmconfig, direct, and bios options? I think it would be
better placed under the "Bus options/PCI Access" menu but I wasn't sure
if all the backends and frontends needed to be listed together. 

Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>

[-- Attachment #2: pci-ddi.patch --]
[-- Type: text/x-patch, Size: 75428 bytes --]

diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/arch/i386/pci/Makefile
--- a/linux-2.6-xen-sparse/arch/i386/pci/Makefile	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/arch/i386/pci/Makefile	Tue Feb  7 20:10:43 2006
@@ -3,6 +3,10 @@
 obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
 obj-$(CONFIG_PCI_MMCONFIG)	+= mmconfig.o direct.o
 obj-$(CONFIG_PCI_DIRECT)	+= direct.o
+
+# pcifront should be after pcbios.o, mmconfig.o, and direct.o as it should only
+# take over if direct access to the PCI bus is unavailable
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront.o
 
 pci-y				:= fixup.o
 pci-$(CONFIG_ACPI)		+= acpi.o
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/Kconfig
--- a/linux-2.6-xen-sparse/drivers/xen/Kconfig	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig	Tue Feb  7 20:10:43 2006
@@ -28,6 +28,57 @@
 config XEN_UNPRIVILEGED_GUEST
 	bool
 	default !XEN_PRIVILEGED_GUEST
+
+config XEN_PCIDEV_BACKEND
+	bool "PCI device backend driver"
+	select PCI
+	default y if XEN_PRIVILEGED_GUEST
+	help
+	  The PCI device backend driver allows the kernel to export arbitrary
+	  PCI devices to other guests.
+
+choice
+	prompt "PCI Backend Mode"
+	depends on XEN_PCIDEV_BACKEND
+	default XEN_PCIDEV_BACKEND_VPCI
+
+config XEN_PCIDEV_BACKEND_VPCI
+	bool "Virtual PCI"
+	---help---
+	  This PCI Backend hides the true PCI topology and makes the frontend
+	  think there is a single PCI bus with only the exported devices on it.
+	  For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
+	  second device at 02:1a.0 will be re-assigned to 00:01.0.
+
+config XEN_PCIDEV_BACKEND_PASS
+	bool "Passthrough"
+	---help---
+	  This PCI Backend provides a real view of the PCI topology to the
+	  frontend (for example, a device at 06:01.b will still appear at
+	  06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
+	  PCI devices to its driver domains. This may be required for drivers
+	  which depend on finding their hardward in certain bus/slot
+	  locations.
+
+endchoice
+
+config XEN_PCIDEV_BE_DEBUG
+	bool "PCI Backend Debugging"
+	depends on XEN_PCIDEV_BACKEND
+	default n
+
+config XEN_PCIDEV_FRONTEND
+	bool "PCI device frontend driver"
+	select PCI
+	default y if !XEN_PRIVILEGED_GUEST
+	help
+	  The PCI device frontend driver allows the kernel to import arbitrary
+	  PCI devices from a PCI backend.
+
+config XEN_PCIDEV_FE_DEBUG
+	bool "PCI Frontend Debugging"
+	depends on XEN_PCIDEV_FRONTEND
+	default n
 
 config XEN_BLKDEV_BACKEND
 	bool "Block-device backend driver"
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Tue Feb  7 20:10:43 2006
@@ -17,4 +17,6 @@
 obj-$(CONFIG_XEN_NETDEV_FRONTEND)	+= netfront/
 obj-$(CONFIG_XEN_BLKDEV_TAP)    	+= blktap/
 obj-$(CONFIG_XEN_TPMDEV_FRONTEND)	+= tpmfront/
+obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= pciback/
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront/
 
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h	Tue Feb  7 20:10:43 2006
@@ -134,6 +134,10 @@
 
 #endif /* __KERNEL__ */
 
+#ifdef CONFIG_XEN_PCIDEV_FRONTEND
+#include <xen/pcifront.h>
+#endif /* CONFIG_XEN_PCIDEV_FRONTEND */
+
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
 #include <asm-generic/pci-dma-compat.h>
 
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/arch/i386/pci/pcifront.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/arch/i386/pci/pcifront.c	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,48 @@
+/*
+ * PCI Frontend Stub - puts some "dummy" functions in to the Linux x86 PCI core
+ *                     to support the Xen PCI Frontend's operation
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include "pci.h"
+
+static int pcifront_enable_irq(struct pci_dev *dev)
+{
+	u8 irq;
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	dev->irq = irq;
+
+	return 0;
+}
+
+extern u8 pci_cache_line_size;
+
+static int __init pcifront_x86_stub_init(void)
+{
+	struct cpuinfo_x86 *c = &boot_cpu_data;
+
+	/* Only install our method if we haven't found real hardware already */
+	if (raw_pci_ops)
+		return 0;
+
+	printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
+
+	/* Copied from arch/i386/pci/common.c */
+	pci_cache_line_size = 32 >> 2;
+	if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
+		pci_cache_line_size = 64 >> 2;	/* K7 & K8 */
+	else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL)
+		pci_cache_line_size = 128 >> 2;	/* P4 */
+
+	/* On x86, we need to disable the normal IRQ routing table and
+	 * just ask the backend
+	 */
+	pcibios_enable_irq = pcifront_enable_irq;
+
+	return 0;
+}
+
+arch_initcall(pcifront_x86_stub_init);
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pciback/Makefile
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,10 @@
+obj-y += pciback.o
+
+pciback-y := pci_stub.o pciback_ops.o xenbus.o
+pciback-y += conf_space.o conf_space_header.o
+pciback-${CONFIG_XEN_PCIDEV_BACKEND_VPCI} += vpci.o
+pciback-${CONFIG_XEN_PCIDEV_BACKEND_PASS} += passthrough.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,324 @@
+/*
+ * PCI Backend - Functions for creating a virtual configuration space for
+ *               exported PCI Devices.
+ *               It's dangerous to allow PCI Driver Domains to change their
+ *               device's resources (memory, i/o ports, interrupts). We need to
+ *               restrict changes to certain PCI Configuration registers:
+ *               BARs, INTERRUPT_PIN, most registers in the header...
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+
+#define DEFINE_PCI_CONFIG(op,size,type) 					\
+int pciback_##op##_config_##size 							\
+(struct pci_dev *dev, int offset, type value, void *data)	\
+{															\
+	return pci_##op##_config_##size (dev, offset, value);	\
+}
+
+DEFINE_PCI_CONFIG(read, byte, u8 *)
+DEFINE_PCI_CONFIG(read, word, u16 *)
+DEFINE_PCI_CONFIG(read, dword, u32 *)
+
+DEFINE_PCI_CONFIG(write, byte, u8)
+DEFINE_PCI_CONFIG(write, word, u16)
+DEFINE_PCI_CONFIG(write, dword, u32)
+
+static int conf_space_read(struct pci_dev *dev,
+			   struct config_field_entry *entry, int offset,
+			   u32 * value)
+{
+	int ret = 0;
+	struct config_field *field = entry->field;
+
+	*value = 0;
+
+	switch (field->size) {
+	case 1:
+		if (field->u.b.read)
+			ret = field->u.b.read(dev, offset, (u8 *) value,
+					      entry->data);
+		break;
+	case 2:
+		if (field->u.w.read)
+			ret = field->u.w.read(dev, offset, (u16 *) value,
+					      entry->data);
+		break;
+	case 4:
+		if (field->u.dw.read)
+			ret = field->u.dw.read(dev, offset, value, entry->data);
+		break;
+	}
+	return ret;
+}
+
+static int conf_space_write(struct pci_dev *dev,
+			    struct config_field_entry *entry, int offset,
+			    u32 value)
+{
+	int ret = 0;
+	struct config_field *field = entry->field;
+
+	switch (field->size) {
+	case 1:
+		if (field->u.b.write)
+			ret = field->u.b.write(dev, offset, (u8) value,
+					       entry->data);
+		break;
+	case 2:
+		if (field->u.w.write)
+			ret = field->u.w.write(dev, offset, (u16) value,
+					       entry->data);
+		break;
+	case 4:
+		if (field->u.dw.write)
+			ret = field->u.dw.write(dev, offset, value,
+					        entry->data);
+		break;
+	}
+	return ret;
+}
+
+static inline u32 get_mask(int size)
+{
+	if (size == 1)
+		return 0xff;
+	else if (size == 2)
+		return 0xffff;
+	else
+		return 0xffffffff;
+}
+
+static inline int valid_request(int offset, int size)
+{
+	/* Validate request (no un-aligned requests) */
+	if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0)
+		return 1;
+	return 0;
+}
+
+static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
+			      u32 offset)
+{
+	if (offset >= 0) {
+		new_val_mask <<= (offset * 8);
+		new_val <<= (offset * 8);
+	} else {
+		new_val_mask >>= (offset * -8);
+		new_val >>= (offset * -8);
+	}
+	val = (val & ~new_val_mask) | (new_val & new_val_mask);
+
+	return val;
+}
+
+static int pcibios_err_to_errno(int err)
+{
+	switch (err) {
+	case PCIBIOS_SUCCESSFUL:
+		return XEN_PCI_ERR_success;
+	case PCIBIOS_DEVICE_NOT_FOUND:
+		return XEN_PCI_ERR_dev_not_found;
+	case PCIBIOS_BAD_REGISTER_NUMBER:
+		return XEN_PCI_ERR_invalid_offset;
+	case PCIBIOS_FUNC_NOT_SUPPORTED:
+		return XEN_PCI_ERR_not_implemented;
+	case PCIBIOS_SET_FAILED:
+		return XEN_PCI_ERR_access_denied;
+	}
+	return err;
+}
+
+int pciback_config_read(struct pci_dev *dev, int offset, int size,
+			u32 * ret_val)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+	int req_start, req_end, field_start, field_end;
+	/* if read fails for any reason, return 0 (as if device didn't respond) */
+	u32 value = 0, tmp_val;
+
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n",
+		       pci_name(dev), size, offset);
+
+	if (!valid_request(offset, size)) {
+		err = XEN_PCI_ERR_invalid_offset;
+		goto out;
+	}
+
+	/* Get the real value first, then modify as appropriate */
+	switch (size) {
+	case 1:
+		err = pci_read_config_byte(dev, offset, (u8 *) & value);
+		break;
+	case 2:
+		err = pci_read_config_word(dev, offset, (u16 *) & value);
+		break;
+	case 4:
+		err = pci_read_config_dword(dev, offset, &value);
+		break;
+	}
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		req_start = offset;
+		req_end = offset + size;
+		field_start = field->offset;
+		field_end = field->offset + field->size;
+
+		if ((req_start >= field_start && req_start < field_end)
+		    || (req_end > field_start && req_end <= field_end)) {
+			err = conf_space_read(dev, cfg_entry, offset, &tmp_val);
+			if (err)
+				goto out;
+
+			value = merge_value(value, tmp_val,
+					    get_mask(field->size),
+					    field_start - req_start);
+		}
+	}
+
+      out:
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
+		       pci_name(dev), size, offset, value);
+
+	*ret_val = value;
+	return pcibios_err_to_errno(err);
+}
+
+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+	u32 tmp_val;
+	int req_start, req_end, field_start, field_end;
+
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG
+		       "pciback: %s: write request %d bytes at 0x%x = %x\n",
+		       pci_name(dev), size, offset, value);
+
+	if (!valid_request(offset, size))
+		return XEN_PCI_ERR_invalid_offset;
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		req_start = offset;
+		req_end = offset + size;
+		field_start = field->offset;
+		field_end = field->offset + field->size;
+
+		if ((req_start >= field_start && req_start < field_end)
+		    || (req_end > field_start && req_end <= field_end)) {
+			tmp_val = 0;
+
+			err = pciback_config_read(dev, offset, size, &tmp_val);
+			if (err)
+				break;
+
+			tmp_val = merge_value(tmp_val, value, get_mask(size),
+					      field_start - req_start);
+
+			err = conf_space_write(dev, cfg_entry, offset, tmp_val);
+		}
+	}
+
+	return pcibios_err_to_errno(err);
+}
+
+void pciback_config_reset(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		if (field->reset)
+			field->reset(dev, field->offset, cfg_entry->data);
+	}
+}
+
+void pciback_config_free(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry, *t;
+	struct config_field *field;
+
+	list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
+		list_del(&cfg_entry->list);
+
+		field = cfg_entry->field;
+
+		if (field->release)
+			field->release(dev, field->offset, cfg_entry->data);
+
+		kfree(cfg_entry);
+	}
+}
+
+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	void *tmp;
+
+	cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
+	if (!cfg_entry) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	cfg_entry->data = NULL;
+	cfg_entry->field = field;
+
+	if (field->init) {
+		tmp = field->init(dev, field->offset);
+
+		if (IS_ERR(tmp)) {
+			err = PTR_ERR(tmp);
+			goto out;
+		}
+
+		cfg_entry->data = tmp;
+	}
+
+	list_add_tail(&cfg_entry->list, &dev_data->config_fields);
+
+      out:
+	if (err)
+		kfree(cfg_entry);
+
+	return err;
+}
+
+/* This sets up the device's virtual configuration space to keep track of 
+ * certain registers (like the base address registers (BARs) so that we can
+ * keep the client from manipulating them directly.
+ */
+int pciback_config_init(struct pci_dev *dev)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+
+	INIT_LIST_HEAD(&dev_data->config_fields);
+
+	err = pciback_config_header_add_fields(dev);
+
+	return err;
+}
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,97 @@
+/*
+ * PCI Backend - Common data structures for overriding the configuration space
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#ifndef __XEN_PCIBACK_CONF_SPACE_H__
+#define __XEN_PCIBACK_CONF_SPACE_H__
+
+#include <linux/list.h>
+
+typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
+typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data);
+typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
+
+typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value,
+				 void *data);
+typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value,
+				void *data);
+typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value,
+				void *data);
+typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value,
+				void *data);
+typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value,
+			       void *data);
+typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
+			       void *data);
+
+/* These are the fields within the configuration space which we
+ * are interested in intercepting reads/writes to and changing their
+ * values.
+ */
+struct config_field {
+	unsigned int     offset;
+	unsigned int     size;
+	conf_field_init  init;
+	conf_field_reset reset;
+	conf_field_free  release;
+	union {
+		struct {
+			conf_dword_write write;
+			conf_dword_read read;
+		} dw;
+		struct {
+			conf_word_write write;
+			conf_word_read read;
+		} w;
+		struct {
+			conf_byte_write write;
+			conf_byte_read read;
+		} b;
+	} u;
+};
+
+struct config_field_entry {
+	struct list_head list;
+	struct config_field *field;
+	void *data;
+};
+
+/* Add fields to a device - the add_fields macro expects to get a pointer to
+ * the first entry in an array (of which the ending is marked by size==0)
+ */
+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field);
+static inline int pciback_config_add_fields(struct pci_dev *dev,
+					    struct config_field *field)
+{
+	int i, err = 0;
+	for (i = 0; field[i].size != 0; i++) {
+		err = pciback_config_add_field(dev, &field[i]);
+		if (err)
+			break;
+	}
+	return err;
+}
+
+/* Initializers which add fields to the virtual configuration space
+ * ** We could add initializers to allow a guest domain to touch
+ * the capability lists (for power management, the AGP bridge, etc.)
+ */
+int pciback_config_header_add_fields(struct pci_dev *dev);
+
+/* Read/Write the real configuration space */
+int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
+			     void *data);
+int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value,
+			     void *data);
+int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value,
+			      void *data);
+int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
+			      void *data);
+int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value,
+			      void *data);
+int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
+			       void *data);
+
+#endif				/* __XEN_PCIBACK_CONF_SPACE_H__ */
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,269 @@
+/*
+ * PCI Backend - Handles the virtual fields in the configuration space headers.
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+
+struct pci_bar_info {
+	u32 val;
+	u32 len_val;
+	int which;
+};
+
+#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
+#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
+
+static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
+{
+	if (!dev->is_enabled && is_enable_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: enable\n",
+			       pci_name(dev));
+		dev->is_enabled = 1;
+		pcibios_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
+	} else if (dev->is_enabled && !is_enable_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: disable\n",
+			       pci_name(dev));
+		pciback_disable_device(dev);
+	}
+
+	if (!dev->is_busmaster && is_master_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: set bus master\n",
+			       pci_name(dev));
+		dev->is_busmaster = 1;
+		pcibios_set_master(dev);
+	}
+
+	if (value & PCI_COMMAND_INVALIDATE) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG
+			       "pciback: %s: enable memory-write-invalidate\n",
+			       pci_name(dev));
+		pci_set_mwi(dev);
+	}
+
+	return pci_write_config_word(dev, offset, value);
+}
+
+static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	/* A write to obtain the length must happen as a 32-bit write.
+	 * This does not (yet) support writing individual bytes
+	 */
+	if (value == ~PCI_ROM_ADDRESS_ENABLE)
+		bar->which = 1;
+	else
+		bar->which = 0;
+
+	/* Do we need to support enabling/disabling the rom address here? */
+
+	return 0;
+}
+
+/* For the BARs, only allow writes which write ~0 or
+ * the correct resource information
+ * (Needed for when the driver probes the resource usage)
+ */
+static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	/* A write to obtain the length must happen as a 32-bit write.
+	 * This does not (yet) support writing individual bytes
+	 */
+	if (value == ~0)
+		bar->which = 1;
+	else
+		bar->which = 0;
+
+	return 0;
+}
+
+static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	*value = bar->which ? bar->len_val : bar->val;
+
+	return 0;
+}
+
+static inline void read_dev_bar(struct pci_dev *dev,
+				struct pci_bar_info *bar_info, int offset,
+				u32 len_mask)
+{
+	pci_read_config_dword(dev, offset, &bar_info->val);
+	pci_write_config_dword(dev, offset, len_mask);
+	pci_read_config_dword(dev, offset, &bar_info->len_val);
+	pci_write_config_dword(dev, offset, bar_info->val);
+}
+
+static void *bar_init(struct pci_dev *dev, int offset)
+{
+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
+
+	if (!bar)
+		return ERR_PTR(-ENOMEM);
+
+	read_dev_bar(dev, bar, offset, ~0);
+	bar->which = 0;
+
+	return bar;
+}
+
+static void *rom_init(struct pci_dev *dev, int offset)
+{
+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
+
+	if (!bar)
+		return ERR_PTR(-ENOMEM);
+
+	read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
+	bar->which = 0;
+
+	return bar;
+}
+
+static void bar_reset(struct pci_dev *dev, int offset, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	bar->which = 0;
+}
+
+static void bar_release(struct pci_dev *dev, int offset, void *data)
+{
+	kfree(data);
+}
+
+static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
+			  void *data)
+{
+	*value = (u8) dev->irq;
+
+	return 0;
+}
+
+struct config_field header_common[] = {
+	{
+	 .offset    = PCI_COMMAND,
+	 .size      = 2,
+	 .u.w.read  = pciback_read_config_word,
+	 .u.w.write = command_write,
+	 },
+	{
+	 .offset    = PCI_INTERRUPT_LINE,
+	 .size      = 1,
+	 .u.b.read  = interrupt_read,
+	 .u.b.write = NULL,
+	 },
+	{
+	 /* Any side effects of letting driver domain control cache line? */
+	 .offset    = PCI_CACHE_LINE_SIZE,
+	 .size      = 1,
+	 .u.b.read  = pciback_read_config_byte,
+	 .u.b.write = pciback_write_config_byte,
+	 },
+	{
+	 .size = 0,
+	 },
+};
+
+#define CFG_FIELD_BAR(reg_offset) 			\
+	{ 						\
+	 .offset     = reg_offset, 			\
+	 .size       = 4, 				\
+	 .init       = bar_init, 			\
+	 .reset      = bar_reset, 			\
+	 .release    = bar_release, 			\
+	 .u.dw.read  = bar_read, 			\
+	 .u.dw.write = bar_write, 			\
+	 }
+
+#define CFG_FIELD_ROM(reg_offset) 			\
+	{ 						\
+	 .offset     = reg_offset, 			\
+	 .size       = 4, 				\
+	 .init       = rom_init, 			\
+	 .reset      = bar_reset, 			\
+	 .release    = bar_release, 			\
+	 .u.dw.read  = bar_read, 			\
+	 .u.dw.write = rom_write, 			\
+	 }
+
+struct config_field header_0[] = {
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
+	CFG_FIELD_ROM(PCI_ROM_ADDRESS),
+	{
+	 .size = 0,
+	 },
+};
+
+struct config_field header_1[] = {
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
+	CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
+	{
+	 .size = 0,
+	 },
+};
+
+int pciback_config_header_add_fields(struct pci_dev *dev)
+{
+	int err;
+
+	err = pciback_config_add_fields(dev, header_common);
+	if (err)
+		goto out;
+
+	switch (dev->hdr_type) {
+	case PCI_HEADER_TYPE_NORMAL:
+		err = pciback_config_add_fields(dev, header_0);
+		break;
+
+	case PCI_HEADER_TYPE_BRIDGE:
+		err = pciback_config_add_fields(dev, header_1);
+		break;
+
+	default:
+		err = -EINVAL;
+		printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
+		       pci_name(dev), dev->hdr_type);
+		break;
+	}
+
+      out:
+	return err;
+}
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,116 @@
+/*
+ * PCI Backend - Provides restricted access to the real PCI bus topology
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/list.h>
+#include <linux/pci.h>
+#include "pciback.h"
+
+struct passthrough_dev_data {
+	struct list_head dev_list;
+};
+
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry;
+
+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
+		if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
+		    && bus == (unsigned int)dev_entry->dev->bus->number
+		    && devfn == dev_entry->dev->devfn)
+			return dev_entry->dev;
+	}
+
+	return NULL;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry;
+
+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
+	if (!dev_entry)
+		return -ENOMEM;
+	dev_entry->dev = dev;
+
+	list_add_tail(&dev_entry->list, &dev_data->dev_list);
+
+	return 0;
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+	struct passthrough_dev_data *dev_data;
+
+	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
+	if (!dev_data)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&dev_data->dev_list);
+
+	pdev->pci_dev_data = dev_data;
+
+	return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb publish_root_cb)
+{
+	int err = 0;
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry, *e;
+	struct pci_dev *dev;
+	int found;
+	unsigned int domain, bus;
+
+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
+		/* Only publish this device as a root if none of its
+		 * parent bridges are exported
+		 */
+		found = 0;
+		dev = dev_entry->dev->bus->self;
+		for (; !found && dev != NULL; dev = dev->bus->self) {
+			list_for_each_entry(e, &dev_data->dev_list, list) {
+				if (dev == e->dev) {
+					found = 1;
+					break;
+				}
+			}
+		}
+
+		domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
+		bus = (unsigned int)dev_entry->dev->bus->number;
+
+		if (!found) {
+			err = publish_root_cb(pdev, domain, bus);
+			if (err)
+				break;
+		}
+	}
+
+	return err;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry, *t;
+
+	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
+		list_del(&dev_entry->list);
+		pcistub_put_pci_dev(dev_entry->dev);
+		kfree(dev_entry);
+	}
+
+	kfree(dev_data);
+	pdev->pci_dev_data = NULL;
+}
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,377 @@
+/*
+ * PCI Stub Driver - Grabs devices in backend to be exported later
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include "pciback.h"
+
+static char *pci_devs_to_hide = NULL;
+module_param_named(hide, pci_devs_to_hide, charp, 0444);
+
+struct pci_stub_device_id {
+	struct list_head slot_list;
+	int domain;
+	unsigned char bus;
+	unsigned int devfn;
+};
+LIST_HEAD(pci_stub_device_ids);
+
+struct pci_stub_device {
+	struct list_head dev_list;
+	struct pci_dev *dev;
+	atomic_t in_use;
+};
+/* Access to pci_stub_devices & seized_devices lists and the initialize_devices
+ * flag must be locked with pci_stub_devices_lock
+ */
+DEFINE_SPINLOCK(pci_stub_devices_lock);
+LIST_HEAD(pci_stub_devices);
+
+/* wait for device_initcall before initializing our devices
+ * (see pcistub_init_devices_late)
+ */
+static int initialize_devices = 0;
+LIST_HEAD(seized_devices);
+
+static inline struct pci_dev *get_pci_dev(struct pci_stub_device *psdev)
+{
+	if (atomic_dec_and_test(&psdev->in_use))
+		return psdev->dev;
+	else {
+		atomic_inc(&psdev->in_use);
+		return NULL;
+	}
+}
+
+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
+					    int slot, int func)
+{
+	struct pci_stub_device *psdev;
+	struct pci_dev *found_dev = NULL;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev != NULL
+		    && domain == pci_domain_nr(psdev->dev->bus)
+		    && bus == psdev->dev->bus->number
+		    && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
+			found_dev = get_pci_dev(psdev);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+	return found_dev;
+}
+
+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+	struct pci_dev *found_dev = NULL;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev == dev) {
+			found_dev = get_pci_dev(psdev);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+	return found_dev;
+}
+
+void pcistub_put_pci_dev(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev == dev) {
+			/* Cleanup our device
+			 * (so it's ready for the next domain)
+			 */
+			pciback_reset_device(psdev->dev);
+
+			atomic_inc(&psdev->in_use);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+}
+
+static int __devinit pcistub_match(struct pci_dev *dev,
+				   struct pci_stub_device_id *pdev_id)
+{
+	/* Match the specified device by domain, bus, slot, func and also if
+	 * any of the device's parent bridges match.
+	 */
+	for (; dev != NULL; dev = dev->bus->self) {
+		if (pci_domain_nr(dev->bus) == pdev_id->domain
+		    && dev->bus->number == pdev_id->bus
+		    && dev->devfn == pdev_id->devfn)
+			return 1;
+	}
+
+	return 0;
+}
+
+static int __devinit pcistub_init_device(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data;
+	int err = 0;
+
+	/* The PCI backend is not intended to be a module (or to work with
+	 * removable PCI devices (yet). If it were, pciback_config_free()
+	 * would need to be called somewhere to free the memory allocated
+	 * here and then to call kfree(pci_get_drvdata(psdev->dev)).
+	 */
+	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
+	if (!dev_data) {
+		err = -ENOMEM;
+		goto out;
+	}
+	pci_set_drvdata(dev, dev_data);
+
+	err = pciback_config_init(dev);
+	if (err)
+		goto out;
+
+	/* HACK: Force device (& ACPI) to determine what IRQ it's on - we
+	 * must do this here because pcibios_enable_device may specify
+	 * the pci device's true irq (and possibly its other resources)
+	 * if they differ from what's in the configuration space.
+	 * This makes the assumption that the device's resources won't
+	 * change after this point (otherwise this code may break!)
+	 */
+	err = pci_enable_device(dev);
+	if (err)
+		goto config_release;
+
+	/* Now disable the device (this also ensures some private device
+	 * data is setup before we export)
+	 * This calls pciback_config_reset(dev)
+	 */
+	pciback_reset_device(dev);
+
+	return 0;
+
+      config_release:
+	pciback_config_free(dev);
+
+      out:
+	pci_set_drvdata(dev, NULL);
+	kfree(dev_data);
+	return err;
+}
+
+/*
+ * Because some initialization still happens on
+ * devices during fs_initcall, we need to defer
+ * full initialization of our devices until
+ * device_initcall.
+ */
+static int __init pcistub_init_devices_late(void)
+{
+	struct pci_stub_device *psdev, *t;
+	int err = 0;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry_safe(psdev, t, &seized_devices, dev_list) {
+		list_del(&psdev->dev_list);
+		err = pcistub_init_device(psdev->dev);
+		if (err) {
+			printk(KERN_ERR
+			       "pciback: %s error %d initializing device\n",
+			       pci_name(psdev->dev), err);
+			kfree(psdev);
+			continue;
+		}
+
+		list_add_tail(&psdev->dev_list, &pci_stub_devices);
+	}
+
+	initialize_devices = 1;
+
+	spin_unlock(&pci_stub_devices_lock);
+
+	return 0;
+}
+
+device_initcall(pcistub_init_devices_late);
+
+static int __devinit pcistub_seize(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+	int err = 0;
+
+	psdev = kmalloc(sizeof(*psdev), GFP_KERNEL);
+	if (!psdev)
+		return -ENOMEM;
+
+	psdev->dev = dev;
+	atomic_set(&psdev->in_use, 1);
+
+	spin_lock(&pci_stub_devices_lock);
+
+	if (initialize_devices) {
+		err = pcistub_init_device(psdev->dev);
+		if (err)
+			goto out;
+
+		list_add(&psdev->dev_list, &pci_stub_devices);
+	} else
+		list_add(&psdev->dev_list, &seized_devices);
+
+      out:
+	spin_unlock(&pci_stub_devices_lock);
+
+	if (err)
+		kfree(psdev);
+
+	return err;
+}
+
+static int __devinit pcistub_probe(struct pci_dev *dev,
+				   const struct pci_device_id *id)
+{
+	struct pci_stub_device_id *pdev_id;
+	struct pci_dev *seized_dev;
+	int err = 0;
+
+	list_for_each_entry(pdev_id, &pci_stub_device_ids, slot_list) {
+
+		if (!pcistub_match(dev, pdev_id))
+			continue;
+
+		if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
+		    && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
+			printk(KERN_ERR
+			       "pciback: %s: can't export pci devices that "
+			       "don't have a normal (0) or bridge (1) "
+			       "header type!\n", pci_name(dev));
+			break;
+		}
+
+		pr_info("pciback: seizing PCI device %s\n", pci_name(dev));
+		seized_dev = pci_dev_get(dev);
+
+		if (seized_dev) {
+			err = pcistub_seize(seized_dev);
+			if (err) {
+				pci_dev_put(dev);
+				goto out;
+			}
+
+			/* Success! */
+			goto out;
+		}
+	}
+
+	/* Didn't find the device */
+	err = -ENODEV;
+
+      out:
+	return err;
+}
+
+struct pci_device_id pcistub_ids[] = {
+	{
+	 .vendor = PCI_ANY_ID,
+	 .device = PCI_ANY_ID,
+	 .subvendor = PCI_ANY_ID,
+	 .subdevice = PCI_ANY_ID,
+	 },
+	{0,},
+};
+
+/*
+ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't
+ * for a normal device. I don't want it to be loaded automatically.
+ */
+
+struct pci_driver pciback_pci_driver = {
+	.name = "pciback",
+	.id_table = pcistub_ids,
+	.probe = pcistub_probe,
+};
+
+static int __init pcistub_init(void)
+{
+	int pos = 0;
+	struct pci_stub_device_id *pci_dev_id;
+	int err = 0;
+	int domain, bus, slot, func;
+	int parsed;
+
+	if (pci_devs_to_hide && *pci_devs_to_hide) {
+		do {
+			parsed = 0;
+
+			err = sscanf(pci_devs_to_hide + pos,
+				     " (%x:%x:%x.%x) %n",
+				     &domain, &bus, &slot, &func, &parsed);
+			if (err != 4) {
+				domain = 0;
+				err = sscanf(pci_devs_to_hide + pos,
+					     " (%x:%x.%x) %n",
+					     &bus, &slot, &func, &parsed);
+				if (err != 3)
+					goto parse_error;
+			}
+
+			pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
+			if (!pci_dev_id) {
+				err = -ENOMEM;
+				goto out;
+			}
+
+			pci_dev_id->domain = domain;
+			pci_dev_id->bus = bus;
+			pci_dev_id->devfn = PCI_DEVFN(slot, func);
+
+			pr_debug
+			    ("pciback: wants to seize %04x:%02x:%02x.%01x\n",
+			     domain, bus, slot, func);
+
+			list_add_tail(&pci_dev_id->slot_list,
+				      &pci_stub_device_ids);
+
+			/* if parsed<=0, we've reached the end of the string */
+			pos += parsed;
+		} while (parsed > 0 && pci_devs_to_hide[pos]);
+
+		/* If we're the first PCI Device Driver to register, we're the
+		 * first one to get offered PCI devices as they become
+		 * available (and thus we can be the first to grab them)
+		 */
+		pci_register_driver(&pciback_pci_driver);
+	}
+
+      out:
+	return err;
+
+      parse_error:
+	printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n",
+	       pci_devs_to_hide + pos);
+	return -EINVAL;
+}
+
+/*
+ * fs_initcall happens before device_initcall
+ * so pciback *should* get called first (b/c we 
+ * want to suck up any device before other drivers
+ * get a chance by being the first pci device
+ * driver to register)
+ */
+fs_initcall(pcistub_init);
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,73 @@
+/*
+ * PCI Backend Common Data Structures & Function Declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCIBACK_H__
+#define __XEN_PCIBACK_H__
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <xen/xenbus.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <xen/interface/io/pciif.h>
+
+struct pci_dev_entry {
+	struct list_head list;
+	struct pci_dev *dev;
+};
+
+struct pciback_device {
+	void *pci_dev_data;
+	spinlock_t dev_lock;
+
+	struct xenbus_device *xdev;
+
+	struct xenbus_watch be_watch;
+	u8 be_watching;
+
+	int evtchn_irq;
+
+	struct xen_pci_sharedinfo *sh_info;
+};
+
+struct pciback_dev_data {
+	struct list_head config_fields;
+};
+
+/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
+					    int slot, int func);
+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev);
+void pcistub_put_pci_dev(struct pci_dev *dev);
+
+/* Ensure a device is turned off or reset */
+void pciback_disable_device(struct pci_dev *dev);
+void pciback_reset_device(struct pci_dev *pdev);
+
+/* Access a virtual configuration space for a PCI device */
+int pciback_config_init(struct pci_dev *dev);
+void pciback_config_reset(struct pci_dev *dev);
+void pciback_config_free(struct pci_dev *dev);
+int pciback_config_read(struct pci_dev *dev, int offset, int size,
+			u32 * ret_val);
+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
+
+/* Handle requests for specific devices from the frontend */
+typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
+				    unsigned int domain, unsigned int bus);
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn);
+int pciback_init_devices(struct pciback_device *pdev);
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb cb);
+void pciback_release_devices(struct pciback_device *pdev);
+
+/* Handles events from front-end */
+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
+
+extern int verbose_request;
+#endif
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,84 @@
+/*
+ * PCI Backend Operations - respond to PCI requests from Frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <asm/bitops.h>
+#include "pciback.h"
+
+int verbose_request = 0;
+module_param(verbose_request, int, 0644);
+
+/* For those architectures without a pcibios_disable_device */
+void __attribute__ ((weak)) pcibios_disable_device(struct pci_dev *dev) { }
+
+void pciback_disable_device(struct pci_dev *dev)
+{
+	if (dev->is_enabled) {
+		dev->is_enabled = 0;
+		pcibios_disable_device(dev);
+	}
+}
+
+/* Ensure a device is "turned off" and ready to be exported.
+ * This also sets up the device's private data to keep track of what should
+ * be in the base address registers (BARs) so that we can keep the
+ * client from manipulating them directly.
+ */
+void pciback_reset_device(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	/* Disable devices (but not bridges) */
+	if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
+		pciback_disable_device(dev);
+
+		pci_write_config_word(dev, PCI_COMMAND, 0);
+
+		dev->is_enabled = 0;
+		dev->is_busmaster = 0;
+	} else {
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		if (cmd & (PCI_COMMAND_INVALIDATE)) {
+			cmd &= ~(PCI_COMMAND_INVALIDATE);
+			pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+			dev->is_busmaster = 0;
+		}
+	}
+
+	pciback_config_reset(dev);
+}
+
+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pciback_device *pdev = dev_id;
+	struct pci_dev *dev;
+	struct xen_pci_op *op = &pdev->sh_info->op;
+
+	if (unlikely(!test_bit(_XEN_PCIF_active,
+			       (unsigned long *)&pdev->sh_info->flags))) {
+		pr_debug("pciback: interrupt, but no active operation\n");
+		goto out;
+	}
+
+	dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
+
+	if (dev == NULL)
+		op->err = XEN_PCI_ERR_dev_not_found;
+	else if (op->cmd == XEN_PCI_OP_conf_read)
+		op->err = pciback_config_read(dev, op->offset, op->size,
+					      &op->value);
+	else if (op->cmd == XEN_PCI_OP_conf_write)
+		op->err = pciback_config_write(dev, op->offset, op->size,
+					       op->value);
+	else
+		op->err = XEN_PCI_ERR_not_implemented;
+
+	wmb();
+	clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+
+      out:
+	return IRQ_HANDLED;
+}
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,163 @@
+/*
+ * PCI Backend - Provides a Virtual PCI bus (with real devices)
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include "pciback.h"
+
+#define PCI_SLOT_MAX 32
+
+struct vpci_dev_data {
+	struct list_head dev_list[PCI_SLOT_MAX];
+};
+
+static inline struct list_head *list_first(struct list_head *head)
+{
+	return head->next;
+}
+
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn)
+{
+	struct pci_dev_entry *dev_entry;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	if (domain != 0 || bus != 0)
+		return NULL;
+
+	if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
+		/* we don't need to lock the list here because once the backend
+		 * is in operation, it won't have any more devices addeded
+		 * (or removed).
+		 */
+		list_for_each_entry(dev_entry,
+				    &vpci_dev->dev_list[PCI_SLOT(devfn)],
+				    list) {
+			if (PCI_FUNC(dev_entry->dev->devfn) == PCI_FUNC(devfn))
+				return dev_entry->dev;
+		}
+	}
+	return NULL;
+}
+
+static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
+{
+	if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
+	    && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn))
+		return 1;
+
+	return 0;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+	int err = 0, slot;
+	struct pci_dev_entry *t, *dev_entry;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
+		err = -EFAULT;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Can't export bridges on the virtual PCI bus");
+		goto out;
+	}
+
+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
+	if (!dev_entry) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error adding entry to virtual PCI bus");
+		goto out;
+	}
+
+	dev_entry->dev = dev;
+
+	/* Keep multi-function devices together on the virtual PCI bus */
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		if (!list_empty(&vpci_dev->dev_list[slot])) {
+			t = list_entry(list_first(&vpci_dev->dev_list[slot]),
+				       struct pci_dev_entry, list);
+
+			if (match_slot(dev, t->dev)) {
+				pr_info("pciback: vpci: %s: "
+					"assign to virtual slot %d func %d\n",
+					pci_name(dev), slot,
+					PCI_FUNC(dev->devfn));
+				list_add_tail(&dev_entry->list,
+					      &vpci_dev->dev_list[slot]);
+				goto out;
+			}
+		}
+	}
+
+	/* Assign to a new slot on the virtual PCI bus */
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		if (list_empty(&vpci_dev->dev_list[slot])) {
+			printk(KERN_INFO
+			       "pciback: vpci: %s: assign to virtual slot %d\n",
+			       pci_name(dev), slot);
+			list_add_tail(&dev_entry->list,
+				      &vpci_dev->dev_list[slot]);
+			goto out;
+		}
+	}
+
+	err = -ENOMEM;
+	xenbus_dev_fatal(pdev->xdev, err,
+			 "No more space on root virtual PCI bus");
+
+      out:
+	return err;
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+	int slot;
+	struct vpci_dev_data *vpci_dev;
+
+	vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
+	if (!vpci_dev)
+		return -ENOMEM;
+
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
+	}
+
+	pdev->pci_dev_data = vpci_dev;
+
+	return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb publish_cb)
+{
+	/* The Virtual PCI bus has only one root */
+	return publish_cb(pdev, 0, 0);
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+	int slot;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		struct pci_dev_entry *e, *tmp;
+		list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
+					 list) {
+			list_del(&e->list);
+			pcistub_put_pci_dev(e->dev);
+			kfree(e);
+		}
+	}
+
+	kfree(vpci_dev);
+	pdev->pci_dev_data = NULL;
+}
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,439 @@
+/*
+ * PCI Backend Xenbus Setup - handles setup with frontend and xend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <xen/xenbus.h>
+#include <xen/evtchn.h>
+#include "pciback.h"
+
+#define INVALID_EVTCHN_IRQ  (-1)
+
+struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
+{
+	struct pciback_device *pdev;
+
+	pdev = kmalloc(sizeof(struct pciback_device), GFP_KERNEL);
+	if (pdev == NULL)
+		goto out;
+	dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
+
+	pdev->xdev = xdev;
+	xdev->data = pdev;
+
+	spin_lock_init(&pdev->dev_lock);
+
+	pdev->sh_info = NULL;
+	pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
+	pdev->be_watching = 0;
+
+	if (pciback_init_devices(pdev)) {
+		kfree(pdev);
+		pdev = NULL;
+	}
+      out:
+	return pdev;
+}
+
+void free_pdev(struct pciback_device *pdev)
+{
+	if (pdev->be_watching)
+		unregister_xenbus_watch(&pdev->be_watch);
+
+	/* Ensure the guest can't trigger our handler before removing devices */
+	if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ)
+		unbind_from_irqhandler(pdev->evtchn_irq, pdev);
+
+	if (pdev->sh_info)
+		xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
+
+	pciback_release_devices(pdev);
+
+	pdev->xdev->data = NULL;
+	pdev->xdev = NULL;
+
+	kfree(pdev);
+}
+
+static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
+			     int remote_evtchn)
+{
+	int err = 0;
+	int evtchn;
+	dev_dbg(&pdev->xdev->dev,
+		"Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
+		gnt_ref, remote_evtchn);
+
+	err =
+	    xenbus_map_ring_valloc(pdev->xdev, gnt_ref,
+				   (void **)&pdev->sh_info);
+	if (err)
+		goto out;
+
+	err = xenbus_bind_evtchn(pdev->xdev, remote_evtchn, &evtchn);
+	if (err)
+		goto out;
+
+	err = bind_evtchn_to_irqhandler(evtchn, pciback_handle_event,
+					SA_SAMPLE_RANDOM, "pciback", pdev);
+	if (err < 0) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error binding event channel to IRQ");
+		goto out;
+	}
+	pdev->evtchn_irq = err;
+	err = 0;
+
+	dev_dbg(&pdev->xdev->dev, "Attached!\n");
+      out:
+	return err;
+}
+
+static int pciback_attach(struct pciback_device *pdev)
+{
+	int err = 0;
+	int gnt_ref, remote_evtchn;
+	char *magic = NULL;
+
+	spin_lock(&pdev->dev_lock);
+
+	/* Make sure we only do this setup once */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	/* Wait for frontend to state that it has published the configuration */
+	if (xenbus_read_driver_state(pdev->xdev->otherend) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
+
+	err = xenbus_gather(XBT_NULL, pdev->xdev->otherend,
+			    "pci-op-ref", "%u", &gnt_ref,
+			    "event-channel", "%u", &remote_evtchn,
+			    "magic", NULL, &magic, NULL);
+	if (err) {
+		/* If configuration didn't get read correctly, wait longer */
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading configuration from frontend");
+		goto out;
+	}
+
+	if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
+		xenbus_dev_fatal(pdev->xdev, -EFAULT,
+				 "version mismatch (%s/%s) with pcifront - "
+				 "halting pciback",
+				 magic, XEN_PCI_MAGIC);
+		goto out;
+	}
+
+	err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
+	if (err)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "Connecting...\n");
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
+	if (err)
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error switching to connected state!");
+
+	dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
+      out:
+	spin_unlock(&pdev->dev_lock);
+
+	if (magic)
+		kfree(magic);
+
+	return err;
+}
+
+static void pciback_frontend_changed(struct xenbus_device *xdev,
+				     XenbusState fe_state)
+{
+	struct pciback_device *pdev = xdev->data;
+
+	dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
+
+	switch (fe_state) {
+	case XenbusStateInitialised:
+		pciback_attach(pdev);
+		break;
+
+	case XenbusStateClosing:
+		xenbus_switch_state(xdev, XBT_NULL, XenbusStateClosing);
+		break;
+
+	case XenbusStateClosed:
+		dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
+		device_unregister(&xdev->dev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pciback_publish_pci_root(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus)
+{
+	unsigned int d, b;
+	int i, root_num, len, err;
+	char str[64];
+
+	dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
+			   "root_num", "%d", &root_num);
+	if (err == 0 || err == -ENOENT)
+		root_num = 0;
+	else if (err < 0)
+		goto out;
+
+	/* Verify that we haven't already published this pci root */
+	for (i = 0; i < root_num; i++) {
+		len = snprintf(str, sizeof(str), "root-%d", i);
+		if (unlikely(len >= (sizeof(str) - 1))) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
+				   str, "%x:%x", &d, &b);
+		if (err < 0)
+			goto out;
+		if (err != 2) {
+			err = -EINVAL;
+			goto out;
+		}
+
+		if (d == domain && b == bus) {
+			err = 0;
+			goto out;
+		}
+	}
+
+	len = snprintf(str, sizeof(str), "root-%d", root_num);
+	if (unlikely(len >= (sizeof(str) - 1))) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
+		root_num, domain, bus);
+
+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename, str,
+			    "%04x:%02x", domain, bus);
+	if (err)
+		goto out;
+
+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename,
+			    "root_num", "%d", (root_num + 1));
+
+      out:
+	return err;
+}
+
+static int pciback_export_device(struct pciback_device *pdev,
+				 int domain, int bus, int slot, int func)
+{
+	struct pci_dev *dev;
+	int err = 0;
+
+	dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
+		domain, bus, slot, func);
+
+	dev = pcistub_get_pci_dev_by_slot(domain, bus, slot, func);
+	if (!dev) {
+		err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Couldn't locate PCI device "
+				 "(%04x:%02x:%02x.%01x)! "
+				 "perhaps already in-use?",
+				 domain, bus, slot, func);
+		goto out;
+	}
+
+	err = pciback_add_pci_dev(pdev, dev);
+	if (err)
+		goto out;
+
+	/* TODO: It'd be nice to export a bridge and have all of its children
+	 * get exported with it. This may be best done in xend (which will
+	 * have to calculate resource usage anyway) but we probably want to
+	 * put something in here to ensure that if a bridge gets given to a
+	 * driver domain, that all devices under that bridge are not given
+	 * to other driver domains (as he who controls the bridge can disable
+	 * it and stop the other devices from working).
+	 */
+      out:
+	return err;
+}
+
+static int pciback_setup_backend(struct pciback_device *pdev)
+{
+	/* Get configuration from xend (if available now) */
+	int domain, bus, slot, func;
+	int err = 0;
+	int i, num_devs;
+	char dev_str[64];
+
+	spin_lock(&pdev->dev_lock);
+
+	/* It's possible we could get the call to setup twice, so make sure
+	 * we're not already connected.
+	 */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitWait)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "getting be setup\n");
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, "num_devs", "%d",
+			   &num_devs);
+	if (err != 1) {
+		if (err >= 0)
+			err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading number of devices");
+		goto out;
+	}
+
+	for (i = 0; i < num_devs; i++) {
+		int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
+		if (unlikely(l >= (sizeof(dev_str) - 1))) {
+			err = -ENOMEM;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "String overflow while reading "
+					 "configuration");
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, dev_str,
+				   "%x:%x:%x.%x", &domain, &bus, &slot, &func);
+		if (err < 0) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error reading device configuration");
+			goto out;
+		}
+		if (err != 4) {
+			err = -EINVAL;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error parsing pci device "
+					 "configuration");
+			goto out;
+		}
+
+		err = pciback_export_device(pdev, domain, bus, slot, func);
+		if (err)
+			goto out;
+	}
+
+	err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error while publish PCI root buses "
+				 "for frontend");
+		goto out;
+	}
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateInitialised);
+	if (err)
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error switching to initialised state!");
+
+      out:
+	spin_unlock(&pdev->dev_lock);
+
+	if (!err)
+		/* see if pcifront is already configured (if not, we'll wait) */
+		pciback_attach(pdev);
+
+	return err;
+}
+
+static void pciback_be_watch(struct xenbus_watch *watch,
+			     const char **vec, unsigned int len)
+{
+	struct pciback_device *pdev =
+	    container_of(watch, struct pciback_device, be_watch);
+
+	switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
+	case XenbusStateInitWait:
+		pciback_setup_backend(pdev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pciback_xenbus_probe(struct xenbus_device *dev,
+				const struct xenbus_device_id *id)
+{
+	int err = 0;
+	struct pciback_device *pdev = alloc_pdev(dev);
+
+	if (pdev == NULL) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(dev, err,
+				 "Error allocating pciback_device struct");
+		goto out;
+	}
+
+	/* wait for xend to configure us */
+	err = xenbus_switch_state(dev, XBT_NULL, XenbusStateInitWait);
+	if (err)
+		goto out;
+
+	/* watch the backend node for backend configuration information */
+	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
+				pciback_be_watch);
+	if (err)
+		goto out;
+	pdev->be_watching = 1;
+
+	/* We need to force a call to our callback here in case
+	 * xend already configured us!
+	 */
+	pciback_be_watch(&pdev->be_watch, NULL, 0);
+
+      out:
+	return err;
+}
+
+static int pciback_xenbus_remove(struct xenbus_device *dev)
+{
+	struct pciback_device *pdev = dev->data;
+
+	if (pdev != NULL)
+		free_pdev(pdev);
+
+	return 0;
+}
+
+static struct xenbus_device_id xenpci_ids[] = {
+	{"pci"},
+	{{0}},
+};
+
+static struct xenbus_driver xenbus_pciback_driver = {
+	.name 			= "pciback",
+	.owner 			= THIS_MODULE,
+	.ids 			= xenpci_ids,
+	.probe 			= pciback_xenbus_probe,
+	.remove 		= pciback_xenbus_remove,
+	.otherend_changed 	= pciback_frontend_changed,
+};
+
+static __init int pciback_xenbus_register(void)
+{
+	return xenbus_register_backend(&xenbus_pciback_driver);
+}
+
+/* Must only initialize our xenbus driver after the pcistub driver */
+device_initcall(pciback_xenbus_register);
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,7 @@
+obj-y += pcifront.o
+
+pcifront-y := pci_op.o xenbus.o pci.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,44 @@
+/*
+ * PCI Frontend Operations - ensure only one PCI frontend runs at a time
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include "pcifront.h"
+
+DEFINE_SPINLOCK(pcifront_dev_lock);
+static struct pcifront_device *pcifront_dev = NULL;
+
+int pcifront_connect(struct pcifront_device *pdev)
+{
+	int err = 0;
+
+	spin_lock(&pcifront_dev_lock);
+
+	if (!pcifront_dev)
+		dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
+	else {
+		dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
+		err = -EEXIST;
+	}
+
+	spin_unlock(&pcifront_dev_lock);
+
+	return err;
+}
+
+void pcifront_disconnect(struct pcifront_device *pdev)
+{
+	spin_lock(&pcifront_dev_lock);
+
+	if (pdev == pcifront_dev) {
+		dev_info(&pdev->xdev->dev,
+			 "Disconnecting PCI Frontend Buses\n");
+		pcifront_dev = NULL;
+	}
+
+	spin_unlock(&pcifront_dev_lock);
+}
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,245 @@
+/*
+ * PCI Frontend Operations - Communicates with frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <xen/evtchn.h>
+#include "pcifront.h"
+
+static int verbose_request = 0;
+module_param(verbose_request, int, 0644);
+
+static int errno_to_pcibios_err(int errno)
+{
+	switch (errno) {
+	case XEN_PCI_ERR_success:
+		return PCIBIOS_SUCCESSFUL;
+
+	case XEN_PCI_ERR_dev_not_found:
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	case XEN_PCI_ERR_invalid_offset:
+	case XEN_PCI_ERR_op_failed:
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	case XEN_PCI_ERR_not_implemented:
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+	case XEN_PCI_ERR_access_denied:
+		return PCIBIOS_SET_FAILED;
+	}
+	return errno;
+}
+
+static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
+{
+	int err = 0;
+	struct xen_pci_op *active_op = &pdev->sh_info->op;
+	unsigned long irq_flags;
+
+	unsigned int volatile ttl = (1U << 29);
+
+	spin_lock_irqsave(&pdev->sh_info_lock, irq_flags);
+
+	memcpy(active_op, op, sizeof(struct xen_pci_op));
+
+	/* Go */
+	wmb();
+	set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+	notify_remote_via_evtchn(pdev->evtchn);
+
+	/* IRQs are disabled for the pci config. space reads/writes,
+	 * which means no event channel to notify us that the backend
+	 * is done so spin while waiting for the answer */
+	while (test_bit
+	       (_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)) {
+		if (!ttl) {
+			dev_err(&pdev->xdev->dev,
+				"pciback not responding!!!\n");
+			clear_bit(_XEN_PCIF_active,
+				  (unsigned long *)&pdev->sh_info->flags);
+			err = XEN_PCI_ERR_dev_not_found;
+			goto out;
+		}
+		ttl--;
+	}
+
+	memcpy(op, active_op, sizeof(struct xen_pci_op));
+
+	err = op->err;
+      out:
+	spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags);
+	return err;
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
+			     int where, int size, u32 * val)
+{
+	int err = 0;
+	struct xen_pci_op op = {
+		.cmd    = XEN_PCI_OP_conf_read,
+		.domain = pci_domain_nr(bus),
+		.bus    = bus->number,
+		.devfn  = devfn,
+		.offset = where,
+		.size   = size,
+	};
+	struct pcifront_sd *sd = bus->sysdata;
+	struct pcifront_device *pdev = sd->pdev;
+
+	if (verbose_request)
+		dev_info(&pdev->xdev->dev,
+			 "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n",
+			 pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
+			 PCI_FUNC(devfn), where, size);
+
+	err = do_pci_op(pdev, &op);
+
+	if (likely(!err)) {
+		if (verbose_request)
+			dev_info(&pdev->xdev->dev, "read got back value %x\n",
+				 op.value);
+
+		*val = op.value;
+	} else if (err == -ENODEV) {
+		/* No device here, pretend that it just returned 0 */
+		err = 0;
+		*val = 0;
+	}
+
+	return errno_to_pcibios_err(err);
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
+			      int where, int size, u32 val)
+{
+	struct xen_pci_op op = {
+		.cmd    = XEN_PCI_OP_conf_write,
+		.domain = pci_domain_nr(bus),
+		.bus    = bus->number,
+		.devfn  = devfn,
+		.offset = where,
+		.size   = size,
+		.value  = val,
+	};
+	struct pcifront_sd *sd = bus->sysdata;
+	struct pcifront_device *pdev = sd->pdev;
+
+	if (verbose_request)
+		dev_info(&pdev->xdev->dev,
+			 "write dev=%04x:%02x:%02x.%01x - "
+			 "offset %x size %d val %x\n",
+			 pci_domain_nr(bus), bus->number,
+			 PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
+
+	return errno_to_pcibios_err(do_pci_op(pdev, &op));
+}
+
+struct pci_ops pcifront_bus_ops = {
+	.read = pcifront_bus_read,
+	.write = pcifront_bus_write,
+};
+
+/* Claim resources for the PCI frontend as-is, backend won't allow changes */
+static void pcifront_claim_resource(struct pci_dev *dev, void *data)
+{
+	struct pcifront_device *pdev = data;
+	int i;
+	struct resource *r;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		r = &dev->resource[i];
+
+		if (!r->parent && r->start && r->flags) {
+			dev_dbg(&pdev->xdev->dev, "claiming resource %s/%d\n",
+					pci_name(dev), i);
+			pci_claim_resource(dev, i);
+		}
+	}
+}
+
+int pcifront_scan_root(struct pcifront_device *pdev,
+		       unsigned int domain, unsigned int bus)
+{
+	struct pci_bus *b;
+	struct pcifront_sd *sd = NULL;
+	struct pci_bus_entry *bus_entry = NULL;
+	int err = 0;
+
+#ifndef CONFIG_PCI_DOMAINS
+	if (domain != 0) {
+		dev_err(&pdev->xdev->dev,
+			"PCI Root in non-zero PCI Domain! domain=%d\n", domain);
+		dev_err(&pdev->xdev->dev,
+			"Please compile with CONFIG_PCI_DOMAINS\n");
+		err = -EINVAL;
+		goto err_out;
+	}
+#endif
+
+	dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
+		 domain, bus);
+
+	bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
+	sd = kmalloc(sizeof(*sd), GFP_KERNEL);
+	if (!bus_entry || !sd) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+	sd->domain = domain;
+	sd->pdev = pdev;
+
+	b = pci_scan_bus_parented(&pdev->xdev->dev, bus, &pcifront_bus_ops, sd);
+	if (!b) {
+		dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+	bus_entry->bus = b;
+
+	list_add(&bus_entry->list, &pdev->root_buses);
+
+	/* Claim resources before going "live" with our devices */
+	pci_walk_bus(b, pcifront_claim_resource, pdev);
+
+	pci_bus_add_devices(b);
+
+	return 0;
+
+      err_out:
+	kfree(bus_entry);
+	kfree(sd);
+
+	return err;
+}
+
+void pcifront_free_roots(struct pcifront_device *pdev)
+{
+	struct pci_bus_entry *bus_entry, *t;
+
+	list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
+		/* TODO: Removing a PCI Bus is untested (as it normally
+		 * just goes away on domain shutdown)
+		 */
+		list_del(&bus_entry->list);
+
+		spin_lock(&pci_bus_lock);
+		list_del(&bus_entry->bus->node);
+		spin_unlock(&pci_bus_lock);
+
+		kfree(bus_entry->bus->sysdata);
+
+		device_unregister(bus_entry->bus->bridge);
+
+		/* Do we need to free() the bus itself? */
+
+		kfree(bus_entry);
+	}
+}
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,40 @@
+/*
+ * PCI Frontend - Common data structures & function declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCIFRONT_H__
+#define __XEN_PCIFRONT_H__
+
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <xen/xenbus.h>
+#include <xen/interface/io/pciif.h>
+#include <xen/pcifront.h>
+
+struct pci_bus_entry {
+	struct list_head list;
+	struct pci_bus *bus;
+};
+
+struct pcifront_device {
+	struct xenbus_device *xdev;
+	struct list_head root_buses;
+	spinlock_t dev_lock;
+
+	int evtchn;
+	int gnt_ref;
+
+	/* Lock this when doing any operations in sh_info */
+	spinlock_t sh_info_lock;
+	struct xen_pci_sharedinfo *sh_info;
+};
+
+int pcifront_connect(struct pcifront_device *pdev);
+void pcifront_disconnect(struct pcifront_device *pdev);
+
+int pcifront_scan_root(struct pcifront_device *pdev,
+		       unsigned int domain, unsigned int bus);
+void pcifront_free_roots(struct pcifront_device *pdev);
+
+#endif	/* __XEN_PCIFRONT_H__ */
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,295 @@
+/*
+ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn)
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <xen/xenbus.h>
+#include "pcifront.h"
+
+#define INVALID_GRANT_REF (0)
+#define INVALID_EVTCHN    (-1)
+
+static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
+{
+	struct pcifront_device *pdev;
+
+	pdev = kmalloc(sizeof(struct pcifront_device), GFP_KERNEL);
+	if (pdev == NULL)
+		goto out;
+
+	pdev->sh_info =
+	    (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
+	if (pdev->sh_info == NULL) {
+		kfree(pdev);
+		pdev = NULL;
+		goto out;
+	}
+	pdev->sh_info->flags = 0;
+
+	xdev->data = pdev;
+	pdev->xdev = xdev;
+
+	INIT_LIST_HEAD(&pdev->root_buses);
+
+	spin_lock_init(&pdev->dev_lock);
+	spin_lock_init(&pdev->sh_info_lock);
+
+	pdev->evtchn = INVALID_EVTCHN;
+	pdev->gnt_ref = INVALID_GRANT_REF;
+
+	dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n",
+		pdev, pdev->sh_info);
+      out:
+	return pdev;
+}
+
+static void free_pdev(struct pcifront_device *pdev)
+{
+	dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev);
+
+	if (pdev->evtchn != INVALID_EVTCHN)
+		xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
+
+	if (pdev->gnt_ref != INVALID_GRANT_REF)
+		gnttab_end_foreign_access(pdev->gnt_ref, 0,
+					  (unsigned long)pdev->sh_info);
+
+	pdev->xdev->data = NULL;
+
+	kfree(pdev);
+}
+
+static int pcifront_publish_info(struct pcifront_device *pdev)
+{
+	int err = 0;
+	xenbus_transaction_t trans;
+
+	err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info));
+	if (err < 0)
+		goto out;
+
+	pdev->gnt_ref = err;
+
+	err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
+	if (err)
+		goto out;
+
+      do_publish:
+	err = xenbus_transaction_start(&trans);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error writing configuration for backend "
+				 "(start transaction)");
+		goto out;
+	}
+
+	err = xenbus_printf(trans, pdev->xdev->nodename,
+			    "pci-op-ref", "%u", pdev->gnt_ref);
+	if (!err)
+		err = xenbus_printf(trans, pdev->xdev->nodename,
+				    "event-channel", "%u", pdev->evtchn);
+	if (!err)
+		err = xenbus_printf(trans, pdev->xdev->nodename,
+				    "magic", XEN_PCI_MAGIC);
+	if (!err)
+		err =
+		    xenbus_switch_state(pdev->xdev, trans,
+					XenbusStateInitialised);
+
+	if (err) {
+		xenbus_transaction_end(trans, 1);
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error writing configuration for backend");
+		goto out;
+	} else {
+		err = xenbus_transaction_end(trans, 0);
+		if (err == -EAGAIN)
+			goto do_publish;
+		else if (err) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error completing transaction "
+					 "for backend");
+			goto out;
+		}
+	}
+
+	dev_dbg(&pdev->xdev->dev, "publishing successful!\n");
+
+      out:
+	return err;
+}
+
+static int pcifront_try_connect(struct pcifront_device *pdev)
+{
+	int err = -EFAULT;
+	int i, num_roots, len;
+	char str[64];
+	unsigned int domain, bus;
+
+	spin_lock(&pdev->dev_lock);
+
+	/* Only connect once */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	err = pcifront_connect(pdev);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error connecting PCI Frontend");
+		goto out;
+	}
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend,
+			   "root_num", "%d", &num_roots);
+	if (err == -ENOENT) {
+		xenbus_dev_error(pdev->xdev, err,
+				 "No PCI Roots found, trying 0000:00");
+		err = pcifront_scan_root(pdev, 0, 0);
+		num_roots = 0;
+	} else if (err != 1) {
+		if (err == 0)
+			err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading number of PCI roots");
+		goto out;
+	}
+
+	for (i = 0; i < num_roots; i++) {
+		len = snprintf(str, sizeof(str), "root-%d", i);
+		if (unlikely(len >= (sizeof(str) - 1))) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend, str,
+				   "%x:%x", &domain, &bus);
+		if (err != 2) {
+			if (err >= 0)
+				err = -EINVAL;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error reading PCI root %d", i);
+			goto out;
+		}
+
+		err = pcifront_scan_root(pdev, domain, bus);
+		if (err) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error scanning PCI root %04x:%02x",
+					 domain, bus);
+			goto out;
+		}
+	}
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
+	if (err)
+		goto out;
+
+      out:
+	spin_unlock(&pdev->dev_lock);
+	return err;
+}
+
+static int pcifront_try_disconnect(struct pcifront_device *pdev)
+{
+	int err = 0;
+	XenbusState prev_state;
+
+	spin_lock(&pdev->dev_lock);
+
+	prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
+
+	if (prev_state < XenbusStateClosing)
+		err = xenbus_switch_state(pdev->xdev, XBT_NULL,
+					XenbusStateClosing);
+
+	if (!err && prev_state == XenbusStateConnected)
+		pcifront_disconnect(pdev);
+
+	spin_unlock(&pdev->dev_lock);
+
+	return err;
+}
+
+static void pcifront_backend_changed(struct xenbus_device *xdev,
+				     XenbusState be_state)
+{
+	struct pcifront_device *pdev = xdev->data;
+
+	switch (be_state) {
+	case XenbusStateClosing:
+		dev_warn(&xdev->dev, "backend going away!\n");
+		pcifront_try_disconnect(pdev);
+		break;
+
+	case XenbusStateClosed:
+		dev_warn(&xdev->dev, "backend went away!\n");
+		pcifront_try_disconnect(pdev);
+
+		device_unregister(&pdev->xdev->dev);
+		break;
+
+	case XenbusStateConnected:
+		pcifront_try_connect(pdev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pcifront_xenbus_probe(struct xenbus_device *xdev,
+				 const struct xenbus_device_id *id)
+{
+	int err = 0;
+	struct pcifront_device *pdev = alloc_pdev(xdev);
+
+	if (pdev == NULL) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(xdev, err,
+				 "Error allocating pcifront_device struct");
+		goto out;
+	}
+
+	err = pcifront_publish_info(pdev);
+
+      out:
+	return err;
+}
+
+static int pcifront_xenbus_remove(struct xenbus_device *xdev)
+{
+	if (xdev->data)
+		free_pdev(xdev->data);
+
+	return 0;
+}
+
+static struct xenbus_device_id xenpci_ids[] = {
+	{"pci"},
+	{{0}},
+};
+
+static struct xenbus_driver xenbus_pcifront_driver = {
+	.name 			= "pcifront",
+	.owner 			= THIS_MODULE,
+	.ids 			= xenpci_ids,
+	.probe 			= pcifront_xenbus_probe,
+	.remove 		= pcifront_xenbus_remove,
+	.otherend_changed 	= pcifront_backend_changed,
+};
+
+static int __init pcifront_init(void)
+{
+	int err = 0;
+
+	err = xenbus_register_frontend(&xenbus_pcifront_driver);
+
+	return err;
+}
+
+/* Initialize after the Xen PCI Frontend Stub is initialized */
+subsys_initcall(pcifront_init);
diff -r 55268b90a519 -r df275977573e linux-2.6-xen-sparse/include/xen/pcifront.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/include/xen/pcifront.h	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,39 @@
+/*
+ * PCI Frontend - arch-dependendent declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_ASM_PCIFRONT_H__
+#define __XEN_ASM_PCIFRONT_H__
+
+#include <linux/config.h>
+#include <linux/spinlock.h>
+
+#ifdef __KERNEL__
+
+struct pcifront_device;
+
+struct pcifront_sd {
+	int domain;
+	struct pcifront_device *pdev;
+};
+
+struct pci_bus;
+
+#ifdef CONFIG_PCI_DOMAINS
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+	struct pcifront_sd *sd = bus->sysdata;
+	return sd->domain;
+}
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+	return pci_domain_nr(bus);
+}
+#endif /* CONFIG_PCI_DOMAINS */
+
+extern spinlock_t pci_bus_lock;
+
+#endif /* __KERNEL__ */
+
+#endif /* __XEN_ASM_PCIFRONT_H__ */
diff -r 55268b90a519 -r df275977573e xen/include/public/io/pciif.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/xen/include/public/io/pciif.h	Tue Feb  7 20:10:43 2006
@@ -0,0 +1,55 @@
+/*
+ * PCI Backend/Frontend Common Data Structures & Macros
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCI_COMMON_H__
+#define __XEN_PCI_COMMON_H__
+
+/* Be sure to bump this number if you change this file */
+#define XEN_PCI_MAGIC		"7"
+
+/* xen_pci_sharedinfo flags */
+#define _XEN_PCIF_active     (0)
+#define XEN_PCIF_active      (1<<_XEN_PCI_active)
+
+/* xen_pci_op commands */
+#define XEN_PCI_OP_conf_read    (0)
+#define XEN_PCI_OP_conf_write   (1)
+
+/* xen_pci_op error numbers */
+#define XEN_PCI_ERR_success          (0)
+#define XEN_PCI_ERR_dev_not_found   (-1)
+#define XEN_PCI_ERR_invalid_offset  (-2)
+#define XEN_PCI_ERR_access_denied   (-3)
+#define XEN_PCI_ERR_not_implemented (-4)
+/* XEN_PCI_ERR_op_failed - backend failed to complete the operation */
+#define XEN_PCI_ERR_op_failed       (-5)
+
+struct xen_pci_op {
+	/* IN: what action to perform: XEN_PCI_OP_* */
+	uint32_t cmd;
+
+	/* OUT: will contain an error number (if any) from errno.h */
+	int32_t err;
+
+	/* IN: which device to touch */
+	uint32_t domain; /* PCI Domain/Segment */
+	uint32_t bus;
+	uint32_t devfn;
+
+	/* IN: which configuration registers to touch */
+	int32_t offset;
+	int32_t size;
+
+	/* IN/OUT: Contains the result after a READ or the value to WRITE */
+	uint32_t value;
+};
+
+struct xen_pci_sharedinfo {
+	/* flags - XEN_PCIF_* */
+	uint32_t flags;
+	struct xen_pci_op op;
+};
+
+#endif /* __XEN_PCI_COMMON_H__ */

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
  2006-02-07 19:58         ` Ryan
@ 2006-02-07 23:17           ` Keir Fraser
  2006-02-08 17:36             ` Ryan
  0 siblings, 1 reply; 15+ messages in thread
From: Keir Fraser @ 2006-02-07 23:17 UTC (permalink / raw)
  To: Ryan; +Cc: xen-devel


On 7 Feb 2006, at 19:58, Ryan wrote:

> One issue with this patch (at least the frontend part of it) is that it
> will probably only work correctly with x86 (I don't have access to 
> other
> architectures to test on) and the kconfig menu entries will appear
> regardless of the architecture (they don't list x86 as a dependency).
> Should they list x86 as a dependency? Right now, they're under the 
> "Xen"
> menu with the other backends and frontends. Should I move the PCI
> frontend configuration option into the "Bus options/PCI Access" menu
> next to the mmconfig, direct, and bios options? I think it would be
> better placed under the "Bus options/PCI Access" menu but I wasn't sure
> if all the backends and frontends needed to be listed together.

By x86 you mean i386 and x86_64? I guess it makes sense to list X86 as 
a dependency for now. And yes, I think 'Bus Options/PCI Access' is the 
correct place to place the pci frontend option. Maybe call the option 
'Xen PCI channel' or something like that?

  -- Keir

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
  2006-02-07 23:17           ` Keir Fraser
@ 2006-02-08 17:36             ` Ryan
  0 siblings, 0 replies; 15+ messages in thread
From: Ryan @ 2006-02-08 17:36 UTC (permalink / raw)
  To: Keir Fraser; +Cc: xen-devel

[-- Attachment #1: Type: text/plain, Size: 1456 bytes --]

On Tue, 2006-02-07 at 23:17 +0000, Keir Fraser wrote:
> On 7 Feb 2006, at 19:58, Ryan wrote:
> 
> > One issue with this patch (at least the frontend part of it) is that it
> > will probably only work correctly with x86 (I don't have access to 
> > other
> > architectures to test on) and the kconfig menu entries will appear
> > regardless of the architecture (they don't list x86 as a dependency).
> > Should they list x86 as a dependency? Right now, they're under the 
> > "Xen"
> > menu with the other backends and frontends. Should I move the PCI
> > frontend configuration option into the "Bus options/PCI Access" menu
> > next to the mmconfig, direct, and bios options? I think it would be
> > better placed under the "Bus options/PCI Access" menu but I wasn't sure
> > if all the backends and frontends needed to be listed together.
> 
> By x86 you mean i386 and x86_64? I guess it makes sense to list X86 as 
> a dependency for now. And yes, I think 'Bus Options/PCI Access' is the 
> correct place to place the pci frontend option. Maybe call the option 
> 'Xen PCI channel' or something like that?

I can only say i386 because that's all I've tested, but I would think it
should work for x86_64 unmodified (although I haven't placed the PCI
frontend options in the x86_64 kconfig file since I can't test it).

Here's the updated patch with the PCI frontend configuration option in
its new place.

Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>

[-- Attachment #2: pci-ddi.patch --]
[-- Type: text/x-patch, Size: 76176 bytes --]

diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/arch/i386/Kconfig
--- a/linux-2.6-xen-sparse/arch/i386/Kconfig	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/arch/i386/Kconfig	Wed Feb  8 17:15:57 2006
@@ -996,6 +996,13 @@
 config PCI_GODIRECT
 	bool "Direct"
 
+config PCI_GOXEN_FE
+	bool "Xen PCI Frontend"
+	depends on X86_XEN
+	help
+	  The PCI device frontend driver allows the kernel to import arbitrary
+	  PCI devices from a PCI backend to support PCI driver domains.
+
 config PCI_GOANY
 	bool "Any"
 
@@ -1015,6 +1022,18 @@
 	bool
 	depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
 	default y
+
+config XEN_PCIDEV_FRONTEND
+	bool
+	depends on PCI && X86_XEN && (PCI_GOXEN_FE || PCI_GOANY)
+	default y
+
+config XEN_PCIDEV_FE_DEBUG
+	bool "Xen PCI Frontend Debugging"
+	depends on XEN_PCIDEV_FRONTEND
+	default n
+	help
+	  Enables some debug statements within the PCI Frontend.
 
 source "drivers/pci/pcie/Kconfig"
 
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/arch/i386/pci/Makefile
--- a/linux-2.6-xen-sparse/arch/i386/pci/Makefile	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/arch/i386/pci/Makefile	Wed Feb  8 17:15:57 2006
@@ -3,6 +3,10 @@
 obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
 obj-$(CONFIG_PCI_MMCONFIG)	+= mmconfig.o direct.o
 obj-$(CONFIG_PCI_DIRECT)	+= direct.o
+
+# pcifront should be after pcbios.o, mmconfig.o, and direct.o as it should only
+# take over if direct access to the PCI bus is unavailable
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront.o
 
 pci-y				:= fixup.o
 pci-$(CONFIG_ACPI)		+= acpi.o
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/Kconfig
--- a/linux-2.6-xen-sparse/drivers/xen/Kconfig	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig	Wed Feb  8 17:15:57 2006
@@ -28,6 +28,44 @@
 config XEN_UNPRIVILEGED_GUEST
 	bool
 	default !XEN_PRIVILEGED_GUEST
+
+config XEN_PCIDEV_BACKEND
+	bool "PCI device backend driver"
+	select PCI
+	default y if XEN_PRIVILEGED_GUEST
+	help
+	  The PCI device backend driver allows the kernel to export arbitrary
+	  PCI devices to other guests.
+
+choice
+	prompt "PCI Backend Mode"
+	depends on XEN_PCIDEV_BACKEND
+	default XEN_PCIDEV_BACKEND_VPCI
+
+config XEN_PCIDEV_BACKEND_VPCI
+	bool "Virtual PCI"
+	---help---
+	  This PCI Backend hides the true PCI topology and makes the frontend
+	  think there is a single PCI bus with only the exported devices on it.
+	  For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
+	  second device at 02:1a.0 will be re-assigned to 00:01.0.
+
+config XEN_PCIDEV_BACKEND_PASS
+	bool "Passthrough"
+	---help---
+	  This PCI Backend provides a real view of the PCI topology to the
+	  frontend (for example, a device at 06:01.b will still appear at
+	  06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
+	  PCI devices to its driver domains. This may be required for drivers
+	  which depend on finding their hardward in certain bus/slot
+	  locations.
+
+endchoice
+
+config XEN_PCIDEV_BE_DEBUG
+	bool "PCI Backend Debugging"
+	depends on XEN_PCIDEV_BACKEND
+	default n
 
 config XEN_BLKDEV_BACKEND
 	bool "Block-device backend driver"
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Wed Feb  8 17:15:57 2006
@@ -17,4 +17,6 @@
 obj-$(CONFIG_XEN_NETDEV_FRONTEND)	+= netfront/
 obj-$(CONFIG_XEN_BLKDEV_TAP)    	+= blktap/
 obj-$(CONFIG_XEN_TPMDEV_FRONTEND)	+= tpmfront/
+obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= pciback/
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront/
 
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h	Wed Feb  8 17:15:57 2006
@@ -134,6 +134,10 @@
 
 #endif /* __KERNEL__ */
 
+#ifdef CONFIG_XEN_PCIDEV_FRONTEND
+#include <xen/pcifront.h>
+#endif /* CONFIG_XEN_PCIDEV_FRONTEND */
+
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
 #include <asm-generic/pci-dma-compat.h>
 
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/arch/i386/pci/pcifront.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/arch/i386/pci/pcifront.c	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,55 @@
+/*
+ * PCI Frontend Stub - puts some "dummy" functions in to the Linux x86 PCI core
+ *                     to support the Xen PCI Frontend's operation
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/acpi.h>
+#include "pci.h"
+
+static int pcifront_enable_irq(struct pci_dev *dev)
+{
+	u8 irq;
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	dev->irq = irq;
+
+	return 0;
+}
+
+extern u8 pci_cache_line_size;
+
+static int __init pcifront_x86_stub_init(void)
+{
+	struct cpuinfo_x86 *c = &boot_cpu_data;
+
+	/* Only install our method if we haven't found real hardware already */
+	if (raw_pci_ops)
+		return 0;
+
+	printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
+
+	/* Copied from arch/i386/pci/common.c */
+	pci_cache_line_size = 32 >> 2;
+	if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
+		pci_cache_line_size = 64 >> 2;	/* K7 & K8 */
+	else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL)
+		pci_cache_line_size = 128 >> 2;	/* P4 */
+
+	/* On x86, we need to disable the normal IRQ routing table and
+	 * just ask the backend
+	 */
+	pcibios_enable_irq = pcifront_enable_irq;
+	pcibios_disable_irq = NULL;
+
+#ifdef CONFIG_ACPI
+	/* Keep ACPI out of the picture */
+	acpi_noirq = 1;
+#endif
+
+	return 0;
+}
+
+arch_initcall(pcifront_x86_stub_init);
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pciback/Makefile
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,10 @@
+obj-y += pciback.o
+
+pciback-y := pci_stub.o pciback_ops.o xenbus.o
+pciback-y += conf_space.o conf_space_header.o
+pciback-${CONFIG_XEN_PCIDEV_BACKEND_VPCI} += vpci.o
+pciback-${CONFIG_XEN_PCIDEV_BACKEND_PASS} += passthrough.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,324 @@
+/*
+ * PCI Backend - Functions for creating a virtual configuration space for
+ *               exported PCI Devices.
+ *               It's dangerous to allow PCI Driver Domains to change their
+ *               device's resources (memory, i/o ports, interrupts). We need to
+ *               restrict changes to certain PCI Configuration registers:
+ *               BARs, INTERRUPT_PIN, most registers in the header...
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+
+#define DEFINE_PCI_CONFIG(op,size,type) 					\
+int pciback_##op##_config_##size 							\
+(struct pci_dev *dev, int offset, type value, void *data)	\
+{															\
+	return pci_##op##_config_##size (dev, offset, value);	\
+}
+
+DEFINE_PCI_CONFIG(read, byte, u8 *)
+DEFINE_PCI_CONFIG(read, word, u16 *)
+DEFINE_PCI_CONFIG(read, dword, u32 *)
+
+DEFINE_PCI_CONFIG(write, byte, u8)
+DEFINE_PCI_CONFIG(write, word, u16)
+DEFINE_PCI_CONFIG(write, dword, u32)
+
+static int conf_space_read(struct pci_dev *dev,
+			   struct config_field_entry *entry, int offset,
+			   u32 * value)
+{
+	int ret = 0;
+	struct config_field *field = entry->field;
+
+	*value = 0;
+
+	switch (field->size) {
+	case 1:
+		if (field->u.b.read)
+			ret = field->u.b.read(dev, offset, (u8 *) value,
+					      entry->data);
+		break;
+	case 2:
+		if (field->u.w.read)
+			ret = field->u.w.read(dev, offset, (u16 *) value,
+					      entry->data);
+		break;
+	case 4:
+		if (field->u.dw.read)
+			ret = field->u.dw.read(dev, offset, value, entry->data);
+		break;
+	}
+	return ret;
+}
+
+static int conf_space_write(struct pci_dev *dev,
+			    struct config_field_entry *entry, int offset,
+			    u32 value)
+{
+	int ret = 0;
+	struct config_field *field = entry->field;
+
+	switch (field->size) {
+	case 1:
+		if (field->u.b.write)
+			ret = field->u.b.write(dev, offset, (u8) value,
+					       entry->data);
+		break;
+	case 2:
+		if (field->u.w.write)
+			ret = field->u.w.write(dev, offset, (u16) value,
+					       entry->data);
+		break;
+	case 4:
+		if (field->u.dw.write)
+			ret = field->u.dw.write(dev, offset, value,
+					        entry->data);
+		break;
+	}
+	return ret;
+}
+
+static inline u32 get_mask(int size)
+{
+	if (size == 1)
+		return 0xff;
+	else if (size == 2)
+		return 0xffff;
+	else
+		return 0xffffffff;
+}
+
+static inline int valid_request(int offset, int size)
+{
+	/* Validate request (no un-aligned requests) */
+	if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0)
+		return 1;
+	return 0;
+}
+
+static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
+			      u32 offset)
+{
+	if (offset >= 0) {
+		new_val_mask <<= (offset * 8);
+		new_val <<= (offset * 8);
+	} else {
+		new_val_mask >>= (offset * -8);
+		new_val >>= (offset * -8);
+	}
+	val = (val & ~new_val_mask) | (new_val & new_val_mask);
+
+	return val;
+}
+
+static int pcibios_err_to_errno(int err)
+{
+	switch (err) {
+	case PCIBIOS_SUCCESSFUL:
+		return XEN_PCI_ERR_success;
+	case PCIBIOS_DEVICE_NOT_FOUND:
+		return XEN_PCI_ERR_dev_not_found;
+	case PCIBIOS_BAD_REGISTER_NUMBER:
+		return XEN_PCI_ERR_invalid_offset;
+	case PCIBIOS_FUNC_NOT_SUPPORTED:
+		return XEN_PCI_ERR_not_implemented;
+	case PCIBIOS_SET_FAILED:
+		return XEN_PCI_ERR_access_denied;
+	}
+	return err;
+}
+
+int pciback_config_read(struct pci_dev *dev, int offset, int size,
+			u32 * ret_val)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+	int req_start, req_end, field_start, field_end;
+	/* if read fails for any reason, return 0 (as if device didn't respond) */
+	u32 value = 0, tmp_val;
+
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n",
+		       pci_name(dev), size, offset);
+
+	if (!valid_request(offset, size)) {
+		err = XEN_PCI_ERR_invalid_offset;
+		goto out;
+	}
+
+	/* Get the real value first, then modify as appropriate */
+	switch (size) {
+	case 1:
+		err = pci_read_config_byte(dev, offset, (u8 *) & value);
+		break;
+	case 2:
+		err = pci_read_config_word(dev, offset, (u16 *) & value);
+		break;
+	case 4:
+		err = pci_read_config_dword(dev, offset, &value);
+		break;
+	}
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		req_start = offset;
+		req_end = offset + size;
+		field_start = field->offset;
+		field_end = field->offset + field->size;
+
+		if ((req_start >= field_start && req_start < field_end)
+		    || (req_end > field_start && req_end <= field_end)) {
+			err = conf_space_read(dev, cfg_entry, offset, &tmp_val);
+			if (err)
+				goto out;
+
+			value = merge_value(value, tmp_val,
+					    get_mask(field->size),
+					    field_start - req_start);
+		}
+	}
+
+      out:
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
+		       pci_name(dev), size, offset, value);
+
+	*ret_val = value;
+	return pcibios_err_to_errno(err);
+}
+
+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+	u32 tmp_val;
+	int req_start, req_end, field_start, field_end;
+
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG
+		       "pciback: %s: write request %d bytes at 0x%x = %x\n",
+		       pci_name(dev), size, offset, value);
+
+	if (!valid_request(offset, size))
+		return XEN_PCI_ERR_invalid_offset;
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		req_start = offset;
+		req_end = offset + size;
+		field_start = field->offset;
+		field_end = field->offset + field->size;
+
+		if ((req_start >= field_start && req_start < field_end)
+		    || (req_end > field_start && req_end <= field_end)) {
+			tmp_val = 0;
+
+			err = pciback_config_read(dev, offset, size, &tmp_val);
+			if (err)
+				break;
+
+			tmp_val = merge_value(tmp_val, value, get_mask(size),
+					      field_start - req_start);
+
+			err = conf_space_write(dev, cfg_entry, offset, tmp_val);
+		}
+	}
+
+	return pcibios_err_to_errno(err);
+}
+
+void pciback_config_reset(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		if (field->reset)
+			field->reset(dev, field->offset, cfg_entry->data);
+	}
+}
+
+void pciback_config_free(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry, *t;
+	struct config_field *field;
+
+	list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
+		list_del(&cfg_entry->list);
+
+		field = cfg_entry->field;
+
+		if (field->release)
+			field->release(dev, field->offset, cfg_entry->data);
+
+		kfree(cfg_entry);
+	}
+}
+
+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	void *tmp;
+
+	cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
+	if (!cfg_entry) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	cfg_entry->data = NULL;
+	cfg_entry->field = field;
+
+	if (field->init) {
+		tmp = field->init(dev, field->offset);
+
+		if (IS_ERR(tmp)) {
+			err = PTR_ERR(tmp);
+			goto out;
+		}
+
+		cfg_entry->data = tmp;
+	}
+
+	list_add_tail(&cfg_entry->list, &dev_data->config_fields);
+
+      out:
+	if (err)
+		kfree(cfg_entry);
+
+	return err;
+}
+
+/* This sets up the device's virtual configuration space to keep track of 
+ * certain registers (like the base address registers (BARs) so that we can
+ * keep the client from manipulating them directly.
+ */
+int pciback_config_init(struct pci_dev *dev)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+
+	INIT_LIST_HEAD(&dev_data->config_fields);
+
+	err = pciback_config_header_add_fields(dev);
+
+	return err;
+}
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,97 @@
+/*
+ * PCI Backend - Common data structures for overriding the configuration space
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#ifndef __XEN_PCIBACK_CONF_SPACE_H__
+#define __XEN_PCIBACK_CONF_SPACE_H__
+
+#include <linux/list.h>
+
+typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
+typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data);
+typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
+
+typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value,
+				 void *data);
+typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value,
+				void *data);
+typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value,
+				void *data);
+typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value,
+				void *data);
+typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value,
+			       void *data);
+typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
+			       void *data);
+
+/* These are the fields within the configuration space which we
+ * are interested in intercepting reads/writes to and changing their
+ * values.
+ */
+struct config_field {
+	unsigned int     offset;
+	unsigned int     size;
+	conf_field_init  init;
+	conf_field_reset reset;
+	conf_field_free  release;
+	union {
+		struct {
+			conf_dword_write write;
+			conf_dword_read read;
+		} dw;
+		struct {
+			conf_word_write write;
+			conf_word_read read;
+		} w;
+		struct {
+			conf_byte_write write;
+			conf_byte_read read;
+		} b;
+	} u;
+};
+
+struct config_field_entry {
+	struct list_head list;
+	struct config_field *field;
+	void *data;
+};
+
+/* Add fields to a device - the add_fields macro expects to get a pointer to
+ * the first entry in an array (of which the ending is marked by size==0)
+ */
+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field);
+static inline int pciback_config_add_fields(struct pci_dev *dev,
+					    struct config_field *field)
+{
+	int i, err = 0;
+	for (i = 0; field[i].size != 0; i++) {
+		err = pciback_config_add_field(dev, &field[i]);
+		if (err)
+			break;
+	}
+	return err;
+}
+
+/* Initializers which add fields to the virtual configuration space
+ * ** We could add initializers to allow a guest domain to touch
+ * the capability lists (for power management, the AGP bridge, etc.)
+ */
+int pciback_config_header_add_fields(struct pci_dev *dev);
+
+/* Read/Write the real configuration space */
+int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
+			     void *data);
+int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value,
+			     void *data);
+int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value,
+			      void *data);
+int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
+			      void *data);
+int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value,
+			      void *data);
+int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
+			       void *data);
+
+#endif				/* __XEN_PCIBACK_CONF_SPACE_H__ */
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,269 @@
+/*
+ * PCI Backend - Handles the virtual fields in the configuration space headers.
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+
+struct pci_bar_info {
+	u32 val;
+	u32 len_val;
+	int which;
+};
+
+#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
+#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
+
+static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
+{
+	if (!dev->is_enabled && is_enable_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: enable\n",
+			       pci_name(dev));
+		dev->is_enabled = 1;
+		pcibios_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
+	} else if (dev->is_enabled && !is_enable_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: disable\n",
+			       pci_name(dev));
+		pciback_disable_device(dev);
+	}
+
+	if (!dev->is_busmaster && is_master_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: set bus master\n",
+			       pci_name(dev));
+		dev->is_busmaster = 1;
+		pcibios_set_master(dev);
+	}
+
+	if (value & PCI_COMMAND_INVALIDATE) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG
+			       "pciback: %s: enable memory-write-invalidate\n",
+			       pci_name(dev));
+		pci_set_mwi(dev);
+	}
+
+	return pci_write_config_word(dev, offset, value);
+}
+
+static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	/* A write to obtain the length must happen as a 32-bit write.
+	 * This does not (yet) support writing individual bytes
+	 */
+	if (value == ~PCI_ROM_ADDRESS_ENABLE)
+		bar->which = 1;
+	else
+		bar->which = 0;
+
+	/* Do we need to support enabling/disabling the rom address here? */
+
+	return 0;
+}
+
+/* For the BARs, only allow writes which write ~0 or
+ * the correct resource information
+ * (Needed for when the driver probes the resource usage)
+ */
+static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	/* A write to obtain the length must happen as a 32-bit write.
+	 * This does not (yet) support writing individual bytes
+	 */
+	if (value == ~0)
+		bar->which = 1;
+	else
+		bar->which = 0;
+
+	return 0;
+}
+
+static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	*value = bar->which ? bar->len_val : bar->val;
+
+	return 0;
+}
+
+static inline void read_dev_bar(struct pci_dev *dev,
+				struct pci_bar_info *bar_info, int offset,
+				u32 len_mask)
+{
+	pci_read_config_dword(dev, offset, &bar_info->val);
+	pci_write_config_dword(dev, offset, len_mask);
+	pci_read_config_dword(dev, offset, &bar_info->len_val);
+	pci_write_config_dword(dev, offset, bar_info->val);
+}
+
+static void *bar_init(struct pci_dev *dev, int offset)
+{
+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
+
+	if (!bar)
+		return ERR_PTR(-ENOMEM);
+
+	read_dev_bar(dev, bar, offset, ~0);
+	bar->which = 0;
+
+	return bar;
+}
+
+static void *rom_init(struct pci_dev *dev, int offset)
+{
+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
+
+	if (!bar)
+		return ERR_PTR(-ENOMEM);
+
+	read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
+	bar->which = 0;
+
+	return bar;
+}
+
+static void bar_reset(struct pci_dev *dev, int offset, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	bar->which = 0;
+}
+
+static void bar_release(struct pci_dev *dev, int offset, void *data)
+{
+	kfree(data);
+}
+
+static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
+			  void *data)
+{
+	*value = (u8) dev->irq;
+
+	return 0;
+}
+
+struct config_field header_common[] = {
+	{
+	 .offset    = PCI_COMMAND,
+	 .size      = 2,
+	 .u.w.read  = pciback_read_config_word,
+	 .u.w.write = command_write,
+	 },
+	{
+	 .offset    = PCI_INTERRUPT_LINE,
+	 .size      = 1,
+	 .u.b.read  = interrupt_read,
+	 .u.b.write = NULL,
+	 },
+	{
+	 /* Any side effects of letting driver domain control cache line? */
+	 .offset    = PCI_CACHE_LINE_SIZE,
+	 .size      = 1,
+	 .u.b.read  = pciback_read_config_byte,
+	 .u.b.write = pciback_write_config_byte,
+	 },
+	{
+	 .size = 0,
+	 },
+};
+
+#define CFG_FIELD_BAR(reg_offset) 			\
+	{ 						\
+	 .offset     = reg_offset, 			\
+	 .size       = 4, 				\
+	 .init       = bar_init, 			\
+	 .reset      = bar_reset, 			\
+	 .release    = bar_release, 			\
+	 .u.dw.read  = bar_read, 			\
+	 .u.dw.write = bar_write, 			\
+	 }
+
+#define CFG_FIELD_ROM(reg_offset) 			\
+	{ 						\
+	 .offset     = reg_offset, 			\
+	 .size       = 4, 				\
+	 .init       = rom_init, 			\
+	 .reset      = bar_reset, 			\
+	 .release    = bar_release, 			\
+	 .u.dw.read  = bar_read, 			\
+	 .u.dw.write = rom_write, 			\
+	 }
+
+struct config_field header_0[] = {
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
+	CFG_FIELD_ROM(PCI_ROM_ADDRESS),
+	{
+	 .size = 0,
+	 },
+};
+
+struct config_field header_1[] = {
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
+	CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
+	{
+	 .size = 0,
+	 },
+};
+
+int pciback_config_header_add_fields(struct pci_dev *dev)
+{
+	int err;
+
+	err = pciback_config_add_fields(dev, header_common);
+	if (err)
+		goto out;
+
+	switch (dev->hdr_type) {
+	case PCI_HEADER_TYPE_NORMAL:
+		err = pciback_config_add_fields(dev, header_0);
+		break;
+
+	case PCI_HEADER_TYPE_BRIDGE:
+		err = pciback_config_add_fields(dev, header_1);
+		break;
+
+	default:
+		err = -EINVAL;
+		printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
+		       pci_name(dev), dev->hdr_type);
+		break;
+	}
+
+      out:
+	return err;
+}
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,116 @@
+/*
+ * PCI Backend - Provides restricted access to the real PCI bus topology
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/list.h>
+#include <linux/pci.h>
+#include "pciback.h"
+
+struct passthrough_dev_data {
+	struct list_head dev_list;
+};
+
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry;
+
+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
+		if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
+		    && bus == (unsigned int)dev_entry->dev->bus->number
+		    && devfn == dev_entry->dev->devfn)
+			return dev_entry->dev;
+	}
+
+	return NULL;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry;
+
+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
+	if (!dev_entry)
+		return -ENOMEM;
+	dev_entry->dev = dev;
+
+	list_add_tail(&dev_entry->list, &dev_data->dev_list);
+
+	return 0;
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+	struct passthrough_dev_data *dev_data;
+
+	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
+	if (!dev_data)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&dev_data->dev_list);
+
+	pdev->pci_dev_data = dev_data;
+
+	return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb publish_root_cb)
+{
+	int err = 0;
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry, *e;
+	struct pci_dev *dev;
+	int found;
+	unsigned int domain, bus;
+
+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
+		/* Only publish this device as a root if none of its
+		 * parent bridges are exported
+		 */
+		found = 0;
+		dev = dev_entry->dev->bus->self;
+		for (; !found && dev != NULL; dev = dev->bus->self) {
+			list_for_each_entry(e, &dev_data->dev_list, list) {
+				if (dev == e->dev) {
+					found = 1;
+					break;
+				}
+			}
+		}
+
+		domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
+		bus = (unsigned int)dev_entry->dev->bus->number;
+
+		if (!found) {
+			err = publish_root_cb(pdev, domain, bus);
+			if (err)
+				break;
+		}
+	}
+
+	return err;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry, *t;
+
+	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
+		list_del(&dev_entry->list);
+		pcistub_put_pci_dev(dev_entry->dev);
+		kfree(dev_entry);
+	}
+
+	kfree(dev_data);
+	pdev->pci_dev_data = NULL;
+}
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,377 @@
+/*
+ * PCI Stub Driver - Grabs devices in backend to be exported later
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include "pciback.h"
+
+static char *pci_devs_to_hide = NULL;
+module_param_named(hide, pci_devs_to_hide, charp, 0444);
+
+struct pci_stub_device_id {
+	struct list_head slot_list;
+	int domain;
+	unsigned char bus;
+	unsigned int devfn;
+};
+LIST_HEAD(pci_stub_device_ids);
+
+struct pci_stub_device {
+	struct list_head dev_list;
+	struct pci_dev *dev;
+	atomic_t in_use;
+};
+/* Access to pci_stub_devices & seized_devices lists and the initialize_devices
+ * flag must be locked with pci_stub_devices_lock
+ */
+DEFINE_SPINLOCK(pci_stub_devices_lock);
+LIST_HEAD(pci_stub_devices);
+
+/* wait for device_initcall before initializing our devices
+ * (see pcistub_init_devices_late)
+ */
+static int initialize_devices = 0;
+LIST_HEAD(seized_devices);
+
+static inline struct pci_dev *get_pci_dev(struct pci_stub_device *psdev)
+{
+	if (atomic_dec_and_test(&psdev->in_use))
+		return psdev->dev;
+	else {
+		atomic_inc(&psdev->in_use);
+		return NULL;
+	}
+}
+
+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
+					    int slot, int func)
+{
+	struct pci_stub_device *psdev;
+	struct pci_dev *found_dev = NULL;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev != NULL
+		    && domain == pci_domain_nr(psdev->dev->bus)
+		    && bus == psdev->dev->bus->number
+		    && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
+			found_dev = get_pci_dev(psdev);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+	return found_dev;
+}
+
+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+	struct pci_dev *found_dev = NULL;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev == dev) {
+			found_dev = get_pci_dev(psdev);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+	return found_dev;
+}
+
+void pcistub_put_pci_dev(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev == dev) {
+			/* Cleanup our device
+			 * (so it's ready for the next domain)
+			 */
+			pciback_reset_device(psdev->dev);
+
+			atomic_inc(&psdev->in_use);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+}
+
+static int __devinit pcistub_match(struct pci_dev *dev,
+				   struct pci_stub_device_id *pdev_id)
+{
+	/* Match the specified device by domain, bus, slot, func and also if
+	 * any of the device's parent bridges match.
+	 */
+	for (; dev != NULL; dev = dev->bus->self) {
+		if (pci_domain_nr(dev->bus) == pdev_id->domain
+		    && dev->bus->number == pdev_id->bus
+		    && dev->devfn == pdev_id->devfn)
+			return 1;
+	}
+
+	return 0;
+}
+
+static int __devinit pcistub_init_device(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data;
+	int err = 0;
+
+	/* The PCI backend is not intended to be a module (or to work with
+	 * removable PCI devices (yet). If it were, pciback_config_free()
+	 * would need to be called somewhere to free the memory allocated
+	 * here and then to call kfree(pci_get_drvdata(psdev->dev)).
+	 */
+	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
+	if (!dev_data) {
+		err = -ENOMEM;
+		goto out;
+	}
+	pci_set_drvdata(dev, dev_data);
+
+	err = pciback_config_init(dev);
+	if (err)
+		goto out;
+
+	/* HACK: Force device (& ACPI) to determine what IRQ it's on - we
+	 * must do this here because pcibios_enable_device may specify
+	 * the pci device's true irq (and possibly its other resources)
+	 * if they differ from what's in the configuration space.
+	 * This makes the assumption that the device's resources won't
+	 * change after this point (otherwise this code may break!)
+	 */
+	err = pci_enable_device(dev);
+	if (err)
+		goto config_release;
+
+	/* Now disable the device (this also ensures some private device
+	 * data is setup before we export)
+	 * This calls pciback_config_reset(dev)
+	 */
+	pciback_reset_device(dev);
+
+	return 0;
+
+      config_release:
+	pciback_config_free(dev);
+
+      out:
+	pci_set_drvdata(dev, NULL);
+	kfree(dev_data);
+	return err;
+}
+
+/*
+ * Because some initialization still happens on
+ * devices during fs_initcall, we need to defer
+ * full initialization of our devices until
+ * device_initcall.
+ */
+static int __init pcistub_init_devices_late(void)
+{
+	struct pci_stub_device *psdev, *t;
+	int err = 0;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry_safe(psdev, t, &seized_devices, dev_list) {
+		list_del(&psdev->dev_list);
+		err = pcistub_init_device(psdev->dev);
+		if (err) {
+			printk(KERN_ERR
+			       "pciback: %s error %d initializing device\n",
+			       pci_name(psdev->dev), err);
+			kfree(psdev);
+			continue;
+		}
+
+		list_add_tail(&psdev->dev_list, &pci_stub_devices);
+	}
+
+	initialize_devices = 1;
+
+	spin_unlock(&pci_stub_devices_lock);
+
+	return 0;
+}
+
+device_initcall(pcistub_init_devices_late);
+
+static int __devinit pcistub_seize(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+	int err = 0;
+
+	psdev = kmalloc(sizeof(*psdev), GFP_KERNEL);
+	if (!psdev)
+		return -ENOMEM;
+
+	psdev->dev = dev;
+	atomic_set(&psdev->in_use, 1);
+
+	spin_lock(&pci_stub_devices_lock);
+
+	if (initialize_devices) {
+		err = pcistub_init_device(psdev->dev);
+		if (err)
+			goto out;
+
+		list_add(&psdev->dev_list, &pci_stub_devices);
+	} else
+		list_add(&psdev->dev_list, &seized_devices);
+
+      out:
+	spin_unlock(&pci_stub_devices_lock);
+
+	if (err)
+		kfree(psdev);
+
+	return err;
+}
+
+static int __devinit pcistub_probe(struct pci_dev *dev,
+				   const struct pci_device_id *id)
+{
+	struct pci_stub_device_id *pdev_id;
+	struct pci_dev *seized_dev;
+	int err = 0;
+
+	list_for_each_entry(pdev_id, &pci_stub_device_ids, slot_list) {
+
+		if (!pcistub_match(dev, pdev_id))
+			continue;
+
+		if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
+		    && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
+			printk(KERN_ERR
+			       "pciback: %s: can't export pci devices that "
+			       "don't have a normal (0) or bridge (1) "
+			       "header type!\n", pci_name(dev));
+			break;
+		}
+
+		pr_info("pciback: seizing PCI device %s\n", pci_name(dev));
+		seized_dev = pci_dev_get(dev);
+
+		if (seized_dev) {
+			err = pcistub_seize(seized_dev);
+			if (err) {
+				pci_dev_put(dev);
+				goto out;
+			}
+
+			/* Success! */
+			goto out;
+		}
+	}
+
+	/* Didn't find the device */
+	err = -ENODEV;
+
+      out:
+	return err;
+}
+
+struct pci_device_id pcistub_ids[] = {
+	{
+	 .vendor = PCI_ANY_ID,
+	 .device = PCI_ANY_ID,
+	 .subvendor = PCI_ANY_ID,
+	 .subdevice = PCI_ANY_ID,
+	 },
+	{0,},
+};
+
+/*
+ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't
+ * for a normal device. I don't want it to be loaded automatically.
+ */
+
+struct pci_driver pciback_pci_driver = {
+	.name = "pciback",
+	.id_table = pcistub_ids,
+	.probe = pcistub_probe,
+};
+
+static int __init pcistub_init(void)
+{
+	int pos = 0;
+	struct pci_stub_device_id *pci_dev_id;
+	int err = 0;
+	int domain, bus, slot, func;
+	int parsed;
+
+	if (pci_devs_to_hide && *pci_devs_to_hide) {
+		do {
+			parsed = 0;
+
+			err = sscanf(pci_devs_to_hide + pos,
+				     " (%x:%x:%x.%x) %n",
+				     &domain, &bus, &slot, &func, &parsed);
+			if (err != 4) {
+				domain = 0;
+				err = sscanf(pci_devs_to_hide + pos,
+					     " (%x:%x.%x) %n",
+					     &bus, &slot, &func, &parsed);
+				if (err != 3)
+					goto parse_error;
+			}
+
+			pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
+			if (!pci_dev_id) {
+				err = -ENOMEM;
+				goto out;
+			}
+
+			pci_dev_id->domain = domain;
+			pci_dev_id->bus = bus;
+			pci_dev_id->devfn = PCI_DEVFN(slot, func);
+
+			pr_debug
+			    ("pciback: wants to seize %04x:%02x:%02x.%01x\n",
+			     domain, bus, slot, func);
+
+			list_add_tail(&pci_dev_id->slot_list,
+				      &pci_stub_device_ids);
+
+			/* if parsed<=0, we've reached the end of the string */
+			pos += parsed;
+		} while (parsed > 0 && pci_devs_to_hide[pos]);
+
+		/* If we're the first PCI Device Driver to register, we're the
+		 * first one to get offered PCI devices as they become
+		 * available (and thus we can be the first to grab them)
+		 */
+		pci_register_driver(&pciback_pci_driver);
+	}
+
+      out:
+	return err;
+
+      parse_error:
+	printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n",
+	       pci_devs_to_hide + pos);
+	return -EINVAL;
+}
+
+/*
+ * fs_initcall happens before device_initcall
+ * so pciback *should* get called first (b/c we 
+ * want to suck up any device before other drivers
+ * get a chance by being the first pci device
+ * driver to register)
+ */
+fs_initcall(pcistub_init);
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,73 @@
+/*
+ * PCI Backend Common Data Structures & Function Declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCIBACK_H__
+#define __XEN_PCIBACK_H__
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <xen/xenbus.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <xen/interface/io/pciif.h>
+
+struct pci_dev_entry {
+	struct list_head list;
+	struct pci_dev *dev;
+};
+
+struct pciback_device {
+	void *pci_dev_data;
+	spinlock_t dev_lock;
+
+	struct xenbus_device *xdev;
+
+	struct xenbus_watch be_watch;
+	u8 be_watching;
+
+	int evtchn_irq;
+
+	struct xen_pci_sharedinfo *sh_info;
+};
+
+struct pciback_dev_data {
+	struct list_head config_fields;
+};
+
+/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
+					    int slot, int func);
+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev);
+void pcistub_put_pci_dev(struct pci_dev *dev);
+
+/* Ensure a device is turned off or reset */
+void pciback_disable_device(struct pci_dev *dev);
+void pciback_reset_device(struct pci_dev *pdev);
+
+/* Access a virtual configuration space for a PCI device */
+int pciback_config_init(struct pci_dev *dev);
+void pciback_config_reset(struct pci_dev *dev);
+void pciback_config_free(struct pci_dev *dev);
+int pciback_config_read(struct pci_dev *dev, int offset, int size,
+			u32 * ret_val);
+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
+
+/* Handle requests for specific devices from the frontend */
+typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
+				    unsigned int domain, unsigned int bus);
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn);
+int pciback_init_devices(struct pciback_device *pdev);
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb cb);
+void pciback_release_devices(struct pciback_device *pdev);
+
+/* Handles events from front-end */
+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
+
+extern int verbose_request;
+#endif
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,84 @@
+/*
+ * PCI Backend Operations - respond to PCI requests from Frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <asm/bitops.h>
+#include "pciback.h"
+
+int verbose_request = 0;
+module_param(verbose_request, int, 0644);
+
+/* For those architectures without a pcibios_disable_device */
+void __attribute__ ((weak)) pcibios_disable_device(struct pci_dev *dev) { }
+
+void pciback_disable_device(struct pci_dev *dev)
+{
+	if (dev->is_enabled) {
+		dev->is_enabled = 0;
+		pcibios_disable_device(dev);
+	}
+}
+
+/* Ensure a device is "turned off" and ready to be exported.
+ * This also sets up the device's private data to keep track of what should
+ * be in the base address registers (BARs) so that we can keep the
+ * client from manipulating them directly.
+ */
+void pciback_reset_device(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	/* Disable devices (but not bridges) */
+	if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
+		pciback_disable_device(dev);
+
+		pci_write_config_word(dev, PCI_COMMAND, 0);
+
+		dev->is_enabled = 0;
+		dev->is_busmaster = 0;
+	} else {
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		if (cmd & (PCI_COMMAND_INVALIDATE)) {
+			cmd &= ~(PCI_COMMAND_INVALIDATE);
+			pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+			dev->is_busmaster = 0;
+		}
+	}
+
+	pciback_config_reset(dev);
+}
+
+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pciback_device *pdev = dev_id;
+	struct pci_dev *dev;
+	struct xen_pci_op *op = &pdev->sh_info->op;
+
+	if (unlikely(!test_bit(_XEN_PCIF_active,
+			       (unsigned long *)&pdev->sh_info->flags))) {
+		pr_debug("pciback: interrupt, but no active operation\n");
+		goto out;
+	}
+
+	dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
+
+	if (dev == NULL)
+		op->err = XEN_PCI_ERR_dev_not_found;
+	else if (op->cmd == XEN_PCI_OP_conf_read)
+		op->err = pciback_config_read(dev, op->offset, op->size,
+					      &op->value);
+	else if (op->cmd == XEN_PCI_OP_conf_write)
+		op->err = pciback_config_write(dev, op->offset, op->size,
+					       op->value);
+	else
+		op->err = XEN_PCI_ERR_not_implemented;
+
+	wmb();
+	clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+
+      out:
+	return IRQ_HANDLED;
+}
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,163 @@
+/*
+ * PCI Backend - Provides a Virtual PCI bus (with real devices)
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include "pciback.h"
+
+#define PCI_SLOT_MAX 32
+
+struct vpci_dev_data {
+	struct list_head dev_list[PCI_SLOT_MAX];
+};
+
+static inline struct list_head *list_first(struct list_head *head)
+{
+	return head->next;
+}
+
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn)
+{
+	struct pci_dev_entry *dev_entry;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	if (domain != 0 || bus != 0)
+		return NULL;
+
+	if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
+		/* we don't need to lock the list here because once the backend
+		 * is in operation, it won't have any more devices addeded
+		 * (or removed).
+		 */
+		list_for_each_entry(dev_entry,
+				    &vpci_dev->dev_list[PCI_SLOT(devfn)],
+				    list) {
+			if (PCI_FUNC(dev_entry->dev->devfn) == PCI_FUNC(devfn))
+				return dev_entry->dev;
+		}
+	}
+	return NULL;
+}
+
+static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
+{
+	if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
+	    && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn))
+		return 1;
+
+	return 0;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+	int err = 0, slot;
+	struct pci_dev_entry *t, *dev_entry;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
+		err = -EFAULT;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Can't export bridges on the virtual PCI bus");
+		goto out;
+	}
+
+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
+	if (!dev_entry) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error adding entry to virtual PCI bus");
+		goto out;
+	}
+
+	dev_entry->dev = dev;
+
+	/* Keep multi-function devices together on the virtual PCI bus */
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		if (!list_empty(&vpci_dev->dev_list[slot])) {
+			t = list_entry(list_first(&vpci_dev->dev_list[slot]),
+				       struct pci_dev_entry, list);
+
+			if (match_slot(dev, t->dev)) {
+				pr_info("pciback: vpci: %s: "
+					"assign to virtual slot %d func %d\n",
+					pci_name(dev), slot,
+					PCI_FUNC(dev->devfn));
+				list_add_tail(&dev_entry->list,
+					      &vpci_dev->dev_list[slot]);
+				goto out;
+			}
+		}
+	}
+
+	/* Assign to a new slot on the virtual PCI bus */
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		if (list_empty(&vpci_dev->dev_list[slot])) {
+			printk(KERN_INFO
+			       "pciback: vpci: %s: assign to virtual slot %d\n",
+			       pci_name(dev), slot);
+			list_add_tail(&dev_entry->list,
+				      &vpci_dev->dev_list[slot]);
+			goto out;
+		}
+	}
+
+	err = -ENOMEM;
+	xenbus_dev_fatal(pdev->xdev, err,
+			 "No more space on root virtual PCI bus");
+
+      out:
+	return err;
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+	int slot;
+	struct vpci_dev_data *vpci_dev;
+
+	vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
+	if (!vpci_dev)
+		return -ENOMEM;
+
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
+	}
+
+	pdev->pci_dev_data = vpci_dev;
+
+	return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb publish_cb)
+{
+	/* The Virtual PCI bus has only one root */
+	return publish_cb(pdev, 0, 0);
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+	int slot;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		struct pci_dev_entry *e, *tmp;
+		list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
+					 list) {
+			list_del(&e->list);
+			pcistub_put_pci_dev(e->dev);
+			kfree(e);
+		}
+	}
+
+	kfree(vpci_dev);
+	pdev->pci_dev_data = NULL;
+}
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,439 @@
+/*
+ * PCI Backend Xenbus Setup - handles setup with frontend and xend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <xen/xenbus.h>
+#include <xen/evtchn.h>
+#include "pciback.h"
+
+#define INVALID_EVTCHN_IRQ  (-1)
+
+struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
+{
+	struct pciback_device *pdev;
+
+	pdev = kmalloc(sizeof(struct pciback_device), GFP_KERNEL);
+	if (pdev == NULL)
+		goto out;
+	dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
+
+	pdev->xdev = xdev;
+	xdev->data = pdev;
+
+	spin_lock_init(&pdev->dev_lock);
+
+	pdev->sh_info = NULL;
+	pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
+	pdev->be_watching = 0;
+
+	if (pciback_init_devices(pdev)) {
+		kfree(pdev);
+		pdev = NULL;
+	}
+      out:
+	return pdev;
+}
+
+void free_pdev(struct pciback_device *pdev)
+{
+	if (pdev->be_watching)
+		unregister_xenbus_watch(&pdev->be_watch);
+
+	/* Ensure the guest can't trigger our handler before removing devices */
+	if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ)
+		unbind_from_irqhandler(pdev->evtchn_irq, pdev);
+
+	if (pdev->sh_info)
+		xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
+
+	pciback_release_devices(pdev);
+
+	pdev->xdev->data = NULL;
+	pdev->xdev = NULL;
+
+	kfree(pdev);
+}
+
+static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
+			     int remote_evtchn)
+{
+	int err = 0;
+	int evtchn;
+	dev_dbg(&pdev->xdev->dev,
+		"Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
+		gnt_ref, remote_evtchn);
+
+	err =
+	    xenbus_map_ring_valloc(pdev->xdev, gnt_ref,
+				   (void **)&pdev->sh_info);
+	if (err)
+		goto out;
+
+	err = xenbus_bind_evtchn(pdev->xdev, remote_evtchn, &evtchn);
+	if (err)
+		goto out;
+
+	err = bind_evtchn_to_irqhandler(evtchn, pciback_handle_event,
+					SA_SAMPLE_RANDOM, "pciback", pdev);
+	if (err < 0) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error binding event channel to IRQ");
+		goto out;
+	}
+	pdev->evtchn_irq = err;
+	err = 0;
+
+	dev_dbg(&pdev->xdev->dev, "Attached!\n");
+      out:
+	return err;
+}
+
+static int pciback_attach(struct pciback_device *pdev)
+{
+	int err = 0;
+	int gnt_ref, remote_evtchn;
+	char *magic = NULL;
+
+	spin_lock(&pdev->dev_lock);
+
+	/* Make sure we only do this setup once */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	/* Wait for frontend to state that it has published the configuration */
+	if (xenbus_read_driver_state(pdev->xdev->otherend) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
+
+	err = xenbus_gather(XBT_NULL, pdev->xdev->otherend,
+			    "pci-op-ref", "%u", &gnt_ref,
+			    "event-channel", "%u", &remote_evtchn,
+			    "magic", NULL, &magic, NULL);
+	if (err) {
+		/* If configuration didn't get read correctly, wait longer */
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading configuration from frontend");
+		goto out;
+	}
+
+	if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
+		xenbus_dev_fatal(pdev->xdev, -EFAULT,
+				 "version mismatch (%s/%s) with pcifront - "
+				 "halting pciback",
+				 magic, XEN_PCI_MAGIC);
+		goto out;
+	}
+
+	err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
+	if (err)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "Connecting...\n");
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
+	if (err)
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error switching to connected state!");
+
+	dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
+      out:
+	spin_unlock(&pdev->dev_lock);
+
+	if (magic)
+		kfree(magic);
+
+	return err;
+}
+
+static void pciback_frontend_changed(struct xenbus_device *xdev,
+				     XenbusState fe_state)
+{
+	struct pciback_device *pdev = xdev->data;
+
+	dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
+
+	switch (fe_state) {
+	case XenbusStateInitialised:
+		pciback_attach(pdev);
+		break;
+
+	case XenbusStateClosing:
+		xenbus_switch_state(xdev, XBT_NULL, XenbusStateClosing);
+		break;
+
+	case XenbusStateClosed:
+		dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
+		device_unregister(&xdev->dev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pciback_publish_pci_root(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus)
+{
+	unsigned int d, b;
+	int i, root_num, len, err;
+	char str[64];
+
+	dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
+			   "root_num", "%d", &root_num);
+	if (err == 0 || err == -ENOENT)
+		root_num = 0;
+	else if (err < 0)
+		goto out;
+
+	/* Verify that we haven't already published this pci root */
+	for (i = 0; i < root_num; i++) {
+		len = snprintf(str, sizeof(str), "root-%d", i);
+		if (unlikely(len >= (sizeof(str) - 1))) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
+				   str, "%x:%x", &d, &b);
+		if (err < 0)
+			goto out;
+		if (err != 2) {
+			err = -EINVAL;
+			goto out;
+		}
+
+		if (d == domain && b == bus) {
+			err = 0;
+			goto out;
+		}
+	}
+
+	len = snprintf(str, sizeof(str), "root-%d", root_num);
+	if (unlikely(len >= (sizeof(str) - 1))) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
+		root_num, domain, bus);
+
+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename, str,
+			    "%04x:%02x", domain, bus);
+	if (err)
+		goto out;
+
+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename,
+			    "root_num", "%d", (root_num + 1));
+
+      out:
+	return err;
+}
+
+static int pciback_export_device(struct pciback_device *pdev,
+				 int domain, int bus, int slot, int func)
+{
+	struct pci_dev *dev;
+	int err = 0;
+
+	dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
+		domain, bus, slot, func);
+
+	dev = pcistub_get_pci_dev_by_slot(domain, bus, slot, func);
+	if (!dev) {
+		err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Couldn't locate PCI device "
+				 "(%04x:%02x:%02x.%01x)! "
+				 "perhaps already in-use?",
+				 domain, bus, slot, func);
+		goto out;
+	}
+
+	err = pciback_add_pci_dev(pdev, dev);
+	if (err)
+		goto out;
+
+	/* TODO: It'd be nice to export a bridge and have all of its children
+	 * get exported with it. This may be best done in xend (which will
+	 * have to calculate resource usage anyway) but we probably want to
+	 * put something in here to ensure that if a bridge gets given to a
+	 * driver domain, that all devices under that bridge are not given
+	 * to other driver domains (as he who controls the bridge can disable
+	 * it and stop the other devices from working).
+	 */
+      out:
+	return err;
+}
+
+static int pciback_setup_backend(struct pciback_device *pdev)
+{
+	/* Get configuration from xend (if available now) */
+	int domain, bus, slot, func;
+	int err = 0;
+	int i, num_devs;
+	char dev_str[64];
+
+	spin_lock(&pdev->dev_lock);
+
+	/* It's possible we could get the call to setup twice, so make sure
+	 * we're not already connected.
+	 */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitWait)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "getting be setup\n");
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, "num_devs", "%d",
+			   &num_devs);
+	if (err != 1) {
+		if (err >= 0)
+			err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading number of devices");
+		goto out;
+	}
+
+	for (i = 0; i < num_devs; i++) {
+		int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
+		if (unlikely(l >= (sizeof(dev_str) - 1))) {
+			err = -ENOMEM;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "String overflow while reading "
+					 "configuration");
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, dev_str,
+				   "%x:%x:%x.%x", &domain, &bus, &slot, &func);
+		if (err < 0) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error reading device configuration");
+			goto out;
+		}
+		if (err != 4) {
+			err = -EINVAL;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error parsing pci device "
+					 "configuration");
+			goto out;
+		}
+
+		err = pciback_export_device(pdev, domain, bus, slot, func);
+		if (err)
+			goto out;
+	}
+
+	err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error while publish PCI root buses "
+				 "for frontend");
+		goto out;
+	}
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateInitialised);
+	if (err)
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error switching to initialised state!");
+
+      out:
+	spin_unlock(&pdev->dev_lock);
+
+	if (!err)
+		/* see if pcifront is already configured (if not, we'll wait) */
+		pciback_attach(pdev);
+
+	return err;
+}
+
+static void pciback_be_watch(struct xenbus_watch *watch,
+			     const char **vec, unsigned int len)
+{
+	struct pciback_device *pdev =
+	    container_of(watch, struct pciback_device, be_watch);
+
+	switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
+	case XenbusStateInitWait:
+		pciback_setup_backend(pdev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pciback_xenbus_probe(struct xenbus_device *dev,
+				const struct xenbus_device_id *id)
+{
+	int err = 0;
+	struct pciback_device *pdev = alloc_pdev(dev);
+
+	if (pdev == NULL) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(dev, err,
+				 "Error allocating pciback_device struct");
+		goto out;
+	}
+
+	/* wait for xend to configure us */
+	err = xenbus_switch_state(dev, XBT_NULL, XenbusStateInitWait);
+	if (err)
+		goto out;
+
+	/* watch the backend node for backend configuration information */
+	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
+				pciback_be_watch);
+	if (err)
+		goto out;
+	pdev->be_watching = 1;
+
+	/* We need to force a call to our callback here in case
+	 * xend already configured us!
+	 */
+	pciback_be_watch(&pdev->be_watch, NULL, 0);
+
+      out:
+	return err;
+}
+
+static int pciback_xenbus_remove(struct xenbus_device *dev)
+{
+	struct pciback_device *pdev = dev->data;
+
+	if (pdev != NULL)
+		free_pdev(pdev);
+
+	return 0;
+}
+
+static struct xenbus_device_id xenpci_ids[] = {
+	{"pci"},
+	{{0}},
+};
+
+static struct xenbus_driver xenbus_pciback_driver = {
+	.name 			= "pciback",
+	.owner 			= THIS_MODULE,
+	.ids 			= xenpci_ids,
+	.probe 			= pciback_xenbus_probe,
+	.remove 		= pciback_xenbus_remove,
+	.otherend_changed 	= pciback_frontend_changed,
+};
+
+static __init int pciback_xenbus_register(void)
+{
+	return xenbus_register_backend(&xenbus_pciback_driver);
+}
+
+/* Must only initialize our xenbus driver after the pcistub driver */
+device_initcall(pciback_xenbus_register);
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,7 @@
+obj-y += pcifront.o
+
+pcifront-y := pci_op.o xenbus.o pci.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,44 @@
+/*
+ * PCI Frontend Operations - ensure only one PCI frontend runs at a time
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include "pcifront.h"
+
+DEFINE_SPINLOCK(pcifront_dev_lock);
+static struct pcifront_device *pcifront_dev = NULL;
+
+int pcifront_connect(struct pcifront_device *pdev)
+{
+	int err = 0;
+
+	spin_lock(&pcifront_dev_lock);
+
+	if (!pcifront_dev)
+		dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
+	else {
+		dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
+		err = -EEXIST;
+	}
+
+	spin_unlock(&pcifront_dev_lock);
+
+	return err;
+}
+
+void pcifront_disconnect(struct pcifront_device *pdev)
+{
+	spin_lock(&pcifront_dev_lock);
+
+	if (pdev == pcifront_dev) {
+		dev_info(&pdev->xdev->dev,
+			 "Disconnecting PCI Frontend Buses\n");
+		pcifront_dev = NULL;
+	}
+
+	spin_unlock(&pcifront_dev_lock);
+}
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,245 @@
+/*
+ * PCI Frontend Operations - Communicates with frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <xen/evtchn.h>
+#include "pcifront.h"
+
+static int verbose_request = 0;
+module_param(verbose_request, int, 0644);
+
+static int errno_to_pcibios_err(int errno)
+{
+	switch (errno) {
+	case XEN_PCI_ERR_success:
+		return PCIBIOS_SUCCESSFUL;
+
+	case XEN_PCI_ERR_dev_not_found:
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	case XEN_PCI_ERR_invalid_offset:
+	case XEN_PCI_ERR_op_failed:
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	case XEN_PCI_ERR_not_implemented:
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+	case XEN_PCI_ERR_access_denied:
+		return PCIBIOS_SET_FAILED;
+	}
+	return errno;
+}
+
+static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
+{
+	int err = 0;
+	struct xen_pci_op *active_op = &pdev->sh_info->op;
+	unsigned long irq_flags;
+
+	unsigned int volatile ttl = (1U << 29);
+
+	spin_lock_irqsave(&pdev->sh_info_lock, irq_flags);
+
+	memcpy(active_op, op, sizeof(struct xen_pci_op));
+
+	/* Go */
+	wmb();
+	set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+	notify_remote_via_evtchn(pdev->evtchn);
+
+	/* IRQs are disabled for the pci config. space reads/writes,
+	 * which means no event channel to notify us that the backend
+	 * is done so spin while waiting for the answer */
+	while (test_bit
+	       (_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)) {
+		if (!ttl) {
+			dev_err(&pdev->xdev->dev,
+				"pciback not responding!!!\n");
+			clear_bit(_XEN_PCIF_active,
+				  (unsigned long *)&pdev->sh_info->flags);
+			err = XEN_PCI_ERR_dev_not_found;
+			goto out;
+		}
+		ttl--;
+	}
+
+	memcpy(op, active_op, sizeof(struct xen_pci_op));
+
+	err = op->err;
+      out:
+	spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags);
+	return err;
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
+			     int where, int size, u32 * val)
+{
+	int err = 0;
+	struct xen_pci_op op = {
+		.cmd    = XEN_PCI_OP_conf_read,
+		.domain = pci_domain_nr(bus),
+		.bus    = bus->number,
+		.devfn  = devfn,
+		.offset = where,
+		.size   = size,
+	};
+	struct pcifront_sd *sd = bus->sysdata;
+	struct pcifront_device *pdev = sd->pdev;
+
+	if (verbose_request)
+		dev_info(&pdev->xdev->dev,
+			 "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n",
+			 pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
+			 PCI_FUNC(devfn), where, size);
+
+	err = do_pci_op(pdev, &op);
+
+	if (likely(!err)) {
+		if (verbose_request)
+			dev_info(&pdev->xdev->dev, "read got back value %x\n",
+				 op.value);
+
+		*val = op.value;
+	} else if (err == -ENODEV) {
+		/* No device here, pretend that it just returned 0 */
+		err = 0;
+		*val = 0;
+	}
+
+	return errno_to_pcibios_err(err);
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
+			      int where, int size, u32 val)
+{
+	struct xen_pci_op op = {
+		.cmd    = XEN_PCI_OP_conf_write,
+		.domain = pci_domain_nr(bus),
+		.bus    = bus->number,
+		.devfn  = devfn,
+		.offset = where,
+		.size   = size,
+		.value  = val,
+	};
+	struct pcifront_sd *sd = bus->sysdata;
+	struct pcifront_device *pdev = sd->pdev;
+
+	if (verbose_request)
+		dev_info(&pdev->xdev->dev,
+			 "write dev=%04x:%02x:%02x.%01x - "
+			 "offset %x size %d val %x\n",
+			 pci_domain_nr(bus), bus->number,
+			 PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
+
+	return errno_to_pcibios_err(do_pci_op(pdev, &op));
+}
+
+struct pci_ops pcifront_bus_ops = {
+	.read = pcifront_bus_read,
+	.write = pcifront_bus_write,
+};
+
+/* Claim resources for the PCI frontend as-is, backend won't allow changes */
+static void pcifront_claim_resource(struct pci_dev *dev, void *data)
+{
+	struct pcifront_device *pdev = data;
+	int i;
+	struct resource *r;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		r = &dev->resource[i];
+
+		if (!r->parent && r->start && r->flags) {
+			dev_dbg(&pdev->xdev->dev, "claiming resource %s/%d\n",
+					pci_name(dev), i);
+			pci_claim_resource(dev, i);
+		}
+	}
+}
+
+int pcifront_scan_root(struct pcifront_device *pdev,
+		       unsigned int domain, unsigned int bus)
+{
+	struct pci_bus *b;
+	struct pcifront_sd *sd = NULL;
+	struct pci_bus_entry *bus_entry = NULL;
+	int err = 0;
+
+#ifndef CONFIG_PCI_DOMAINS
+	if (domain != 0) {
+		dev_err(&pdev->xdev->dev,
+			"PCI Root in non-zero PCI Domain! domain=%d\n", domain);
+		dev_err(&pdev->xdev->dev,
+			"Please compile with CONFIG_PCI_DOMAINS\n");
+		err = -EINVAL;
+		goto err_out;
+	}
+#endif
+
+	dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
+		 domain, bus);
+
+	bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
+	sd = kmalloc(sizeof(*sd), GFP_KERNEL);
+	if (!bus_entry || !sd) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+	sd->domain = domain;
+	sd->pdev = pdev;
+
+	b = pci_scan_bus_parented(&pdev->xdev->dev, bus, &pcifront_bus_ops, sd);
+	if (!b) {
+		dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+	bus_entry->bus = b;
+
+	list_add(&bus_entry->list, &pdev->root_buses);
+
+	/* Claim resources before going "live" with our devices */
+	pci_walk_bus(b, pcifront_claim_resource, pdev);
+
+	pci_bus_add_devices(b);
+
+	return 0;
+
+      err_out:
+	kfree(bus_entry);
+	kfree(sd);
+
+	return err;
+}
+
+void pcifront_free_roots(struct pcifront_device *pdev)
+{
+	struct pci_bus_entry *bus_entry, *t;
+
+	list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
+		/* TODO: Removing a PCI Bus is untested (as it normally
+		 * just goes away on domain shutdown)
+		 */
+		list_del(&bus_entry->list);
+
+		spin_lock(&pci_bus_lock);
+		list_del(&bus_entry->bus->node);
+		spin_unlock(&pci_bus_lock);
+
+		kfree(bus_entry->bus->sysdata);
+
+		device_unregister(bus_entry->bus->bridge);
+
+		/* Do we need to free() the bus itself? */
+
+		kfree(bus_entry);
+	}
+}
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,40 @@
+/*
+ * PCI Frontend - Common data structures & function declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCIFRONT_H__
+#define __XEN_PCIFRONT_H__
+
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <xen/xenbus.h>
+#include <xen/interface/io/pciif.h>
+#include <xen/pcifront.h>
+
+struct pci_bus_entry {
+	struct list_head list;
+	struct pci_bus *bus;
+};
+
+struct pcifront_device {
+	struct xenbus_device *xdev;
+	struct list_head root_buses;
+	spinlock_t dev_lock;
+
+	int evtchn;
+	int gnt_ref;
+
+	/* Lock this when doing any operations in sh_info */
+	spinlock_t sh_info_lock;
+	struct xen_pci_sharedinfo *sh_info;
+};
+
+int pcifront_connect(struct pcifront_device *pdev);
+void pcifront_disconnect(struct pcifront_device *pdev);
+
+int pcifront_scan_root(struct pcifront_device *pdev,
+		       unsigned int domain, unsigned int bus);
+void pcifront_free_roots(struct pcifront_device *pdev);
+
+#endif	/* __XEN_PCIFRONT_H__ */
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,295 @@
+/*
+ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn)
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <xen/xenbus.h>
+#include "pcifront.h"
+
+#define INVALID_GRANT_REF (0)
+#define INVALID_EVTCHN    (-1)
+
+static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
+{
+	struct pcifront_device *pdev;
+
+	pdev = kmalloc(sizeof(struct pcifront_device), GFP_KERNEL);
+	if (pdev == NULL)
+		goto out;
+
+	pdev->sh_info =
+	    (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
+	if (pdev->sh_info == NULL) {
+		kfree(pdev);
+		pdev = NULL;
+		goto out;
+	}
+	pdev->sh_info->flags = 0;
+
+	xdev->data = pdev;
+	pdev->xdev = xdev;
+
+	INIT_LIST_HEAD(&pdev->root_buses);
+
+	spin_lock_init(&pdev->dev_lock);
+	spin_lock_init(&pdev->sh_info_lock);
+
+	pdev->evtchn = INVALID_EVTCHN;
+	pdev->gnt_ref = INVALID_GRANT_REF;
+
+	dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n",
+		pdev, pdev->sh_info);
+      out:
+	return pdev;
+}
+
+static void free_pdev(struct pcifront_device *pdev)
+{
+	dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev);
+
+	if (pdev->evtchn != INVALID_EVTCHN)
+		xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
+
+	if (pdev->gnt_ref != INVALID_GRANT_REF)
+		gnttab_end_foreign_access(pdev->gnt_ref, 0,
+					  (unsigned long)pdev->sh_info);
+
+	pdev->xdev->data = NULL;
+
+	kfree(pdev);
+}
+
+static int pcifront_publish_info(struct pcifront_device *pdev)
+{
+	int err = 0;
+	xenbus_transaction_t trans;
+
+	err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info));
+	if (err < 0)
+		goto out;
+
+	pdev->gnt_ref = err;
+
+	err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
+	if (err)
+		goto out;
+
+      do_publish:
+	err = xenbus_transaction_start(&trans);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error writing configuration for backend "
+				 "(start transaction)");
+		goto out;
+	}
+
+	err = xenbus_printf(trans, pdev->xdev->nodename,
+			    "pci-op-ref", "%u", pdev->gnt_ref);
+	if (!err)
+		err = xenbus_printf(trans, pdev->xdev->nodename,
+				    "event-channel", "%u", pdev->evtchn);
+	if (!err)
+		err = xenbus_printf(trans, pdev->xdev->nodename,
+				    "magic", XEN_PCI_MAGIC);
+	if (!err)
+		err =
+		    xenbus_switch_state(pdev->xdev, trans,
+					XenbusStateInitialised);
+
+	if (err) {
+		xenbus_transaction_end(trans, 1);
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error writing configuration for backend");
+		goto out;
+	} else {
+		err = xenbus_transaction_end(trans, 0);
+		if (err == -EAGAIN)
+			goto do_publish;
+		else if (err) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error completing transaction "
+					 "for backend");
+			goto out;
+		}
+	}
+
+	dev_dbg(&pdev->xdev->dev, "publishing successful!\n");
+
+      out:
+	return err;
+}
+
+static int pcifront_try_connect(struct pcifront_device *pdev)
+{
+	int err = -EFAULT;
+	int i, num_roots, len;
+	char str[64];
+	unsigned int domain, bus;
+
+	spin_lock(&pdev->dev_lock);
+
+	/* Only connect once */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	err = pcifront_connect(pdev);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error connecting PCI Frontend");
+		goto out;
+	}
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend,
+			   "root_num", "%d", &num_roots);
+	if (err == -ENOENT) {
+		xenbus_dev_error(pdev->xdev, err,
+				 "No PCI Roots found, trying 0000:00");
+		err = pcifront_scan_root(pdev, 0, 0);
+		num_roots = 0;
+	} else if (err != 1) {
+		if (err == 0)
+			err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading number of PCI roots");
+		goto out;
+	}
+
+	for (i = 0; i < num_roots; i++) {
+		len = snprintf(str, sizeof(str), "root-%d", i);
+		if (unlikely(len >= (sizeof(str) - 1))) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend, str,
+				   "%x:%x", &domain, &bus);
+		if (err != 2) {
+			if (err >= 0)
+				err = -EINVAL;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error reading PCI root %d", i);
+			goto out;
+		}
+
+		err = pcifront_scan_root(pdev, domain, bus);
+		if (err) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error scanning PCI root %04x:%02x",
+					 domain, bus);
+			goto out;
+		}
+	}
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
+	if (err)
+		goto out;
+
+      out:
+	spin_unlock(&pdev->dev_lock);
+	return err;
+}
+
+static int pcifront_try_disconnect(struct pcifront_device *pdev)
+{
+	int err = 0;
+	XenbusState prev_state;
+
+	spin_lock(&pdev->dev_lock);
+
+	prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
+
+	if (prev_state < XenbusStateClosing)
+		err = xenbus_switch_state(pdev->xdev, XBT_NULL,
+					XenbusStateClosing);
+
+	if (!err && prev_state == XenbusStateConnected)
+		pcifront_disconnect(pdev);
+
+	spin_unlock(&pdev->dev_lock);
+
+	return err;
+}
+
+static void pcifront_backend_changed(struct xenbus_device *xdev,
+				     XenbusState be_state)
+{
+	struct pcifront_device *pdev = xdev->data;
+
+	switch (be_state) {
+	case XenbusStateClosing:
+		dev_warn(&xdev->dev, "backend going away!\n");
+		pcifront_try_disconnect(pdev);
+		break;
+
+	case XenbusStateClosed:
+		dev_warn(&xdev->dev, "backend went away!\n");
+		pcifront_try_disconnect(pdev);
+
+		device_unregister(&pdev->xdev->dev);
+		break;
+
+	case XenbusStateConnected:
+		pcifront_try_connect(pdev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pcifront_xenbus_probe(struct xenbus_device *xdev,
+				 const struct xenbus_device_id *id)
+{
+	int err = 0;
+	struct pcifront_device *pdev = alloc_pdev(xdev);
+
+	if (pdev == NULL) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(xdev, err,
+				 "Error allocating pcifront_device struct");
+		goto out;
+	}
+
+	err = pcifront_publish_info(pdev);
+
+      out:
+	return err;
+}
+
+static int pcifront_xenbus_remove(struct xenbus_device *xdev)
+{
+	if (xdev->data)
+		free_pdev(xdev->data);
+
+	return 0;
+}
+
+static struct xenbus_device_id xenpci_ids[] = {
+	{"pci"},
+	{{0}},
+};
+
+static struct xenbus_driver xenbus_pcifront_driver = {
+	.name 			= "pcifront",
+	.owner 			= THIS_MODULE,
+	.ids 			= xenpci_ids,
+	.probe 			= pcifront_xenbus_probe,
+	.remove 		= pcifront_xenbus_remove,
+	.otherend_changed 	= pcifront_backend_changed,
+};
+
+static int __init pcifront_init(void)
+{
+	int err = 0;
+
+	err = xenbus_register_frontend(&xenbus_pcifront_driver);
+
+	return err;
+}
+
+/* Initialize after the Xen PCI Frontend Stub is initialized */
+subsys_initcall(pcifront_init);
diff -r 55268b90a519 -r 71b78c45966c linux-2.6-xen-sparse/include/xen/pcifront.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/linux-2.6-xen-sparse/include/xen/pcifront.h	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,39 @@
+/*
+ * PCI Frontend - arch-dependendent declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_ASM_PCIFRONT_H__
+#define __XEN_ASM_PCIFRONT_H__
+
+#include <linux/config.h>
+#include <linux/spinlock.h>
+
+#ifdef __KERNEL__
+
+struct pcifront_device;
+
+struct pcifront_sd {
+	int domain;
+	struct pcifront_device *pdev;
+};
+
+struct pci_bus;
+
+#ifdef CONFIG_PCI_DOMAINS
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+	struct pcifront_sd *sd = bus->sysdata;
+	return sd->domain;
+}
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+	return pci_domain_nr(bus);
+}
+#endif /* CONFIG_PCI_DOMAINS */
+
+extern spinlock_t pci_bus_lock;
+
+#endif /* __KERNEL__ */
+
+#endif /* __XEN_ASM_PCIFRONT_H__ */
diff -r 55268b90a519 -r 71b78c45966c xen/include/public/io/pciif.h
--- /dev/null	Tue Feb  7 00:02:49 2006
+++ b/xen/include/public/io/pciif.h	Wed Feb  8 17:15:57 2006
@@ -0,0 +1,55 @@
+/*
+ * PCI Backend/Frontend Common Data Structures & Macros
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCI_COMMON_H__
+#define __XEN_PCI_COMMON_H__
+
+/* Be sure to bump this number if you change this file */
+#define XEN_PCI_MAGIC		"7"
+
+/* xen_pci_sharedinfo flags */
+#define _XEN_PCIF_active     (0)
+#define XEN_PCIF_active      (1<<_XEN_PCI_active)
+
+/* xen_pci_op commands */
+#define XEN_PCI_OP_conf_read    (0)
+#define XEN_PCI_OP_conf_write   (1)
+
+/* xen_pci_op error numbers */
+#define XEN_PCI_ERR_success          (0)
+#define XEN_PCI_ERR_dev_not_found   (-1)
+#define XEN_PCI_ERR_invalid_offset  (-2)
+#define XEN_PCI_ERR_access_denied   (-3)
+#define XEN_PCI_ERR_not_implemented (-4)
+/* XEN_PCI_ERR_op_failed - backend failed to complete the operation */
+#define XEN_PCI_ERR_op_failed       (-5)
+
+struct xen_pci_op {
+	/* IN: what action to perform: XEN_PCI_OP_* */
+	uint32_t cmd;
+
+	/* OUT: will contain an error number (if any) from errno.h */
+	int32_t err;
+
+	/* IN: which device to touch */
+	uint32_t domain; /* PCI Domain/Segment */
+	uint32_t bus;
+	uint32_t devfn;
+
+	/* IN: which configuration registers to touch */
+	int32_t offset;
+	int32_t size;
+
+	/* IN/OUT: Contains the result after a READ or the value to WRITE */
+	uint32_t value;
+};
+
+struct xen_pci_sharedinfo {
+	/* flags - XEN_PCIF_* */
+	uint32_t flags;
+	struct xen_pci_op op;
+};
+
+#endif /* __XEN_PCI_COMMON_H__ */

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
@ 2006-02-16 21:56 Ryan
  0 siblings, 0 replies; 15+ messages in thread
From: Ryan @ 2006-02-16 21:56 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: Type: text/plain, Size: 371 bytes --]

Resubmitting the driver domain patches against the latest xen-unstable.
These should apply cleanly to 8857:40d7eef7d3f5.

This patch contains the PCI backend and frontend drivers for Linux
2.6.16-rc3.

These patches have now been tested on x86_64 and this patch includes the
configuration options for that architecture.

Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>


[-- Attachment #2: pci-ddi.patch --]
[-- Type: text/x-patch, Size: 77901 bytes --]

diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/arch/i386/Kconfig
--- a/linux-2.6-xen-sparse/arch/i386/Kconfig	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/arch/i386/Kconfig	Thu Feb 16 20:53:52 2006
@@ -997,6 +997,13 @@
 config PCI_GODIRECT
 	bool "Direct"
 
+config PCI_GOXEN_FE
+	bool "Xen PCI Frontend"
+	depends on X86_XEN
+	help
+	  The PCI device frontend driver allows the kernel to import arbitrary
+	  PCI devices from a PCI backend to support PCI driver domains.
+
 config PCI_GOANY
 	bool "Any"
 
@@ -1016,6 +1023,18 @@
 	bool
 	depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
 	default y
+
+config XEN_PCIDEV_FRONTEND
+	bool
+	depends on PCI && X86_XEN && (PCI_GOXEN_FE || PCI_GOANY)
+	default y
+
+config XEN_PCIDEV_FE_DEBUG
+	bool "Xen PCI Frontend Debugging"
+	depends on XEN_PCIDEV_FRONTEND
+	default n
+	help
+	  Enables some debug statements within the PCI Frontend.
 
 source "drivers/pci/pcie/Kconfig"
 
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/arch/i386/pci/Makefile
--- a/linux-2.6-xen-sparse/arch/i386/pci/Makefile	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/arch/i386/pci/Makefile	Thu Feb 16 20:53:52 2006
@@ -3,6 +3,10 @@
 obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
 obj-$(CONFIG_PCI_MMCONFIG)	+= mmconfig.o direct.o
 obj-$(CONFIG_PCI_DIRECT)	+= direct.o
+
+# pcifront should be after pcbios.o, mmconfig.o, and direct.o as it should only
+# take over if direct access to the PCI bus is unavailable
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront.o
 
 pci-y				:= fixup.o
 pci-$(CONFIG_ACPI)		+= acpi.o
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/arch/x86_64/Kconfig
--- a/linux-2.6-xen-sparse/arch/x86_64/Kconfig	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/arch/x86_64/Kconfig	Thu Feb 16 20:53:52 2006
@@ -550,6 +550,21 @@
 	bool "Support mmconfig PCI config space access"
 	depends on PCI && ACPI
 
+config XEN_PCIDEV_FRONTEND
+	bool "Xen PCI Frontend"
+	depends on PCI && X86_64_XEN
+	default y
+	help
+	  The PCI device frontend driver allows the kernel to import arbitrary
+	  PCI devices from a PCI backend to support PCI driver domains.
+
+config XEN_PCIDEV_FE_DEBUG
+	bool "Xen PCI Frontend Debugging"
+	depends on XEN_PCIDEV_FRONTEND
+	default n
+	help
+	  Enables some debug statements within the PCI Frontend.
+
 config UNORDERED_IO
        bool "Unordered IO mapping access"
        depends on EXPERIMENTAL
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/arch/x86_64/pci/Makefile
--- a/linux-2.6-xen-sparse/arch/x86_64/pci/Makefile	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/arch/x86_64/pci/Makefile	Thu Feb 16 20:53:52 2006
@@ -15,8 +15,13 @@
 
 obj-$(CONFIG_NUMA)	+= k8-bus.o
 
+# pcifront should be after mmconfig.o and direct.o as it should only
+# take over if direct access to the PCI bus is unavailable
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront.o
+
 direct-y += ../../i386/pci/direct.o
 acpi-y   += ../../i386/pci/acpi.o
+pcifront-y += ../../i386/pci/pcifront.o
 legacy-y += ../../i386/pci/legacy.o
 irq-y    += ../../i386/pci/irq.o
 common-y += ../../i386/pci/common.o
@@ -25,7 +30,6 @@
 
 ifdef CONFIG_XEN
 irq-y		:= ../../i386/pci/irq-xen.o
-i386-y		:= ../../i386/pci/i386.o
 include $(srctree)/scripts/Makefile.xen
 
 obj-y := $(call cherrypickxen, $(obj-y))
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/Kconfig
--- a/linux-2.6-xen-sparse/drivers/xen/Kconfig	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig	Thu Feb 16 20:53:52 2006
@@ -28,6 +28,44 @@
 config XEN_UNPRIVILEGED_GUEST
 	bool
 	default !XEN_PRIVILEGED_GUEST
+
+config XEN_PCIDEV_BACKEND
+	bool "PCI device backend driver"
+	select PCI
+	default y if XEN_PRIVILEGED_GUEST
+	help
+	  The PCI device backend driver allows the kernel to export arbitrary
+	  PCI devices to other guests.
+
+choice
+	prompt "PCI Backend Mode"
+	depends on XEN_PCIDEV_BACKEND
+	default XEN_PCIDEV_BACKEND_VPCI
+
+config XEN_PCIDEV_BACKEND_VPCI
+	bool "Virtual PCI"
+	---help---
+	  This PCI Backend hides the true PCI topology and makes the frontend
+	  think there is a single PCI bus with only the exported devices on it.
+	  For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
+	  second device at 02:1a.0 will be re-assigned to 00:01.0.
+
+config XEN_PCIDEV_BACKEND_PASS
+	bool "Passthrough"
+	---help---
+	  This PCI Backend provides a real view of the PCI topology to the
+	  frontend (for example, a device at 06:01.b will still appear at
+	  06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
+	  PCI devices to its driver domains. This may be required for drivers
+	  which depend on finding their hardward in certain bus/slot
+	  locations.
+
+endchoice
+
+config XEN_PCIDEV_BE_DEBUG
+	bool "PCI Backend Debugging"
+	depends on XEN_PCIDEV_BACKEND
+	default n
 
 config XEN_BLKDEV_BACKEND
 	bool "Block-device backend driver"
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Thu Feb 16 20:53:52 2006
@@ -17,4 +17,6 @@
 obj-$(CONFIG_XEN_NETDEV_FRONTEND)	+= netfront/
 obj-$(CONFIG_XEN_BLKDEV_TAP)    	+= blktap/
 obj-$(CONFIG_XEN_TPMDEV_FRONTEND)	+= tpmfront/
+obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= pciback/
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront/
 
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h	Thu Feb 16 20:53:52 2006
@@ -134,6 +134,10 @@
 
 #endif /* __KERNEL__ */
 
+#ifdef CONFIG_XEN_PCIDEV_FRONTEND
+#include <xen/pcifront.h>
+#endif /* CONFIG_XEN_PCIDEV_FRONTEND */
+
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
 #include <asm-generic/pci-dma-compat.h>
 
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/arch/i386/pci/pcifront.c
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/arch/i386/pci/pcifront.c	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,55 @@
+/*
+ * PCI Frontend Stub - puts some "dummy" functions in to the Linux x86 PCI core
+ *                     to support the Xen PCI Frontend's operation
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/acpi.h>
+#include "pci.h"
+
+static int pcifront_enable_irq(struct pci_dev *dev)
+{
+	u8 irq;
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	dev->irq = irq;
+
+	return 0;
+}
+
+extern u8 pci_cache_line_size;
+
+static int __init pcifront_x86_stub_init(void)
+{
+	struct cpuinfo_x86 *c = &boot_cpu_data;
+
+	/* Only install our method if we haven't found real hardware already */
+	if (raw_pci_ops)
+		return 0;
+
+	printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
+
+	/* Copied from arch/i386/pci/common.c */
+	pci_cache_line_size = 32 >> 2;
+	if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
+		pci_cache_line_size = 64 >> 2;	/* K7 & K8 */
+	else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL)
+		pci_cache_line_size = 128 >> 2;	/* P4 */
+
+	/* On x86, we need to disable the normal IRQ routing table and
+	 * just ask the backend
+	 */
+	pcibios_enable_irq = pcifront_enable_irq;
+	pcibios_disable_irq = NULL;
+
+#ifdef CONFIG_ACPI
+	/* Keep ACPI out of the picture */
+	acpi_noirq = 1;
+#endif
+
+	return 0;
+}
+
+arch_initcall(pcifront_x86_stub_init);
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pciback/Makefile
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,10 @@
+obj-y += pciback.o
+
+pciback-y := pci_stub.o pciback_ops.o xenbus.o
+pciback-y += conf_space.o conf_space_header.o
+pciback-${CONFIG_XEN_PCIDEV_BACKEND_VPCI} += vpci.o
+pciback-${CONFIG_XEN_PCIDEV_BACKEND_PASS} += passthrough.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,324 @@
+/*
+ * PCI Backend - Functions for creating a virtual configuration space for
+ *               exported PCI Devices.
+ *               It's dangerous to allow PCI Driver Domains to change their
+ *               device's resources (memory, i/o ports, interrupts). We need to
+ *               restrict changes to certain PCI Configuration registers:
+ *               BARs, INTERRUPT_PIN, most registers in the header...
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+
+#define DEFINE_PCI_CONFIG(op,size,type) 					\
+int pciback_##op##_config_##size 							\
+(struct pci_dev *dev, int offset, type value, void *data)	\
+{															\
+	return pci_##op##_config_##size (dev, offset, value);	\
+}
+
+DEFINE_PCI_CONFIG(read, byte, u8 *)
+DEFINE_PCI_CONFIG(read, word, u16 *)
+DEFINE_PCI_CONFIG(read, dword, u32 *)
+
+DEFINE_PCI_CONFIG(write, byte, u8)
+DEFINE_PCI_CONFIG(write, word, u16)
+DEFINE_PCI_CONFIG(write, dword, u32)
+
+static int conf_space_read(struct pci_dev *dev,
+			   struct config_field_entry *entry, int offset,
+			   u32 * value)
+{
+	int ret = 0;
+	struct config_field *field = entry->field;
+
+	*value = 0;
+
+	switch (field->size) {
+	case 1:
+		if (field->u.b.read)
+			ret = field->u.b.read(dev, offset, (u8 *) value,
+					      entry->data);
+		break;
+	case 2:
+		if (field->u.w.read)
+			ret = field->u.w.read(dev, offset, (u16 *) value,
+					      entry->data);
+		break;
+	case 4:
+		if (field->u.dw.read)
+			ret = field->u.dw.read(dev, offset, value, entry->data);
+		break;
+	}
+	return ret;
+}
+
+static int conf_space_write(struct pci_dev *dev,
+			    struct config_field_entry *entry, int offset,
+			    u32 value)
+{
+	int ret = 0;
+	struct config_field *field = entry->field;
+
+	switch (field->size) {
+	case 1:
+		if (field->u.b.write)
+			ret = field->u.b.write(dev, offset, (u8) value,
+					       entry->data);
+		break;
+	case 2:
+		if (field->u.w.write)
+			ret = field->u.w.write(dev, offset, (u16) value,
+					       entry->data);
+		break;
+	case 4:
+		if (field->u.dw.write)
+			ret = field->u.dw.write(dev, offset, value,
+					        entry->data);
+		break;
+	}
+	return ret;
+}
+
+static inline u32 get_mask(int size)
+{
+	if (size == 1)
+		return 0xff;
+	else if (size == 2)
+		return 0xffff;
+	else
+		return 0xffffffff;
+}
+
+static inline int valid_request(int offset, int size)
+{
+	/* Validate request (no un-aligned requests) */
+	if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0)
+		return 1;
+	return 0;
+}
+
+static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
+			      u32 offset)
+{
+	if (offset >= 0) {
+		new_val_mask <<= (offset * 8);
+		new_val <<= (offset * 8);
+	} else {
+		new_val_mask >>= (offset * -8);
+		new_val >>= (offset * -8);
+	}
+	val = (val & ~new_val_mask) | (new_val & new_val_mask);
+
+	return val;
+}
+
+static int pcibios_err_to_errno(int err)
+{
+	switch (err) {
+	case PCIBIOS_SUCCESSFUL:
+		return XEN_PCI_ERR_success;
+	case PCIBIOS_DEVICE_NOT_FOUND:
+		return XEN_PCI_ERR_dev_not_found;
+	case PCIBIOS_BAD_REGISTER_NUMBER:
+		return XEN_PCI_ERR_invalid_offset;
+	case PCIBIOS_FUNC_NOT_SUPPORTED:
+		return XEN_PCI_ERR_not_implemented;
+	case PCIBIOS_SET_FAILED:
+		return XEN_PCI_ERR_access_denied;
+	}
+	return err;
+}
+
+int pciback_config_read(struct pci_dev *dev, int offset, int size,
+			u32 * ret_val)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+	int req_start, req_end, field_start, field_end;
+	/* if read fails for any reason, return 0 (as if device didn't respond) */
+	u32 value = 0, tmp_val;
+
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n",
+		       pci_name(dev), size, offset);
+
+	if (!valid_request(offset, size)) {
+		err = XEN_PCI_ERR_invalid_offset;
+		goto out;
+	}
+
+	/* Get the real value first, then modify as appropriate */
+	switch (size) {
+	case 1:
+		err = pci_read_config_byte(dev, offset, (u8 *) & value);
+		break;
+	case 2:
+		err = pci_read_config_word(dev, offset, (u16 *) & value);
+		break;
+	case 4:
+		err = pci_read_config_dword(dev, offset, &value);
+		break;
+	}
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		req_start = offset;
+		req_end = offset + size;
+		field_start = field->offset;
+		field_end = field->offset + field->size;
+
+		if ((req_start >= field_start && req_start < field_end)
+		    || (req_end > field_start && req_end <= field_end)) {
+			err = conf_space_read(dev, cfg_entry, offset, &tmp_val);
+			if (err)
+				goto out;
+
+			value = merge_value(value, tmp_val,
+					    get_mask(field->size),
+					    field_start - req_start);
+		}
+	}
+
+      out:
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
+		       pci_name(dev), size, offset, value);
+
+	*ret_val = value;
+	return pcibios_err_to_errno(err);
+}
+
+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+	u32 tmp_val;
+	int req_start, req_end, field_start, field_end;
+
+	if (unlikely(verbose_request))
+		printk(KERN_DEBUG
+		       "pciback: %s: write request %d bytes at 0x%x = %x\n",
+		       pci_name(dev), size, offset, value);
+
+	if (!valid_request(offset, size))
+		return XEN_PCI_ERR_invalid_offset;
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		req_start = offset;
+		req_end = offset + size;
+		field_start = field->offset;
+		field_end = field->offset + field->size;
+
+		if ((req_start >= field_start && req_start < field_end)
+		    || (req_end > field_start && req_end <= field_end)) {
+			tmp_val = 0;
+
+			err = pciback_config_read(dev, offset, size, &tmp_val);
+			if (err)
+				break;
+
+			tmp_val = merge_value(tmp_val, value, get_mask(size),
+					      field_start - req_start);
+
+			err = conf_space_write(dev, cfg_entry, offset, tmp_val);
+		}
+	}
+
+	return pcibios_err_to_errno(err);
+}
+
+void pciback_config_reset(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	struct config_field *field;
+
+	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+		field = cfg_entry->field;
+
+		if (field->reset)
+			field->reset(dev, field->offset, cfg_entry->data);
+	}
+}
+
+void pciback_config_free(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry, *t;
+	struct config_field *field;
+
+	list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
+		list_del(&cfg_entry->list);
+
+		field = cfg_entry->field;
+
+		if (field->release)
+			field->release(dev, field->offset, cfg_entry->data);
+
+		kfree(cfg_entry);
+	}
+}
+
+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+	struct config_field_entry *cfg_entry;
+	void *tmp;
+
+	cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
+	if (!cfg_entry) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	cfg_entry->data = NULL;
+	cfg_entry->field = field;
+
+	if (field->init) {
+		tmp = field->init(dev, field->offset);
+
+		if (IS_ERR(tmp)) {
+			err = PTR_ERR(tmp);
+			goto out;
+		}
+
+		cfg_entry->data = tmp;
+	}
+
+	list_add_tail(&cfg_entry->list, &dev_data->config_fields);
+
+      out:
+	if (err)
+		kfree(cfg_entry);
+
+	return err;
+}
+
+/* This sets up the device's virtual configuration space to keep track of 
+ * certain registers (like the base address registers (BARs) so that we can
+ * keep the client from manipulating them directly.
+ */
+int pciback_config_init(struct pci_dev *dev)
+{
+	int err = 0;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+
+	INIT_LIST_HEAD(&dev_data->config_fields);
+
+	err = pciback_config_header_add_fields(dev);
+
+	return err;
+}
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,97 @@
+/*
+ * PCI Backend - Common data structures for overriding the configuration space
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#ifndef __XEN_PCIBACK_CONF_SPACE_H__
+#define __XEN_PCIBACK_CONF_SPACE_H__
+
+#include <linux/list.h>
+
+typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
+typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data);
+typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
+
+typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value,
+				 void *data);
+typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value,
+				void *data);
+typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value,
+				void *data);
+typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value,
+				void *data);
+typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value,
+			       void *data);
+typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
+			       void *data);
+
+/* These are the fields within the configuration space which we
+ * are interested in intercepting reads/writes to and changing their
+ * values.
+ */
+struct config_field {
+	unsigned int     offset;
+	unsigned int     size;
+	conf_field_init  init;
+	conf_field_reset reset;
+	conf_field_free  release;
+	union {
+		struct {
+			conf_dword_write write;
+			conf_dword_read read;
+		} dw;
+		struct {
+			conf_word_write write;
+			conf_word_read read;
+		} w;
+		struct {
+			conf_byte_write write;
+			conf_byte_read read;
+		} b;
+	} u;
+};
+
+struct config_field_entry {
+	struct list_head list;
+	struct config_field *field;
+	void *data;
+};
+
+/* Add fields to a device - the add_fields macro expects to get a pointer to
+ * the first entry in an array (of which the ending is marked by size==0)
+ */
+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field);
+static inline int pciback_config_add_fields(struct pci_dev *dev,
+					    struct config_field *field)
+{
+	int i, err = 0;
+	for (i = 0; field[i].size != 0; i++) {
+		err = pciback_config_add_field(dev, &field[i]);
+		if (err)
+			break;
+	}
+	return err;
+}
+
+/* Initializers which add fields to the virtual configuration space
+ * ** We could add initializers to allow a guest domain to touch
+ * the capability lists (for power management, the AGP bridge, etc.)
+ */
+int pciback_config_header_add_fields(struct pci_dev *dev);
+
+/* Read/Write the real configuration space */
+int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
+			     void *data);
+int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value,
+			     void *data);
+int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value,
+			      void *data);
+int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
+			      void *data);
+int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value,
+			      void *data);
+int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
+			       void *data);
+
+#endif				/* __XEN_PCIBACK_CONF_SPACE_H__ */
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,269 @@
+/*
+ * PCI Backend - Handles the virtual fields in the configuration space headers.
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+
+struct pci_bar_info {
+	u32 val;
+	u32 len_val;
+	int which;
+};
+
+#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
+#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
+
+static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
+{
+	if (!dev->is_enabled && is_enable_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: enable\n",
+			       pci_name(dev));
+		dev->is_enabled = 1;
+		pcibios_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
+	} else if (dev->is_enabled && !is_enable_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: disable\n",
+			       pci_name(dev));
+		pciback_disable_device(dev);
+	}
+
+	if (!dev->is_busmaster && is_master_cmd(value)) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG "pciback: %s: set bus master\n",
+			       pci_name(dev));
+		dev->is_busmaster = 1;
+		pcibios_set_master(dev);
+	}
+
+	if (value & PCI_COMMAND_INVALIDATE) {
+		if (unlikely(verbose_request))
+			printk(KERN_DEBUG
+			       "pciback: %s: enable memory-write-invalidate\n",
+			       pci_name(dev));
+		pci_set_mwi(dev);
+	}
+
+	return pci_write_config_word(dev, offset, value);
+}
+
+static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	/* A write to obtain the length must happen as a 32-bit write.
+	 * This does not (yet) support writing individual bytes
+	 */
+	if (value == ~PCI_ROM_ADDRESS_ENABLE)
+		bar->which = 1;
+	else
+		bar->which = 0;
+
+	/* Do we need to support enabling/disabling the rom address here? */
+
+	return 0;
+}
+
+/* For the BARs, only allow writes which write ~0 or
+ * the correct resource information
+ * (Needed for when the driver probes the resource usage)
+ */
+static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	/* A write to obtain the length must happen as a 32-bit write.
+	 * This does not (yet) support writing individual bytes
+	 */
+	if (value == ~0)
+		bar->which = 1;
+	else
+		bar->which = 0;
+
+	return 0;
+}
+
+static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	if (unlikely(!bar)) {
+		printk(KERN_WARNING "pciback: driver data not found for %s\n",
+		       pci_name(dev));
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	*value = bar->which ? bar->len_val : bar->val;
+
+	return 0;
+}
+
+static inline void read_dev_bar(struct pci_dev *dev,
+				struct pci_bar_info *bar_info, int offset,
+				u32 len_mask)
+{
+	pci_read_config_dword(dev, offset, &bar_info->val);
+	pci_write_config_dword(dev, offset, len_mask);
+	pci_read_config_dword(dev, offset, &bar_info->len_val);
+	pci_write_config_dword(dev, offset, bar_info->val);
+}
+
+static void *bar_init(struct pci_dev *dev, int offset)
+{
+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
+
+	if (!bar)
+		return ERR_PTR(-ENOMEM);
+
+	read_dev_bar(dev, bar, offset, ~0);
+	bar->which = 0;
+
+	return bar;
+}
+
+static void *rom_init(struct pci_dev *dev, int offset)
+{
+	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
+
+	if (!bar)
+		return ERR_PTR(-ENOMEM);
+
+	read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
+	bar->which = 0;
+
+	return bar;
+}
+
+static void bar_reset(struct pci_dev *dev, int offset, void *data)
+{
+	struct pci_bar_info *bar = data;
+
+	bar->which = 0;
+}
+
+static void bar_release(struct pci_dev *dev, int offset, void *data)
+{
+	kfree(data);
+}
+
+static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
+			  void *data)
+{
+	*value = (u8) dev->irq;
+
+	return 0;
+}
+
+struct config_field header_common[] = {
+	{
+	 .offset    = PCI_COMMAND,
+	 .size      = 2,
+	 .u.w.read  = pciback_read_config_word,
+	 .u.w.write = command_write,
+	 },
+	{
+	 .offset    = PCI_INTERRUPT_LINE,
+	 .size      = 1,
+	 .u.b.read  = interrupt_read,
+	 .u.b.write = NULL,
+	 },
+	{
+	 /* Any side effects of letting driver domain control cache line? */
+	 .offset    = PCI_CACHE_LINE_SIZE,
+	 .size      = 1,
+	 .u.b.read  = pciback_read_config_byte,
+	 .u.b.write = pciback_write_config_byte,
+	 },
+	{
+	 .size = 0,
+	 },
+};
+
+#define CFG_FIELD_BAR(reg_offset) 			\
+	{ 						\
+	 .offset     = reg_offset, 			\
+	 .size       = 4, 				\
+	 .init       = bar_init, 			\
+	 .reset      = bar_reset, 			\
+	 .release    = bar_release, 			\
+	 .u.dw.read  = bar_read, 			\
+	 .u.dw.write = bar_write, 			\
+	 }
+
+#define CFG_FIELD_ROM(reg_offset) 			\
+	{ 						\
+	 .offset     = reg_offset, 			\
+	 .size       = 4, 				\
+	 .init       = rom_init, 			\
+	 .reset      = bar_reset, 			\
+	 .release    = bar_release, 			\
+	 .u.dw.read  = bar_read, 			\
+	 .u.dw.write = rom_write, 			\
+	 }
+
+struct config_field header_0[] = {
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
+	CFG_FIELD_ROM(PCI_ROM_ADDRESS),
+	{
+	 .size = 0,
+	 },
+};
+
+struct config_field header_1[] = {
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
+	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
+	CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
+	{
+	 .size = 0,
+	 },
+};
+
+int pciback_config_header_add_fields(struct pci_dev *dev)
+{
+	int err;
+
+	err = pciback_config_add_fields(dev, header_common);
+	if (err)
+		goto out;
+
+	switch (dev->hdr_type) {
+	case PCI_HEADER_TYPE_NORMAL:
+		err = pciback_config_add_fields(dev, header_0);
+		break;
+
+	case PCI_HEADER_TYPE_BRIDGE:
+		err = pciback_config_add_fields(dev, header_1);
+		break;
+
+	default:
+		err = -EINVAL;
+		printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
+		       pci_name(dev), dev->hdr_type);
+		break;
+	}
+
+      out:
+	return err;
+}
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,116 @@
+/*
+ * PCI Backend - Provides restricted access to the real PCI bus topology
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/list.h>
+#include <linux/pci.h>
+#include "pciback.h"
+
+struct passthrough_dev_data {
+	struct list_head dev_list;
+};
+
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry;
+
+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
+		if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
+		    && bus == (unsigned int)dev_entry->dev->bus->number
+		    && devfn == dev_entry->dev->devfn)
+			return dev_entry->dev;
+	}
+
+	return NULL;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry;
+
+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
+	if (!dev_entry)
+		return -ENOMEM;
+	dev_entry->dev = dev;
+
+	list_add_tail(&dev_entry->list, &dev_data->dev_list);
+
+	return 0;
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+	struct passthrough_dev_data *dev_data;
+
+	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
+	if (!dev_data)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&dev_data->dev_list);
+
+	pdev->pci_dev_data = dev_data;
+
+	return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb publish_root_cb)
+{
+	int err = 0;
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry, *e;
+	struct pci_dev *dev;
+	int found;
+	unsigned int domain, bus;
+
+	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
+		/* Only publish this device as a root if none of its
+		 * parent bridges are exported
+		 */
+		found = 0;
+		dev = dev_entry->dev->bus->self;
+		for (; !found && dev != NULL; dev = dev->bus->self) {
+			list_for_each_entry(e, &dev_data->dev_list, list) {
+				if (dev == e->dev) {
+					found = 1;
+					break;
+				}
+			}
+		}
+
+		domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
+		bus = (unsigned int)dev_entry->dev->bus->number;
+
+		if (!found) {
+			err = publish_root_cb(pdev, domain, bus);
+			if (err)
+				break;
+		}
+	}
+
+	return err;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+	struct pci_dev_entry *dev_entry, *t;
+
+	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
+		list_del(&dev_entry->list);
+		pcistub_put_pci_dev(dev_entry->dev);
+		kfree(dev_entry);
+	}
+
+	kfree(dev_data);
+	pdev->pci_dev_data = NULL;
+}
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,377 @@
+/*
+ * PCI Stub Driver - Grabs devices in backend to be exported later
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include "pciback.h"
+
+static char *pci_devs_to_hide = NULL;
+module_param_named(hide, pci_devs_to_hide, charp, 0444);
+
+struct pci_stub_device_id {
+	struct list_head slot_list;
+	int domain;
+	unsigned char bus;
+	unsigned int devfn;
+};
+LIST_HEAD(pci_stub_device_ids);
+
+struct pci_stub_device {
+	struct list_head dev_list;
+	struct pci_dev *dev;
+	atomic_t in_use;
+};
+/* Access to pci_stub_devices & seized_devices lists and the initialize_devices
+ * flag must be locked with pci_stub_devices_lock
+ */
+DEFINE_SPINLOCK(pci_stub_devices_lock);
+LIST_HEAD(pci_stub_devices);
+
+/* wait for device_initcall before initializing our devices
+ * (see pcistub_init_devices_late)
+ */
+static int initialize_devices = 0;
+LIST_HEAD(seized_devices);
+
+static inline struct pci_dev *get_pci_dev(struct pci_stub_device *psdev)
+{
+	if (atomic_dec_and_test(&psdev->in_use))
+		return psdev->dev;
+	else {
+		atomic_inc(&psdev->in_use);
+		return NULL;
+	}
+}
+
+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
+					    int slot, int func)
+{
+	struct pci_stub_device *psdev;
+	struct pci_dev *found_dev = NULL;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev != NULL
+		    && domain == pci_domain_nr(psdev->dev->bus)
+		    && bus == psdev->dev->bus->number
+		    && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
+			found_dev = get_pci_dev(psdev);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+	return found_dev;
+}
+
+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+	struct pci_dev *found_dev = NULL;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev == dev) {
+			found_dev = get_pci_dev(psdev);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+	return found_dev;
+}
+
+void pcistub_put_pci_dev(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+		if (psdev->dev == dev) {
+			/* Cleanup our device
+			 * (so it's ready for the next domain)
+			 */
+			pciback_reset_device(psdev->dev);
+
+			atomic_inc(&psdev->in_use);
+			break;
+		}
+	}
+
+	spin_unlock(&pci_stub_devices_lock);
+}
+
+static int __devinit pcistub_match(struct pci_dev *dev,
+				   struct pci_stub_device_id *pdev_id)
+{
+	/* Match the specified device by domain, bus, slot, func and also if
+	 * any of the device's parent bridges match.
+	 */
+	for (; dev != NULL; dev = dev->bus->self) {
+		if (pci_domain_nr(dev->bus) == pdev_id->domain
+		    && dev->bus->number == pdev_id->bus
+		    && dev->devfn == pdev_id->devfn)
+			return 1;
+	}
+
+	return 0;
+}
+
+static int __devinit pcistub_init_device(struct pci_dev *dev)
+{
+	struct pciback_dev_data *dev_data;
+	int err = 0;
+
+	/* The PCI backend is not intended to be a module (or to work with
+	 * removable PCI devices (yet). If it were, pciback_config_free()
+	 * would need to be called somewhere to free the memory allocated
+	 * here and then to call kfree(pci_get_drvdata(psdev->dev)).
+	 */
+	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
+	if (!dev_data) {
+		err = -ENOMEM;
+		goto out;
+	}
+	pci_set_drvdata(dev, dev_data);
+
+	err = pciback_config_init(dev);
+	if (err)
+		goto out;
+
+	/* HACK: Force device (& ACPI) to determine what IRQ it's on - we
+	 * must do this here because pcibios_enable_device may specify
+	 * the pci device's true irq (and possibly its other resources)
+	 * if they differ from what's in the configuration space.
+	 * This makes the assumption that the device's resources won't
+	 * change after this point (otherwise this code may break!)
+	 */
+	err = pci_enable_device(dev);
+	if (err)
+		goto config_release;
+
+	/* Now disable the device (this also ensures some private device
+	 * data is setup before we export)
+	 * This calls pciback_config_reset(dev)
+	 */
+	pciback_reset_device(dev);
+
+	return 0;
+
+      config_release:
+	pciback_config_free(dev);
+
+      out:
+	pci_set_drvdata(dev, NULL);
+	kfree(dev_data);
+	return err;
+}
+
+/*
+ * Because some initialization still happens on
+ * devices during fs_initcall, we need to defer
+ * full initialization of our devices until
+ * device_initcall.
+ */
+static int __init pcistub_init_devices_late(void)
+{
+	struct pci_stub_device *psdev, *t;
+	int err = 0;
+
+	spin_lock(&pci_stub_devices_lock);
+
+	list_for_each_entry_safe(psdev, t, &seized_devices, dev_list) {
+		list_del(&psdev->dev_list);
+		err = pcistub_init_device(psdev->dev);
+		if (err) {
+			printk(KERN_ERR
+			       "pciback: %s error %d initializing device\n",
+			       pci_name(psdev->dev), err);
+			kfree(psdev);
+			continue;
+		}
+
+		list_add_tail(&psdev->dev_list, &pci_stub_devices);
+	}
+
+	initialize_devices = 1;
+
+	spin_unlock(&pci_stub_devices_lock);
+
+	return 0;
+}
+
+device_initcall(pcistub_init_devices_late);
+
+static int __devinit pcistub_seize(struct pci_dev *dev)
+{
+	struct pci_stub_device *psdev;
+	int err = 0;
+
+	psdev = kmalloc(sizeof(*psdev), GFP_KERNEL);
+	if (!psdev)
+		return -ENOMEM;
+
+	psdev->dev = dev;
+	atomic_set(&psdev->in_use, 1);
+
+	spin_lock(&pci_stub_devices_lock);
+
+	if (initialize_devices) {
+		err = pcistub_init_device(psdev->dev);
+		if (err)
+			goto out;
+
+		list_add(&psdev->dev_list, &pci_stub_devices);
+	} else
+		list_add(&psdev->dev_list, &seized_devices);
+
+      out:
+	spin_unlock(&pci_stub_devices_lock);
+
+	if (err)
+		kfree(psdev);
+
+	return err;
+}
+
+static int __devinit pcistub_probe(struct pci_dev *dev,
+				   const struct pci_device_id *id)
+{
+	struct pci_stub_device_id *pdev_id;
+	struct pci_dev *seized_dev;
+	int err = 0;
+
+	list_for_each_entry(pdev_id, &pci_stub_device_ids, slot_list) {
+
+		if (!pcistub_match(dev, pdev_id))
+			continue;
+
+		if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
+		    && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
+			printk(KERN_ERR
+			       "pciback: %s: can't export pci devices that "
+			       "don't have a normal (0) or bridge (1) "
+			       "header type!\n", pci_name(dev));
+			break;
+		}
+
+		pr_info("pciback: seizing PCI device %s\n", pci_name(dev));
+		seized_dev = pci_dev_get(dev);
+
+		if (seized_dev) {
+			err = pcistub_seize(seized_dev);
+			if (err) {
+				pci_dev_put(dev);
+				goto out;
+			}
+
+			/* Success! */
+			goto out;
+		}
+	}
+
+	/* Didn't find the device */
+	err = -ENODEV;
+
+      out:
+	return err;
+}
+
+struct pci_device_id pcistub_ids[] = {
+	{
+	 .vendor = PCI_ANY_ID,
+	 .device = PCI_ANY_ID,
+	 .subvendor = PCI_ANY_ID,
+	 .subdevice = PCI_ANY_ID,
+	 },
+	{0,},
+};
+
+/*
+ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't
+ * for a normal device. I don't want it to be loaded automatically.
+ */
+
+struct pci_driver pciback_pci_driver = {
+	.name = "pciback",
+	.id_table = pcistub_ids,
+	.probe = pcistub_probe,
+};
+
+static int __init pcistub_init(void)
+{
+	int pos = 0;
+	struct pci_stub_device_id *pci_dev_id;
+	int err = 0;
+	int domain, bus, slot, func;
+	int parsed;
+
+	if (pci_devs_to_hide && *pci_devs_to_hide) {
+		do {
+			parsed = 0;
+
+			err = sscanf(pci_devs_to_hide + pos,
+				     " (%x:%x:%x.%x) %n",
+				     &domain, &bus, &slot, &func, &parsed);
+			if (err != 4) {
+				domain = 0;
+				err = sscanf(pci_devs_to_hide + pos,
+					     " (%x:%x.%x) %n",
+					     &bus, &slot, &func, &parsed);
+				if (err != 3)
+					goto parse_error;
+			}
+
+			pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
+			if (!pci_dev_id) {
+				err = -ENOMEM;
+				goto out;
+			}
+
+			pci_dev_id->domain = domain;
+			pci_dev_id->bus = bus;
+			pci_dev_id->devfn = PCI_DEVFN(slot, func);
+
+			pr_debug
+			    ("pciback: wants to seize %04x:%02x:%02x.%01x\n",
+			     domain, bus, slot, func);
+
+			list_add_tail(&pci_dev_id->slot_list,
+				      &pci_stub_device_ids);
+
+			/* if parsed<=0, we've reached the end of the string */
+			pos += parsed;
+		} while (parsed > 0 && pci_devs_to_hide[pos]);
+
+		/* If we're the first PCI Device Driver to register, we're the
+		 * first one to get offered PCI devices as they become
+		 * available (and thus we can be the first to grab them)
+		 */
+		pci_register_driver(&pciback_pci_driver);
+	}
+
+      out:
+	return err;
+
+      parse_error:
+	printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n",
+	       pci_devs_to_hide + pos);
+	return -EINVAL;
+}
+
+/*
+ * fs_initcall happens before device_initcall
+ * so pciback *should* get called first (b/c we 
+ * want to suck up any device before other drivers
+ * get a chance by being the first pci device
+ * driver to register)
+ */
+fs_initcall(pcistub_init);
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,73 @@
+/*
+ * PCI Backend Common Data Structures & Function Declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCIBACK_H__
+#define __XEN_PCIBACK_H__
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <xen/xenbus.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <xen/interface/io/pciif.h>
+
+struct pci_dev_entry {
+	struct list_head list;
+	struct pci_dev *dev;
+};
+
+struct pciback_device {
+	void *pci_dev_data;
+	spinlock_t dev_lock;
+
+	struct xenbus_device *xdev;
+
+	struct xenbus_watch be_watch;
+	u8 be_watching;
+
+	int evtchn_irq;
+
+	struct xen_pci_sharedinfo *sh_info;
+};
+
+struct pciback_dev_data {
+	struct list_head config_fields;
+};
+
+/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
+					    int slot, int func);
+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev);
+void pcistub_put_pci_dev(struct pci_dev *dev);
+
+/* Ensure a device is turned off or reset */
+void pciback_disable_device(struct pci_dev *dev);
+void pciback_reset_device(struct pci_dev *pdev);
+
+/* Access a virtual configuration space for a PCI device */
+int pciback_config_init(struct pci_dev *dev);
+void pciback_config_reset(struct pci_dev *dev);
+void pciback_config_free(struct pci_dev *dev);
+int pciback_config_read(struct pci_dev *dev, int offset, int size,
+			u32 * ret_val);
+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
+
+/* Handle requests for specific devices from the frontend */
+typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
+				    unsigned int domain, unsigned int bus);
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn);
+int pciback_init_devices(struct pciback_device *pdev);
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb cb);
+void pciback_release_devices(struct pciback_device *pdev);
+
+/* Handles events from front-end */
+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
+
+extern int verbose_request;
+#endif
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,84 @@
+/*
+ * PCI Backend Operations - respond to PCI requests from Frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <asm/bitops.h>
+#include "pciback.h"
+
+int verbose_request = 0;
+module_param(verbose_request, int, 0644);
+
+/* For those architectures without a pcibios_disable_device */
+void __attribute__ ((weak)) pcibios_disable_device(struct pci_dev *dev) { }
+
+void pciback_disable_device(struct pci_dev *dev)
+{
+	if (dev->is_enabled) {
+		dev->is_enabled = 0;
+		pcibios_disable_device(dev);
+	}
+}
+
+/* Ensure a device is "turned off" and ready to be exported.
+ * This also sets up the device's private data to keep track of what should
+ * be in the base address registers (BARs) so that we can keep the
+ * client from manipulating them directly.
+ */
+void pciback_reset_device(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	/* Disable devices (but not bridges) */
+	if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
+		pciback_disable_device(dev);
+
+		pci_write_config_word(dev, PCI_COMMAND, 0);
+
+		dev->is_enabled = 0;
+		dev->is_busmaster = 0;
+	} else {
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		if (cmd & (PCI_COMMAND_INVALIDATE)) {
+			cmd &= ~(PCI_COMMAND_INVALIDATE);
+			pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+			dev->is_busmaster = 0;
+		}
+	}
+
+	pciback_config_reset(dev);
+}
+
+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pciback_device *pdev = dev_id;
+	struct pci_dev *dev;
+	struct xen_pci_op *op = &pdev->sh_info->op;
+
+	if (unlikely(!test_bit(_XEN_PCIF_active,
+			       (unsigned long *)&pdev->sh_info->flags))) {
+		pr_debug("pciback: interrupt, but no active operation\n");
+		goto out;
+	}
+
+	dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
+
+	if (dev == NULL)
+		op->err = XEN_PCI_ERR_dev_not_found;
+	else if (op->cmd == XEN_PCI_OP_conf_read)
+		op->err = pciback_config_read(dev, op->offset, op->size,
+					      &op->value);
+	else if (op->cmd == XEN_PCI_OP_conf_write)
+		op->err = pciback_config_write(dev, op->offset, op->size,
+					       op->value);
+	else
+		op->err = XEN_PCI_ERR_not_implemented;
+
+	wmb();
+	clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+
+      out:
+	return IRQ_HANDLED;
+}
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,163 @@
+/*
+ * PCI Backend - Provides a Virtual PCI bus (with real devices)
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include "pciback.h"
+
+#define PCI_SLOT_MAX 32
+
+struct vpci_dev_data {
+	struct list_head dev_list[PCI_SLOT_MAX];
+};
+
+static inline struct list_head *list_first(struct list_head *head)
+{
+	return head->next;
+}
+
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus,
+				    unsigned int devfn)
+{
+	struct pci_dev_entry *dev_entry;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	if (domain != 0 || bus != 0)
+		return NULL;
+
+	if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
+		/* we don't need to lock the list here because once the backend
+		 * is in operation, it won't have any more devices addeded
+		 * (or removed).
+		 */
+		list_for_each_entry(dev_entry,
+				    &vpci_dev->dev_list[PCI_SLOT(devfn)],
+				    list) {
+			if (PCI_FUNC(dev_entry->dev->devfn) == PCI_FUNC(devfn))
+				return dev_entry->dev;
+		}
+	}
+	return NULL;
+}
+
+static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
+{
+	if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
+	    && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn))
+		return 1;
+
+	return 0;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+	int err = 0, slot;
+	struct pci_dev_entry *t, *dev_entry;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
+		err = -EFAULT;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Can't export bridges on the virtual PCI bus");
+		goto out;
+	}
+
+	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
+	if (!dev_entry) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error adding entry to virtual PCI bus");
+		goto out;
+	}
+
+	dev_entry->dev = dev;
+
+	/* Keep multi-function devices together on the virtual PCI bus */
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		if (!list_empty(&vpci_dev->dev_list[slot])) {
+			t = list_entry(list_first(&vpci_dev->dev_list[slot]),
+				       struct pci_dev_entry, list);
+
+			if (match_slot(dev, t->dev)) {
+				pr_info("pciback: vpci: %s: "
+					"assign to virtual slot %d func %d\n",
+					pci_name(dev), slot,
+					PCI_FUNC(dev->devfn));
+				list_add_tail(&dev_entry->list,
+					      &vpci_dev->dev_list[slot]);
+				goto out;
+			}
+		}
+	}
+
+	/* Assign to a new slot on the virtual PCI bus */
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		if (list_empty(&vpci_dev->dev_list[slot])) {
+			printk(KERN_INFO
+			       "pciback: vpci: %s: assign to virtual slot %d\n",
+			       pci_name(dev), slot);
+			list_add_tail(&dev_entry->list,
+				      &vpci_dev->dev_list[slot]);
+			goto out;
+		}
+	}
+
+	err = -ENOMEM;
+	xenbus_dev_fatal(pdev->xdev, err,
+			 "No more space on root virtual PCI bus");
+
+      out:
+	return err;
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+	int slot;
+	struct vpci_dev_data *vpci_dev;
+
+	vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
+	if (!vpci_dev)
+		return -ENOMEM;
+
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
+	}
+
+	pdev->pci_dev_data = vpci_dev;
+
+	return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+			      publish_pci_root_cb publish_cb)
+{
+	/* The Virtual PCI bus has only one root */
+	return publish_cb(pdev, 0, 0);
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+	int slot;
+	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+		struct pci_dev_entry *e, *tmp;
+		list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
+					 list) {
+			list_del(&e->list);
+			pcistub_put_pci_dev(e->dev);
+			kfree(e);
+		}
+	}
+
+	kfree(vpci_dev);
+	pdev->pci_dev_data = NULL;
+}
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,439 @@
+/*
+ * PCI Backend Xenbus Setup - handles setup with frontend and xend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <xen/xenbus.h>
+#include <xen/evtchn.h>
+#include "pciback.h"
+
+#define INVALID_EVTCHN_IRQ  (-1)
+
+struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
+{
+	struct pciback_device *pdev;
+
+	pdev = kmalloc(sizeof(struct pciback_device), GFP_KERNEL);
+	if (pdev == NULL)
+		goto out;
+	dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
+
+	pdev->xdev = xdev;
+	xdev->data = pdev;
+
+	spin_lock_init(&pdev->dev_lock);
+
+	pdev->sh_info = NULL;
+	pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
+	pdev->be_watching = 0;
+
+	if (pciback_init_devices(pdev)) {
+		kfree(pdev);
+		pdev = NULL;
+	}
+      out:
+	return pdev;
+}
+
+void free_pdev(struct pciback_device *pdev)
+{
+	if (pdev->be_watching)
+		unregister_xenbus_watch(&pdev->be_watch);
+
+	/* Ensure the guest can't trigger our handler before removing devices */
+	if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ)
+		unbind_from_irqhandler(pdev->evtchn_irq, pdev);
+
+	if (pdev->sh_info)
+		xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
+
+	pciback_release_devices(pdev);
+
+	pdev->xdev->data = NULL;
+	pdev->xdev = NULL;
+
+	kfree(pdev);
+}
+
+static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
+			     int remote_evtchn)
+{
+	int err = 0;
+	int evtchn;
+	dev_dbg(&pdev->xdev->dev,
+		"Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
+		gnt_ref, remote_evtchn);
+
+	err =
+	    xenbus_map_ring_valloc(pdev->xdev, gnt_ref,
+				   (void **)&pdev->sh_info);
+	if (err)
+		goto out;
+
+	err = xenbus_bind_evtchn(pdev->xdev, remote_evtchn, &evtchn);
+	if (err)
+		goto out;
+
+	err = bind_evtchn_to_irqhandler(evtchn, pciback_handle_event,
+					SA_SAMPLE_RANDOM, "pciback", pdev);
+	if (err < 0) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error binding event channel to IRQ");
+		goto out;
+	}
+	pdev->evtchn_irq = err;
+	err = 0;
+
+	dev_dbg(&pdev->xdev->dev, "Attached!\n");
+      out:
+	return err;
+}
+
+static int pciback_attach(struct pciback_device *pdev)
+{
+	int err = 0;
+	int gnt_ref, remote_evtchn;
+	char *magic = NULL;
+
+	spin_lock(&pdev->dev_lock);
+
+	/* Make sure we only do this setup once */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	/* Wait for frontend to state that it has published the configuration */
+	if (xenbus_read_driver_state(pdev->xdev->otherend) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
+
+	err = xenbus_gather(XBT_NULL, pdev->xdev->otherend,
+			    "pci-op-ref", "%u", &gnt_ref,
+			    "event-channel", "%u", &remote_evtchn,
+			    "magic", NULL, &magic, NULL);
+	if (err) {
+		/* If configuration didn't get read correctly, wait longer */
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading configuration from frontend");
+		goto out;
+	}
+
+	if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
+		xenbus_dev_fatal(pdev->xdev, -EFAULT,
+				 "version mismatch (%s/%s) with pcifront - "
+				 "halting pciback",
+				 magic, XEN_PCI_MAGIC);
+		goto out;
+	}
+
+	err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
+	if (err)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "Connecting...\n");
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
+	if (err)
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error switching to connected state!");
+
+	dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
+      out:
+	spin_unlock(&pdev->dev_lock);
+
+	if (magic)
+		kfree(magic);
+
+	return err;
+}
+
+static void pciback_frontend_changed(struct xenbus_device *xdev,
+				     XenbusState fe_state)
+{
+	struct pciback_device *pdev = xdev->data;
+
+	dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
+
+	switch (fe_state) {
+	case XenbusStateInitialised:
+		pciback_attach(pdev);
+		break;
+
+	case XenbusStateClosing:
+		xenbus_switch_state(xdev, XBT_NULL, XenbusStateClosing);
+		break;
+
+	case XenbusStateClosed:
+		dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
+		device_unregister(&xdev->dev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pciback_publish_pci_root(struct pciback_device *pdev,
+				    unsigned int domain, unsigned int bus)
+{
+	unsigned int d, b;
+	int i, root_num, len, err;
+	char str[64];
+
+	dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
+			   "root_num", "%d", &root_num);
+	if (err == 0 || err == -ENOENT)
+		root_num = 0;
+	else if (err < 0)
+		goto out;
+
+	/* Verify that we haven't already published this pci root */
+	for (i = 0; i < root_num; i++) {
+		len = snprintf(str, sizeof(str), "root-%d", i);
+		if (unlikely(len >= (sizeof(str) - 1))) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
+				   str, "%x:%x", &d, &b);
+		if (err < 0)
+			goto out;
+		if (err != 2) {
+			err = -EINVAL;
+			goto out;
+		}
+
+		if (d == domain && b == bus) {
+			err = 0;
+			goto out;
+		}
+	}
+
+	len = snprintf(str, sizeof(str), "root-%d", root_num);
+	if (unlikely(len >= (sizeof(str) - 1))) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
+		root_num, domain, bus);
+
+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename, str,
+			    "%04x:%02x", domain, bus);
+	if (err)
+		goto out;
+
+	err = xenbus_printf(XBT_NULL, pdev->xdev->nodename,
+			    "root_num", "%d", (root_num + 1));
+
+      out:
+	return err;
+}
+
+static int pciback_export_device(struct pciback_device *pdev,
+				 int domain, int bus, int slot, int func)
+{
+	struct pci_dev *dev;
+	int err = 0;
+
+	dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
+		domain, bus, slot, func);
+
+	dev = pcistub_get_pci_dev_by_slot(domain, bus, slot, func);
+	if (!dev) {
+		err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Couldn't locate PCI device "
+				 "(%04x:%02x:%02x.%01x)! "
+				 "perhaps already in-use?",
+				 domain, bus, slot, func);
+		goto out;
+	}
+
+	err = pciback_add_pci_dev(pdev, dev);
+	if (err)
+		goto out;
+
+	/* TODO: It'd be nice to export a bridge and have all of its children
+	 * get exported with it. This may be best done in xend (which will
+	 * have to calculate resource usage anyway) but we probably want to
+	 * put something in here to ensure that if a bridge gets given to a
+	 * driver domain, that all devices under that bridge are not given
+	 * to other driver domains (as he who controls the bridge can disable
+	 * it and stop the other devices from working).
+	 */
+      out:
+	return err;
+}
+
+static int pciback_setup_backend(struct pciback_device *pdev)
+{
+	/* Get configuration from xend (if available now) */
+	int domain, bus, slot, func;
+	int err = 0;
+	int i, num_devs;
+	char dev_str[64];
+
+	spin_lock(&pdev->dev_lock);
+
+	/* It's possible we could get the call to setup twice, so make sure
+	 * we're not already connected.
+	 */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitWait)
+		goto out;
+
+	dev_dbg(&pdev->xdev->dev, "getting be setup\n");
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, "num_devs", "%d",
+			   &num_devs);
+	if (err != 1) {
+		if (err >= 0)
+			err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading number of devices");
+		goto out;
+	}
+
+	for (i = 0; i < num_devs; i++) {
+		int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
+		if (unlikely(l >= (sizeof(dev_str) - 1))) {
+			err = -ENOMEM;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "String overflow while reading "
+					 "configuration");
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, dev_str,
+				   "%x:%x:%x.%x", &domain, &bus, &slot, &func);
+		if (err < 0) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error reading device configuration");
+			goto out;
+		}
+		if (err != 4) {
+			err = -EINVAL;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error parsing pci device "
+					 "configuration");
+			goto out;
+		}
+
+		err = pciback_export_device(pdev, domain, bus, slot, func);
+		if (err)
+			goto out;
+	}
+
+	err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error while publish PCI root buses "
+				 "for frontend");
+		goto out;
+	}
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateInitialised);
+	if (err)
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error switching to initialised state!");
+
+      out:
+	spin_unlock(&pdev->dev_lock);
+
+	if (!err)
+		/* see if pcifront is already configured (if not, we'll wait) */
+		pciback_attach(pdev);
+
+	return err;
+}
+
+static void pciback_be_watch(struct xenbus_watch *watch,
+			     const char **vec, unsigned int len)
+{
+	struct pciback_device *pdev =
+	    container_of(watch, struct pciback_device, be_watch);
+
+	switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
+	case XenbusStateInitWait:
+		pciback_setup_backend(pdev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pciback_xenbus_probe(struct xenbus_device *dev,
+				const struct xenbus_device_id *id)
+{
+	int err = 0;
+	struct pciback_device *pdev = alloc_pdev(dev);
+
+	if (pdev == NULL) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(dev, err,
+				 "Error allocating pciback_device struct");
+		goto out;
+	}
+
+	/* wait for xend to configure us */
+	err = xenbus_switch_state(dev, XBT_NULL, XenbusStateInitWait);
+	if (err)
+		goto out;
+
+	/* watch the backend node for backend configuration information */
+	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
+				pciback_be_watch);
+	if (err)
+		goto out;
+	pdev->be_watching = 1;
+
+	/* We need to force a call to our callback here in case
+	 * xend already configured us!
+	 */
+	pciback_be_watch(&pdev->be_watch, NULL, 0);
+
+      out:
+	return err;
+}
+
+static int pciback_xenbus_remove(struct xenbus_device *dev)
+{
+	struct pciback_device *pdev = dev->data;
+
+	if (pdev != NULL)
+		free_pdev(pdev);
+
+	return 0;
+}
+
+static struct xenbus_device_id xenpci_ids[] = {
+	{"pci"},
+	{{0}},
+};
+
+static struct xenbus_driver xenbus_pciback_driver = {
+	.name 			= "pciback",
+	.owner 			= THIS_MODULE,
+	.ids 			= xenpci_ids,
+	.probe 			= pciback_xenbus_probe,
+	.remove 		= pciback_xenbus_remove,
+	.otherend_changed 	= pciback_frontend_changed,
+};
+
+static __init int pciback_xenbus_register(void)
+{
+	return xenbus_register_backend(&xenbus_pciback_driver);
+}
+
+/* Must only initialize our xenbus driver after the pcistub driver */
+device_initcall(pciback_xenbus_register);
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,7 @@
+obj-y += pcifront.o
+
+pcifront-y := pci_op.o xenbus.o pci.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,44 @@
+/*
+ * PCI Frontend Operations - ensure only one PCI frontend runs at a time
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include "pcifront.h"
+
+DEFINE_SPINLOCK(pcifront_dev_lock);
+static struct pcifront_device *pcifront_dev = NULL;
+
+int pcifront_connect(struct pcifront_device *pdev)
+{
+	int err = 0;
+
+	spin_lock(&pcifront_dev_lock);
+
+	if (!pcifront_dev)
+		dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
+	else {
+		dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
+		err = -EEXIST;
+	}
+
+	spin_unlock(&pcifront_dev_lock);
+
+	return err;
+}
+
+void pcifront_disconnect(struct pcifront_device *pdev)
+{
+	spin_lock(&pcifront_dev_lock);
+
+	if (pdev == pcifront_dev) {
+		dev_info(&pdev->xdev->dev,
+			 "Disconnecting PCI Frontend Buses\n");
+		pcifront_dev = NULL;
+	}
+
+	spin_unlock(&pcifront_dev_lock);
+}
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,245 @@
+/*
+ * PCI Frontend Operations - Communicates with frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <xen/evtchn.h>
+#include "pcifront.h"
+
+static int verbose_request = 0;
+module_param(verbose_request, int, 0644);
+
+static int errno_to_pcibios_err(int errno)
+{
+	switch (errno) {
+	case XEN_PCI_ERR_success:
+		return PCIBIOS_SUCCESSFUL;
+
+	case XEN_PCI_ERR_dev_not_found:
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	case XEN_PCI_ERR_invalid_offset:
+	case XEN_PCI_ERR_op_failed:
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	case XEN_PCI_ERR_not_implemented:
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+	case XEN_PCI_ERR_access_denied:
+		return PCIBIOS_SET_FAILED;
+	}
+	return errno;
+}
+
+static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
+{
+	int err = 0;
+	struct xen_pci_op *active_op = &pdev->sh_info->op;
+	unsigned long irq_flags;
+
+	unsigned int volatile ttl = (1U << 29);
+
+	spin_lock_irqsave(&pdev->sh_info_lock, irq_flags);
+
+	memcpy(active_op, op, sizeof(struct xen_pci_op));
+
+	/* Go */
+	wmb();
+	set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+	notify_remote_via_evtchn(pdev->evtchn);
+
+	/* IRQs are disabled for the pci config. space reads/writes,
+	 * which means no event channel to notify us that the backend
+	 * is done so spin while waiting for the answer */
+	while (test_bit
+	       (_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)) {
+		if (!ttl) {
+			dev_err(&pdev->xdev->dev,
+				"pciback not responding!!!\n");
+			clear_bit(_XEN_PCIF_active,
+				  (unsigned long *)&pdev->sh_info->flags);
+			err = XEN_PCI_ERR_dev_not_found;
+			goto out;
+		}
+		ttl--;
+	}
+
+	memcpy(op, active_op, sizeof(struct xen_pci_op));
+
+	err = op->err;
+      out:
+	spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags);
+	return err;
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
+			     int where, int size, u32 * val)
+{
+	int err = 0;
+	struct xen_pci_op op = {
+		.cmd    = XEN_PCI_OP_conf_read,
+		.domain = pci_domain_nr(bus),
+		.bus    = bus->number,
+		.devfn  = devfn,
+		.offset = where,
+		.size   = size,
+	};
+	struct pcifront_sd *sd = bus->sysdata;
+	struct pcifront_device *pdev = sd->pdev;
+
+	if (verbose_request)
+		dev_info(&pdev->xdev->dev,
+			 "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n",
+			 pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
+			 PCI_FUNC(devfn), where, size);
+
+	err = do_pci_op(pdev, &op);
+
+	if (likely(!err)) {
+		if (verbose_request)
+			dev_info(&pdev->xdev->dev, "read got back value %x\n",
+				 op.value);
+
+		*val = op.value;
+	} else if (err == -ENODEV) {
+		/* No device here, pretend that it just returned 0 */
+		err = 0;
+		*val = 0;
+	}
+
+	return errno_to_pcibios_err(err);
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
+			      int where, int size, u32 val)
+{
+	struct xen_pci_op op = {
+		.cmd    = XEN_PCI_OP_conf_write,
+		.domain = pci_domain_nr(bus),
+		.bus    = bus->number,
+		.devfn  = devfn,
+		.offset = where,
+		.size   = size,
+		.value  = val,
+	};
+	struct pcifront_sd *sd = bus->sysdata;
+	struct pcifront_device *pdev = sd->pdev;
+
+	if (verbose_request)
+		dev_info(&pdev->xdev->dev,
+			 "write dev=%04x:%02x:%02x.%01x - "
+			 "offset %x size %d val %x\n",
+			 pci_domain_nr(bus), bus->number,
+			 PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
+
+	return errno_to_pcibios_err(do_pci_op(pdev, &op));
+}
+
+struct pci_ops pcifront_bus_ops = {
+	.read = pcifront_bus_read,
+	.write = pcifront_bus_write,
+};
+
+/* Claim resources for the PCI frontend as-is, backend won't allow changes */
+static void pcifront_claim_resource(struct pci_dev *dev, void *data)
+{
+	struct pcifront_device *pdev = data;
+	int i;
+	struct resource *r;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		r = &dev->resource[i];
+
+		if (!r->parent && r->start && r->flags) {
+			dev_dbg(&pdev->xdev->dev, "claiming resource %s/%d\n",
+					pci_name(dev), i);
+			pci_claim_resource(dev, i);
+		}
+	}
+}
+
+int pcifront_scan_root(struct pcifront_device *pdev,
+		       unsigned int domain, unsigned int bus)
+{
+	struct pci_bus *b;
+	struct pcifront_sd *sd = NULL;
+	struct pci_bus_entry *bus_entry = NULL;
+	int err = 0;
+
+#ifndef CONFIG_PCI_DOMAINS
+	if (domain != 0) {
+		dev_err(&pdev->xdev->dev,
+			"PCI Root in non-zero PCI Domain! domain=%d\n", domain);
+		dev_err(&pdev->xdev->dev,
+			"Please compile with CONFIG_PCI_DOMAINS\n");
+		err = -EINVAL;
+		goto err_out;
+	}
+#endif
+
+	dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
+		 domain, bus);
+
+	bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
+	sd = kmalloc(sizeof(*sd), GFP_KERNEL);
+	if (!bus_entry || !sd) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+	sd->domain = domain;
+	sd->pdev = pdev;
+
+	b = pci_scan_bus_parented(&pdev->xdev->dev, bus, &pcifront_bus_ops, sd);
+	if (!b) {
+		dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+	bus_entry->bus = b;
+
+	list_add(&bus_entry->list, &pdev->root_buses);
+
+	/* Claim resources before going "live" with our devices */
+	pci_walk_bus(b, pcifront_claim_resource, pdev);
+
+	pci_bus_add_devices(b);
+
+	return 0;
+
+      err_out:
+	kfree(bus_entry);
+	kfree(sd);
+
+	return err;
+}
+
+void pcifront_free_roots(struct pcifront_device *pdev)
+{
+	struct pci_bus_entry *bus_entry, *t;
+
+	list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
+		/* TODO: Removing a PCI Bus is untested (as it normally
+		 * just goes away on domain shutdown)
+		 */
+		list_del(&bus_entry->list);
+
+		spin_lock(&pci_bus_lock);
+		list_del(&bus_entry->bus->node);
+		spin_unlock(&pci_bus_lock);
+
+		kfree(bus_entry->bus->sysdata);
+
+		device_unregister(bus_entry->bus->bridge);
+
+		/* Do we need to free() the bus itself? */
+
+		kfree(bus_entry);
+	}
+}
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,40 @@
+/*
+ * PCI Frontend - Common data structures & function declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCIFRONT_H__
+#define __XEN_PCIFRONT_H__
+
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <xen/xenbus.h>
+#include <xen/interface/io/pciif.h>
+#include <xen/pcifront.h>
+
+struct pci_bus_entry {
+	struct list_head list;
+	struct pci_bus *bus;
+};
+
+struct pcifront_device {
+	struct xenbus_device *xdev;
+	struct list_head root_buses;
+	spinlock_t dev_lock;
+
+	int evtchn;
+	int gnt_ref;
+
+	/* Lock this when doing any operations in sh_info */
+	spinlock_t sh_info_lock;
+	struct xen_pci_sharedinfo *sh_info;
+};
+
+int pcifront_connect(struct pcifront_device *pdev);
+void pcifront_disconnect(struct pcifront_device *pdev);
+
+int pcifront_scan_root(struct pcifront_device *pdev,
+		       unsigned int domain, unsigned int bus);
+void pcifront_free_roots(struct pcifront_device *pdev);
+
+#endif	/* __XEN_PCIFRONT_H__ */
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,295 @@
+/*
+ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn)
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <xen/xenbus.h>
+#include "pcifront.h"
+
+#define INVALID_GRANT_REF (0)
+#define INVALID_EVTCHN    (-1)
+
+static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
+{
+	struct pcifront_device *pdev;
+
+	pdev = kmalloc(sizeof(struct pcifront_device), GFP_KERNEL);
+	if (pdev == NULL)
+		goto out;
+
+	pdev->sh_info =
+	    (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
+	if (pdev->sh_info == NULL) {
+		kfree(pdev);
+		pdev = NULL;
+		goto out;
+	}
+	pdev->sh_info->flags = 0;
+
+	xdev->data = pdev;
+	pdev->xdev = xdev;
+
+	INIT_LIST_HEAD(&pdev->root_buses);
+
+	spin_lock_init(&pdev->dev_lock);
+	spin_lock_init(&pdev->sh_info_lock);
+
+	pdev->evtchn = INVALID_EVTCHN;
+	pdev->gnt_ref = INVALID_GRANT_REF;
+
+	dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n",
+		pdev, pdev->sh_info);
+      out:
+	return pdev;
+}
+
+static void free_pdev(struct pcifront_device *pdev)
+{
+	dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev);
+
+	if (pdev->evtchn != INVALID_EVTCHN)
+		xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
+
+	if (pdev->gnt_ref != INVALID_GRANT_REF)
+		gnttab_end_foreign_access(pdev->gnt_ref, 0,
+					  (unsigned long)pdev->sh_info);
+
+	pdev->xdev->data = NULL;
+
+	kfree(pdev);
+}
+
+static int pcifront_publish_info(struct pcifront_device *pdev)
+{
+	int err = 0;
+	xenbus_transaction_t trans;
+
+	err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info));
+	if (err < 0)
+		goto out;
+
+	pdev->gnt_ref = err;
+
+	err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
+	if (err)
+		goto out;
+
+      do_publish:
+	err = xenbus_transaction_start(&trans);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error writing configuration for backend "
+				 "(start transaction)");
+		goto out;
+	}
+
+	err = xenbus_printf(trans, pdev->xdev->nodename,
+			    "pci-op-ref", "%u", pdev->gnt_ref);
+	if (!err)
+		err = xenbus_printf(trans, pdev->xdev->nodename,
+				    "event-channel", "%u", pdev->evtchn);
+	if (!err)
+		err = xenbus_printf(trans, pdev->xdev->nodename,
+				    "magic", XEN_PCI_MAGIC);
+	if (!err)
+		err =
+		    xenbus_switch_state(pdev->xdev, trans,
+					XenbusStateInitialised);
+
+	if (err) {
+		xenbus_transaction_end(trans, 1);
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error writing configuration for backend");
+		goto out;
+	} else {
+		err = xenbus_transaction_end(trans, 0);
+		if (err == -EAGAIN)
+			goto do_publish;
+		else if (err) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error completing transaction "
+					 "for backend");
+			goto out;
+		}
+	}
+
+	dev_dbg(&pdev->xdev->dev, "publishing successful!\n");
+
+      out:
+	return err;
+}
+
+static int pcifront_try_connect(struct pcifront_device *pdev)
+{
+	int err = -EFAULT;
+	int i, num_roots, len;
+	char str[64];
+	unsigned int domain, bus;
+
+	spin_lock(&pdev->dev_lock);
+
+	/* Only connect once */
+	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+	    XenbusStateInitialised)
+		goto out;
+
+	err = pcifront_connect(pdev);
+	if (err) {
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error connecting PCI Frontend");
+		goto out;
+	}
+
+	err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend,
+			   "root_num", "%d", &num_roots);
+	if (err == -ENOENT) {
+		xenbus_dev_error(pdev->xdev, err,
+				 "No PCI Roots found, trying 0000:00");
+		err = pcifront_scan_root(pdev, 0, 0);
+		num_roots = 0;
+	} else if (err != 1) {
+		if (err == 0)
+			err = -EINVAL;
+		xenbus_dev_fatal(pdev->xdev, err,
+				 "Error reading number of PCI roots");
+		goto out;
+	}
+
+	for (i = 0; i < num_roots; i++) {
+		len = snprintf(str, sizeof(str), "root-%d", i);
+		if (unlikely(len >= (sizeof(str) - 1))) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend, str,
+				   "%x:%x", &domain, &bus);
+		if (err != 2) {
+			if (err >= 0)
+				err = -EINVAL;
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error reading PCI root %d", i);
+			goto out;
+		}
+
+		err = pcifront_scan_root(pdev, domain, bus);
+		if (err) {
+			xenbus_dev_fatal(pdev->xdev, err,
+					 "Error scanning PCI root %04x:%02x",
+					 domain, bus);
+			goto out;
+		}
+	}
+
+	err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
+	if (err)
+		goto out;
+
+      out:
+	spin_unlock(&pdev->dev_lock);
+	return err;
+}
+
+static int pcifront_try_disconnect(struct pcifront_device *pdev)
+{
+	int err = 0;
+	XenbusState prev_state;
+
+	spin_lock(&pdev->dev_lock);
+
+	prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
+
+	if (prev_state < XenbusStateClosing)
+		err = xenbus_switch_state(pdev->xdev, XBT_NULL,
+					XenbusStateClosing);
+
+	if (!err && prev_state == XenbusStateConnected)
+		pcifront_disconnect(pdev);
+
+	spin_unlock(&pdev->dev_lock);
+
+	return err;
+}
+
+static void pcifront_backend_changed(struct xenbus_device *xdev,
+				     XenbusState be_state)
+{
+	struct pcifront_device *pdev = xdev->data;
+
+	switch (be_state) {
+	case XenbusStateClosing:
+		dev_warn(&xdev->dev, "backend going away!\n");
+		pcifront_try_disconnect(pdev);
+		break;
+
+	case XenbusStateClosed:
+		dev_warn(&xdev->dev, "backend went away!\n");
+		pcifront_try_disconnect(pdev);
+
+		device_unregister(&pdev->xdev->dev);
+		break;
+
+	case XenbusStateConnected:
+		pcifront_try_connect(pdev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int pcifront_xenbus_probe(struct xenbus_device *xdev,
+				 const struct xenbus_device_id *id)
+{
+	int err = 0;
+	struct pcifront_device *pdev = alloc_pdev(xdev);
+
+	if (pdev == NULL) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(xdev, err,
+				 "Error allocating pcifront_device struct");
+		goto out;
+	}
+
+	err = pcifront_publish_info(pdev);
+
+      out:
+	return err;
+}
+
+static int pcifront_xenbus_remove(struct xenbus_device *xdev)
+{
+	if (xdev->data)
+		free_pdev(xdev->data);
+
+	return 0;
+}
+
+static struct xenbus_device_id xenpci_ids[] = {
+	{"pci"},
+	{{0}},
+};
+
+static struct xenbus_driver xenbus_pcifront_driver = {
+	.name 			= "pcifront",
+	.owner 			= THIS_MODULE,
+	.ids 			= xenpci_ids,
+	.probe 			= pcifront_xenbus_probe,
+	.remove 		= pcifront_xenbus_remove,
+	.otherend_changed 	= pcifront_backend_changed,
+};
+
+static int __init pcifront_init(void)
+{
+	int err = 0;
+
+	err = xenbus_register_frontend(&xenbus_pcifront_driver);
+
+	return err;
+}
+
+/* Initialize after the Xen PCI Frontend Stub is initialized */
+subsys_initcall(pcifront_init);
diff -r c6c739bf254d -r 51077c2b9d96 linux-2.6-xen-sparse/include/xen/pcifront.h
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/linux-2.6-xen-sparse/include/xen/pcifront.h	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,39 @@
+/*
+ * PCI Frontend - arch-dependendent declarations
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_ASM_PCIFRONT_H__
+#define __XEN_ASM_PCIFRONT_H__
+
+#include <linux/config.h>
+#include <linux/spinlock.h>
+
+#ifdef __KERNEL__
+
+struct pcifront_device;
+
+struct pcifront_sd {
+	int domain;
+	struct pcifront_device *pdev;
+};
+
+struct pci_bus;
+
+#ifdef CONFIG_PCI_DOMAINS
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+	struct pcifront_sd *sd = bus->sysdata;
+	return sd->domain;
+}
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+	return pci_domain_nr(bus);
+}
+#endif /* CONFIG_PCI_DOMAINS */
+
+extern spinlock_t pci_bus_lock;
+
+#endif /* __KERNEL__ */
+
+#endif /* __XEN_ASM_PCIFRONT_H__ */
diff -r c6c739bf254d -r 51077c2b9d96 xen/include/public/io/pciif.h
--- /dev/null	Thu Feb 16 14:26:02 2006
+++ b/xen/include/public/io/pciif.h	Thu Feb 16 20:53:52 2006
@@ -0,0 +1,55 @@
+/*
+ * PCI Backend/Frontend Common Data Structures & Macros
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#ifndef __XEN_PCI_COMMON_H__
+#define __XEN_PCI_COMMON_H__
+
+/* Be sure to bump this number if you change this file */
+#define XEN_PCI_MAGIC		"7"
+
+/* xen_pci_sharedinfo flags */
+#define _XEN_PCIF_active     (0)
+#define XEN_PCIF_active      (1<<_XEN_PCI_active)
+
+/* xen_pci_op commands */
+#define XEN_PCI_OP_conf_read    (0)
+#define XEN_PCI_OP_conf_write   (1)
+
+/* xen_pci_op error numbers */
+#define XEN_PCI_ERR_success          (0)
+#define XEN_PCI_ERR_dev_not_found   (-1)
+#define XEN_PCI_ERR_invalid_offset  (-2)
+#define XEN_PCI_ERR_access_denied   (-3)
+#define XEN_PCI_ERR_not_implemented (-4)
+/* XEN_PCI_ERR_op_failed - backend failed to complete the operation */
+#define XEN_PCI_ERR_op_failed       (-5)
+
+struct xen_pci_op {
+	/* IN: what action to perform: XEN_PCI_OP_* */
+	uint32_t cmd;
+
+	/* OUT: will contain an error number (if any) from errno.h */
+	int32_t err;
+
+	/* IN: which device to touch */
+	uint32_t domain; /* PCI Domain/Segment */
+	uint32_t bus;
+	uint32_t devfn;
+
+	/* IN: which configuration registers to touch */
+	int32_t offset;
+	int32_t size;
+
+	/* IN/OUT: Contains the result after a READ or the value to WRITE */
+	uint32_t value;
+};
+
+struct xen_pci_sharedinfo {
+	/* flags - XEN_PCIF_* */
+	uint32_t flags;
+	struct xen_pci_op op;
+};
+
+#endif /* __XEN_PCI_COMMON_H__ */

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2006-02-16 21:56 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-01-30 13:24 [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend Ryan
2006-01-30 15:06 ` Anthony Liguori
2006-01-30 18:43   ` Ryan
2006-01-31  0:37     ` Anthony Liguori
  -- strict thread matches above, loose matches on Subject: below --
2006-02-06 18:45 Dave Thompson (davetho)
2006-02-06 20:08 ` Ryan
2006-02-07 14:37 Ryan
2006-02-07 15:19 ` Keir Fraser
2006-02-07 15:50   ` Ryan
2006-02-07 15:59     ` Ryan
2006-02-07 17:57       ` Keir Fraser
2006-02-07 19:58         ` Ryan
2006-02-07 23:17           ` Keir Fraser
2006-02-08 17:36             ` Ryan
2006-02-16 21:56 Ryan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.