diff --git a/UefiCpuPkg/SecCore/SecBist.c b/UefiCpuPkg/SecCore/SecBist.c index cd2e340171..5016f37d7b 100644 --- a/UefiCpuPkg/SecCore/SecBist.c +++ b/UefiCpuPkg/SecCore/SecBist.c @@ -8,6 +8,45 @@ #include "SecMain.h" +/** + Implementation of the PlatformInformation service in EFI_SEC_PLATFORM_INFORMATION_PPI. + + @param PeiServices Pointer to the PEI Services Table. + @param StructureSize Pointer to the variable describing size of the input buffer. + @param PlatformInformationRecord Pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD. + + @retval EFI_SUCCESS The data was successfully returned. + @retval EFI_BUFFER_TOO_SMALL The buffer was too small. + +**/ +EFI_STATUS +EFIAPI +SecPlatformInformationBist ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN OUT UINT64 *StructureSize, + OUT EFI_SEC_PLATFORM_INFORMATION_RECORD *PlatformInformationRecord + ); + +/** + Implementation of the PlatformInformation2 service in EFI_SEC_PLATFORM_INFORMATION2_PPI. + + @param PeiServices The pointer to the PEI Services Table. + @param StructureSize The pointer to the variable describing size of the input buffer. + @param PlatformInformationRecord2 The pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD2. + + @retval EFI_SUCCESS The data was successfully returned. + @retval EFI_BUFFER_TOO_SMALL The buffer was too small. The current buffer size needed to + hold the record is returned in StructureSize. + +**/ +EFI_STATUS +EFIAPI +SecPlatformInformation2Bist ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN OUT UINT64 *StructureSize, + OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 *PlatformInformationRecord2 + ); + EFI_SEC_PLATFORM_INFORMATION_PPI mSecPlatformInformation = { SecPlatformInformationBist }; diff --git a/UefiCpuPkg/SecCore/SecCore.inf b/UefiCpuPkg/SecCore/SecCore.inf index 94966f4edf..255d3a9a3f 100644 --- a/UefiCpuPkg/SecCore/SecCore.inf +++ b/UefiCpuPkg/SecCore/SecCore.inf @@ -31,11 +31,14 @@ SecMain.c SecMain.h FindPeiCore.c - SecBist.c [Sources.IA32] Ia32/ResetVec.nasmb +[Sources.IA32, Sources.X64] + SecBist.c + SecTemporaryRamDone.c + [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec @@ -55,9 +58,11 @@ PeiServicesLib PeiServicesTablePointerLib HobLib - CpuPageTableLib StackCheckLib +[LibraryClasses.IA32, LibraryClasses.X64] + CpuPageTableLib + [Ppis] ## SOMETIMES_CONSUMES ## PRODUCES diff --git a/UefiCpuPkg/SecCore/SecCoreNative.inf b/UefiCpuPkg/SecCore/SecCoreNative.inf index facb79c2c4..4d9f385e06 100644 --- a/UefiCpuPkg/SecCore/SecCoreNative.inf +++ b/UefiCpuPkg/SecCore/SecCoreNative.inf @@ -31,7 +31,10 @@ SecMain.c SecMain.h FindPeiCore.c + +[Sources.IA32, Sources.X64] SecBist.c + SecTemporaryRamDone.c [Packages] MdePkg/MdePkg.dec @@ -52,9 +55,11 @@ PeiServicesLib PeiServicesTablePointerLib HobLib - CpuPageTableLib StackCheckLib +[LibraryClasses.IA32, LibraryClasses.X64] + CpuPageTableLib + [Ppis] ## SOMETIMES_CONSUMES ## PRODUCES diff --git a/UefiCpuPkg/SecCore/SecMain.c b/UefiCpuPkg/SecCore/SecMain.c index 23a75d3076..f6917e88d1 100644 --- a/UefiCpuPkg/SecCore/SecMain.c +++ b/UefiCpuPkg/SecCore/SecMain.c @@ -2,12 +2,48 @@ C functions in SEC Copyright (c) 2008 - 2019, Intel Corporation. All rights reserved.
+ Copyright (c) 2025, Ventana Micro Systems Inc. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "SecMain.h" +#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64) + +#define SEC_IDT_ENTRY_COUNT 34 + +typedef struct _SEC_IDT_TABLE { + // + // Reserved 8 bytes preceding IDT to store EFI_PEI_SERVICES**, since IDT base + // address should be 8-byte alignment. + // Note: For IA32, only the 4 bytes immediately preceding IDT is used to store + // EFI_PEI_SERVICES** + // + UINT64 PeiService; + IA32_IDT_GATE_DESCRIPTOR IdtTable[SEC_IDT_ENTRY_COUNT]; +} SEC_IDT_TABLE; + +// +// These are IDT entries pointing to 10:FFFFFFE4h. +// +UINT64 mIdtEntryTemplate = 0xffff8e000010ffe4ULL; + +/** + TemporaryRamDone() disables the use of Temporary RAM. If present, this service is invoked + by the PEI Foundation after the EFI_PEI_PERMANANT_MEMORY_INSTALLED_PPI is installed. + + @retval EFI_SUCCESS Use of Temporary RAM was disabled. + @retval EFI_INVALID_PARAMETER Temporary RAM could not be disabled. + +**/ +EFI_STATUS +EFIAPI +SecTemporaryRamDone ( + VOID + ); + EFI_PEI_TEMPORARY_RAM_DONE_PPI gSecTemporaryRamDonePpi = { SecTemporaryRamDone }; @@ -34,136 +70,18 @@ EFI_PEI_PPI_DESCRIPTOR mPeiSecPlatformInformationPpi[] = { &mSecPlatformInformationPpi } }; - -/** - Migrates the Global Descriptor Table (GDT) to permanent memory. - - @retval EFI_SUCCESS The GDT was migrated successfully. - @retval EFI_OUT_OF_RESOURCES The GDT could not be migrated due to lack of available memory. - -**/ -EFI_STATUS -MigrateGdt ( - VOID - ) -{ - EFI_STATUS Status; - UINTN GdtBufferSize; - IA32_DESCRIPTOR Gdtr; - VOID *GdtBuffer; - - AsmReadGdtr ((IA32_DESCRIPTOR *)&Gdtr); - GdtBufferSize = sizeof (IA32_SEGMENT_DESCRIPTOR) -1 + Gdtr.Limit + 1; - - Status = PeiServicesAllocatePool ( - GdtBufferSize, - &GdtBuffer - ); - ASSERT (GdtBuffer != NULL); - if (EFI_ERROR (Status)) { - return EFI_OUT_OF_RESOURCES; - } - - GdtBuffer = ALIGN_POINTER (GdtBuffer, sizeof (IA32_SEGMENT_DESCRIPTOR)); - CopyMem (GdtBuffer, (VOID *)Gdtr.Base, Gdtr.Limit + 1); - Gdtr.Base = (UINTN)GdtBuffer; - AsmWriteGdtr (&Gdtr); - - return EFI_SUCCESS; -} - -/** - Get Paging Mode - - @retval Paging Mode. -**/ -PAGING_MODE -GetPagingMode ( - VOID - ) -{ - IA32_CR4 Cr4; - BOOLEAN Page5LevelSupport; - UINT32 RegEax; - CPUID_EXTENDED_CPU_SIG_EDX RegEdx; - BOOLEAN Page1GSupport; - PAGING_MODE PagingMode; - - // - // Check Page5Level Support or not. - // - Cr4.UintN = AsmReadCr4 (); - Page5LevelSupport = (Cr4.Bits.LA57 ? TRUE : FALSE); - - // - // Check Page1G Support or not. - // - Page1GSupport = FALSE; - AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL); - if (RegEax >= CPUID_EXTENDED_CPU_SIG) { - AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx.Uint32); - if (RegEdx.Bits.Page1GB != 0) { - Page1GSupport = TRUE; - } - } - - // - // Decide Paging Mode according Page5LevelSupport & Page1GSupport. - // - if (Page5LevelSupport) { - PagingMode = Page1GSupport ? Paging5Level1GB : Paging5Level; - } else { - PagingMode = Page1GSupport ? Paging4Level1GB : Paging4Level; - } - - return PagingMode; -} - -/** - Get max physical address supported by specific page mode - - @param[in] PagingMode The paging mode. - - @retval Max Address. -**/ -UINT32 -GetMaxAddress ( - IN PAGING_MODE PagingMode - ) -{ - CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize; - UINT32 MaxExtendedFunctionId; - UINT32 MaxAddressBits; - - VirPhyAddressSize.Uint32 = 0; - - // - // Get Maximum Physical Address Bits - // Get the number of address lines; Maximum Physical Address is 2^PhysicalAddressBits - 1. - // If CPUID does not supported, then use a max value of 36 as per SDM 3A, 4.1.4. - // - AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunctionId, NULL, NULL, NULL); - if (MaxExtendedFunctionId >= CPUID_VIR_PHY_ADDRESS_SIZE) { - AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL); - MaxAddressBits = VirPhyAddressSize.Bits.PhysicalAddressBits; - } else { - MaxAddressBits = 36; - } - - if ((PagingMode == Paging4Level1GB) || (PagingMode == Paging4Level)) { +#else +EFI_PEI_PPI_DESCRIPTOR mPeiSecPlatformInformationPpi[] = { + { // - // The max liner address bits is 48 for 4 level page table. + // SecPerformance PPI notify descriptor. // - MaxAddressBits = MIN (VirPhyAddressSize.Bits.PhysicalAddressBits, 48); + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gPeiSecPerformancePpiGuid, + (VOID *)(UINTN)SecPerformancePpiCallBack } - - return MaxAddressBits; -} - -// -// These are IDT entries pointing to 10:FFFFFFE4h. -// -UINT64 mIdtEntryTemplate = 0xffff8e000010ffe4ULL; +}; +#endif /** Caller provided function to be invoked at the end of InitializeDebugAgent(). @@ -241,9 +159,6 @@ SecStartup ( ) { EFI_SEC_PEI_HAND_OFF SecCoreData; - IA32_DESCRIPTOR IdtDescriptor; - SEC_IDT_TABLE IdtTableInStack; - UINT32 Index; UINT32 PeiStackSize; EFI_STATUS Status; @@ -282,6 +197,11 @@ SecStartup ( // InitializeFloatingPointUnits (); + #if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64) + IA32_DESCRIPTOR IdtDescriptor; + SEC_IDT_TABLE IdtTableInStack; + UINT32 Index; + // |-------------------|----> // |IDT Table | // |-------------------| @@ -307,6 +227,7 @@ SecStartup ( IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1); AsmWriteIdtr (&IdtDescriptor); + #endif // // Setup the default exception handlers @@ -520,179 +441,3 @@ SecStartupPhase2 ( // UNREACHABLE (); } - -/** - TemporaryRamDone() disables the use of Temporary RAM. If present, this service is invoked - by the PEI Foundation after the EFI_PEI_PERMANANT_MEMORY_INSTALLED_PPI is installed. - - @retval EFI_SUCCESS Use of Temporary RAM was disabled. - @retval EFI_INVALID_PARAMETER Temporary RAM could not be disabled. - -**/ -EFI_STATUS -EFIAPI -SecTemporaryRamDone ( - VOID - ) -{ - EFI_STATUS Status; - EFI_STATUS Status2; - UINTN Index; - BOOLEAN State; - EFI_PEI_PPI_DESCRIPTOR *PeiPpiDescriptor; - REPUBLISH_SEC_PPI_PPI *RepublishSecPpiPpi; - IA32_CR0 Cr0; - PAGING_MODE PagingMode; - UINT32 MaxAddressBits; - UINTN PageTable; - EFI_PHYSICAL_ADDRESS Buffer; - UINTN BufferSize; - UINT64 Length; - UINT64 Address; - IA32_MAP_ATTRIBUTE MapAttribute; - IA32_MAP_ATTRIBUTE MapMask; - - PageTable = 0; - BufferSize = 0; - MapAttribute.Uint64 = 0; - MapAttribute.Bits.Present = 1; - MapAttribute.Bits.ReadWrite = 1; - MapMask.Uint64 = MAX_UINT64; - - // - // Republish Sec Platform Information(2) PPI - // - RepublishSecPlatformInformationPpi (); - - // - // Re-install SEC PPIs using a PEIM produced service if published - // - for (Index = 0, Status = EFI_SUCCESS; Status == EFI_SUCCESS; Index++) { - Status = PeiServicesLocatePpi ( - &gRepublishSecPpiPpiGuid, - Index, - &PeiPpiDescriptor, - (VOID **)&RepublishSecPpiPpi - ); - if (!EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "Calling RepublishSecPpi instance %d.\n", Index)); - Status2 = RepublishSecPpiPpi->RepublishSecPpis (); - ASSERT_EFI_ERROR (Status2); - } - } - - // - // Migrate DebugAgentContext. - // - InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, NULL, NULL); - - // - // Disable interrupts and save current interrupt state - // - State = SaveAndDisableInterrupts (); - - // - // Migrate GDT before NEM near down - // - if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) { - Status = MigrateGdt (); - ASSERT_EFI_ERROR (Status); - } - - // - // Migrate page table to permanent memory mapping entire physical address space if CR0.PG is set. - // - Cr0.UintN = AsmReadCr0 (); - if (Cr0.Bits.PG != 0) { - // - // Assume CPU runs in 64bit mode if paging is enabled. - // - ASSERT (sizeof (UINTN) == sizeof (UINT64)); - - // - // Get PagingMode & MaxAddressBits. - // - PagingMode = GetPagingMode (); - MaxAddressBits = GetMaxAddress (PagingMode); - DEBUG ((DEBUG_INFO, "SecTemporaryRamDone: PagingMode = 0x%lx, MaxAddressBits = %d\n", PagingMode, MaxAddressBits)); - - // - // Create page table to cover the max mapping address in physical memory before Temp - // Ram Exit. The max mapping address is defined by PcdMaxMappingAddressBeforeTempRamExit. - // - Length = FixedPcdGet64 (PcdMaxMappingAddressBeforeTempRamExit); - Length = MIN (LShiftU64 (1, MaxAddressBits), Length); - if (Length != 0) { - Status = PageTableMap (&PageTable, PagingMode, 0, &BufferSize, 0, Length, &MapAttribute, &MapMask, NULL); - ASSERT (Status == EFI_BUFFER_TOO_SMALL); - if (Status != EFI_BUFFER_TOO_SMALL) { - return Status; - } - - Status = PeiServicesAllocatePages ( - EfiBootServicesData, - EFI_SIZE_TO_PAGES (BufferSize), - &Buffer - ); - if (EFI_ERROR (Status)) { - return EFI_OUT_OF_RESOURCES; - } - - Status = PageTableMap (&PageTable, PagingMode, (VOID *)(UINTN)Buffer, &BufferSize, 0, Length, &MapAttribute, &MapMask, NULL); - ASSERT (BufferSize == 0); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "SecTemporaryRamDone: Failed to create page table in physical memory before Temp Ram Exit: %r.\n", Status)); - CpuDeadLoop (); - } - - AsmWriteCr3 (PageTable); - } - } - - // - // Disable Temporary RAM after Stack and Heap have been migrated at this point. - // - SecPlatformDisableTemporaryMemory (); - - // - // Expanding the page table to cover the entire memory space since the physical memory is WB after TempRamExit. - // - if ((Cr0.Bits.PG != 0) && (Length < LShiftU64 (1, MaxAddressBits))) { - Address = Length; - Length = LShiftU64 (1, MaxAddressBits) - Length; - - MapAttribute.Uint64 = Address; - MapAttribute.Bits.Present = 1; - MapAttribute.Bits.ReadWrite = 1; - - Status = PageTableMap (&PageTable, PagingMode, 0, &BufferSize, Address, Length, &MapAttribute, &MapMask, NULL); - ASSERT (Status == EFI_BUFFER_TOO_SMALL); - if (Status != EFI_BUFFER_TOO_SMALL) { - return Status; - } - - Status = PeiServicesAllocatePages ( - EfiBootServicesData, - EFI_SIZE_TO_PAGES (BufferSize), - &Buffer - ); - if (EFI_ERROR (Status)) { - return EFI_OUT_OF_RESOURCES; - } - - Status = PageTableMap (&PageTable, PagingMode, (VOID *)(UINTN)Buffer, &BufferSize, Address, Length, &MapAttribute, &MapMask, NULL); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "SecTemporaryRamDone: Failed to create full range page table in physical memory after Temp Ram Exit: %r.\n", Status)); - CpuDeadLoop (); - } - - AsmWriteCr3 (PageTable); - } - - // - // Restore original interrupt state - // - SetInterruptState (State); - - return EFI_SUCCESS; -} diff --git a/UefiCpuPkg/SecCore/SecMain.h b/UefiCpuPkg/SecCore/SecMain.h index 81c561424e..6b312a8ac1 100644 --- a/UefiCpuPkg/SecCore/SecMain.h +++ b/UefiCpuPkg/SecCore/SecMain.h @@ -33,36 +33,6 @@ #include #include #include -#include -#include -#include - -#define SEC_IDT_ENTRY_COUNT 34 - -typedef struct _SEC_IDT_TABLE { - // - // Reserved 8 bytes preceding IDT to store EFI_PEI_SERVICES**, since IDT base - // address should be 8-byte alignment. - // Note: For IA32, only the 4 bytes immediately preceding IDT is used to store - // EFI_PEI_SERVICES** - // - UINT64 PeiService; - IA32_IDT_GATE_DESCRIPTOR IdtTable[SEC_IDT_ENTRY_COUNT]; -} SEC_IDT_TABLE; - -/** - TemporaryRamDone() disables the use of Temporary RAM. If present, this service is invoked - by the PEI Foundation after the EFI_PEI_PERMANANT_MEMORY_INSTALLED_PPI is installed. - - @retval EFI_SUCCESS Use of Temporary RAM was disabled. - @retval EFI_INVALID_PARAMETER Temporary RAM could not be disabled. - -**/ -EFI_STATUS -EFIAPI -SecTemporaryRamDone ( - VOID - ); /** Entry point to the C language phase of SEC. After the SEC assembly @@ -101,45 +71,6 @@ FindAndReportEntryPoints ( OUT EFI_PEI_CORE_ENTRY_POINT *PeiCoreEntryPoint ); -/** - Implementation of the PlatformInformation service in EFI_SEC_PLATFORM_INFORMATION_PPI. - - @param PeiServices Pointer to the PEI Services Table. - @param StructureSize Pointer to the variable describing size of the input buffer. - @param PlatformInformationRecord Pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD. - - @retval EFI_SUCCESS The data was successfully returned. - @retval EFI_BUFFER_TOO_SMALL The buffer was too small. - -**/ -EFI_STATUS -EFIAPI -SecPlatformInformationBist ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN OUT UINT64 *StructureSize, - OUT EFI_SEC_PLATFORM_INFORMATION_RECORD *PlatformInformationRecord - ); - -/** - Implementation of the PlatformInformation2 service in EFI_SEC_PLATFORM_INFORMATION2_PPI. - - @param PeiServices The pointer to the PEI Services Table. - @param StructureSize The pointer to the variable describing size of the input buffer. - @param PlatformInformationRecord2 The pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD2. - - @retval EFI_SUCCESS The data was successfully returned. - @retval EFI_BUFFER_TOO_SMALL The buffer was too small. The current buffer size needed to - hold the record is returned in StructureSize. - -**/ -EFI_STATUS -EFIAPI -SecPlatformInformation2Bist ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN OUT UINT64 *StructureSize, - OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 *PlatformInformationRecord2 - ); - /** Republish SecPlatformInformationPpi/SecPlatformInformation2Ppi. diff --git a/UefiCpuPkg/SecCore/SecTemporaryRamDone.c b/UefiCpuPkg/SecCore/SecTemporaryRamDone.c new file mode 100644 index 0000000000..f921d457e8 --- /dev/null +++ b/UefiCpuPkg/SecCore/SecTemporaryRamDone.c @@ -0,0 +1,315 @@ +/** @file + SEC platform information(2) PPI. + + Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
+ Copyright (c) 2025, Ventana Micro Systems Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include "SecMain.h" + +/** + Migrates the Global Descriptor Table (GDT) to permanent memory. + + @retval EFI_SUCCESS The GDT was migrated successfully. + @retval EFI_OUT_OF_RESOURCES The GDT could not be migrated due to lack of available memory. + +**/ +EFI_STATUS +MigrateGdt ( + VOID + ) +{ + EFI_STATUS Status; + UINTN GdtBufferSize; + IA32_DESCRIPTOR Gdtr; + VOID *GdtBuffer; + + AsmReadGdtr ((IA32_DESCRIPTOR *)&Gdtr); + GdtBufferSize = sizeof (IA32_SEGMENT_DESCRIPTOR) -1 + Gdtr.Limit + 1; + + Status = PeiServicesAllocatePool ( + GdtBufferSize, + &GdtBuffer + ); + ASSERT (GdtBuffer != NULL); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + GdtBuffer = ALIGN_POINTER (GdtBuffer, sizeof (IA32_SEGMENT_DESCRIPTOR)); + CopyMem (GdtBuffer, (VOID *)Gdtr.Base, Gdtr.Limit + 1); + Gdtr.Base = (UINTN)GdtBuffer; + AsmWriteGdtr (&Gdtr); + + return EFI_SUCCESS; +} + +/** + Get Paging Mode + + @retval Paging Mode. +**/ +PAGING_MODE +GetPagingMode ( + VOID + ) +{ + IA32_CR4 Cr4; + BOOLEAN Page5LevelSupport; + UINT32 RegEax; + CPUID_EXTENDED_CPU_SIG_EDX RegEdx; + BOOLEAN Page1GSupport; + PAGING_MODE PagingMode; + + // + // Check Page5Level Support or not. + // + Cr4.UintN = AsmReadCr4 (); + Page5LevelSupport = (Cr4.Bits.LA57 ? TRUE : FALSE); + + // + // Check Page1G Support or not. + // + Page1GSupport = FALSE; + AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL); + if (RegEax >= CPUID_EXTENDED_CPU_SIG) { + AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx.Uint32); + if (RegEdx.Bits.Page1GB != 0) { + Page1GSupport = TRUE; + } + } + + // + // Decide Paging Mode according Page5LevelSupport & Page1GSupport. + // + if (Page5LevelSupport) { + PagingMode = Page1GSupport ? Paging5Level1GB : Paging5Level; + } else { + PagingMode = Page1GSupport ? Paging4Level1GB : Paging4Level; + } + + return PagingMode; +} + +/** + Get max physical address supported by specific page mode + + @param[in] PagingMode The paging mode. + + @retval Max Address. +**/ +UINT32 +GetMaxAddress ( + IN PAGING_MODE PagingMode + ) +{ + CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize; + UINT32 MaxExtendedFunctionId; + UINT32 MaxAddressBits; + + VirPhyAddressSize.Uint32 = 0; + + // + // Get Maximum Physical Address Bits + // Get the number of address lines; Maximum Physical Address is 2^PhysicalAddressBits - 1. + // If CPUID does not supported, then use a max value of 36 as per SDM 3A, 4.1.4. + // + AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunctionId, NULL, NULL, NULL); + if (MaxExtendedFunctionId >= CPUID_VIR_PHY_ADDRESS_SIZE) { + AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL); + MaxAddressBits = VirPhyAddressSize.Bits.PhysicalAddressBits; + } else { + MaxAddressBits = 36; + } + + if ((PagingMode == Paging4Level1GB) || (PagingMode == Paging4Level)) { + // + // The max liner address bits is 48 for 4 level page table. + // + MaxAddressBits = MIN (VirPhyAddressSize.Bits.PhysicalAddressBits, 48); + } + + return MaxAddressBits; +} + +/** + TemporaryRamDone() disables the use of Temporary RAM. If present, this service is invoked + by the PEI Foundation after the EFI_PEI_PERMANANT_MEMORY_INSTALLED_PPI is installed. + + @retval EFI_SUCCESS Use of Temporary RAM was disabled. + @retval EFI_INVALID_PARAMETER Temporary RAM could not be disabled. + +**/ +EFI_STATUS +EFIAPI +SecTemporaryRamDone ( + VOID + ) +{ + EFI_STATUS Status; + EFI_STATUS Status2; + UINTN Index; + BOOLEAN State; + EFI_PEI_PPI_DESCRIPTOR *PeiPpiDescriptor; + REPUBLISH_SEC_PPI_PPI *RepublishSecPpiPpi; + IA32_CR0 Cr0; + PAGING_MODE PagingMode; + UINT32 MaxAddressBits; + UINTN PageTable; + EFI_PHYSICAL_ADDRESS Buffer; + UINTN BufferSize; + UINT64 Length; + UINT64 Address; + IA32_MAP_ATTRIBUTE MapAttribute; + IA32_MAP_ATTRIBUTE MapMask; + + PageTable = 0; + BufferSize = 0; + MapAttribute.Uint64 = 0; + MapAttribute.Bits.Present = 1; + MapAttribute.Bits.ReadWrite = 1; + MapMask.Uint64 = MAX_UINT64; + + // + // Republish Sec Platform Information(2) PPI + // + RepublishSecPlatformInformationPpi (); + + // + // Re-install SEC PPIs using a PEIM produced service if published + // + for (Index = 0, Status = EFI_SUCCESS; Status == EFI_SUCCESS; Index++) { + Status = PeiServicesLocatePpi ( + &gRepublishSecPpiPpiGuid, + Index, + &PeiPpiDescriptor, + (VOID **)&RepublishSecPpiPpi + ); + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "Calling RepublishSecPpi instance %d.\n", Index)); + Status2 = RepublishSecPpiPpi->RepublishSecPpis (); + ASSERT_EFI_ERROR (Status2); + } + } + + // + // Migrate DebugAgentContext. + // + InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, NULL, NULL); + + // + // Disable interrupts and save current interrupt state + // + State = SaveAndDisableInterrupts (); + + // + // Migrate GDT before NEM near down + // + if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) { + Status = MigrateGdt (); + ASSERT_EFI_ERROR (Status); + } + + // + // Migrate page table to permanent memory mapping entire physical address space if CR0.PG is set. + // + Cr0.UintN = AsmReadCr0 (); + if (Cr0.Bits.PG != 0) { + // + // Assume CPU runs in 64bit mode if paging is enabled. + // + ASSERT (sizeof (UINTN) == sizeof (UINT64)); + + // + // Get PagingMode & MaxAddressBits. + // + PagingMode = GetPagingMode (); + MaxAddressBits = GetMaxAddress (PagingMode); + DEBUG ((DEBUG_INFO, "SecTemporaryRamDone: PagingMode = 0x%lx, MaxAddressBits = %d\n", PagingMode, MaxAddressBits)); + + // + // Create page table to cover the max mapping address in physical memory before Temp + // Ram Exit. The max mapping address is defined by PcdMaxMappingAddressBeforeTempRamExit. + // + Length = FixedPcdGet64 (PcdMaxMappingAddressBeforeTempRamExit); + Length = MIN (LShiftU64 (1, MaxAddressBits), Length); + if (Length != 0) { + Status = PageTableMap (&PageTable, PagingMode, 0, &BufferSize, 0, Length, &MapAttribute, &MapMask, NULL); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + if (Status != EFI_BUFFER_TOO_SMALL) { + return Status; + } + + Status = PeiServicesAllocatePages ( + EfiBootServicesData, + EFI_SIZE_TO_PAGES (BufferSize), + &Buffer + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Status = PageTableMap (&PageTable, PagingMode, (VOID *)(UINTN)Buffer, &BufferSize, 0, Length, &MapAttribute, &MapMask, NULL); + ASSERT (BufferSize == 0); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SecTemporaryRamDone: Failed to create page table in physical memory before Temp Ram Exit: %r.\n", Status)); + CpuDeadLoop (); + } + + AsmWriteCr3 (PageTable); + } + } + + // + // Disable Temporary RAM after Stack and Heap have been migrated at this point. + // + SecPlatformDisableTemporaryMemory (); + + // + // Expanding the page table to cover the entire memory space since the physical memory is WB after TempRamExit. + // + if ((Cr0.Bits.PG != 0) && (Length < LShiftU64 (1, MaxAddressBits))) { + Address = Length; + Length = LShiftU64 (1, MaxAddressBits) - Length; + + MapAttribute.Uint64 = Address; + MapAttribute.Bits.Present = 1; + MapAttribute.Bits.ReadWrite = 1; + + Status = PageTableMap (&PageTable, PagingMode, 0, &BufferSize, Address, Length, &MapAttribute, &MapMask, NULL); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + if (Status != EFI_BUFFER_TOO_SMALL) { + return Status; + } + + Status = PeiServicesAllocatePages ( + EfiBootServicesData, + EFI_SIZE_TO_PAGES (BufferSize), + &Buffer + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Status = PageTableMap (&PageTable, PagingMode, (VOID *)(UINTN)Buffer, &BufferSize, Address, Length, &MapAttribute, &MapMask, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SecTemporaryRamDone: Failed to create full range page table in physical memory after Temp Ram Exit: %r.\n", Status)); + CpuDeadLoop (); + } + + AsmWriteCr3 (PageTable); + } + + // + // Restore original interrupt state + // + SetInterruptState (State); + + return EFI_SUCCESS; +}