]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdePkg/Library/BaseLib/x86Thunk.c
Removed unnecessary ASSERT condition (assertion of real mode buffers' alignment)
[mirror_edk2.git] / MdePkg / Library / BaseLib / x86Thunk.c
index 8cb5f4f8bdfce04b3dcecd41f0c2dbfb506a5b00..d4e37ae59e6671a6cc060f3d527fd8da00ccd8cc 100644 (file)
 \r
 **/\r
 \r
+//\r
+// Byte packed structure for a segment descriptor in a GDT/LDT\r
+//\r
+typedef union {\r
+  struct {\r
+    UINT32  LimitLow:16;\r
+    UINT32  BaseLow:16;\r
+    UINT32  BaseMid:8;\r
+    UINT32  Type:4;\r
+    UINT32  S:1;\r
+    UINT32  DPL:2;\r
+    UINT32  P:1;\r
+    UINT32  LimitHigh:4;\r
+    UINT32  AVL:1;\r
+    UINT32  L:1;\r
+    UINT32  DB:1;\r
+    UINT32  G:1;\r
+    UINT32  BaseHigh:8;\r
+  } Bits;\r
+  UINT64  Uint64;\r
+} IA32_SEGMENT_DESCRIPTOR;\r
+\r
+extern CONST UINT8                  m16Start;\r
+extern CONST UINT16                 m16Size;\r
+extern CONST UINT16                 mThunk16Attr;\r
+extern CONST UINT16                 m16Gdt;\r
+extern CONST UINT16                 m16GdtrBase;\r
+extern CONST UINT16                 mTransition;\r
+\r
 /**\r
   Invokes 16-bit code in big real mode and returns the updated register set.\r
 \r
@@ -22,7 +51,7 @@
   on the real mode stack and the starting address of the save area is returned.\r
 \r
   @param  RegisterSet Values of registers before invocation of 16-bit code.\r
-  @param  Patch       Pointer to the area following the 16-bit code.\r
+  @param  Transition  Pointer to the transition code under 1MB.\r
 \r
   @return The pointer to a IA32_REGISTER_SET structure containing the updated\r
           register values.\r
 IA32_REGISTER_SET *\r
 InternalAsmThunk16 (\r
   IN      IA32_REGISTER_SET         *RegisterSet,\r
-  IN OUT  VOID                      *Patch\r
+  IN OUT  VOID                      *Transition\r
   );\r
 \r
+/**\r
+  Retrieves the properties for 16-bit thunk functions.\r
+\r
+  Computes the size of the buffer and stack below 1MB required to use the\r
+  AsmPrepareThunk16(), AsmThunk16() and AsmPrepareAndThunk16() functions. This\r
+  buffer size is returned in RealModeBufferSize, and the stack size is returned\r
+  in ExtraStackSize. If parameters are passed to the 16-bit real mode code,\r
+  then the actual minimum stack size is ExtraStackSize plus the maximum number\r
+  of bytes that need to be passed to the 16-bit real mode code.\r
+\r
+  If RealModeBufferSize is NULL, then ASSERT().\r
+  If ExtraStackSize is NULL, then ASSERT().\r
+\r
+  @param  RealModeBufferSize  A pointer to the size of the buffer below 1MB\r
+                              required to use the 16-bit thunk functions.\r
+  @param  ExtraStackSize      A pointer to the extra size of stack below 1MB\r
+                              that the 16-bit thunk functions require for\r
+                              temporary storage in the transition to and from\r
+                              16-bit real mode.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AsmGetThunk16Properties (\r
+  OUT     UINT32                    *RealModeBufferSize,\r
+  OUT     UINT32                    *ExtraStackSize\r
+  )\r
+{\r
+  ASSERT (RealModeBufferSize != NULL);\r
+  ASSERT (ExtraStackSize != NULL);\r
+\r
+  *RealModeBufferSize = m16Size;\r
+  *ExtraStackSize = sizeof (IA32_DWORD_REGS) + 8;\r
+}\r
+\r
 /**\r
   Prepares all structures a code required to use AsmThunk16().\r
 \r
@@ -51,7 +115,63 @@ AsmPrepareThunk16 (
   OUT     THUNK_CONTEXT             *ThunkContext\r
   )\r
 {\r
+  IA32_SEGMENT_DESCRIPTOR           *RealModeGdt;\r
+\r
   ASSERT (ThunkContext != NULL);\r
+  ASSERT ((UINTN)ThunkContext->RealModeBuffer < 0x100000);\r
+  ASSERT (ThunkContext->RealModeBufferSize >= m16Size);\r
+  ASSERT ((UINTN)ThunkContext->RealModeBuffer + m16Size <= 0x100000);\r
+\r
+  CopyMem (ThunkContext->RealModeBuffer, &m16Start, m16Size);\r
+\r
+  //\r
+  // Point RealModeGdt to the GDT to be used in transition\r
+  //\r
+  // RealModeGdt[0]: Reserved as NULL descriptor\r
+  // RealModeGdt[1]: Code Segment\r
+  // RealModeGdt[2]: Data Segment\r
+  // RealModeGdt[3]: Call Gate\r
+  //\r
+  RealModeGdt = (IA32_SEGMENT_DESCRIPTOR*)(\r
+                  (UINTN)ThunkContext->RealModeBuffer + m16Gdt);\r
+\r
+  //\r
+  // Update Code & Data Segment Descriptor\r
+  //\r
+  RealModeGdt[1].Bits.BaseLow =\r
+    (UINT32)(UINTN)ThunkContext->RealModeBuffer & ~0xf;\r
+  RealModeGdt[1].Bits.BaseMid =\r
+    (UINT32)(UINTN)ThunkContext->RealModeBuffer >> 16;\r
+\r
+  //\r
+  // Update transition code entry point offset\r
+  //\r
+  *(UINT32*)((UINTN)ThunkContext->RealModeBuffer + mTransition) +=\r
+    (UINT32)(UINTN)ThunkContext->RealModeBuffer & 0xf;\r
+\r
+  //\r
+  // Update Segment Limits for both Code and Data Segment Descriptors\r
+  //\r
+  if ((ThunkContext->ThunkAttributes & THUNK_ATTRIBUTE_BIG_REAL_MODE) == 0) {\r
+    //\r
+    // Set segment limits to 64KB\r
+    //\r
+    RealModeGdt[1].Bits.LimitHigh = 0;\r
+    RealModeGdt[1].Bits.G = 0;\r
+    RealModeGdt[2].Bits.LimitHigh = 0;\r
+    RealModeGdt[2].Bits.G = 0;\r
+  }\r
+\r
+  //\r
+  // Update GDTBASE for this thunk context\r
+  //\r
+  *(VOID**)((UINTN)ThunkContext->RealModeBuffer + m16GdtrBase) = RealModeGdt;\r
+\r
+  //\r
+  // Update Thunk Attributes\r
+  //\r
+  *(UINT32*)((UINTN)ThunkContext->RealModeBuffer + mThunk16Attr) =\r
+    ThunkContext->ThunkAttributes;\r
 }\r
 \r
 /**\r
@@ -74,28 +194,19 @@ AsmThunk16 (
   IN OUT  THUNK_CONTEXT             *ThunkContext\r
   )\r
 {\r
-  UINT16                            *Patch;\r
+  IA32_REGISTER_SET                 *UpdatedRegs;\r
 \r
   ASSERT (ThunkContext != NULL);\r
+  ASSERT ((UINTN)ThunkContext->RealModeBuffer < 0x100000);\r
+  ASSERT (ThunkContext->RealModeBufferSize >= m16Size);\r
+  ASSERT ((UINTN)ThunkContext->RealModeBuffer + m16Size <= 0x100000);\r
 \r
-  Patch = (UINT16*)(\r
-            (UINTN)ThunkContext->RealModeCode +\r
-            ThunkContext->RealModeCodeSize\r
-            );\r
+  UpdatedRegs = InternalAsmThunk16 (\r
+                  ThunkContext->RealModeState,\r
+                  ThunkContext->RealModeBuffer\r
+                  );\r
 \r
-  //\r
-  // 0x9a66 is the OpCode of far call with an operand size override.\r
-  //\r
-  *Patch = 0x9a66;\r
-\r
-  //\r
-  // CopyMem() here copies the updated register values back to RealModeState\r
-  //\r
-  CopyMem (\r
-    &ThunkContext->RealModeState,\r
-    InternalAsmThunk16 (&ThunkContext->RealModeState, Patch + 1),\r
-    sizeof (ThunkContext->RealModeState)\r
-    );\r
+  CopyMem (ThunkContext->RealModeState, UpdatedRegs, sizeof (*UpdatedRegs));\r
 }\r
 \r
 /**\r