]>
Commit | Line | Data |
---|---|---|
a04ef65d | 1 | /* This file is only used when not able to compile the MASM CpuIoAccess.asm\r |
2 | NOTE: Compiling with -fomit-frame-pointer would get you to roughly the exact\r | |
3 | same code as the MASM file although GCC will typically include movzbl %al, %eax\r | |
4 | or movzwl %ax, %eax instructions on the read functions such that the entire\r | |
5 | eax result register will be valid, not just the lowest 8 or 16 bits.\r | |
6 | */\r | |
7 | #ifdef __GNUC__\r | |
8 | \r | |
9 | /* A quick note about GCC inline asm and the GNU assembler:\r | |
10 | When gas encounters an instruction with a suffix (e.g. inb, inw, or inl vs. just in) it will\r | |
11 | warn if the operand corresponding to the suffix is not of the correct size and will assume you\r | |
12 | meant what you said when you specified the suffix.\r | |
13 | \r | |
14 | Because GCC does not enable us to see whether it is replacing %0 with %al, %ax, or %eax it is\r | |
15 | helpful to have the assembler warn us that GCC is making an incorrect assumption. The actual\r | |
16 | in or out instruction will always be generated correctly in this case since the assembler is\r | |
17 | correct in assuming we meant what we said when we specified the suffix. However, GCC might\r | |
18 | generate incorrect surrounding code. For example, if we were to incorrectly specify the\r | |
19 | output size of an in instruction as UINT32, GCC would potentially fail to issue movz(b|w)l after\r | |
20 | it under the assumption that the in instruction filled the entire eax register and not just\r | |
21 | the al or ax portion.\r | |
22 | \r | |
23 | GCC determines which size of register to use based on the C data type. So for in instructions\r | |
24 | the interesting type is that of the automatic variable named Data which is specified as an\r | |
25 | output operand to the inline assembly statement. For example:\r | |
26 | \r | |
27 | UINT8 Data;\r | |
28 | asm ( "inb %1, %0"\r | |
29 | : "=a"(Data)\r | |
30 | : "d"(Port)\r | |
31 | );\r | |
32 | return Data;\r | |
33 | \r | |
34 | In this case, GCC will replace %0 with %al. If Data had been specified as UINT16, it would replace\r | |
35 | %0 with %ax, and for UINT32 with %eax.\r | |
36 | \r | |
37 | Likewise in the case of IA32 out instructions, GCC will replace %0 with the appropriately sized\r | |
38 | register based on the size of the input operand. There is one gotcha though. The CpuIoWrite\r | |
39 | series of functions all use UINT32 as the type of the second (Data) argument. This means that\r | |
40 | for GCC to output the correct register size we must cast it appropriately.\r | |
41 | \r | |
42 | The Port number is always a UINT16 so GCC will always ouput %dx.\r | |
43 | */\r | |
44 | \r | |
45 | #include "CpuIoAccess.h"\r | |
46 | \r | |
47 | UINT8\r | |
d8bee43c | 48 | EFIAPI\r |
a04ef65d | 49 | CpuIoRead8 (\r |
50 | IN UINT16 Port\r | |
51 | )\r | |
52 | {\r | |
53 | UINT8 Data;\r | |
54 | asm ( "inb %1, %0"\r | |
55 | : "=a"(Data)\r | |
56 | : "d"(Port)\r | |
57 | );\r | |
58 | return Data;\r | |
59 | }\r | |
60 | \r | |
61 | UINT16\r | |
d8bee43c | 62 | EFIAPI\r |
a04ef65d | 63 | CpuIoRead16 (\r |
64 | IN UINT16 Port\r | |
65 | )\r | |
66 | {\r | |
67 | UINT16 Data;\r | |
68 | asm ( "inw %1, %0"\r | |
69 | : "=a"(Data)\r | |
70 | : "d"(Port)\r | |
71 | );\r | |
72 | return Data;\r | |
73 | }\r | |
74 | \r | |
75 | UINT32\r | |
d8bee43c | 76 | EFIAPI\r |
a04ef65d | 77 | CpuIoRead32 (\r |
78 | IN UINT16 Port\r | |
79 | )\r | |
80 | {\r | |
81 | UINT32 Data;\r | |
82 | asm ( "inl %1, %0"\r | |
83 | : "=a"(Data)\r | |
84 | : "d"(Port)\r | |
85 | );\r | |
86 | return Data;\r | |
87 | }\r | |
88 | \r | |
89 | VOID\r | |
d8bee43c | 90 | EFIAPI\r |
a04ef65d | 91 | CpuIoWrite8 (\r |
92 | IN UINT16 Port,\r | |
93 | IN UINT32 Data\r | |
94 | )\r | |
95 | {\r | |
96 | asm ( "outb %1, %0"\r | |
97 | : /* No outputs */\r | |
98 | : "d"(Port)\r | |
99 | , "a"((UINT8)Data)\r | |
100 | );\r | |
101 | }\r | |
102 | \r | |
103 | VOID\r | |
d8bee43c | 104 | EFIAPI\r |
a04ef65d | 105 | CpuIoWrite16 (\r |
106 | IN UINT16 Port,\r | |
107 | IN UINT32 Data\r | |
108 | )\r | |
109 | {\r | |
110 | asm ( "outw %1, %0"\r | |
111 | : /* No outputs */\r | |
112 | : "d"(Port)\r | |
113 | , "a"((UINT16)Data)\r | |
114 | );\r | |
115 | }\r | |
116 | \r | |
117 | VOID\r | |
d8bee43c | 118 | EFIAPI\r |
a04ef65d | 119 | CpuIoWrite32 (\r |
120 | IN UINT16 Port,\r | |
121 | IN UINT32 Data\r | |
122 | )\r | |
123 | {\r | |
124 | asm ( "outl %1, %0"\r | |
125 | : /* No outputs */\r | |
126 | : "d"(Port)\r | |
127 | /* NOTE: Cast is technically unnecessary but we use it to illustrate\r | |
128 | that we always want to output a UINT32 and never anything else.\r | |
129 | */\r | |
130 | , "a"((UINT32)Data) \r | |
131 | );\r | |
132 | }\r | |
133 | \r | |
134 | #endif /* def __GNUC__ */\r |