[PATCH] Memmory mapped PCI configuration

Nico Huber <[email protected]> Tue, 18 Feb 2014 12:50:26 +0100
Newsgroups gmane.comp.emulators.bochs.devel
Message-ID <[email protected]>
Dear Bochs developers,

please find attached a patch to implement memory mapped PCI
configuration (MMConf) in Bochs. This PCIe style of configuration maps
one 4K page for each PCI device' configuration space. My patch maps for
this the 256MB from 0xd0000000 to 0xdfffffff. I haven't looked very deep
if this conflicts with any other resources but first tests showed it
working.

If you wonder, we use MMConf to map individual PCI devices into VMX
guests. Which is way easier than i/o port emulation.

I'm not sure if I did everything the right way. Any comments on this
patch are welcome. I can provide another patch that advertises this
memory region through ACPI if anyone cares.

Kind regards,
Nico Huber

-- 
M. Sc. Nico Huber
Berater, SINA-Softwareentwicklung
Public Sector
secunet Security Networks AG

Tel.: +49-201-5454-3635, Fax: +49-201-5454-1325
E-Mail: [email protected]
Mergenthalerallee 77, 65760 Eschborn, Deutschland
www.secunet.com
______________________________________________________________________

Sitz: Kronprinzenstraße 30, 45128 Essen, Deutschland
Amtsgericht Essen HRB 13615
Vorstand: Dr. Rainer Baumgart (Vors.), Willem Bulthuis, Thomas Pleines 
Aufsichtsratsvorsitzender: Dr. Peter Zattler
______________________________________________________________________

Index: iodev/iodev.h
===================================================================
--- iodev/iodev.h	(Revision 11935)
+++ iodev/iodev.h	(Arbeitskopie)
@@ -538,6 +538,11 @@
   // are use each of the IRQ 0..15 lines are stored here
   char *irq_handler_name[BX_MAX_IRQS];
 
+  static bx_bool mmcfg_read_handler(bx_phy_address a20addr, unsigned len, void *data, void *param);
+  bx_bool mmcfg_read(bx_phy_address a20addr, unsigned len, void *data);
+  static bx_bool mmcfg_write_handler(bx_phy_address a20addr, unsigned len, void *data, void *param);
+  bx_bool mmcfg_write(bx_phy_address a20addr, unsigned len, void *data);
+
   static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
   static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
   BX_DEV_SMF Bit32u read(Bit32u address, unsigned io_len);
Index: iodev/devices.cc
===================================================================
--- iodev/devices.cc	(Revision 11935)
+++ iodev/devices.cc	(Arbeitskopie)
@@ -262,6 +262,8 @@
       DEV_register_ioread_handler(this, read_handler, i, "i440FX", 7);
       DEV_register_iowrite_handler(this, write_handler, i, "i440FX", 7);
     }
+
+    DEV_register_memory_handlers(this, mmcfg_read_handler, mmcfg_write_handler, 0xd0000000, 0xdfffffff);
   }
 #endif
 
@@ -357,6 +359,7 @@
 void bx_devices_c::exit()
 {
   // delete i/o handlers before unloading plugins
+  DEV_unregister_memory_handlers(this, 0xd0000000, 0xdfffffff);
   struct io_handler_struct *io_read_handler = io_read_handlers.next;
   struct io_handler_struct *curr = NULL;
   while (io_read_handler != &io_read_handlers) {
@@ -399,6 +402,77 @@
   init_stubs();
 }
 
+bx_bool bx_devices_c::mmcfg_read_handler(bx_phy_address a20addr, unsigned len, void *data, void *param)
+{
+  bx_devices_c *class_ptr = (bx_devices_c *) param;
+  return class_ptr->mmcfg_read(a20addr, len, data);
+}
+
+bx_bool bx_devices_c::mmcfg_read(bx_phy_address a20addr, unsigned len, void *data)
+{
+  if ((len != 1                          ) &&
+      (len != 2 || (a20addr & 0x1) != 0x0) &&
+      (len != 4 || (a20addr & 0x3) != 0x0)) {
+    BX_PANIC(("Unsupported MMConf read at address 0x" FMT_PHY_ADDRX ", len %u !", a20addr, len));
+    return 1;
+  }
+
+  Bit8u bus, devfunc;
+  Bit16u regnum;
+  Bit32u handle, value;
+
+  bus     = (a20addr >> 20) &  0xff;
+  devfunc = (a20addr >> 12) &  0xff;
+  regnum  =  a20addr        & 0xfff;
+  handle  = pci.handler_id[devfunc];
+  if (!bus && !(regnum & 0xf00) && (handle < BX_MAX_PCI_DEVICES))
+    value = pci.pci_handler[handle].handler->pci_read_handler(regnum & 0xff, len);
+  else
+    value = 0xffffffff;
+
+  switch (len) {
+  case 1:
+    *((Bit8u  *)data) = value & 0xff;
+    break;
+  case 2:
+    *((Bit16u *)data) = value & 0xffff;
+    break;
+  case 4:
+    *((Bit32u *)data) = value;
+    break;
+  }
+  return 1;
+}
+
+bx_bool bx_devices_c::mmcfg_write_handler(bx_phy_address a20addr, unsigned len, void *data, void *param)
+{
+  bx_devices_c *class_ptr = (bx_devices_c *) param;
+  return class_ptr->mmcfg_write(a20addr, len, data);
+}
+
+bx_bool bx_devices_c::mmcfg_write(bx_phy_address a20addr, unsigned len, void *data)
+{
+  if ((len != 1                          ) &&
+      (len != 2 || (a20addr & 0x1) != 0x0) &&
+      (len != 4 || (a20addr & 0x3) != 0x0)) {
+    BX_PANIC(("Unsupported MMConf write to address 0x" FMT_PHY_ADDRX ", len %u !", a20addr, len));
+    return 1;
+  }
+
+  Bit8u bus, devfunc;
+  Bit16u regnum;
+  Bit32u handle, value;
+
+  bus     = (a20addr >> 20) &  0xff;
+  devfunc = (a20addr >> 12) &  0xff;
+  regnum  =  a20addr        & 0xfff;
+  handle  = pci.handler_id[devfunc];
+  if (!bus && !(regnum & 0xf00) && (handle < BX_MAX_PCI_DEVICES))
+    pci.pci_handler[handle].handler->pci_write_handler(regnum & 0xff, *((Bit32u *)data), len);
+
+  return 1;
+}
+
 Bit32u bx_devices_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
 {
 #if !BX_USE_DEV_SMF

------------------------------------------------------------------------------
Managing the Performance of Cloud-Based Applications
Take advantage of what the Cloud has to offer - Avoid Common Pitfalls.
Read the Whitepaper.
http://pubads.g.doubleclick.net/gampad/clk?id=121054471&iu=/4140/ostg.clktrk
_______________________________________________
bochs-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bochs-developers