]> xenbits.xensource.com Git - xen.git/commitdiff
x86: Fix emulation of PCI access register at I/O port 0xcf8.
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 16 Apr 2008 09:04:22 +0000 (10:04 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 16 Apr 2008 09:04:22 +0000 (10:04 +0100)
The register is only visible for DWORD accesses. Furthermore, some
chipsets place other registers in the range 0xf8-0xcfb for sub-DWORD
accesses.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/arch/x86/domain_build.c
xen/arch/x86/traps.c

index 56106bae2f02ebf1a9b3d99742cd37e96938c8f3..10b1460ba38b8334c83a3187bdad2629081605d1 100644 (file)
@@ -957,8 +957,8 @@ int __init construct_dom0(
     rc |= ioports_deny_access(dom0, 0x40, 0x43);
     /* PIT Channel 2 / PC Speaker Control. */
     rc |= ioports_deny_access(dom0, 0x61, 0x61);
-    /* PCI configuration spaces. */
-    rc |= ioports_deny_access(dom0, 0xcf8, 0xcff);
+    /* PCI configuration space (NB. 0xcf8 has special treatment). */
+    rc |= ioports_deny_access(dom0, 0xcfc, 0xcff);
     /* Command-line I/O ranges. */
     process_dom0_ioports_disable();
 
index 5e39c9b4174c29f01f077e672cca43bebebf5d8c..94fb3a3d1fa3dc9b381be9ef9d4240fbf20d3bbc 100644 (file)
@@ -1399,6 +1399,13 @@ static int admin_io_okay(
     unsigned int port, unsigned int bytes,
     struct vcpu *v, struct cpu_user_regs *regs)
 {
+    /*
+     * Port 0xcf8 (CONFIG_ADDRESS) is only visible for DWORD accesses.
+     * We never permit direct access to that register.
+     */
+    if ( (port == 0xcf8) && (bytes == 4) )
+        return 0;
+
     return ioports_access_permitted(v->domain, port, port + bytes - 1);
 }
 
@@ -1431,10 +1438,10 @@ static uint32_t guest_io_read(
         {
             sub_data = pv_pit_handler(port, 0, 0);
         }
-        else if ( (port & 0xfffc) == 0xcf8 )
+        else if ( (port == 0xcf8) && (bytes == 4) )
         {
-            size = min(bytes, 4 - (port & 3));
-            sub_data = v->domain->arch.pci_cf8 >> ((port & 3) * 8);
+            size = 4;
+            sub_data = v->domain->arch.pci_cf8;
         }
         else if ( ((port & 0xfffc) == 0xcfc) && IS_PRIV(v->domain) )
         {
@@ -1489,19 +1496,10 @@ static void guest_io_write(
         {
             pv_pit_handler(port, (uint8_t)data, 1);
         }
-        else if ( (port & 0xfffc) == 0xcf8 )
+        else if ( (port == 0xcf8) && (bytes == 4) )
         {
-            size = min(bytes, 4 - (port & 3));
-            if ( size == 4 )
-            {
-                v->domain->arch.pci_cf8 = data;
-            }
-            else
-            {
-                uint32_t mask = ((1u << (size * 8)) - 1) << ((port & 3) * 8);
-                v->domain->arch.pci_cf8 &= ~mask;
-                v->domain->arch.pci_cf8 |= (data << ((port & 3) * 8)) & mask;
-            }
+            size = 4;
+            v->domain->arch.pci_cf8 = data;
         }
         else if ( ((port & 0xfffc) == 0xcfc) && IS_PRIV(v->domain) )
         {