/** @file\r
Main SEC phase code. Transitions to PEI.\r
\r
- Copyright (c) 2008 - 2013, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\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
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
\r
**/\r
EFI_STATUS\r
-FindFfsSectionInSections (\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
// Look for the requested section type\r
//\r
if (Section->Type == SectionType) {\r
- *FoundSection = Section;\r
- return EFI_SUCCESS;\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
\r
File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;\r
- Size = *(UINT32*) File->Size & 0xffffff;\r
+ Size = FFS_FILE_SIZE (File);\r
if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {\r
return EFI_VOLUME_CORRUPTED;\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 main FV\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
\r
**/\r
EFI_STATUS\r
-DecompressGuidedFv (\r
+DecompressMemFvs (\r
IN OUT EFI_FIRMWARE_VOLUME_HEADER **Fv\r
)\r
{\r
UINT32 AuthenticationStatus;\r
VOID *OutputBuffer;\r
VOID *ScratchBuffer;\r
- EFI_FIRMWARE_VOLUME_IMAGE_SECTION *NewFvSection;\r
- EFI_FIRMWARE_VOLUME_HEADER *NewFv;\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
- NewFvSection = (EFI_FIRMWARE_VOLUME_IMAGE_SECTION*) NULL;\r
+ FvSection = (EFI_COMMON_SECTION_HEADER*) NULL;\r
\r
Status = FindFfsFileAndSection (\r
*Fv,\r
return Status;\r
}\r
\r
- //PcdGet32 (PcdOvmfMemFvBase), PcdGet32 (PcdOvmfMemFvSize)\r
- OutputBuffer = (VOID*) ((UINT8*)(UINTN) PcdGet32 (PcdOvmfMemFvBase) + SIZE_1MB);\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
return Status;\r
}\r
\r
- Status = FindFfsSectionInSections (\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
- (EFI_COMMON_SECTION_HEADER**) &NewFvSection\r
+ 1,\r
+ &FvSection\r
);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "Unable to find FV image in extracted data\n"));\r
+ DEBUG ((EFI_D_ERROR, "Unable to find DXE FV section\n"));\r
return Status;\r
}\r
\r
- NewFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfMemFvBase);\r
- CopyMem (NewFv, (VOID*) (NewFvSection + 1), PcdGet32 (PcdOvmfMemFvSize));\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 (NewFv->Signature != EFI_FVH_SIGNATURE) {\r
- DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", NewFv));\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 = NewFv;\r
+ *Fv = PeiMemFv;\r
return EFI_SUCCESS;\r
}\r
\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
OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase\r
)\r
{\r
+ BOOLEAN S3Resume;\r
+\r
*PeiCoreImageBase = 0;\r
\r
- FindMainFv (BootFv);\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
- DecompressGuidedFv (BootFv);\r
+ DecompressMemFvs (BootFv);\r
+ }\r
\r
FindPeiCoreImageBaseInFv (*BootFv, PeiCoreImageBase);\r
}\r
}\r
\r
File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;\r
- Size = *(UINT32*) File->Size & 0xffffff;\r
+ Size = FFS_FILE_SIZE (File);\r
if (Size < sizeof (*File)) {\r
return EFI_NOT_FOUND;\r
}\r
CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL;\r
Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;\r
\r
- Size = *(UINT32*) Section->Size & 0xffffff;\r
+ Size = SECTION_SIZE (Section);\r
if (Size < sizeof (*Section)) {\r
return EFI_NOT_FOUND;\r
}\r
/*\r
Find and return Pei Core entry point.\r
\r
- It also find SEC and PEI Core file debug inforamtion. It will report them if\r
+ It also find SEC and PEI Core file debug information. It will report them if\r
remote debug is enabled.\r
\r
**/\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
//\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
BASE_LIBRARY_JUMP_BUFFER JumpBuffer;\r
\r
DEBUG ((EFI_D_INFO,\r
- "TemporaryRamMigration(0x%x, 0x%x, 0x%x)\n",\r
- (UINTN) TemporaryMemoryBase,\r
- (UINTN) PermanentMemoryBase,\r
- CopySize\r
+ "TemporaryRamMigration(0x%Lx, 0x%Lx, 0x%Lx)\n",\r
+ TemporaryMemoryBase,\r
+ PermanentMemoryBase,\r
+ (UINT64)CopySize\r
));\r
\r
OldHeap = (VOID*)(UINTN)TemporaryMemoryBase;\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