]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Add missing file
authorklu2 <klu2@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 5 May 2008 07:51:39 +0000 (07:51 +0000)
committerklu2 <klu2@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 5 May 2008 07:51:39 +0000 (07:51 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@5163 6f19259b-4bc3-4df7-8a09-765794883524

DuetPkg/CpuIoDxe/Ia32/CpuIoAccessGNU.c [new file with mode: 0644]

diff --git a/DuetPkg/CpuIoDxe/Ia32/CpuIoAccessGNU.c b/DuetPkg/CpuIoDxe/Ia32/CpuIoAccessGNU.c
new file mode 100644 (file)
index 0000000..6c7b198
--- /dev/null
@@ -0,0 +1,134 @@
+/*  This file is only used when not able to compile the MASM CpuIoAccess.asm\r
+    NOTE: Compiling with -fomit-frame-pointer would get you to roughly the exact\r
+    same code as the MASM file although GCC will typically include movzbl %al, %eax\r
+    or movzwl %ax, %eax instructions on the read functions such that the entire\r
+    eax result register will be valid, not just the lowest 8 or 16 bits.\r
+ */\r
+#ifdef __GNUC__\r
+\r
+/*  A quick note about GCC inline asm and the GNU assembler:\r
+    When gas encounters an instruction with a suffix (e.g. inb, inw, or inl vs. just in) it will\r
+    warn if the operand corresponding to the suffix is not of the correct size and will assume you\r
+    meant what you said when you specified the suffix.\r
+\r
+    Because GCC does not enable us to see whether it is replacing %0 with %al, %ax, or %eax it is\r
+    helpful to have the assembler warn us that GCC is making an incorrect assumption.  The actual\r
+    in or out instruction will always be generated correctly in this case since the assembler is\r
+    correct in assuming we meant what we said when we specified the suffix.  However, GCC might\r
+    generate incorrect surrounding code.  For example, if we were to incorrectly specify the\r
+    output size of an in instruction as UINT32, GCC would potentially fail to issue movz(b|w)l after\r
+    it under the assumption that the in instruction filled the entire eax register and not just\r
+    the al or ax portion.\r
+\r
+    GCC determines which size of register to use based on the C data type.  So for in instructions\r
+    the interesting type is that of the automatic variable named Data which is specified as an\r
+    output operand to the inline assembly statement.  For example:\r
+\r
+      UINT8     Data;\r
+      asm ( "inb %1, %0"\r
+          : "=a"(Data)\r
+          : "d"(Port)\r
+          );\r
+      return Data;\r
+\r
+    In this case, GCC will replace %0 with %al.  If Data had been specified as UINT16, it would replace\r
+    %0 with %ax, and for UINT32 with %eax.\r
+\r
+    Likewise in the case of IA32 out instructions, GCC will replace %0 with the appropriately sized\r
+    register based on the size of the input operand.  There is one gotcha though.  The CpuIoWrite\r
+    series of functions all use UINT32 as the type of the second (Data) argument.  This means that\r
+    for GCC to output the correct register size we must cast it appropriately.\r
+\r
+    The Port number is always a UINT16 so GCC will always ouput %dx.\r
+ */\r
+\r
+#include "CpuIoAccess.h"\r
+\r
+UINT8\r
+IA32API\r
+CpuIoRead8 (\r
+  IN  UINT16  Port\r
+  )\r
+{\r
+  UINT8     Data;\r
+  asm ( "inb %1, %0"\r
+      : "=a"(Data)\r
+      : "d"(Port)\r
+      );\r
+  return Data;\r
+}\r
+\r
+UINT16\r
+IA32API\r
+CpuIoRead16 (\r
+  IN  UINT16  Port\r
+  )\r
+{\r
+  UINT16    Data;\r
+  asm ( "inw %1, %0"\r
+      : "=a"(Data)\r
+      : "d"(Port)\r
+      );\r
+  return Data;\r
+}\r
+\r
+UINT32\r
+IA32API\r
+CpuIoRead32 (\r
+  IN  UINT16  Port\r
+  )\r
+{\r
+  UINT32    Data;\r
+  asm ( "inl %1, %0"\r
+      : "=a"(Data)\r
+      : "d"(Port)\r
+      );\r
+  return Data;\r
+}\r
+\r
+VOID\r
+IA32API\r
+CpuIoWrite8 (\r
+  IN  UINT16  Port,\r
+  IN  UINT32  Data\r
+  )\r
+{\r
+  asm ( "outb %1, %0"\r
+      : /* No outputs */\r
+      : "d"(Port)\r
+      , "a"((UINT8)Data)\r
+      );\r
+}\r
+\r
+VOID\r
+IA32API\r
+CpuIoWrite16 (\r
+  IN  UINT16  Port,\r
+  IN  UINT32  Data\r
+  )\r
+{\r
+  asm ( "outw %1, %0"\r
+      : /* No outputs */\r
+      : "d"(Port)\r
+      , "a"((UINT16)Data)\r
+      );\r
+}\r
+\r
+VOID\r
+IA32API\r
+CpuIoWrite32 (\r
+  IN  UINT16  Port,\r
+  IN  UINT32  Data\r
+  )\r
+{\r
+  asm ( "outl %1, %0"\r
+      : /* No outputs */\r
+      : "d"(Port)\r
+      /*  NOTE: Cast is technically unnecessary but we use it to illustrate\r
+          that we always want to output a UINT32 and never anything else.\r
+       */\r
+      , "a"((UINT32)Data) \r
+      );\r
+}\r
+\r
+#endif /* def __GNUC__ */\r