diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2007-12-06 11:23:04 +0000 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2007-12-06 11:23:04 +0000 |
commit | 37f5ccfb57bc748ac51f1948e107079ee001d7d8 (patch) | |
tree | bef26afe5c2f112fe571cb54743e7fbd28241fde | |
parent | 5048bfb26073bffccc96a0cd2eee8306caa8e82e (diff) | |
download | xen-37f5ccfb57bc748ac51f1948e107079ee001d7d8.tar.gz xen-37f5ccfb57bc748ac51f1948e107079ee001d7d8.tar.bz2 xen-37f5ccfb57bc748ac51f1948e107079ee001d7d8.zip |
x86: Fix management support on HP ProLiant systems.
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>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
-rw-r--r-- | xen/arch/x86/Makefile | 1 | ||||
-rw-r--r-- | xen/arch/x86/ioport_emulate.c | 125 | ||||
-rw-r--r-- | xen/arch/x86/traps.c | 7 |
3 files changed, 132 insertions, 1 deletions
diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index d61514b0a3..086a7b530f 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -24,6 +24,7 @@ obj-y += platform_hypercall.o obj-y += i387.o obj-y += i8259.o obj-y += io_apic.o +obj-y += ioport_emulate.o obj-y += irq.o obj-y += microcode.o obj-y += mm.o diff --git a/xen/arch/x86/ioport_emulate.c b/xen/arch/x86/ioport_emulate.c new file mode 100644 index 0000000000..2180b6027b --- /dev/null +++ b/xen/arch/x86/ioport_emulate.c @@ -0,0 +1,125 @@ +/****************************************************************************** + * ioport_emulate.c + * + * Handle I/O port access quirks of various platforms. + */ + +#include <xen/config.h> +#include <xen/init.h> +#include <xen/sched.h> +#include <xen/dmi.h> + +/* Function pointer used to handle platform specific I/O port emulation. */ +extern void (*ioemul_handle_quirk)( + u8 opcode, char *io_emul_stub, struct cpu_user_regs *regs); + +static void ioemul_handle_proliant_quirk( + u8 opcode, char *io_emul_stub, struct cpu_user_regs *regs) +{ + uint16_t port = regs->edx; + uint8_t value = regs->eax; + + if ( (opcode != 0xee) || (port != 0xcd4) || !(value & 0x80) ) + return; + + /* pushfw */ + io_emul_stub[ 0] = 0x66; + io_emul_stub[ 1] = 0x9c; + /* cli */ + io_emul_stub[ 2] = 0xfa; + /* out %al,%dx */ + io_emul_stub[ 3] = 0xee; + /* 1: in %dx,%al */ + io_emul_stub[ 4] = 0xec; + /* test $0x80,%al */ + io_emul_stub[ 5] = 0xa8; + io_emul_stub[ 6] = 0x80; + /* jnz 1b */ + io_emul_stub[ 7] = 0x75; + io_emul_stub[ 8] = 0xfb; + /* popfw */ + io_emul_stub[ 9] = 0x66; + io_emul_stub[10] = 0x9d; + /* ret */ + io_emul_stub[11] = 0xc3; +} + +int __init proliant_quirk(struct dmi_system_id *d) +{ + ioemul_handle_quirk = ioemul_handle_proliant_quirk; + return 0; +} + +/* This table is the set of system-specific I/O emulation hooks. */ +static struct dmi_system_id __initdata ioport_quirks_tbl[] = { + /* + * I/O emulation hook for certain HP ProLiant servers with + * 'special' SMM goodness. + */ + { + .callback = proliant_quirk, + .ident = "HP ProLiant DL3xx", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL3"), + }, + }, + { + .callback = proliant_quirk, + .ident = "HP ProLiant DL5xx", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL5"), + }, + }, + { + .callback = proliant_quirk, + .ident = "HP ProLiant ML3xx", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant ML3"), + }, + }, + { + .callback = proliant_quirk, + .ident = "HP ProLiant ML5xx", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant ML5"), + }, + }, + { + .callback = proliant_quirk, + .ident = "HP ProLiant BL4xx", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL4"), + }, + }, + { + .callback = proliant_quirk, + .ident = "HP ProLiant BL6xx", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL6"), + }, + }, + { } +}; + +int __init ioport_quirks_init(void) +{ + dmi_check_system(ioport_quirks_tbl); + return 0; +} +__initcall(ioport_quirks_init); + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index e02cfcf3ae..35cb44b6ff 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -110,6 +110,8 @@ DECLARE_TRAP_HANDLER(spurious_interrupt_bug); long do_set_debugreg(int reg, unsigned long value); unsigned long do_get_debugreg(int reg); +void (*ioemul_handle_quirk)( + u8 opcode, char *io_emul_stub, struct cpu_user_regs *regs); static int debug_stack_lines = 20; integer_param("debug_stack_lines", debug_stack_lines); @@ -1379,7 +1381,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) ? (*(u32 *)®s->reg = (val)) \ : (*(u16 *)®s->reg = (val))) unsigned long code_base, code_limit; - char io_emul_stub[16]; + char io_emul_stub[32]; void (*io_emul)(struct cpu_user_regs *) __attribute__((__regparm__(1))); u32 l, h, eax, edx; @@ -1636,6 +1638,9 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) /* Handy function-typed pointer to the stub. */ io_emul = (void *)io_emul_stub; + if ( ioemul_handle_quirk ) + ioemul_handle_quirk(opcode, &io_emul_stub[12], regs); + /* I/O Port and Interrupt Flag instructions. */ switch ( opcode ) { |