X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=OvmfPkg%2FLibrary%2FSmmCpuFeaturesLib%2FSmmCpuFeaturesLib.c;h=75b9ce0e2b12743b9ac815e147f5d8bcfced322b;hb=4a9b250bca569276c1d1e0cfef2dd96eb3525a30;hp=3b6f186ee817375a831faa292869f42f70ca7b28;hpb=d7e71b2925012c9706d1d044ca466173aac802a8;p=mirror_edk2.git diff --git a/OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c b/OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c index 3b6f186ee8..75b9ce0e2b 100644 --- a/OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c +++ b/OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c @@ -1,24 +1,31 @@ /** @file -The CPU specific programming for PiSmmCpuDxeSmm module. + The CPU specific programming for PiSmmCpuDxeSmm module. -Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
-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 + Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + 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 -#include #include -#include -#include +#include #include -#include +#include +#include +#include +#include +#include +#include + +// +// EFER register LMA bit +// +#define LMA BIT10 /** The constructor function @@ -75,13 +82,20 @@ SmmCpuFeaturesInitializeProcessor ( IN CPU_HOT_PLUG_DATA *CpuHotPlugData ) { - SMRAM_SAVE_STATE_MAP *CpuState; + QEMU_SMRAM_SAVE_STATE_MAP *CpuState; // // Configure SMBASE. // - CpuState = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET); - CpuState->x86.SMBASE = (UINT32)CpuHotPlugData->SmBase[CpuIndex]; + CpuState = (QEMU_SMRAM_SAVE_STATE_MAP *)(UINTN)( + SMM_DEFAULT_SMBASE + + SMRAM_SAVE_STATE_MAP_OFFSET + ); + if ((CpuState->x86.SMMRevId & 0xFFFF) == 0) { + CpuState->x86.SMBASE = (UINT32)CpuHotPlugData->SmBase[CpuIndex]; + } else { + CpuState->x64.SMBASE = (UINT32)CpuHotPlugData->SmBase[CpuIndex]; + } // // No need to program SMRRs on our virtual platform. @@ -106,8 +120,8 @@ SmmCpuFeaturesInitializeProcessor ( @param[in] CpuIndex The index of the CPU to hook. The value must be between 0 and the NumberOfCpus - field in the System Management System Table - (SMST). + field in the System Management System + Table (SMST). @param[in] CpuState Pointer to SMRAM Save State Map for the currently executing CPU. @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to @@ -128,7 +142,36 @@ SmmCpuFeaturesHookReturnFromSmm ( IN UINT64 NewInstructionPointer ) { - return 0; + UINT64 OriginalInstructionPointer; + QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState; + + CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)CpuState; + if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) { + OriginalInstructionPointer = (UINT64)CpuSaveState->x86._EIP; + CpuSaveState->x86._EIP = (UINT32)NewInstructionPointer; + // + // Clear the auto HALT restart flag so the RSM instruction returns + // program control to the instruction following the HLT instruction. + // + if ((CpuSaveState->x86.AutoHALTRestart & BIT0) != 0) { + CpuSaveState->x86.AutoHALTRestart &= ~BIT0; + } + } else { + OriginalInstructionPointer = CpuSaveState->x64._RIP; + if ((CpuSaveState->x64.IA32_EFER & LMA) == 0) { + CpuSaveState->x64._RIP = (UINT32)NewInstructionPointer32; + } else { + CpuSaveState->x64._RIP = (UINT32)NewInstructionPointer; + } + // + // Clear the auto HALT restart flag so the RSM instruction returns + // program control to the instruction following the HLT instruction. + // + if ((CpuSaveState->x64.AutoHALTRestart & BIT0) != 0) { + CpuSaveState->x64.AutoHALTRestart &= ~BIT0; + } + } + return OriginalInstructionPointer; } /** @@ -152,9 +195,10 @@ SmmCpuFeaturesSmmRelocationComplete ( and the default SMI handler must be used. @retval 0 Use the default SMI handler. - @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler() - The caller is required to allocate enough SMRAM for each CPU to - support the size of the custom SMI handler. + @retval > 0 Use the SMI handler installed by + SmmCpuFeaturesInstallSmiHandler(). The caller is required to + allocate enough SMRAM for each CPU to support the size of the + custom SMI handler. **/ UINTN EFIAPI @@ -166,10 +210,10 @@ SmmCpuFeaturesGetSmiHandlerSize ( } /** - Install a custom SMI handler for the CPU specified by CpuIndex. This function - is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater - than zero and is called by the CPU that was elected as monarch during System - Management Mode initialization. + Install a custom SMI handler for the CPU specified by CpuIndex. This + function is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size + is greater than zero and is called by the CPU that was elected as monarch + during System Management Mode initialization. @param[in] CpuIndex The index of the CPU to install the custom SMI handler. The value must be between 0 and the NumberOfCpus field @@ -224,8 +268,8 @@ SmmCpuFeaturesNeedConfigureMtrrs ( } /** - Disable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs() - returns TRUE. + Disable SMRR register if SMRR is supported and + SmmCpuFeaturesNeedConfigureMtrrs() returns TRUE. **/ VOID EFIAPI @@ -239,8 +283,8 @@ SmmCpuFeaturesDisableSmrr ( } /** - Enable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs() - returns TRUE. + Enable SMRR register if SMRR is supported and + SmmCpuFeaturesNeedConfigureMtrrs() returns TRUE. **/ VOID EFIAPI @@ -274,9 +318,9 @@ SmmCpuFeaturesRendezvousEntry ( /** Processor specific hook point each time a CPU exits System Management Mode. - @param[in] CpuIndex The index of the CPU that is exiting SMM. The value must - be between 0 and the NumberOfCpus field in the System - Management System Table (SMST). + @param[in] CpuIndex The index of the CPU that is exiting SMM. The value + must be between 0 and the NumberOfCpus field in the + System Management System Table (SMST). **/ VOID EFIAPI @@ -359,6 +403,558 @@ SmmCpuFeaturesSetSmmRegister ( ASSERT (FALSE); } +/// +/// Macro used to simplify the lookup table entries of type +/// CPU_SMM_SAVE_STATE_LOOKUP_ENTRY +/// +#define SMM_CPU_OFFSET(Field) OFFSET_OF (QEMU_SMRAM_SAVE_STATE_MAP, Field) + +/// +/// Macro used to simplify the lookup table entries of type +/// CPU_SMM_SAVE_STATE_REGISTER_RANGE +/// +#define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 } + +/// +/// Structure used to describe a range of registers +/// +typedef struct { + EFI_SMM_SAVE_STATE_REGISTER Start; + EFI_SMM_SAVE_STATE_REGISTER End; + UINTN Length; +} CPU_SMM_SAVE_STATE_REGISTER_RANGE; + +/// +/// Structure used to build a lookup table to retrieve the widths and offsets +/// associated with each supported EFI_SMM_SAVE_STATE_REGISTER value +/// + +#define SMM_SAVE_STATE_REGISTER_FIRST_INDEX 1 + +typedef struct { + UINT8 Width32; + UINT8 Width64; + UINT16 Offset32; + UINT16 Offset64Lo; + UINT16 Offset64Hi; + BOOLEAN Writeable; +} CPU_SMM_SAVE_STATE_LOOKUP_ENTRY; + +/// +/// Table used by GetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER +/// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY +/// +STATIC CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges[] = { + SMM_REGISTER_RANGE ( + EFI_SMM_SAVE_STATE_REGISTER_GDTBASE, + EFI_SMM_SAVE_STATE_REGISTER_LDTINFO + ), + SMM_REGISTER_RANGE ( + EFI_SMM_SAVE_STATE_REGISTER_ES, + EFI_SMM_SAVE_STATE_REGISTER_RIP + ), + SMM_REGISTER_RANGE ( + EFI_SMM_SAVE_STATE_REGISTER_RFLAGS, + EFI_SMM_SAVE_STATE_REGISTER_CR4 + ), + { (EFI_SMM_SAVE_STATE_REGISTER)0, (EFI_SMM_SAVE_STATE_REGISTER)0, 0 } +}; + +/// +/// Lookup table used to retrieve the widths and offsets associated with each +/// supported EFI_SMM_SAVE_STATE_REGISTER value +/// +STATIC CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset[] = { + { + 0, // Width32 + 0, // Width64 + 0, // Offset32 + 0, // Offset64Lo + 0, // Offset64Hi + FALSE // Writeable + }, // Reserved + + // + // CPU Save State registers defined in PI SMM CPU Protocol. + // + { + 0, // Width32 + 8, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._GDTRBase), // Offset64Lo + SMM_CPU_OFFSET (x64._GDTRBase) + 4, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_GDTBASE = 4 + + { + 0, // Width32 + 8, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._IDTRBase), // Offset64Lo + SMM_CPU_OFFSET (x64._IDTRBase) + 4, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_IDTBASE = 5 + + { + 0, // Width32 + 8, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._LDTRBase), // Offset64Lo + SMM_CPU_OFFSET (x64._LDTRBase) + 4, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_LDTBASE = 6 + + { + 0, // Width32 + 0, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._GDTRLimit), // Offset64Lo + SMM_CPU_OFFSET (x64._GDTRLimit) + 4, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7 + + { + 0, // Width32 + 0, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._IDTRLimit), // Offset64Lo + SMM_CPU_OFFSET (x64._IDTRLimit) + 4, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8 + + { + 0, // Width32 + 0, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._LDTRLimit), // Offset64Lo + SMM_CPU_OFFSET (x64._LDTRLimit) + 4, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9 + + { + 0, // Width32 + 0, // Width64 + 0, // Offset32 + 0, // Offset64Lo + 0 + 4, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_LDTINFO = 10 + + { + 4, // Width32 + 4, // Width64 + SMM_CPU_OFFSET (x86._ES), // Offset32 + SMM_CPU_OFFSET (x64._ES), // Offset64Lo + 0, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_ES = 20 + + { + 4, // Width32 + 4, // Width64 + SMM_CPU_OFFSET (x86._CS), // Offset32 + SMM_CPU_OFFSET (x64._CS), // Offset64Lo + 0, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_CS = 21 + + { + 4, // Width32 + 4, // Width64 + SMM_CPU_OFFSET (x86._SS), // Offset32 + SMM_CPU_OFFSET (x64._SS), // Offset64Lo + 0, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_SS = 22 + + { + 4, // Width32 + 4, // Width64 + SMM_CPU_OFFSET (x86._DS), // Offset32 + SMM_CPU_OFFSET (x64._DS), // Offset64Lo + 0, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_DS = 23 + + { + 4, // Width32 + 4, // Width64 + SMM_CPU_OFFSET (x86._FS), // Offset32 + SMM_CPU_OFFSET (x64._FS), // Offset64Lo + 0, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_FS = 24 + + { + 4, // Width32 + 4, // Width64 + SMM_CPU_OFFSET (x86._GS), // Offset32 + SMM_CPU_OFFSET (x64._GS), // Offset64Lo + 0, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_GS = 25 + + { + 0, // Width32 + 4, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._LDTR), // Offset64Lo + 0, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26 + + { + 4, // Width32 + 4, // Width64 + SMM_CPU_OFFSET (x86._TR), // Offset32 + SMM_CPU_OFFSET (x64._TR), // Offset64Lo + 0, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_TR_SEL = 27 + + { + 4, // Width32 + 8, // Width64 + SMM_CPU_OFFSET (x86._DR7), // Offset32 + SMM_CPU_OFFSET (x64._DR7), // Offset64Lo + SMM_CPU_OFFSET (x64._DR7) + 4, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_DR7 = 28 + + { + 4, // Width32 + 8, // Width64 + SMM_CPU_OFFSET (x86._DR6), // Offset32 + SMM_CPU_OFFSET (x64._DR6), // Offset64Lo + SMM_CPU_OFFSET (x64._DR6) + 4, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_DR6 = 29 + + { + 0, // Width32 + 8, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._R8), // Offset64Lo + SMM_CPU_OFFSET (x64._R8) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_R8 = 30 + + { + 0, // Width32 + 8, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._R9), // Offset64Lo + SMM_CPU_OFFSET (x64._R9) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_R9 = 31 + + { + 0, // Width32 + 8, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._R10), // Offset64Lo + SMM_CPU_OFFSET (x64._R10) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_R10 = 32 + + { + 0, // Width32 + 8, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._R11), // Offset64Lo + SMM_CPU_OFFSET (x64._R11) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_R11 = 33 + + { + 0, // Width32 + 8, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._R12), // Offset64Lo + SMM_CPU_OFFSET (x64._R12) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_R12 = 34 + + { + 0, // Width32 + 8, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._R13), // Offset64Lo + SMM_CPU_OFFSET (x64._R13) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_R13 = 35 + + { + 0, // Width32 + 8, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._R14), // Offset64Lo + SMM_CPU_OFFSET (x64._R14) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_R14 = 36 + + { + 0, // Width32 + 8, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._R15), // Offset64Lo + SMM_CPU_OFFSET (x64._R15) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_R15 = 37 + + { + 4, // Width32 + 8, // Width64 + SMM_CPU_OFFSET (x86._EAX), // Offset32 + SMM_CPU_OFFSET (x64._RAX), // Offset64Lo + SMM_CPU_OFFSET (x64._RAX) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_RAX = 38 + + { + 4, // Width32 + 8, // Width64 + SMM_CPU_OFFSET (x86._EBX), // Offset32 + SMM_CPU_OFFSET (x64._RBX), // Offset64Lo + SMM_CPU_OFFSET (x64._RBX) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_RBX = 39 + + { + 4, // Width32 + 8, // Width64 + SMM_CPU_OFFSET (x86._ECX), // Offset32 + SMM_CPU_OFFSET (x64._RCX), // Offset64Lo + SMM_CPU_OFFSET (x64._RCX) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_RCX = 40 + + { + 4, // Width32 + 8, // Width64 + SMM_CPU_OFFSET (x86._EDX), // Offset32 + SMM_CPU_OFFSET (x64._RDX), // Offset64Lo + SMM_CPU_OFFSET (x64._RDX) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_RDX = 41 + + { + 4, // Width32 + 8, // Width64 + SMM_CPU_OFFSET (x86._ESP), // Offset32 + SMM_CPU_OFFSET (x64._RSP), // Offset64Lo + SMM_CPU_OFFSET (x64._RSP) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_RSP = 42 + + { + 4, // Width32 + 8, // Width64 + SMM_CPU_OFFSET (x86._EBP), // Offset32 + SMM_CPU_OFFSET (x64._RBP), // Offset64Lo + SMM_CPU_OFFSET (x64._RBP) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_RBP = 43 + + { + 4, // Width32 + 8, // Width64 + SMM_CPU_OFFSET (x86._ESI), // Offset32 + SMM_CPU_OFFSET (x64._RSI), // Offset64Lo + SMM_CPU_OFFSET (x64._RSI) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_RSI = 44 + + { + 4, // Width32 + 8, // Width64 + SMM_CPU_OFFSET (x86._EDI), // Offset32 + SMM_CPU_OFFSET (x64._RDI), // Offset64Lo + SMM_CPU_OFFSET (x64._RDI) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_RDI = 45 + + { + 4, // Width32 + 8, // Width64 + SMM_CPU_OFFSET (x86._EIP), // Offset32 + SMM_CPU_OFFSET (x64._RIP), // Offset64Lo + SMM_CPU_OFFSET (x64._RIP) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_RIP = 46 + + { + 4, // Width32 + 8, // Width64 + SMM_CPU_OFFSET (x86._EFLAGS), // Offset32 + SMM_CPU_OFFSET (x64._RFLAGS), // Offset64Lo + SMM_CPU_OFFSET (x64._RFLAGS) + 4, // Offset64Hi + TRUE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_RFLAGS = 51 + + { + 4, // Width32 + 8, // Width64 + SMM_CPU_OFFSET (x86._CR0), // Offset32 + SMM_CPU_OFFSET (x64._CR0), // Offset64Lo + SMM_CPU_OFFSET (x64._CR0) + 4, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_CR0 = 52 + + { + 4, // Width32 + 8, // Width64 + SMM_CPU_OFFSET (x86._CR3), // Offset32 + SMM_CPU_OFFSET (x64._CR3), // Offset64Lo + SMM_CPU_OFFSET (x64._CR3) + 4, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_CR3 = 53 + + { + 0, // Width32 + 4, // Width64 + 0, // Offset32 + SMM_CPU_OFFSET (x64._CR4), // Offset64Lo + SMM_CPU_OFFSET (x64._CR4) + 4, // Offset64Hi + FALSE // Writeable + }, // EFI_SMM_SAVE_STATE_REGISTER_CR4 = 54 +}; + +// +// No support for I/O restart +// + +/** + Read information from the CPU save state. + + @param Register Specifies the CPU register to read form the save state. + + @retval 0 Register is not valid + @retval >0 Index into mSmmCpuWidthOffset[] associated with Register + +**/ +STATIC +UINTN +GetRegisterIndex ( + IN EFI_SMM_SAVE_STATE_REGISTER Register + ) +{ + UINTN Index; + UINTN Offset; + + for (Index = 0, Offset = SMM_SAVE_STATE_REGISTER_FIRST_INDEX; + mSmmCpuRegisterRanges[Index].Length != 0; + Index++) { + if (Register >= mSmmCpuRegisterRanges[Index].Start && + Register <= mSmmCpuRegisterRanges[Index].End) { + return Register - mSmmCpuRegisterRanges[Index].Start + Offset; + } + Offset += mSmmCpuRegisterRanges[Index].Length; + } + return 0; +} + +/** + Read a CPU Save State register on the target processor. + + This function abstracts the differences that whether the CPU Save State + register is in the IA32 CPU Save State Map or X64 CPU Save State Map. + + This function supports reading a CPU Save State register in SMBase relocation + handler. + + @param[in] CpuIndex Specifies the zero-based index of the CPU save + state. + @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table. + @param[in] Width The number of bytes to read from the CPU save + state. + @param[out] Buffer Upon return, this holds the CPU register value + read from the save state. + + @retval EFI_SUCCESS The register was read from Save State. + @retval EFI_NOT_FOUND The register is not defined for the Save State + of Processor. + @retval EFI_INVALID_PARAMTER This or Buffer is NULL. + +**/ +STATIC +EFI_STATUS +ReadSaveStateRegisterByIndex ( + IN UINTN CpuIndex, + IN UINTN RegisterIndex, + IN UINTN Width, + OUT VOID *Buffer + ) +{ + QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState; + + CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex]; + + if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) { + // + // If 32-bit mode width is zero, then the specified register can not be + // accessed + // + if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) { + return EFI_NOT_FOUND; + } + + // + // If Width is bigger than the 32-bit mode width, then the specified + // register can not be accessed + // + if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) { + return EFI_INVALID_PARAMETER; + } + + // + // Write return buffer + // + ASSERT(CpuSaveState != NULL); + CopyMem ( + Buffer, + (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, + Width + ); + } else { + // + // If 64-bit mode width is zero, then the specified register can not be + // accessed + // + if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) { + return EFI_NOT_FOUND; + } + + // + // If Width is bigger than the 64-bit mode width, then the specified + // register can not be accessed + // + if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) { + return EFI_INVALID_PARAMETER; + } + + // + // Write lower 32-bits of return buffer + // + CopyMem ( + Buffer, + (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, + MIN (4, Width) + ); + if (Width >= 4) { + // + // Write upper 32-bits of return buffer + // + CopyMem ( + (UINT8 *)Buffer + 4, + (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, + Width - 4 + ); + } + } + return EFI_SUCCESS; +} + /** Read an SMM Save State register on the target processor. If this function returns EFI_UNSUPPORTED, then the caller is responsible for reading the @@ -374,8 +970,8 @@ SmmCpuFeaturesSetSmmRegister ( @retval EFI_SUCCESS The register was read from Save State. @retval EFI_INVALID_PARAMTER Buffer is NULL. - @retval EFI_UNSUPPORTED This function does not support reading Register. - + @retval EFI_UNSUPPORTED This function does not support reading + Register. **/ EFI_STATUS EFIAPI @@ -386,7 +982,54 @@ SmmCpuFeaturesReadSaveStateRegister ( OUT VOID *Buffer ) { - return EFI_UNSUPPORTED; + UINTN RegisterIndex; + QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState; + + // + // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA + // + if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) { + // + // Only byte access is supported for this register + // + if (Width != 1) { + return EFI_INVALID_PARAMETER; + } + + CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex]; + + // + // Check CPU mode + // + if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) { + *(UINT8 *)Buffer = 32; + } else { + *(UINT8 *)Buffer = 64; + } + + return EFI_SUCCESS; + } + + // + // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO + // + if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) { + return EFI_NOT_FOUND; + } + + // + // Convert Register to a register lookup table index. Let + // PiSmmCpuDxeSmm implement other special registers (currently + // there is only EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID). + // + RegisterIndex = GetRegisterIndex (Register); + if (RegisterIndex == 0) { + return (Register < EFI_SMM_SAVE_STATE_REGISTER_IO ? + EFI_NOT_FOUND : + EFI_UNSUPPORTED); + } + + return ReadSaveStateRegisterByIndex (CpuIndex, RegisterIndex, Width, Buffer); } /** @@ -403,7 +1046,8 @@ SmmCpuFeaturesReadSaveStateRegister ( @retval EFI_SUCCESS The register was written to Save State. @retval EFI_INVALID_PARAMTER Buffer is NULL. - @retval EFI_UNSUPPORTED This function does not support writing Register. + @retval EFI_UNSUPPORTED This function does not support writing + Register. **/ EFI_STATUS EFIAPI @@ -414,7 +1058,109 @@ SmmCpuFeaturesWriteSaveStateRegister ( IN CONST VOID *Buffer ) { - return EFI_UNSUPPORTED; + UINTN RegisterIndex; + QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState; + + // + // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored + // + if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) { + return EFI_SUCCESS; + } + + // + // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported + // + if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) { + return EFI_NOT_FOUND; + } + + // + // Convert Register to a register lookup table index. Let + // PiSmmCpuDxeSmm implement other special registers (currently + // there is only EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID). + // + RegisterIndex = GetRegisterIndex (Register); + if (RegisterIndex == 0) { + return (Register < EFI_SMM_SAVE_STATE_REGISTER_IO ? + EFI_NOT_FOUND : + EFI_UNSUPPORTED); + } + + CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex]; + + // + // Do not write non-writable SaveState, because it will cause exception. + // + if (!mSmmCpuWidthOffset[RegisterIndex].Writeable) { + return EFI_UNSUPPORTED; + } + + // + // Check CPU mode + // + if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) { + // + // If 32-bit mode width is zero, then the specified register can not be + // accessed + // + if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) { + return EFI_NOT_FOUND; + } + + // + // If Width is bigger than the 32-bit mode width, then the specified + // register can not be accessed + // + if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) { + return EFI_INVALID_PARAMETER; + } + // + // Write SMM State register + // + ASSERT (CpuSaveState != NULL); + CopyMem ( + (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, + Buffer, + Width + ); + } else { + // + // If 64-bit mode width is zero, then the specified register can not be + // accessed + // + if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) { + return EFI_NOT_FOUND; + } + + // + // If Width is bigger than the 64-bit mode width, then the specified + // register can not be accessed + // + if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) { + return EFI_INVALID_PARAMETER; + } + + // + // Write lower 32-bits of SMM State register + // + CopyMem ( + (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, + Buffer, + MIN (4, Width) + ); + if (Width >= 4) { + // + // Write upper 32-bits of SMM State register + // + CopyMem ( + (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, + (UINT8 *)Buffer + 4, + Width - 4 + ); + } + } + return EFI_SUCCESS; } /** @@ -430,22 +1176,25 @@ SmmCpuFeaturesCompleteSmmReadyToLock ( } /** - This API provides a method for a CPU to allocate a specific region for storing page tables. + This API provides a method for a CPU to allocate a specific region for + storing page tables. This API can be called more once to allocate memory for page tables. - Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the - allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL - is returned. If there is not enough memory remaining to satisfy the request, then NULL is - returned. + Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns + a pointer to the allocated buffer. The buffer returned is aligned on a 4KB + boundary. If Pages is 0, then NULL is returned. If there is not enough + memory remaining to satisfy the request, then NULL is returned. - This function can also return NULL if there is no preference on where the page tables are allocated in SMRAM. + This function can also return NULL if there is no preference on where the + page tables are allocated in SMRAM. @param Pages The number of 4 KB pages to allocate. @return A pointer to the allocated buffer for page tables. @retval NULL Fail to allocate a specific region for storing page tables, - Or there is no preference on where the page tables are allocated in SMRAM. + Or there is no preference on where the page tables are + allocated in SMRAM. **/ VOID *