-/** @file
- Main SEC phase code. Transitions to PEI.
-
- Copyright (c) 2008 - 2009, 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
-
- 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/BaseLib.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/PeimEntryPoint.h>
-#include <Library/PeiServicesLib.h>
-#include <Ppi/TemporaryRamSupport.h>
-#include <Library/PcdLib.h>
-#include <Library/UefiCpuLib.h>
-
-#include "SecMain.h"
-
-EFI_STATUS
-EFIAPI
-TemporaryRamMigration (
- IN CONST EFI_PEI_SERVICES **PeiServices,
- IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
- IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
- IN UINTN CopySize
- );
-
-STATIC TEMPORARY_RAM_SUPPORT_PPI mTempRamSupportPpi = {
- (TEMPORARY_RAM_MIGRATION) TemporaryRamMigration
-};
-
-STATIC EFI_PEI_PPI_DESCRIPTOR mPrivateDispatchTable[] = {
- {
- (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
- &gEfiTemporaryRamSupportPpiGuid,
- &mTempRamSupportPpi
- },
-};
-
-
-VOID
-InitializeIdtPtr (
- IN VOID* IdtPtr
- )
-{
- IA32_DESCRIPTOR IdtDescriptor;
-
- IdtDescriptor.Base = (UINTN)IdtPtr;
- IdtDescriptor.Limit = (UINT16) 0;
- AsmWriteIdtr (&IdtDescriptor);
-}
-
-VOID
-EFIAPI
-SecCoreStartupWithStack (
- IN EFI_FIRMWARE_VOLUME_HEADER *BootFv,
- IN VOID *TopOfCurrentStack
- )
-{
- EFI_SEC_PEI_HAND_OFF *SecCoreData;
- UINT8 *BottomOfTempRam;
- UINT8 *TopOfTempRam;
- UINTN SizeOfTempRam;
- VOID *IdtPtr;
- VOID *PeiCoreEntryPoint;
-
- DEBUG ((EFI_D_INFO,
- "SecCoreStartupWithStack(0x%x, 0x%x)\n",
- (UINT32)(UINTN)BootFv,
- (UINT32)(UINTN)TopOfCurrentStack
- ));
-
- ProcessLibraryConstructorList (NULL, NULL);
-
- //
- // Initialize floating point operating environment
- // to be compliant with UEFI spec.
- //
- InitializeFloatingPointUnits ();
-
- BottomOfTempRam = (UINT8*)(UINTN) INITIAL_TOP_OF_STACK;
- SizeOfTempRam = (UINTN) SIZE_64KB;
- TopOfTempRam = BottomOfTempRam + SizeOfTempRam;
-
- //
- // |-------------|
- // | SecCoreData | 4k
- // |-------------|
- // | Heap | 28k
- // |-------------|
- // | Stack | 32k
- // |-------------| <---- INITIAL_TOP_OF_STACK
- //
-
- //
- // Bind this information into the SEC hand-off state
- //
- SecCoreData = (EFI_SEC_PEI_HAND_OFF*)((UINTN) TopOfTempRam - SIZE_4KB);
- SecCoreData->DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
-
- SecCoreData->TemporaryRamBase = (VOID*) BottomOfTempRam;
- SecCoreData->TemporaryRamSize = SizeOfTempRam;
-
- SecCoreData->PeiTemporaryRamSize = 28 * SIZE_1KB;
- SecCoreData->PeiTemporaryRamBase = (VOID*)((UINTN)SecCoreData - SecCoreData->PeiTemporaryRamSize);
-
- SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
- SecCoreData->StackSize = (UINTN)SecCoreData->PeiTemporaryRamBase - (UINTN)SecCoreData->TemporaryRamBase;
-
- //
- // Initialize the IDT Pointer, since IA32 & X64 architectures
- // use it to store the PEI Services pointer.
- //
- IdtPtr = (VOID*)((UINT8*)SecCoreData + sizeof (*SecCoreData) + sizeof (UINTN));
- IdtPtr = ALIGN_POINTER(IdtPtr, 16);
- InitializeIdtPtr (IdtPtr);
-
- FindPeiCoreEntryPoint (&BootFv, &PeiCoreEntryPoint);
-
- SecCoreData->BootFirmwareVolumeBase = BootFv;
- SecCoreData->BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
-
- if (PeiCoreEntryPoint != NULL) {
- DEBUG ((EFI_D_INFO,
- "Calling PEI Core entry point at 0x%x\n",
- PeiCoreEntryPoint
- ));
- //
- // Transfer control to the PEI Core
- //
- PeiSwitchStacks (
- (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,
- SecCoreData,
- (VOID *) (UINTN) ((EFI_PEI_PPI_DESCRIPTOR *) &mPrivateDispatchTable),
- NULL,
- TopOfCurrentStack,
- (VOID *)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)
- );
- }
-
- //
- // If we get here, then either we couldn't locate the PEI Core, or
- // the PEI Core returned.
- //
- // Both of these errors are unrecoverable.
- //
- ASSERT (FALSE);
- CpuDeadLoop ();
-}
-
-EFI_STATUS
-EFIAPI
-TemporaryRamMigration (
- IN CONST EFI_PEI_SERVICES **PeiServices,
- IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
- IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
- IN UINTN CopySize
- )
-{
- DEBUG ((EFI_D_ERROR, "TemporaryRamMigration(0x%x, 0x%x, 0x%x)\n", (UINTN)TemporaryMemoryBase, (UINTN)PermanentMemoryBase, CopySize));
-
- //
- // Migrate the whole temporary memory to permenent memory.
- //
- CopyMem((VOID*)(UINTN)PermanentMemoryBase, (VOID*)(UINTN)TemporaryMemoryBase, CopySize);
-
- //
- // SecSwitchStack function must be invoked after the memory migration
- // immediatly, also we need fixup the stack change caused by new call into
- // permenent memory.
- //
- SecSwitchStack (
- (UINTN) TemporaryMemoryBase,
- (UINTN) PermanentMemoryBase,
- CopySize
- );
-
- return EFI_SUCCESS;
-}
-
+/** @file\r
+ Main SEC phase code. Transitions to PEI.\r
+\r
+ Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiCpuLib.h>\r
+#include <Library/DebugAgentLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/PeCoffGetEntryPointLib.h>\r
+#include <Library/PeCoffExtraActionLib.h>\r
+#include <Library/ExtractGuidedSectionLib.h>\r
+#include <Library/LocalApicLib.h>\r
+\r
+#include <Ppi/TemporaryRamSupport.h>\r
+\r
+#define SEC_IDT_ENTRY_COUNT 34\r
+\r
+typedef struct _SEC_IDT_TABLE {\r
+ EFI_PEI_SERVICES *PeiService;\r
+ IA32_IDT_GATE_DESCRIPTOR IdtTable[SEC_IDT_ENTRY_COUNT];\r
+} SEC_IDT_TABLE;\r
+\r
+VOID\r
+EFIAPI\r
+SecStartupPhase2 (\r
+ IN VOID *Context\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+TemporaryRamMigration (\r
+ IN CONST EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,\r
+ IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,\r
+ IN UINTN CopySize\r
+ );\r
+\r
+//\r
+//\r
+// \r
+EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mTemporaryRamSupportPpi = {\r
+ TemporaryRamMigration\r
+};\r
+\r
+EFI_PEI_PPI_DESCRIPTOR mPrivateDispatchTable[] = {\r
+ {\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gEfiTemporaryRamSupportPpiGuid,\r
+ &mTemporaryRamSupportPpi\r
+ },\r
+};\r
+\r
+//\r
+// Template of an IDT entry pointing to 10:FFFFFFE4h.\r
+//\r
+IA32_IDT_GATE_DESCRIPTOR mIdtEntryTemplate = {\r
+ { // Bits\r
+ 0xffe4, // OffsetLow\r
+ 0x10, // Selector\r
+ 0x0, // Reserved_0\r
+ IA32_IDT_GATE_TYPE_INTERRUPT_32, // GateType\r
+ 0xffff // OffsetHigh\r
+ } \r
+};\r
+\r
+/**\r
+ Locates the main boot firmware volume.\r
+\r
+ @param[in,out] BootFv On input, the base of the BootFv\r
+ On output, the decompressed main firmware volume\r
+\r
+ @retval EFI_SUCCESS The main firmware volume was located and decompressed\r
+ @retval EFI_NOT_FOUND The main firmware volume was not found\r
+\r
+**/\r
+EFI_STATUS\r
+FindMainFv (\r
+ IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv\r
+ )\r
+{\r
+ EFI_FIRMWARE_VOLUME_HEADER *Fv;\r
+ UINTN Distance;\r
+\r
+ ASSERT (((UINTN) *BootFv & EFI_PAGE_MASK) == 0);\r
+\r
+ Fv = *BootFv;\r
+ Distance = (UINTN) (*BootFv)->FvLength;\r
+ do {\r
+ Fv = (EFI_FIRMWARE_VOLUME_HEADER*) ((UINT8*) Fv - EFI_PAGE_SIZE);\r
+ Distance += EFI_PAGE_SIZE;\r
+ if (Distance > SIZE_32MB) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Fv->Signature != EFI_FVH_SIGNATURE) {\r
+ continue;\r
+ }\r
+\r
+ if ((UINTN) Fv->FvLength > Distance) {\r
+ continue;\r
+ }\r
+\r
+ *BootFv = Fv;\r
+ return EFI_SUCCESS;\r
+\r
+ } while (TRUE);\r
+}\r
+\r
+/**\r
+ Locates a section within a series of sections\r
+ with the specified section type.\r
+\r
+ The Instance parameter indicates which instance of the section\r
+ type to return. (0 is first instance, 1 is second...)\r
+\r
+ @param[in] Sections The sections to search\r
+ @param[in] SizeOfSections Total size of all sections\r
+ @param[in] SectionType The section type to locate\r
+ @param[in] Instance The section instance number\r
+ @param[out] FoundSection The FFS section if found\r
+\r
+ @retval EFI_SUCCESS The file and section was found\r
+ @retval EFI_NOT_FOUND The file and section was not found\r
+ @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted\r
+\r
+**/\r
+EFI_STATUS\r
+FindFfsSectionInstance (\r
+ IN VOID *Sections,\r
+ IN UINTN SizeOfSections,\r
+ IN EFI_SECTION_TYPE SectionType,\r
+ IN UINTN Instance,\r
+ OUT EFI_COMMON_SECTION_HEADER **FoundSection\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS CurrentAddress;\r
+ UINT32 Size;\r
+ EFI_PHYSICAL_ADDRESS EndOfSections;\r
+ EFI_COMMON_SECTION_HEADER *Section;\r
+ EFI_PHYSICAL_ADDRESS EndOfSection;\r
+\r
+ //\r
+ // Loop through the FFS file sections within the PEI Core FFS file\r
+ //\r
+ EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) Sections;\r
+ EndOfSections = EndOfSection + SizeOfSections;\r
+ for (;;) {\r
+ if (EndOfSection == EndOfSections) {\r
+ break;\r
+ }\r
+ CurrentAddress = (EndOfSection + 3) & ~(3ULL);\r
+ if (CurrentAddress >= EndOfSections) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;\r
+\r
+ Size = SECTION_SIZE (Section);\r
+ if (Size < sizeof (*Section)) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ EndOfSection = CurrentAddress + Size;\r
+ if (EndOfSection > EndOfSections) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ //\r
+ // Look for the requested section type\r
+ //\r
+ if (Section->Type == SectionType) {\r
+ if (Instance == 0) {\r
+ *FoundSection = Section;\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ Instance--;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ Locates a section within a series of sections\r
+ with the specified section type.\r
+\r
+ @param[in] Sections The sections to search\r
+ @param[in] SizeOfSections Total size of all sections\r
+ @param[in] SectionType The section type to locate\r
+ @param[out] FoundSection The FFS section if found\r
+\r
+ @retval EFI_SUCCESS The file and section was found\r
+ @retval EFI_NOT_FOUND The file and section was not found\r
+ @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted\r
+\r
+**/\r
+EFI_STATUS\r
+FindFfsSectionInSections (\r
+ IN VOID *Sections,\r
+ IN UINTN SizeOfSections,\r
+ IN EFI_SECTION_TYPE SectionType,\r
+ OUT EFI_COMMON_SECTION_HEADER **FoundSection\r
+ )\r
+{\r
+ return FindFfsSectionInstance (\r
+ Sections,\r
+ SizeOfSections,\r
+ SectionType,\r
+ 0,\r
+ FoundSection\r
+ );\r
+}\r
+\r
+/**\r
+ Locates a FFS file with the specified file type and a section\r
+ within that file with the specified section type.\r
+\r
+ @param[in] Fv The firmware volume to search\r
+ @param[in] FileType The file type to locate\r
+ @param[in] SectionType The section type to locate\r
+ @param[out] FoundSection The FFS section if found\r
+\r
+ @retval EFI_SUCCESS The file and section was found\r
+ @retval EFI_NOT_FOUND The file and section was not found\r
+ @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted\r
+\r
+**/\r
+EFI_STATUS\r
+FindFfsFileAndSection (\r
+ IN EFI_FIRMWARE_VOLUME_HEADER *Fv,\r
+ IN EFI_FV_FILETYPE FileType,\r
+ IN EFI_SECTION_TYPE SectionType,\r
+ OUT EFI_COMMON_SECTION_HEADER **FoundSection\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS CurrentAddress;\r
+ EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume;\r
+ EFI_FFS_FILE_HEADER *File;\r
+ UINT32 Size;\r
+ EFI_PHYSICAL_ADDRESS EndOfFile;\r
+\r
+ if (Fv->Signature != EFI_FVH_SIGNATURE) {\r
+ DEBUG ((EFI_D_ERROR, "FV at %p does not have FV header signature\n", Fv));\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Fv;\r
+ EndOfFirmwareVolume = CurrentAddress + Fv->FvLength;\r
+\r
+ //\r
+ // Loop through the FFS files in the Boot Firmware Volume\r
+ //\r
+ for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {\r
+\r
+ CurrentAddress = (EndOfFile + 7) & ~(7ULL);\r
+ if (CurrentAddress > EndOfFirmwareVolume) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;\r
+ Size = FFS_FILE_SIZE (File);\r
+ if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ EndOfFile = CurrentAddress + Size;\r
+ if (EndOfFile > EndOfFirmwareVolume) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ //\r
+ // Look for the request file type\r
+ //\r
+ if (File->Type != FileType) {\r
+ continue;\r
+ }\r
+\r
+ Status = FindFfsSectionInSections (\r
+ (VOID*) (File + 1),\r
+ (UINTN) EndOfFile - (UINTN) (File + 1),\r
+ SectionType,\r
+ FoundSection\r
+ );\r
+ if (!EFI_ERROR (Status) || (Status == EFI_VOLUME_CORRUPTED)) {\r
+ return Status;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Locates the compressed main firmware volume and decompresses it.\r
+\r
+ @param[in,out] Fv On input, the firmware volume to search\r
+ On output, the decompressed BOOT/PEI FV\r
+\r
+ @retval EFI_SUCCESS The file and section was found\r
+ @retval EFI_NOT_FOUND The file and section was not found\r
+ @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted\r
+\r
+**/\r
+EFI_STATUS\r
+DecompressMemFvs (\r
+ IN OUT EFI_FIRMWARE_VOLUME_HEADER **Fv\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_GUID_DEFINED_SECTION *Section;\r
+ UINT32 OutputBufferSize;\r
+ UINT32 ScratchBufferSize;\r
+ UINT16 SectionAttribute;\r
+ UINT32 AuthenticationStatus;\r
+ VOID *OutputBuffer;\r
+ VOID *ScratchBuffer;\r
+ EFI_COMMON_SECTION_HEADER *FvSection;\r
+ EFI_FIRMWARE_VOLUME_HEADER *PeiMemFv;\r
+ EFI_FIRMWARE_VOLUME_HEADER *DxeMemFv;\r
+ UINT32 FvHeaderSize;\r
+ UINT32 FvSectionSize;\r
+\r
+ FvSection = (EFI_COMMON_SECTION_HEADER*) NULL;\r
+\r
+ Status = FindFfsFileAndSection (\r
+ *Fv,\r
+ EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,\r
+ EFI_SECTION_GUID_DEFINED,\r
+ (EFI_COMMON_SECTION_HEADER**) &Section\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Unable to find GUID defined section\n"));\r
+ return Status;\r
+ }\r
+\r
+ Status = ExtractGuidedSectionGetInfo (\r
+ Section,\r
+ &OutputBufferSize,\r
+ &ScratchBufferSize,\r
+ &SectionAttribute\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Unable to GetInfo for GUIDed section\n"));\r
+ return Status;\r
+ }\r
+\r
+ OutputBuffer = (VOID*) ((UINT8*)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase) + SIZE_1MB);\r
+ ScratchBuffer = ALIGN_POINTER ((UINT8*) OutputBuffer + OutputBufferSize, SIZE_1MB);\r
+\r
+ DEBUG ((EFI_D_VERBOSE, "%a: OutputBuffer@%p+0x%x ScratchBuffer@%p+0x%x "\r
+ "PcdOvmfDecompressionScratchEnd=0x%x\n", __FUNCTION__, OutputBuffer,\r
+ OutputBufferSize, ScratchBuffer, ScratchBufferSize,\r
+ PcdGet32 (PcdOvmfDecompressionScratchEnd)));\r
+ ASSERT ((UINTN)ScratchBuffer + ScratchBufferSize ==\r
+ PcdGet32 (PcdOvmfDecompressionScratchEnd));\r
+\r
+ Status = ExtractGuidedSectionDecode (\r
+ Section,\r
+ &OutputBuffer,\r
+ ScratchBuffer,\r
+ &AuthenticationStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Error during GUID section decode\n"));\r
+ return Status;\r
+ }\r
+\r
+ Status = FindFfsSectionInstance (\r
+ OutputBuffer,\r
+ OutputBufferSize,\r
+ EFI_SECTION_FIRMWARE_VOLUME_IMAGE,\r
+ 0,\r
+ &FvSection\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Unable to find PEI FV section\n"));\r
+ return Status;\r
+ }\r
+\r
+ ASSERT (SECTION_SIZE (FvSection) ==\r
+ (PcdGet32 (PcdOvmfPeiMemFvSize) + sizeof (*FvSection)));\r
+ ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);\r
+\r
+ PeiMemFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfPeiMemFvBase);\r
+ CopyMem (PeiMemFv, (VOID*) (FvSection + 1), PcdGet32 (PcdOvmfPeiMemFvSize));\r
+\r
+ if (PeiMemFv->Signature != EFI_FVH_SIGNATURE) {\r
+ DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", PeiMemFv));\r
+ CpuDeadLoop ();\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ Status = FindFfsSectionInstance (\r
+ OutputBuffer,\r
+ OutputBufferSize,\r
+ EFI_SECTION_FIRMWARE_VOLUME_IMAGE,\r
+ 1,\r
+ &FvSection\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Unable to find DXE FV section\n"));\r
+ return Status;\r
+ }\r
+\r
+ ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);\r
+\r
+ if (IS_SECTION2 (FvSection)) {\r
+ FvSectionSize = SECTION2_SIZE (FvSection);\r
+ FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2);\r
+ } else {\r
+ FvSectionSize = SECTION_SIZE (FvSection);\r
+ FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);\r
+ }\r
+\r
+ ASSERT (FvSectionSize == (PcdGet32 (PcdOvmfDxeMemFvSize) + FvHeaderSize));\r
+\r
+ DxeMemFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase);\r
+ CopyMem (DxeMemFv, (VOID*) ((UINTN)FvSection + FvHeaderSize), PcdGet32 (PcdOvmfDxeMemFvSize));\r
+\r
+ if (DxeMemFv->Signature != EFI_FVH_SIGNATURE) {\r
+ DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", DxeMemFv));\r
+ CpuDeadLoop ();\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ *Fv = PeiMemFv;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Locates the PEI Core entry point address\r
+\r
+ @param[in] Fv The firmware volume to search\r
+ @param[out] PeiCoreEntryPoint The entry point of the PEI Core image\r
+\r
+ @retval EFI_SUCCESS The file and section was found\r
+ @retval EFI_NOT_FOUND The file and section was not found\r
+ @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted\r
+\r
+**/\r
+EFI_STATUS\r
+FindPeiCoreImageBaseInFv (\r
+ IN EFI_FIRMWARE_VOLUME_HEADER *Fv,\r
+ OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_COMMON_SECTION_HEADER *Section;\r
+\r
+ Status = FindFfsFileAndSection (\r
+ Fv,\r
+ EFI_FV_FILETYPE_PEI_CORE,\r
+ EFI_SECTION_PE32,\r
+ &Section\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Status = FindFfsFileAndSection (\r
+ Fv,\r
+ EFI_FV_FILETYPE_PEI_CORE,\r
+ EFI_SECTION_TE,\r
+ &Section\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Unable to find PEI Core image\n"));\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Reads 8-bits of CMOS data.\r
+\r
+ Reads the 8-bits of CMOS data at the location specified by Index.\r
+ The 8-bit read value is returned.\r
+\r
+ @param Index The CMOS location to read.\r
+\r
+ @return The value read.\r
+\r
+**/\r
+STATIC\r
+UINT8\r
+CmosRead8 (\r
+ IN UINTN Index\r
+ )\r
+{\r
+ IoWrite8 (0x70, (UINT8) Index);\r
+ return IoRead8 (0x71);\r
+}\r
+\r
+\r
+STATIC\r
+BOOLEAN\r
+IsS3Resume (\r
+ VOID\r
+ )\r
+{\r
+ return (CmosRead8 (0xF) == 0xFE);\r
+}\r
+\r
+\r
+STATIC\r
+EFI_STATUS\r
+GetS3ResumePeiFv (\r
+ IN OUT EFI_FIRMWARE_VOLUME_HEADER **PeiFv\r
+ )\r
+{\r
+ *PeiFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfPeiMemFvBase);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Locates the PEI Core entry point address\r
+\r
+ @param[in,out] Fv The firmware volume to search\r
+ @param[out] PeiCoreEntryPoint The entry point of the PEI Core image\r
+\r
+ @retval EFI_SUCCESS The file and section was found\r
+ @retval EFI_NOT_FOUND The file and section was not found\r
+ @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted\r
+\r
+**/\r
+VOID\r
+FindPeiCoreImageBase (\r
+ IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv,\r
+ OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase\r
+ )\r
+{\r
+ BOOLEAN S3Resume;\r
+\r
+ *PeiCoreImageBase = 0;\r
+\r
+ S3Resume = IsS3Resume ();\r
+ if (S3Resume && !FeaturePcdGet (PcdSmmSmramRequire)) {\r
+ //\r
+ // A malicious runtime OS may have injected something into our previously\r
+ // decoded PEI FV, but we don't care about that unless SMM/SMRAM is required.\r
+ //\r
+ DEBUG ((EFI_D_VERBOSE, "SEC: S3 resume\n"));\r
+ GetS3ResumePeiFv (BootFv);\r
+ } else {\r
+ //\r
+ // We're either not resuming, or resuming "securely" -- we'll decompress\r
+ // both PEI FV and DXE FV from pristine flash.\r
+ //\r
+ DEBUG ((EFI_D_VERBOSE, "SEC: %a\n",\r
+ S3Resume ? "S3 resume (with PEI decompression)" : "Normal boot"));\r
+ FindMainFv (BootFv);\r
+\r
+ DecompressMemFvs (BootFv);\r
+ }\r
+\r
+ FindPeiCoreImageBaseInFv (*BootFv, PeiCoreImageBase);\r
+}\r
+\r
+/**\r
+ Find core image base.\r
+\r
+**/\r
+EFI_STATUS\r
+FindImageBase (\r
+ IN EFI_FIRMWARE_VOLUME_HEADER *BootFirmwareVolumePtr,\r
+ OUT EFI_PHYSICAL_ADDRESS *SecCoreImageBase\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS CurrentAddress;\r
+ EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume;\r
+ EFI_FFS_FILE_HEADER *File;\r
+ UINT32 Size;\r
+ EFI_PHYSICAL_ADDRESS EndOfFile;\r
+ EFI_COMMON_SECTION_HEADER *Section;\r
+ EFI_PHYSICAL_ADDRESS EndOfSection;\r
+\r
+ *SecCoreImageBase = 0;\r
+\r
+ CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) BootFirmwareVolumePtr;\r
+ EndOfFirmwareVolume = CurrentAddress + BootFirmwareVolumePtr->FvLength;\r
+\r
+ //\r
+ // Loop through the FFS files in the Boot Firmware Volume\r
+ //\r
+ for (EndOfFile = CurrentAddress + BootFirmwareVolumePtr->HeaderLength; ; ) {\r
+\r
+ CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;\r
+ if (CurrentAddress > EndOfFirmwareVolume) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;\r
+ Size = FFS_FILE_SIZE (File);\r
+ if (Size < sizeof (*File)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ EndOfFile = CurrentAddress + Size;\r
+ if (EndOfFile > EndOfFirmwareVolume) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Look for SEC Core\r
+ //\r
+ if (File->Type != EFI_FV_FILETYPE_SECURITY_CORE) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Loop through the FFS file sections within the FFS file\r
+ //\r
+ EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) (File + 1);\r
+ for (;;) {\r
+ CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL;\r
+ Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;\r
+\r
+ Size = SECTION_SIZE (Section);\r
+ if (Size < sizeof (*Section)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ EndOfSection = CurrentAddress + Size;\r
+ if (EndOfSection > EndOfFile) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Look for executable sections\r
+ //\r
+ if (Section->Type == EFI_SECTION_PE32 || Section->Type == EFI_SECTION_TE) {\r
+ if (File->Type == EFI_FV_FILETYPE_SECURITY_CORE) {\r
+ *SecCoreImageBase = (PHYSICAL_ADDRESS) (UINTN) (Section + 1);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // SEC Core image found\r
+ //\r
+ if (*SecCoreImageBase != 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+ Find and return Pei Core entry point.\r
+\r
+ It also find SEC and PEI Core file debug information. It will report them if\r
+ remote debug is enabled.\r
+\r
+**/\r
+VOID\r
+FindAndReportEntryPoints (\r
+ IN EFI_FIRMWARE_VOLUME_HEADER **BootFirmwareVolumePtr,\r
+ OUT EFI_PEI_CORE_ENTRY_POINT *PeiCoreEntryPoint\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS SecCoreImageBase;\r
+ EFI_PHYSICAL_ADDRESS PeiCoreImageBase;\r
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
+\r
+ //\r
+ // Find SEC Core and PEI Core image base\r
+ //\r
+ Status = FindImageBase (*BootFirmwareVolumePtr, &SecCoreImageBase);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ FindPeiCoreImageBase (BootFirmwareVolumePtr, &PeiCoreImageBase);\r
+ \r
+ ZeroMem ((VOID *) &ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));\r
+ //\r
+ // Report SEC Core debug information when remote debug is enabled\r
+ //\r
+ ImageContext.ImageAddress = SecCoreImageBase;\r
+ ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);\r
+ PeCoffLoaderRelocateImageExtraAction (&ImageContext);\r
+\r
+ //\r
+ // Report PEI Core debug information when remote debug is enabled\r
+ //\r
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase;\r
+ ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);\r
+ PeCoffLoaderRelocateImageExtraAction (&ImageContext);\r
+\r
+ //\r
+ // Find PEI Core entry point\r
+ //\r
+ Status = PeCoffLoaderGetEntryPoint ((VOID *) (UINTN) PeiCoreImageBase, (VOID**) PeiCoreEntryPoint);\r
+ if (EFI_ERROR (Status)) {\r
+ *PeiCoreEntryPoint = 0;\r
+ }\r
+\r
+ return;\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+SecCoreStartupWithStack (\r
+ IN EFI_FIRMWARE_VOLUME_HEADER *BootFv,\r
+ IN VOID *TopOfCurrentStack\r
+ )\r
+{\r
+ EFI_SEC_PEI_HAND_OFF SecCoreData;\r
+ SEC_IDT_TABLE IdtTableInStack;\r
+ IA32_DESCRIPTOR IdtDescriptor;\r
+ UINT32 Index;\r
+ volatile UINT8 *Table;\r
+\r
+ //\r
+ // To ensure SMM can't be compromised on S3 resume, we must force re-init of\r
+ // the BaseExtractGuidedSectionLib. Since this is before library contructors\r
+ // are called, we must use a loop rather than SetMem.\r
+ //\r
+ Table = (UINT8*)(UINTN)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress);\r
+ for (Index = 0;\r
+ Index < FixedPcdGet32 (PcdGuidedExtractHandlerTableSize);\r
+ ++Index) {\r
+ Table[Index] = 0;\r
+ }\r
+\r
+ ProcessLibraryConstructorList (NULL, NULL);\r
+\r
+ DEBUG ((EFI_D_INFO,\r
+ "SecCoreStartupWithStack(0x%x, 0x%x)\n",\r
+ (UINT32)(UINTN)BootFv,\r
+ (UINT32)(UINTN)TopOfCurrentStack\r
+ ));\r
+\r
+ //\r
+ // Initialize floating point operating environment\r
+ // to be compliant with UEFI spec.\r
+ //\r
+ InitializeFloatingPointUnits ();\r
+\r
+ //\r
+ // Initialize IDT\r
+ // \r
+ IdtTableInStack.PeiService = NULL;\r
+ for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) {\r
+ CopyMem (&IdtTableInStack.IdtTable[Index], &mIdtEntryTemplate, sizeof (mIdtEntryTemplate));\r
+ }\r
+\r
+ IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable;\r
+ IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);\r
+\r
+ AsmWriteIdtr (&IdtDescriptor);\r
+\r
+#if defined (MDE_CPU_X64)\r
+ //\r
+ // ASSERT that the Page Tables were set by the reset vector code to\r
+ // the address we expect.\r
+ //\r
+ ASSERT (AsmReadCr3 () == (UINTN) PcdGet32 (PcdOvmfSecPageTablesBase));\r
+#endif\r
+\r
+ //\r
+ // |-------------| <-- TopOfCurrentStack\r
+ // | Stack | 32k\r
+ // |-------------|\r
+ // | Heap | 32k\r
+ // |-------------| <-- SecCoreData.TemporaryRamBase\r
+ //\r
+\r
+ ASSERT ((UINTN) (PcdGet32 (PcdOvmfSecPeiTempRamBase) +\r
+ PcdGet32 (PcdOvmfSecPeiTempRamSize)) ==\r
+ (UINTN) TopOfCurrentStack);\r
+\r
+ //\r
+ // Initialize SEC hand-off state\r
+ //\r
+ SecCoreData.DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);\r
+\r
+ SecCoreData.TemporaryRamSize = (UINTN) PcdGet32 (PcdOvmfSecPeiTempRamSize);\r
+ SecCoreData.TemporaryRamBase = (VOID*)((UINT8 *)TopOfCurrentStack - SecCoreData.TemporaryRamSize);\r
+\r
+ SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase;\r
+ SecCoreData.PeiTemporaryRamSize = SecCoreData.TemporaryRamSize >> 1;\r
+\r
+ SecCoreData.StackBase = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;\r
+ SecCoreData.StackSize = SecCoreData.TemporaryRamSize >> 1;\r
+\r
+ SecCoreData.BootFirmwareVolumeBase = BootFv;\r
+ SecCoreData.BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;\r
+\r
+ //\r
+ // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled\r
+ //\r
+ IoWrite8 (0x21, 0xff);\r
+ IoWrite8 (0xA1, 0xff);\r
+\r
+ //\r
+ // Initialize Local APIC Timer hardware and disable Local APIC Timer\r
+ // interrupts before initializing the Debug Agent and the debug timer is\r
+ // enabled.\r
+ //\r
+ InitializeApicTimer (0, MAX_UINT32, TRUE, 5);\r
+ DisableApicTimerInterrupt ();\r
+ \r
+ //\r
+ // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.\r
+ //\r
+ InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2);\r
+}\r
+ \r
+/**\r
+ Caller provided function to be invoked at the end of InitializeDebugAgent().\r
+\r
+ Entry point to the C language phase of SEC. After the SEC assembly\r
+ code has initialized some temporary memory and set up the stack,\r
+ the control is transferred to this function.\r
+\r
+ @param[in] Context The first input parameter of InitializeDebugAgent().\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SecStartupPhase2(\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_SEC_PEI_HAND_OFF *SecCoreData;\r
+ EFI_FIRMWARE_VOLUME_HEADER *BootFv;\r
+ EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint;\r
+ \r
+ SecCoreData = (EFI_SEC_PEI_HAND_OFF *) Context;\r
+ \r
+ //\r
+ // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug\r
+ // is enabled.\r
+ //\r
+ BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;\r
+ FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);\r
+ SecCoreData->BootFirmwareVolumeBase = BootFv;\r
+ SecCoreData->BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;\r
+\r
+ //\r
+ // Transfer the control to the PEI core\r
+ //\r
+ (*PeiCoreEntryPoint) (SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);\r
+ \r
+ //\r
+ // If we get here then the PEI Core returned, which is not recoverable.\r
+ //\r
+ ASSERT (FALSE);\r
+ CpuDeadLoop ();\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+TemporaryRamMigration (\r
+ IN CONST EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,\r
+ IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,\r
+ IN UINTN CopySize\r
+ )\r
+{\r
+ IA32_DESCRIPTOR IdtDescriptor;\r
+ VOID *OldHeap;\r
+ VOID *NewHeap;\r
+ VOID *OldStack;\r
+ VOID *NewStack;\r
+ DEBUG_AGENT_CONTEXT_POSTMEM_SEC DebugAgentContext;\r
+ BOOLEAN OldStatus;\r
+ BASE_LIBRARY_JUMP_BUFFER JumpBuffer;\r
+ \r
+ DEBUG ((EFI_D_INFO,\r
+ "TemporaryRamMigration(0x%Lx, 0x%Lx, 0x%Lx)\n",\r
+ TemporaryMemoryBase,\r
+ PermanentMemoryBase,\r
+ (UINT64)CopySize\r
+ ));\r
+ \r
+ OldHeap = (VOID*)(UINTN)TemporaryMemoryBase;\r
+ NewHeap = (VOID*)((UINTN)PermanentMemoryBase + (CopySize >> 1));\r
+ \r
+ OldStack = (VOID*)((UINTN)TemporaryMemoryBase + (CopySize >> 1));\r
+ NewStack = (VOID*)(UINTN)PermanentMemoryBase;\r
+\r
+ DebugAgentContext.HeapMigrateOffset = (UINTN)NewHeap - (UINTN)OldHeap;\r
+ DebugAgentContext.StackMigrateOffset = (UINTN)NewStack - (UINTN)OldStack;\r
+ \r
+ OldStatus = SaveAndSetDebugTimerInterrupt (FALSE);\r
+ InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, (VOID *) &DebugAgentContext, NULL);\r
+\r
+ //\r
+ // Migrate Heap\r
+ //\r
+ CopyMem (NewHeap, OldHeap, CopySize >> 1);\r
+\r
+ //\r
+ // Migrate Stack\r
+ //\r
+ CopyMem (NewStack, OldStack, CopySize >> 1);\r
+ \r
+ //\r
+ // Rebase IDT table in permanent memory\r
+ //\r
+ AsmReadIdtr (&IdtDescriptor);\r
+ IdtDescriptor.Base = IdtDescriptor.Base - (UINTN)OldStack + (UINTN)NewStack;\r
+\r
+ AsmWriteIdtr (&IdtDescriptor);\r
+\r
+ //\r
+ // Use SetJump()/LongJump() to switch to a new stack.\r
+ // \r
+ if (SetJump (&JumpBuffer) == 0) {\r
+#if defined (MDE_CPU_IA32)\r
+ JumpBuffer.Esp = JumpBuffer.Esp + DebugAgentContext.StackMigrateOffset;\r
+ JumpBuffer.Ebp = JumpBuffer.Ebp + DebugAgentContext.StackMigrateOffset;\r
+#endif \r
+#if defined (MDE_CPU_X64)\r
+ JumpBuffer.Rsp = JumpBuffer.Rsp + DebugAgentContext.StackMigrateOffset;\r
+ JumpBuffer.Rbp = JumpBuffer.Rbp + DebugAgentContext.StackMigrateOffset;\r
+#endif \r
+ LongJump (&JumpBuffer, (UINTN)-1);\r
+ }\r
+\r
+ SaveAndSetDebugTimerInterrupt (OldStatus);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r