1 /******************************************************************************
2  * ioport_emulate.c
3  *
4  * Handle I/O port access quirks of various platforms.
5  */
6 
7 #include <xen/init.h>
8 #include <xen/sched.h>
9 #include <xen/dmi.h>
10 
ioemul_handle_proliant_quirk(u8 opcode,char * io_emul_stub,struct cpu_user_regs * regs)11 static void ioemul_handle_proliant_quirk(
12     u8 opcode, char *io_emul_stub, struct cpu_user_regs *regs)
13 {
14     uint16_t port = regs->dx;
15     uint8_t value = regs->al;
16 
17     if ( (opcode != 0xee) || (port != 0xcd4) || !(value & 0x80) )
18         return;
19 
20     /*    pushf */
21     io_emul_stub[0] = 0x9c;
22     /*    cli */
23     io_emul_stub[1] = 0xfa;
24     /*    out %al,%dx */
25     io_emul_stub[2] = 0xee;
26     /* 1: in %dx,%al */
27     io_emul_stub[3] = 0xec;
28     /*    test $0x80,%al */
29     io_emul_stub[4] = 0xa8;
30     io_emul_stub[5] = 0x80;
31     /*    jnz 1b */
32     io_emul_stub[6] = 0x75;
33     io_emul_stub[7] = 0xfb;
34     /*    popf */
35     io_emul_stub[8] = 0x9d;
36     /*    ret */
37     io_emul_stub[9] = 0xc3;
38 }
39 
proliant_quirk(struct dmi_system_id * d)40 static int __init proliant_quirk(struct dmi_system_id *d)
41 {
42     ioemul_handle_quirk = ioemul_handle_proliant_quirk;
43     return 0;
44 }
45 
46 /* This table is the set of system-specific I/O emulation hooks. */
47 static struct dmi_system_id __initdata ioport_quirks_tbl[] = {
48     /*
49      * I/O emulation hook for certain HP ProLiant servers with
50      * 'special' SMM goodness.
51      */
52     {
53         .callback = proliant_quirk,
54         .ident = "HP ProLiant DL3xx",
55         .matches = {
56             DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
57             DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL3"),
58         },
59     },
60     {
61         .callback = proliant_quirk,
62         .ident = "HP ProLiant DL5xx",
63         .matches = {
64             DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
65             DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL5"),
66         },
67     },
68     {
69         .callback = proliant_quirk,
70         .ident = "HP ProLiant DL7xx",
71         .matches = {
72             DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
73             DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL7"),
74         },
75     },
76     {
77         .callback = proliant_quirk,
78         .ident = "HP ProLiant ML3xx",
79         .matches = {
80             DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
81             DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant ML3"),
82         },
83     },
84     {
85         .callback = proliant_quirk,
86         .ident = "HP ProLiant ML5xx",
87         .matches = {
88             DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
89             DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant ML5"),
90         },
91     },
92     {
93         .callback = proliant_quirk,
94         .ident = "HP ProLiant BL2xx",
95         .matches = {
96             DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
97             DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL2"),
98         },
99     },
100     {
101         .callback = proliant_quirk,
102         .ident = "HP ProLiant BL4xx",
103         .matches = {
104             DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
105             DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL4"),
106         },
107     },
108     {
109         .callback = proliant_quirk,
110         .ident = "HP ProLiant BL6xx",
111         .matches = {
112             DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
113             DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL6"),
114         },
115     },
116     { }
117 };
118 
ioport_quirks_init(void)119 static int __init ioport_quirks_init(void)
120 {
121     dmi_check_system(ioport_quirks_tbl);
122     return 0;
123 }
124 __initcall(ioport_quirks_init);
125 
126 /*
127  * Local variables:
128  * mode: C
129  * c-file-style: "BSD"
130  * c-basic-offset: 4
131  * tab-width: 4
132  * indent-tabs-mode: nil
133  * End:
134  */
135