: PCI Host Proxy v0.1
RFC PATCH 1/1 : PCI Host Proxy v0.1
Hi,
Attached is the first draft of a patch to add PCI Host <-> Guest proxy mechanism. This allows PCI devices on the host machine to be presented to the guest operating system for usage. This is similar to the bochs 'pcidev' functionality. This code is not ready for inclusion yet, rather it is just to show where I'm at and perhaps provoke some discussion.
The code works only with a Linux host operating system (though should compile everywhere). We use the /proc/bus/pci interface to gain access to the PCI resources in an architecture-portable way.
This code is mainly intended for people who wish to reverse engineer device drivers on proprietary operating systems. This is due to some fairly serious technical shortfalls, most notably our lack of ability to trap and emulate PCI DMA transfers.
How to use:
1. Apply patch to qemu, rebuild and reinstall.
2. Find the bus:dev.fn numbers of the device you wish to map in to qemu using lspci. Run qemu with the "-pci -pciproxy bus:dev.fn" command line switches eg: "-pci -pciproxy 00:0a.0".
Here is a screenshot to prove it works ;)
http://www.scaramanga.co.uk/stuff/qemu-pciproxy-0.1.png (47KB)
Current limitations:
o Memory resources are not mapped in yet.
o ROM resources are not mapped in yet.
o IRQs are not passed along yet.
o Will probably never support PCI DMA without guest OS patching.
Future Ideas:
o Fast logging of information between guest OS -> hardware
o Log reading / conversion tool, so reverse engineers can share info
o Support PCI-DMA by patching guest OS's
o USB proxy along the same lines
o AGP support (map GART with Linux agpgart)
Have fun :)
Makefile.target +1 -1
@@ -232,7 +232,7 @@ endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o monitor.o pci.o +VL_OBJS=vl.o osdep.o block.o monitor.o pci.o pciproxy.o ifeq ($(TARGET_ARCH), i386) # Hardware support
configure +5 -0
@@ -390,6 +390,11 @@ elif test -f "/usr/include/byteswap.h" ; then echo "#define HAVE_BYTESWAP_H 1" >> $config_h fi +if test -f "/usr/include/sys/io.h"; then + echo "#define HAVE_SYS_IO_H 1" >> $config_h + echo "#define HAVE_IOPL 1" >> $config_h + echo "#define HAVE_IOPERM 1" >> $config_h +fi if test "$gdbstub" = "yes" ; then echo "CONFIG_GDBSTUB=yes" >> $config_mak echo "#define CONFIG_GDBSTUB 1" >> $config_h
hw/pc.c +2 -0
@@ -386,6 +386,8 @@if (pci_enabled) {i440fx_init ();piix3_init (); +if ( pciproxy_devpath ) +pciproxy_add_device (pciproxy_devpath); }/* init basic PC hardware */
hw/pciproxy.c +577 -0
577 lines not on this page · raw message
vl.c +6 -0
@@ -129,6 +129,7 @@int audio_enabled =0 ;int pci_enabled =0 ;int prep_enabled =0 ; +char *pciproxy_devpath =NULL ;/***********************************************************/ /* x86 ISA bus support */
@@ -2015,6 +2016,7 @@ QEMU_OPTION_no_code_copy, QEMU_OPTION_pci, QEMU_OPTION_prep, + QEMU_OPTION_pciproxy, }; typedef struct QEMUOption {
@@ -2065,6 +2067,7 @@ #ifdef TARGET_PPC { "prep", 0, QEMU_OPTION_prep }, #endif + { "pciproxy", HAS_ARG, QEMU_OPTION_pciproxy }, { NULL }, };
@@ -2341,6 +2344,9 @@case QEMU_OPTION_prep: prep_enabled =1 ;break ; +case QEMU_OPTION_pciproxy: + pciproxy_devpath = (char *)optarg; +break ; } } }
vl.h +4 -0
@@ -434,6 +434,10 @@void pci_pmac_init (void );void pci_ppc_bios_init (void ); +/* pciproxy.c */ +void pciproxy_add_device (char *devpath); +extern char *pciproxy_devpath; +/* vga.c */ #define VGA_RAM_SIZE (4096 * 1024)
Quoted 1 line · Gianni Tedesco
[snip]
Wow... This is very nice. I can see that it will help with driver support (via reverse engineering) a lot.
Best,
Kyle
Quoted 2 lines · Gianni Tedesco
Current limitations:
o Memory resources are not mapped in yet.
Fabrice,
Will the following work for PCI memory spaces? (I don't have any setups which do MMIO atm to test on).
for (i=addr; i < addr + len; i+=4)
cpu_register_io_memory(i, pciproxy_readl, pciproxy_writel);
If so, can I allow it to pass down an opaque pointer?
Signature · 3 lines
// Gianni Tedesco (gianni at scaramanga dot co dot uk) lynx --source www.scaramanga.co.uk/scaramanga.asc | gpg --import 8646BE7D: 6D9F 2287 870E A2C9 8F60 3A3C 91B5 7669 8646 BE7D
Quoted 11 lines · Gianni Tedesco
Quoted 2 lines · Gianni Tedesco
Current limitations:
o Memory resources are not mapped in yet.Fabrice,
Will the following work for PCI memory spaces? (I don't have any setups which do MMIO atm to test on).
for (i=addr; i < addr + len; i+=4)
cpu_register_io_memory(i, pciproxy_readl, pciproxy_writel);
erm, i mean, actually i do:
#define IOMEM_PCIPROXY (5 << IO_MEM_SHIFT)
cpu_register_io_memory(IOMEM_PCIPROXY >> IO_MEM_SHIFT,
pciproxy_readl,
pciproxy_writel);cpu_register_phys_mem(addr, len, IOMEM_PCIPROXY);
And can i still make the change to cpu_register_io_memory to pass down an opaque pointer? Actually this would be nicer on the cpu_register_phys_mem, but that'd be an impact on hot-paths i guess so I'll just have to work around it in pciproxy.
Signature · 3 lines
// Gianni Tedesco (gianni at scaramanga dot co dot uk) lynx --source www.scaramanga.co.uk/scaramanga.asc | gpg --import 8646BE7D: 6D9F 2287 870E A2C9 8F60 3A3C 91B5 7669 8646 BE7D
Quoted 4 lines · Gianni Tedesco
And can i still make the change to
cpu_register_io_memoryto pass down an opaque pointer? Actually this would be nicer on thecpu_register_phys_mem, but that'd be an impact on hot-paths i guess so I'll just have to work around it in pciproxy.
Actually it would be better served all round if I added an IO_MEM_CALLBACK and added a simple infrastructure to do:
cpu_register_callback_mem(addr, len, read_cbfn, write_cbfn);
That way there'd only be a lookup cost with something that used it. I'll hack up a patch to do that. And post it when ready.
Signature · 3 lines
// Gianni Tedesco (gianni at scaramanga dot co dot uk) lynx --source www.scaramanga.co.uk/scaramanga.asc | gpg --import 8646BE7D: 6D9F 2287 870E A2C9 8F60 3A3C 91B5 7669 8646 BE7D