--- /dev/null
+/** @file\r
+ Execute 32-bit code in Long Mode.\r
+ Provide a thunk function to transition from long mode to compatibility mode to execute 32-bit code and then transit\r
+ back to long mode.\r
+\r
+ Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/BaseLib.h>\r
+#include <FspEas.h>\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ struct {\r
+ UINT32 LimitLow : 16;\r
+ UINT32 BaseLow : 16;\r
+ UINT32 BaseMid : 8;\r
+ UINT32 Type : 4;\r
+ UINT32 System : 1;\r
+ UINT32 Dpl : 2;\r
+ UINT32 Present : 1;\r
+ UINT32 LimitHigh : 4;\r
+ UINT32 Software : 1;\r
+ UINT32 Reserved : 1;\r
+ UINT32 DefaultSize : 1;\r
+ UINT32 Granularity : 1;\r
+ UINT32 BaseHigh : 8;\r
+ } Bits;\r
+ UINT64 Uint64;\r
+} IA32_GDT;\r
+#pragma pack()\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {\r
+ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 0x0: reserve */\r
+ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}}, /* 0x8: compatibility mode */\r
+ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 1, 0, 1, 0}}, /* 0x10: for long mode */\r
+ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}}, /* 0x18: data */\r
+ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 0x20: reserve */\r
+};\r
+\r
+//\r
+// IA32 Gdt register\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {\r
+ sizeof (mGdtEntries) - 1,\r
+ (UINTN) mGdtEntries\r
+ };\r
+\r
+/**\r
+ Assembly function to transition from long mode to compatibility mode to execute 32-bit code and then transit back to\r
+ long mode.\r
+\r
+ @param[in] Function The 32bit code entry to be executed.\r
+ @param[in] Param1 The first parameter to pass to 32bit code\r
+ @param[in] Param2 The second parameter to pass to 32bit code\r
+ @param[in] InternalGdtr The GDT and GDT descriptor used by this library\r
+\r
+ @return status.\r
+**/\r
+UINT32\r
+AsmExecute32BitCode (\r
+ IN UINT64 Function,\r
+ IN UINT64 Param1,\r
+ IN UINT64 Param2,\r
+ IN IA32_DESCRIPTOR *InternalGdtr\r
+ );\r
+\r
+/**\r
+ Wrapper for a thunk to transition from long mode to compatibility mode to execute 32-bit code and then transit back to\r
+ long mode.\r
+\r
+ @param[in] Function The 32bit code entry to be executed.\r
+ @param[in] Param1 The first parameter to pass to 32bit code.\r
+ @param[in] Param2 The second parameter to pass to 32bit code.\r
+\r
+ @return EFI_STATUS.\r
+**/\r
+EFI_STATUS\r
+Execute32BitCode (\r
+ IN UINT64 Function,\r
+ IN UINT64 Param1,\r
+ IN UINT64 Param2\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ IA32_DESCRIPTOR Idtr;\r
+\r
+ //\r
+ // Idtr might be changed inside of FSP. 32bit FSP only knows the <4G address.\r
+ // If IDTR.Base is >4G, FSP can not handle. So we need save/restore IDTR here for X64 only.\r
+ // Interrupt is already disabled here, so it is safety to update IDTR.\r
+ //\r
+ AsmReadIdtr (&Idtr);\r
+ Status = AsmExecute32BitCode (Function, Param1, Param2, &mGdt);\r
+ AsmWriteIdtr (&Idtr);\r
+\r
+ return Status;\r
+}\r
+\r