Garrett, Michael (ISS Software)
2007-Nov-26  20:45 UTC
[Xen-devel] Xen patch to fix management support on HP ProLiant systems
# HG changeset patch
# User Mike Garrett <michael.garrett@hp.com>
# Date 1196108221 21600
# Node ID 32be7dd9fab00cf4fb9014ab235497a39593ffb4
# Parent  ba69fe2dce91cd7ef633b4b21706344f6be1a6de
Adds support to allow host-platform-specific handling of I/O port traps.
Specifically adds support to handle an HP ProLiant I/O port in a special way.
Signed-off-by: Mike Garrett <michael.garrett@hp.com>
diff -r ba69fe2dce91 -r 32be7dd9fab0 xen/arch/x86/Makefile
--- a/xen/arch/x86/Makefile     Tue Nov 13 20:13:50 2007 +0000
+++ b/xen/arch/x86/Makefile     Mon Nov 26 14:17:01 2007 -0600
@@ -31,6 +31,7 @@ obj-y += nmi.o
 obj-y += nmi.o
 obj-y += numa.o
 obj-y += physdev.o
+obj-y += hp_proliant.o
 obj-y += rwlock.o
 obj-y += setup.o
 obj-y += shutdown.o
diff -r ba69fe2dce91 -r 32be7dd9fab0 xen/arch/x86/hp_proliant.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hp_proliant.c        Mon Nov 26 14:17:01 2007 -0600
@@ -0,0 +1,87 @@
+/* HP ProLiant specific code */
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/sched.h>
+#include <xen/lib.h>
+#include <xen/errno.h>
+#include <xen/mm.h>
+#include <xen/console.h>
+#include <xen/shutdown.h>
+#include <asm/regs.h>
+#include <xen/delay.h>
+#include <xen/event.h>
+#include <xen/spinlock.h>
+#include <xen/irq.h>
+#include <xen/perfc.h>
+#include <xen/softirq.h>
+#include <xen/domain_page.h>
+#include <xen/symbols.h>
+#include <xen/iocap.h>
+#include <xen/nmi.h>
+#include <xen/version.h>
+#include <xen/kexec.h>
+#include <asm/paging.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/desc.h>
+#include <asm/debugreg.h>
+#include <asm/smp.h>
+#include <asm/flushtlb.h>
+#include <asm/uaccess.h>
+#include <asm/i387.h>
+#include <asm/debugger.h>
+#include <asm/msr.h>
+#include <asm/shared.h>
+#include <asm/x86_emulate.h>
+#include <asm/hvm/vpt.h>
+#include <xen/dmi.h>
+
+
+/* Declare access to a function pointer used to handle platform specific I/O
port emulation */
+extern u8 (*emulate_platform_specific_io_port)(u8 opcode, u16 port, u8 value,
char* io_emul_stub, struct cpu_user_regs *regs);
+
+/* Do special handling of HP ProLiant port */
+static u8 emulate_proliant_specific_io_port(u8 opcode, u16 port, u8 value,
char* io_emul_stub, struct cpu_user_regs *regs)
+{
+       /* if opcode = I/O write, and port = 0CD4 and we are writing the high
bit to 1 */
+       if (opcode == 0xee && port == 0x0cd4 && (value &
0x80))
+       {
+           void (*io_emul)(struct cpu_user_regs *)
__attribute__((__regparm__(1)));
+
+           /* Handy function-typed pointer to the stub. */
+           io_emul = (void *) io_emul_stub;
+
+               /*
+                * important offsets (from original code)
+                * +0 -> +4/+11:        call host_to_guest_gpr_switch (32 bit
and 64 bit)
+                * ret is rigged to return to guest_to_host_gpr_switch via a
stack stunt
+                */
+
+               io_emul_stub[12] = 0x66;        //
+               io_emul_stub[13] = 0x9c;        // pushf
+               io_emul_stub[14] = 0xfa;        // cli
+               io_emul_stub[15] = 0xee;        // out  dx, al
+               // loop:
+               io_emul_stub[16] = 0xec;        // in al, dx
+               io_emul_stub[17] = 0xa8;        //
+               io_emul_stub[18] = 0x80;        // test al, 80h
+               io_emul_stub[19] = 0x75;        // jnz short loop
+               io_emul_stub[20] = 0xfb;        //
+               io_emul_stub[21] = 0x66;        //
+               io_emul_stub[22] = 0x9d;        // popf
+               io_emul_stub[23] = 0xc3;        // ret
+
+               io_emul(regs);
+
+               return 1;                                       // we handled
it, no need for generic handling
+       }
+       return 0;                                               // we
didn''t handle it, do generic handling
+}
+
+int __init set_proliant_io_emul(struct dmi_system_id *d)
+{
+       /* emulate_platform_specific_io_port should be NULL on entry */
+       emulate_platform_specific_io_port = emulate_proliant_specific_io_port;
+    return 0;
+}
diff -r ba69fe2dce91 -r 32be7dd9fab0 xen/arch/x86/setup.c
--- a/xen/arch/x86/setup.c      Tue Nov 13 20:13:50 2007 +0000
+++ b/xen/arch/x86/setup.c      Mon Nov 26 14:17:01 2007 -0600
@@ -49,6 +49,7 @@
 extern void generic_apic_probe(void);
 extern void numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn);
+extern int __init io_emul_init(void);
 extern u16 boot_edid_caps;
 extern u8 boot_edid_info[128];
@@ -868,6 +869,8 @@ void __init __start_xen(unsigned long mb
     acpi_boot_init();
+       io_emul_init();
+
     init_cpu_to_node();
     if ( smp_found_config )
diff -r ba69fe2dce91 -r 32be7dd9fab0 xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c      Tue Nov 13 20:13:50 2007 +0000
+++ b/xen/arch/x86/traps.c      Mon Nov 26 14:17:01 2007 -0600
@@ -62,6 +62,7 @@
 #include <asm/shared.h>
 #include <asm/x86_emulate.h>
 #include <asm/hvm/vpt.h>
+#include <xen/dmi.h>
 /*
  * opt_nmi: one of ''ignore'', ''dom0'', or
''fatal''.
@@ -110,6 +111,7 @@ DECLARE_TRAP_HANDLER(spurious_interrupt_
 long do_set_debugreg(int reg, unsigned long value);
 unsigned long do_get_debugreg(int reg);
+u8 (*emulate_platform_specific_io_port)(u8 opcode, u16 port, u8 value, char*
io_emul_stub, struct cpu_user_regs *regs) = NULL;
 static int debug_stack_lines = 20;
 integer_param("debug_stack_lines", debug_stack_lines);
@@ -1331,7 +1333,7 @@ static int emulate_privileged_op(struct
                            ? (*(u32 *)®s->reg = (val)) \
                            : (*(u16 *)®s->reg = (val)))
     unsigned long code_base, code_limit;
-    char io_emul_stub[16];
+    char io_emul_stub[32];     /* size increased from 16 to 32 bytes to handle
platform-specific port emulation */
     void (*io_emul)(struct cpu_user_regs *) __attribute__((__regparm__(1)));
     u32 l, h, eax, edx;
@@ -1642,7 +1644,11 @@ static int emulate_privileged_op(struct
         switch ( op_bytes )
         {
         case 1:
-            if ( guest_outb_okay(port, v, regs) )
+                       /* check and emulate platform-specific I/O ports */
+                       if (emulate_platform_specific_io_port != NULL &&
+                               emulate_platform_specific_io_port(opcode, port,
(u8) regs->eax, io_emul_stub, regs))
+                               ; /* no more work to do, if true, the platform
specific handler emulated it fully */
+            else if ( guest_outb_okay(port, v, regs) )
             {
                 io_emul(regs);
                 if ( pv_post_outb_hook )
@@ -2850,6 +2856,67 @@ unsigned long do_get_debugreg(int reg)
     return current->arch.guest_context.debugreg[reg];
 }
+/*     This table is the set of system specific I/O emulation hooks */
+extern int __init set_proliant_io_emul(struct dmi_system_id *d);
+static struct dmi_system_id __initdata io_emul_init_tbl[] = {
+    {    /* Handle I/O emulation hook for certain HP ProLiant servers */
+        .callback = set_proliant_io_emul,
+        .ident = "HP ProLiant DL3xx",
+        .matches = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
+            DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL3"),
+        },
+    },
+    {    /* Handle I/O emulation hook for certain HP ProLiant servers */
+        .callback = set_proliant_io_emul,
+        .ident = "HP ProLiant DL5xx",
+        .matches = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
+            DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL5"),
+        },
+    },
+    {    /* Handle I/O emulation hook for certain HP ProLiant servers */
+        .callback = set_proliant_io_emul,
+        .ident = "HP ProLiant ML3xx",
+        .matches = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
+            DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant ML3"),
+        },
+    },
+    {    /* Handle I/O emulation hook for certain HP ProLiant servers */
+        .callback = set_proliant_io_emul,
+        .ident = "HP ProLiant ML5xx",
+        .matches = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
+            DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant ML5"),
+        },
+    },
+    {    /* Handle I/O emulation hook for certain HP ProLiant servers */
+        .callback = set_proliant_io_emul,
+        .ident = "HP ProLiant BL4xx",
+        .matches = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
+            DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL4"),
+        },
+    },
+    {    /* Handle I/O emulation hook for certain HP ProLiant servers */
+        .callback = set_proliant_io_emul,
+        .ident = "HP ProLiant BL6xx",
+        .matches = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
+            DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL6"),
+        },
+    },
+    { }
+};
+
+/* Called during setup, allows us to hook system-specific I/O emulation hooks
*/
+int __init io_emul_init(void)
+{
+       dmi_check_system(io_emul_init_tbl);
+       return 0;
+}
+
 /*
  * Local variables:
  * mode: C
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel