summaryrefslogtreecommitdiffstats
path: root/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib
diff options
context:
space:
mode:
Diffstat (limited to 'IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib')
-rw-r--r--IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/BaseFspWrapperApiLib.inf71
-rw-r--r--IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/FspWrapperApiLib.c203
-rw-r--r--IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/IA32/DispatchExecute.c58
-rw-r--r--IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/DispatchExecute.c108
-rw-r--r--IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.S230
-rw-r--r--IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.asm230
6 files changed, 900 insertions, 0 deletions
diff --git a/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/BaseFspWrapperApiLib.inf b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/BaseFspWrapperApiLib.inf
new file mode 100644
index 0000000000..b1a9f38f4e
--- /dev/null
+++ b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/BaseFspWrapperApiLib.inf
@@ -0,0 +1,71 @@
+## @file
+# Provide FSP API related function.
+#
+# Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseFspWrapperApiLib
+ FILE_GUID = F42C789F-4D66-49AF-8C73-1AADC00437AC
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = FspWrapperApiLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+################################################################################
+#
+# Sources Section - list of files that are required for the build to succeed.
+#
+################################################################################
+
+[Sources]
+ FspWrapperApiLib.c
+
+[Sources.IA32]
+ IA32/DispatchExecute.c
+
+[Sources.X64]
+ X64/DispatchExecute.c
+ X64/Thunk64To32.asm
+ X64/Thunk64To32.S
+
+################################################################################
+#
+# Package Dependency Section - list of Package files that are required for
+# this module.
+#
+################################################################################
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFsp2Pkg/IntelFsp2Pkg.dec
+ IntelFsp2WrapperPkg/IntelFsp2WrapperPkg.dec
+
+[LibraryClasses]
+ BaseLib
+
+[Guids]
+ gFspHeaderFileGuid ## CONSUMES ## GUID
+
+[Pcd]
+ gFspWrapperTokenSpaceGuid.PcdFspmBaseAddress ## CONSUMES
+ gFspWrapperTokenSpaceGuid.PcdFspsBaseAddress ## CONSUMES
diff --git a/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/FspWrapperApiLib.c b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/FspWrapperApiLib.c
new file mode 100644
index 0000000000..8cf136fe1a
--- /dev/null
+++ b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/FspWrapperApiLib.c
@@ -0,0 +1,203 @@
+/** @file
+ Provide FSP API related function.
+
+ Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+
+#include <Library/FspWrapperApiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+
+/**
+ Wrapper for a thunk to transition from long mode to compatibility mode to execute 32-bit code and then transit back to
+ long mode.
+
+ @param[in] Function The 32bit code entry to be executed.
+ @param[in] Param1 The first parameter to pass to 32bit code.
+ @param[in] Param2 The second parameter to pass to 32bit code.
+
+ @return EFI_STATUS.
+**/
+EFI_STATUS
+Execute32BitCode (
+ IN UINT64 Function,
+ IN UINT64 Param1,
+ IN UINT64 Param2
+ );
+
+/**
+ Find FSP header pointer.
+
+ @param[in] FlashFvFspBase Flash address of FSP FV.
+
+ @return FSP header pointer.
+**/
+FSP_INFO_HEADER *
+EFIAPI
+FspFindFspHeader (
+ IN EFI_PHYSICAL_ADDRESS FlashFvFspBase
+ )
+{
+ UINT8 *CheckPointer;
+
+ CheckPointer = (UINT8 *) (UINTN) FlashFvFspBase;
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER *)CheckPointer)->Signature != EFI_FVH_SIGNATURE) {
+ return NULL;
+ }
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER *)CheckPointer)->ExtHeaderOffset != 0) {
+ CheckPointer = CheckPointer + ((EFI_FIRMWARE_VOLUME_HEADER *)CheckPointer)->ExtHeaderOffset;
+ CheckPointer = CheckPointer + ((EFI_FIRMWARE_VOLUME_EXT_HEADER *)CheckPointer)->ExtHeaderSize;
+ CheckPointer = (UINT8 *) ALIGN_POINTER (CheckPointer, 8);
+ } else {
+ CheckPointer = CheckPointer + ((EFI_FIRMWARE_VOLUME_HEADER *)CheckPointer)->HeaderLength;
+ }
+
+
+ CheckPointer = CheckPointer + sizeof (EFI_FFS_FILE_HEADER);
+
+ if (((EFI_RAW_SECTION *)CheckPointer)->Type != EFI_SECTION_RAW) {
+ return NULL;
+ }
+
+ CheckPointer = CheckPointer + sizeof (EFI_RAW_SECTION);
+
+ return (FSP_INFO_HEADER *)CheckPointer;
+}
+
+/**
+ Call FSP API - FspNotifyPhase.
+
+ @param[in] NotifyPhaseParams Address pointer to the NOTIFY_PHASE_PARAMS structure.
+
+ @return EFI status returned by FspNotifyPhase API.
+**/
+EFI_STATUS
+EFIAPI
+CallFspNotifyPhase (
+ IN NOTIFY_PHASE_PARAMS *NotifyPhaseParams
+ )
+{
+ FSP_INFO_HEADER *FspHeader;
+ FSP_NOTIFY_PHASE NotifyPhaseApi;
+ EFI_STATUS Status;
+ BOOLEAN InterruptState;
+
+ FspHeader = (FSP_INFO_HEADER *)FspFindFspHeader (PcdGet32 (PcdFspsBaseAddress));
+ if (FspHeader == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ NotifyPhaseApi = (FSP_NOTIFY_PHASE)(UINTN)(FspHeader->ImageBase + FspHeader->NotifyPhaseEntryOffset);
+ InterruptState = SaveAndDisableInterrupts ();
+ Status = Execute32BitCode ((UINTN)NotifyPhaseApi, (UINTN)NotifyPhaseParams, (UINTN)NULL);
+ SetInterruptState (InterruptState);
+
+ return Status;
+}
+
+/**
+ Call FSP API - FspMemoryInit.
+
+ @param[in] FspmUpdDataPtr Address pointer to the FSP_MEMORY_INIT_PARAMS structure.
+ @param[out] HobListPtr Address of the HobList pointer.
+
+ @return EFI status returned by FspMemoryInit API.
+**/
+EFI_STATUS
+EFIAPI
+CallFspMemoryInit (
+ IN VOID *FspmUpdDataPtr,
+ OUT VOID **HobListPtr
+ )
+{
+ FSP_INFO_HEADER *FspHeader;
+ FSP_MEMORY_INIT FspMemoryInitApi;
+ EFI_STATUS Status;
+ BOOLEAN InterruptState;
+
+ FspHeader = (FSP_INFO_HEADER *)FspFindFspHeader (PcdGet32 (PcdFspmBaseAddress));
+ if (FspHeader == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ FspMemoryInitApi = (FSP_MEMORY_INIT)(UINTN)(FspHeader->ImageBase + FspHeader->FspMemoryInitEntryOffset);
+ InterruptState = SaveAndDisableInterrupts ();
+ Status = Execute32BitCode ((UINTN)FspMemoryInitApi, (UINTN)FspmUpdDataPtr, (UINTN)HobListPtr);
+ SetInterruptState (InterruptState);
+
+ return Status;
+}
+
+/**
+ Call FSP API - TempRamExit.
+
+ @param[in] TempRamExitParam Address pointer to the TempRamExit parameters structure.
+
+ @return EFI status returned by TempRamExit API.
+**/
+EFI_STATUS
+EFIAPI
+CallTempRamExit (
+ IN VOID *TempRamExitParam
+ )
+{
+ FSP_INFO_HEADER *FspHeader;
+ FSP_TEMP_RAM_EXIT TempRamExitApi;
+ EFI_STATUS Status;
+ BOOLEAN InterruptState;
+
+ FspHeader = (FSP_INFO_HEADER *)FspFindFspHeader (PcdGet32 (PcdFspmBaseAddress));
+ if (FspHeader == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ TempRamExitApi = (FSP_TEMP_RAM_EXIT)(UINTN)(FspHeader->ImageBase + FspHeader->TempRamExitEntryOffset);
+ InterruptState = SaveAndDisableInterrupts ();
+ Status = Execute32BitCode ((UINTN)TempRamExitApi, (UINTN)TempRamExitParam, (UINTN)NULL);
+ SetInterruptState (InterruptState);
+
+ return Status;
+}
+
+/**
+ Call FSP API - FspSiliconInit.
+
+ @param[in] FspsUpdDataPtr Address pointer to the Silicon Init parameters structure.
+
+ @return EFI status returned by FspSiliconInit API.
+**/
+EFI_STATUS
+EFIAPI
+CallFspSiliconInit (
+ IN VOID *FspsUpdDataPtr
+ )
+{
+ FSP_INFO_HEADER *FspHeader;
+ FSP_SILICON_INIT FspSiliconInitApi;
+ EFI_STATUS Status;
+ BOOLEAN InterruptState;
+
+ FspHeader = (FSP_INFO_HEADER *)FspFindFspHeader (PcdGet32 (PcdFspsBaseAddress));
+ if (FspHeader == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ FspSiliconInitApi = (FSP_SILICON_INIT)(UINTN)(FspHeader->ImageBase + FspHeader->FspSiliconInitEntryOffset);
+ InterruptState = SaveAndDisableInterrupts ();
+ Status = Execute32BitCode ((UINTN)FspSiliconInitApi, (UINTN)FspsUpdDataPtr, (UINTN)NULL);
+ SetInterruptState (InterruptState);
+
+ return Status;
+}
diff --git a/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/IA32/DispatchExecute.c b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/IA32/DispatchExecute.c
new file mode 100644
index 0000000000..72b1762f4c
--- /dev/null
+++ b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/IA32/DispatchExecute.c
@@ -0,0 +1,58 @@
+/** @file
+ Execute 32-bit code in Protected Mode.
+
+ Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <FspEas.h>
+
+/**
+ FSP API functions.
+
+ @param[in] Param1 The first parameter to pass to 32bit code.
+ @param[in] Param2 The second parameter to pass to 32bit code.
+
+ @return EFI_STATUS.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *FSP_FUNCTION) (
+ IN VOID *Param1,
+ IN VOID *Param2
+ );
+
+/**
+ Wrapper for a thunk to transition from long mode to compatibility mode to execute 32-bit code and then transit back to
+ long mode.
+
+ @param[in] Function The 32bit code entry to be executed.
+ @param[in] Param1 The first parameter to pass to 32bit code.
+ @param[in] Param2 The second parameter to pass to 32bit code.
+
+ @return EFI_STATUS.
+**/
+EFI_STATUS
+Execute32BitCode (
+ IN UINT64 Function,
+ IN UINT64 Param1,
+ IN UINT64 Param2
+ )
+{
+ FSP_FUNCTION EntryFunc;
+ EFI_STATUS Status;
+
+ EntryFunc = (FSP_FUNCTION) (UINTN) (Function);
+ Status = EntryFunc ((VOID *)(UINTN)Param1, (VOID *)(UINTN)Param2);
+
+ return Status;
+}
+
diff --git a/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/DispatchExecute.c b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/DispatchExecute.c
new file mode 100644
index 0000000000..061d381c1b
--- /dev/null
+++ b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/DispatchExecute.c
@@ -0,0 +1,108 @@
+/** @file
+ Execute 32-bit code in Long Mode.
+ Provide a thunk function to transition from long mode to compatibility mode to execute 32-bit code and then transit
+ back to long mode.
+
+ Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <FspEas.h>
+
+#pragma pack(1)
+typedef union {
+ struct {
+ UINT32 LimitLow : 16;
+ UINT32 BaseLow : 16;
+ UINT32 BaseMid : 8;
+ UINT32 Type : 4;
+ UINT32 System : 1;
+ UINT32 Dpl : 2;
+ UINT32 Present : 1;
+ UINT32 LimitHigh : 4;
+ UINT32 Software : 1;
+ UINT32 Reserved : 1;
+ UINT32 DefaultSize : 1;
+ UINT32 Granularity : 1;
+ UINT32 BaseHigh : 8;
+ } Bits;
+ UINT64 Uint64;
+} IA32_GDT;
+#pragma pack()
+
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {
+ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 0x0: reserve */
+ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}}, /* 0x8: compatibility mode */
+ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 1, 0, 1, 0}}, /* 0x10: for long mode */
+ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}}, /* 0x18: data */
+ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 0x20: reserve */
+};
+
+//
+// IA32 Gdt register
+//
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {
+ sizeof (mGdtEntries) - 1,
+ (UINTN) mGdtEntries
+ };
+
+/**
+ Assembly function to transition from long mode to compatibility mode to execute 32-bit code and then transit back to
+ long mode.
+
+ @param[in] Function The 32bit code entry to be executed.
+ @param[in] Param1 The first parameter to pass to 32bit code
+ @param[in] Param2 The second parameter to pass to 32bit code
+ @param[in] InternalGdtr The GDT and GDT descriptor used by this library
+
+ @return status.
+**/
+UINT32
+AsmExecute32BitCode (
+ IN UINT64 Function,
+ IN UINT64 Param1,
+ IN UINT64 Param2,
+ IN IA32_DESCRIPTOR *InternalGdtr
+ );
+
+/**
+ Wrapper for a thunk to transition from long mode to compatibility mode to execute 32-bit code and then transit back to
+ long mode.
+
+ @param[in] Function The 32bit code entry to be executed.
+ @param[in] Param1 The first parameter to pass to 32bit code.
+ @param[in] Param2 The second parameter to pass to 32bit code.
+
+ @return EFI_STATUS.
+**/
+EFI_STATUS
+Execute32BitCode (
+ IN UINT64 Function,
+ IN UINT64 Param1,
+ IN UINT64 Param2
+ )
+{
+ EFI_STATUS Status;
+ IA32_DESCRIPTOR Idtr;
+
+ //
+ // Idtr might be changed inside of FSP. 32bit FSP only knows the <4G address.
+ // If IDTR.Base is >4G, FSP can not handle. So we need save/restore IDTR here for X64 only.
+ // Interrupt is already disabled here, so it is safety to update IDTR.
+ //
+ AsmReadIdtr (&Idtr);
+ Status = AsmExecute32BitCode (Function, Param1, Param2, &mGdt);
+ AsmWriteIdtr (&Idtr);
+
+ return Status;
+}
+
diff --git a/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.S b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.S
new file mode 100644
index 0000000000..b6b5c1aca8
--- /dev/null
+++ b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.S
@@ -0,0 +1,230 @@
+#
+# Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+# Module Name:
+#
+# Thunk64To32.asm
+#
+# Abstract:
+#
+# This is the assembly code to transition from long mode to compatibility mode to execute 32-bit code and then
+# transit back to long mode.
+#
+#-------------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Procedure: AsmExecute32BitCode
+#
+# Input: None
+#
+# Output: None
+#
+# Prototype: UINT32
+# AsmExecute32BitCode (
+# IN UINT64 Function,
+# IN UINT64 Param1,
+# IN UINT64 Param2,
+# IN IA32_DESCRIPTOR *InternalGdtr
+# );
+#
+#
+# Description: A thunk function to execute 32-bit code in long mode.
+#
+#----------------------------------------------------------------------------
+
+ASM_GLOBAL ASM_PFX(AsmExecute32BitCode)
+ASM_PFX(AsmExecute32BitCode):
+ #
+ # save IFLAG and disable it
+ #
+ pushfq
+ cli
+
+ #
+ # save orignal GDTR and CS
+ #
+ movl %ds, %eax
+ push %rax
+ movl %cs, %eax
+ push %rax
+ subq $0x10, %rsp
+ sgdt (%rsp)
+ #
+ # load internal GDT
+ #
+ lgdt (%r9)
+ #
+ # Save general purpose register and rflag register
+ #
+ pushfq
+ push %rdi
+ push %rsi
+ push %rbp
+ push %rbx
+
+ #
+ # save CR3
+ #
+ movq %cr3, %rax
+ movq %rax, %rbp
+
+ #
+ # Prepare the CS and return address for the transition from 32-bit to 64-bit mode
+ #
+ movq $0x10, %rax # load long mode selector
+ shl $32, %rax
+ lea ReloadCS(%rip), %r9 #Assume the ReloadCS is under 4G
+ orq %r9, %rax
+ push %rax
+ #
+ # Save parameters for 32-bit function call
+ #
+ movq %r8, %rax
+ shl $32, %rax
+ orq %rdx, %rax
+ push %rax
+ #
+ # save the 32-bit function entry and the return address into stack which will be
+ # retrieve in compatibility mode.
+ #
+ lea ReturnBack(%rip), %rax #Assume the ReloadCS is under 4G
+ shl $32, %rax
+ orq %rcx, %rax
+ push %rax
+
+ #
+ # let rax save DS
+ #
+ movq $0x18, %rax
+
+ #
+ # Change to Compatible Segment
+ #
+ movq $8, %rcx # load compatible mode selector
+ shl $32, %rcx
+ lea Compatible(%rip), %rdx # assume address < 4G
+ orq %rdx, %rcx
+ push %rcx
+ .byte 0xcb # retf
+
+Compatible:
+ # reload DS/ES/SS to make sure they are correct referred to current GDT
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+
+ #
+ # Disable paging
+ #
+ movq %cr0, %rcx
+ btc $31, %ecx
+ movq %rcx, %cr0
+ #
+ # Clear EFER.LME
+ #
+ movl $0xC0000080, %ecx
+ rdmsr
+ btc $8, %eax
+ wrmsr
+
+# Now we are in protected mode
+ #
+ # Call 32-bit function. Assume the function entry address and parameter value is less than 4G
+ #
+ pop %rax # Here is the function entry
+ #
+ # Now the parameter is at the bottom of the stack, then call in to IA32 function.
+ #
+ jmp *%rax
+ReturnBack:
+ movl %eax, %ebx # save return status
+ pop %rcx # drop param1
+ pop %rcx # drop param2
+
+ #
+ # restore CR4
+ #
+ movq %cr4, %rax
+ bts $5, %eax
+ movq %rax, %cr4
+
+ #
+ # restore CR3
+ #
+ movl %ebp, %eax
+ movq %rax, %cr3
+
+ #
+ # Set EFER.LME to re-enable ia32-e
+ #
+ movl $0xC0000080, %ecx
+ rdmsr
+ bts $8, %eax
+ wrmsr
+ #
+ # Enable paging
+ #
+ movq %cr0, %rax
+ bts $31, %eax
+ mov %rax, %cr0
+# Now we are in compatible mode
+
+ #
+ # Reload cs register
+ #
+ .byte 0xcb # retf
+ReloadCS:
+ #
+ # Now we're in Long Mode
+ #
+ #
+ # Restore C register and eax hold the return status from 32-bit function.
+ # Note: Do not touch rax from now which hold the return value from IA32 function
+ #
+ movl %ebx, %eax # put return status to EAX
+ pop %rbx
+ pop %rbp
+ pop %rsi
+ pop %rdi
+ popfq
+ #
+ # Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor.
+ #
+ lgdt (%rsp)
+ #
+ # drop GDT descriptor in stack
+ #
+ addq $0x10, %rsp
+ #
+ # switch to orignal CS and GDTR
+ #
+ pop %r9 # get CS
+ shl $32, %r9 # rcx[32..47] <- Cs
+ lea ReturnToLongMode(%rip), %rcx
+ orq %r9, %rcx
+ push %rcx
+ .byte 0xcb # retf
+ReturnToLongMode:
+ #
+ # Reload original DS/ES/SS
+ #
+ pop %rcx
+ movl %ecx, %ds
+ movl %ecx, %es
+ movl %ecx, %ss
+
+ #
+ # Restore IFLAG
+ #
+ popfq
+
+ ret
+
diff --git a/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.asm b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.asm
new file mode 100644
index 0000000000..70e7b5f408
--- /dev/null
+++ b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.asm
@@ -0,0 +1,230 @@
+;
+; Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+;
+; Module Name:
+;
+; Thunk64To32.asm
+;
+; Abstract:
+;
+; This is the assembly code to transition from long mode to compatibility mode to execute 32-bit code and then
+; transit back to long mode.
+;
+;-------------------------------------------------------------------------------
+ .code
+;----------------------------------------------------------------------------
+; Procedure: AsmExecute32BitCode
+;
+; Input: None
+;
+; Output: None
+;
+; Prototype: UINT32
+; AsmExecute32BitCode (
+; IN UINT64 Function,
+; IN UINT64 Param1,
+; IN UINT64 Param2,
+; IN IA32_DESCRIPTOR *InternalGdtr
+; );
+;
+;
+; Description: A thunk function to execute 32-bit code in long mode.
+;
+;----------------------------------------------------------------------------
+AsmExecute32BitCode PROC
+ ;
+ ; save IFLAG and disable it
+ ;
+ pushfq
+ cli
+
+ ;
+ ; save orignal GDTR and CS
+ ;
+ mov rax, ds
+ push rax
+ mov rax, cs
+ push rax
+ sub rsp, 10h
+ sgdt fword ptr [rsp]
+ ;
+ ; load internal GDT
+ ;
+ lgdt fword ptr [r9]
+ ;
+ ; Save general purpose register and rflag register
+ ;
+ pushfq
+ push rdi
+ push rsi
+ push rbp
+ push rbx
+
+ ;
+ ; save CR3
+ ;
+ mov rax, cr3
+ mov rbp, rax
+
+ ;
+ ; Prepare the CS and return address for the transition from 32-bit to 64-bit mode
+ ;
+ mov rax, 10h ; load long mode selector
+ shl rax, 32
+ mov r9, OFFSET ReloadCS ;Assume the ReloadCS is under 4G
+ or rax, r9
+ push rax
+ ;
+ ; Save parameters for 32-bit function call
+ ;
+ mov rax, r8
+ shl rax, 32
+ or rax, rdx
+ push rax
+ ;
+ ; save the 32-bit function entry and the return address into stack which will be
+ ; retrieve in compatibility mode.
+ ;
+ mov rax, OFFSET ReturnBack ;Assume the ReloadCS is under 4G
+ shl rax, 32
+ or rax, rcx
+ push rax
+
+ ;
+ ; let rax save DS
+ ;
+ mov rax, 018h
+
+ ;
+ ; Change to Compatible Segment
+ ;
+ mov rcx, 08h ; load compatible mode selector
+ shl rcx, 32
+ mov rdx, OFFSET Compatible ; assume address < 4G
+ or rcx, rdx
+ push rcx
+ retf
+
+Compatible:
+ ; reload DS/ES/SS to make sure they are correct referred to current GDT
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+
+ ;
+ ; Disable paging
+ ;
+ mov rcx, cr0
+ btc ecx, 31
+ mov cr0, rcx
+ ;
+ ; Clear EFER.LME
+ ;
+ mov ecx, 0C0000080h
+ rdmsr
+ btc eax, 8
+ wrmsr
+
+; Now we are in protected mode
+ ;
+ ; Call 32-bit function. Assume the function entry address and parameter value is less than 4G
+ ;
+ pop rax ; Here is the function entry
+ ;
+ ; Now the parameter is at the bottom of the stack, then call in to IA32 function.
+ ;
+ jmp rax
+ReturnBack:
+ mov ebx, eax ; save return status
+ pop rcx ; drop param1
+ pop rcx ; drop param2
+
+ ;
+ ; restore CR4
+ ;
+ mov rax, cr4
+ bts eax, 5
+ mov cr4, rax
+
+ ;
+ ; restore CR3
+ ;
+ mov eax, ebp
+ mov cr3, rax
+
+ ;
+ ; Set EFER.LME to re-enable ia32-e
+ ;
+ mov ecx, 0C0000080h
+ rdmsr
+ bts eax, 8
+ wrmsr
+ ;
+ ; Enable paging
+ ;
+ mov rax, cr0
+ bts eax, 31
+ mov cr0, rax
+; Now we are in compatible mode
+
+ ;
+ ; Reload cs register
+ ;
+ retf
+ReloadCS:
+ ;
+ ; Now we're in Long Mode
+ ;
+ ;
+ ; Restore C register and eax hold the return status from 32-bit function.
+ ; Note: Do not touch rax from now which hold the return value from IA32 function
+ ;
+ mov eax, ebx ; put return status to EAX
+ pop rbx
+ pop rbp
+ pop rsi
+ pop rdi
+ popfq
+ ;
+ ; Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor.
+ ;
+ lgdt fword ptr[rsp]
+ ;
+ ; drop GDT descriptor in stack
+ ;
+ add rsp, 10h
+ ;
+ ; switch to orignal CS and GDTR
+ ;
+ pop r9 ; get CS
+ shl r9, 32 ; rcx[32..47] <- Cs
+ mov rcx, OFFSET @F
+ or rcx, r9
+ push rcx
+ retf
+@@:
+ ;
+ ; Reload original DS/ES/SS
+ ;
+ pop rcx
+ mov ds, rcx
+ mov es, rcx
+ mov ss, rcx
+
+ ;
+ ; Restore IFLAG
+ ;
+ popfq
+
+ ret
+AsmExecute32BitCode ENDP
+
+ END