X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=OvmfPkg%2FSec%2FSecMain.c;h=f7fec3d8c03b93d73042e480e4400be41f22ce32;hp=ece1c9b517e5bef07942bb3a74aba3de0b0b3336;hb=89796c69d9fdaa9bd13d37b6b1687df5e0104ed5;hpb=b382ede3864e17e8827dbc90c7d4f1540b94ff3f diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c index ece1c9b517..f7fec3d8c0 100644 --- a/OvmfPkg/Sec/SecMain.c +++ b/OvmfPkg/Sec/SecMain.c @@ -1,7 +1,8 @@ /** @file Main SEC phase code. Transitions to PEI. - Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -28,6 +29,7 @@ #include #include #include +#include #include @@ -128,9 +130,13 @@ FindMainFv ( Locates a section within a series of sections with the specified section type. + The Instance parameter indicates which instance of the section + type to return. (0 is first instance, 1 is second...) + @param[in] Sections The sections to search @param[in] SizeOfSections Total size of all sections @param[in] SectionType The section type to locate + @param[in] Instance The section instance number @param[out] FoundSection The FFS section if found @retval EFI_SUCCESS The file and section was found @@ -139,10 +145,11 @@ FindMainFv ( **/ EFI_STATUS -FindFfsSectionInSections ( +FindFfsSectionInstance ( IN VOID *Sections, IN UINTN SizeOfSections, IN EFI_SECTION_TYPE SectionType, + IN UINTN Instance, OUT EFI_COMMON_SECTION_HEADER **FoundSection ) { @@ -167,7 +174,6 @@ FindFfsSectionInSections ( } Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress; - DEBUG ((EFI_D_INFO, "Section->Type: 0x%x\n", Section->Type)); Size = SECTION_SIZE (Section); if (Size < sizeof (*Section)) { @@ -183,15 +189,49 @@ FindFfsSectionInSections ( // Look for the requested section type // if (Section->Type == SectionType) { - *FoundSection = Section; - return EFI_SUCCESS; + if (Instance == 0) { + *FoundSection = Section; + return EFI_SUCCESS; + } else { + Instance--; + } } - DEBUG ((EFI_D_INFO, "Section->Type (0x%x) != SectionType (0x%x)\n", Section->Type, SectionType)); } return EFI_NOT_FOUND; } +/** + Locates a section within a series of sections + with the specified section type. + + @param[in] Sections The sections to search + @param[in] SizeOfSections Total size of all sections + @param[in] SectionType The section type to locate + @param[out] FoundSection The FFS section if found + + @retval EFI_SUCCESS The file and section was found + @retval EFI_NOT_FOUND The file and section was not found + @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted + +**/ +EFI_STATUS +FindFfsSectionInSections ( + IN VOID *Sections, + IN UINTN SizeOfSections, + IN EFI_SECTION_TYPE SectionType, + OUT EFI_COMMON_SECTION_HEADER **FoundSection + ) +{ + return FindFfsSectionInstance ( + Sections, + SizeOfSections, + SectionType, + 0, + FoundSection + ); +} + /** Locates a FFS file with the specified file type and a section within that file with the specified section type. @@ -207,7 +247,6 @@ FindFfsSectionInSections ( **/ EFI_STATUS -EFIAPI FindFfsFileAndSection ( IN EFI_FIRMWARE_VOLUME_HEADER *Fv, IN EFI_FV_FILETYPE FileType, @@ -223,7 +262,7 @@ FindFfsFileAndSection ( EFI_PHYSICAL_ADDRESS EndOfFile; if (Fv->Signature != EFI_FVH_SIGNATURE) { - DEBUG ((EFI_D_INFO, "FV at %p does not have FV header signature\n", Fv)); + DEBUG ((EFI_D_ERROR, "FV at %p does not have FV header signature\n", Fv)); return EFI_VOLUME_CORRUPTED; } @@ -245,7 +284,6 @@ FindFfsFileAndSection ( if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) { return EFI_VOLUME_CORRUPTED; } - DEBUG ((EFI_D_INFO, "File->Type: 0x%x\n", File->Type)); EndOfFile = CurrentAddress + Size; if (EndOfFile > EndOfFirmwareVolume) { @@ -256,7 +294,6 @@ FindFfsFileAndSection ( // Look for the request file type // if (File->Type != FileType) { - DEBUG ((EFI_D_INFO, "File->Type (0x%x) != FileType (0x%x)\n", File->Type, FileType)); continue; } @@ -276,7 +313,7 @@ FindFfsFileAndSection ( Locates the compressed main firmware volume and decompresses it. @param[in,out] Fv On input, the firmware volume to search - On output, the decompressed main FV + On output, the decompressed BOOT/PEI FV @retval EFI_SUCCESS The file and section was found @retval EFI_NOT_FOUND The file and section was not found @@ -284,8 +321,7 @@ FindFfsFileAndSection ( **/ EFI_STATUS -EFIAPI -DecompressGuidedFv ( +DecompressMemFvs ( IN OUT EFI_FIRMWARE_VOLUME_HEADER **Fv ) { @@ -297,10 +333,13 @@ DecompressGuidedFv ( UINT32 AuthenticationStatus; VOID *OutputBuffer; VOID *ScratchBuffer; - EFI_FIRMWARE_VOLUME_IMAGE_SECTION *NewFvSection; - EFI_FIRMWARE_VOLUME_HEADER *NewFv; + EFI_COMMON_SECTION_HEADER *FvSection; + EFI_FIRMWARE_VOLUME_HEADER *PeiMemFv; + EFI_FIRMWARE_VOLUME_HEADER *DxeMemFv; + UINT32 FvHeaderSize; + UINT32 FvSectionSize; - NewFvSection = (EFI_FIRMWARE_VOLUME_IMAGE_SECTION*) NULL; + FvSection = (EFI_COMMON_SECTION_HEADER*) NULL; Status = FindFfsFileAndSection ( *Fv, @@ -324,9 +363,16 @@ DecompressGuidedFv ( return Status; } - //PcdGet32 (PcdOvmfMemFvBase), PcdGet32 (PcdOvmfMemFvSize) - OutputBuffer = (VOID*) ((UINT8*)(UINTN) PcdGet32 (PcdOvmfMemFvBase) + SIZE_1MB); + OutputBuffer = (VOID*) ((UINT8*)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase) + SIZE_1MB); ScratchBuffer = ALIGN_POINTER ((UINT8*) OutputBuffer + OutputBufferSize, SIZE_1MB); + + DEBUG ((EFI_D_VERBOSE, "%a: OutputBuffer@%p+0x%x ScratchBuffer@%p+0x%x " + "PcdOvmfDecompressionScratchEnd=0x%x\n", __FUNCTION__, OutputBuffer, + OutputBufferSize, ScratchBuffer, ScratchBufferSize, + PcdGet32 (PcdOvmfDecompressionScratchEnd))); + ASSERT ((UINTN)ScratchBuffer + ScratchBufferSize == + PcdGet32 (PcdOvmfDecompressionScratchEnd)); + Status = ExtractGuidedSectionDecode ( Section, &OutputBuffer, @@ -338,27 +384,65 @@ DecompressGuidedFv ( return Status; } - Status = FindFfsSectionInSections ( + Status = FindFfsSectionInstance ( OutputBuffer, OutputBufferSize, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, - (EFI_COMMON_SECTION_HEADER**) &NewFvSection + 0, + &FvSection ); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "Unable to find FV image in extracted data\n")); + DEBUG ((EFI_D_ERROR, "Unable to find PEI FV section\n")); return Status; } - NewFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfMemFvBase); - CopyMem (NewFv, (VOID*) (NewFvSection + 1), PcdGet32 (PcdOvmfMemFvSize)); + ASSERT (SECTION_SIZE (FvSection) == + (PcdGet32 (PcdOvmfPeiMemFvSize) + sizeof (*FvSection))); + ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE); + + PeiMemFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfPeiMemFvBase); + CopyMem (PeiMemFv, (VOID*) (FvSection + 1), PcdGet32 (PcdOvmfPeiMemFvSize)); - if (NewFv->Signature != EFI_FVH_SIGNATURE) { - DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", NewFv)); + if (PeiMemFv->Signature != EFI_FVH_SIGNATURE) { + DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", PeiMemFv)); CpuDeadLoop (); return EFI_VOLUME_CORRUPTED; } - *Fv = NewFv; + Status = FindFfsSectionInstance ( + OutputBuffer, + OutputBufferSize, + EFI_SECTION_FIRMWARE_VOLUME_IMAGE, + 1, + &FvSection + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Unable to find DXE FV section\n")); + return Status; + } + + ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE); + + if (IS_SECTION2 (FvSection)) { + FvSectionSize = SECTION2_SIZE (FvSection); + FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2); + } else { + FvSectionSize = SECTION_SIZE (FvSection); + FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER); + } + + ASSERT (FvSectionSize == (PcdGet32 (PcdOvmfDxeMemFvSize) + FvHeaderSize)); + + DxeMemFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase); + CopyMem (DxeMemFv, (VOID*) ((UINTN)FvSection + FvHeaderSize), PcdGet32 (PcdOvmfDxeMemFvSize)); + + if (DxeMemFv->Signature != EFI_FVH_SIGNATURE) { + DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", DxeMemFv)); + CpuDeadLoop (); + return EFI_VOLUME_CORRUPTED; + } + + *Fv = PeiMemFv; return EFI_SUCCESS; } @@ -374,7 +458,6 @@ DecompressGuidedFv ( **/ EFI_STATUS -EFIAPI FindPeiCoreImageBaseInFv ( IN EFI_FIRMWARE_VOLUME_HEADER *Fv, OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase @@ -406,6 +489,50 @@ FindPeiCoreImageBaseInFv ( return EFI_SUCCESS; } + +/** + Reads 8-bits of CMOS data. + + Reads the 8-bits of CMOS data at the location specified by Index. + The 8-bit read value is returned. + + @param Index The CMOS location to read. + + @return The value read. + +**/ +STATIC +UINT8 +CmosRead8 ( + IN UINTN Index + ) +{ + IoWrite8 (0x70, (UINT8) Index); + return IoRead8 (0x71); +} + + +STATIC +BOOLEAN +IsS3Resume ( + VOID + ) +{ + return (CmosRead8 (0xF) == 0xFE); +} + + +STATIC +EFI_STATUS +GetS3ResumePeiFv ( + IN OUT EFI_FIRMWARE_VOLUME_HEADER **PeiFv + ) +{ + *PeiFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfPeiMemFvBase); + return EFI_SUCCESS; +} + + /** Locates the PEI Core entry point address @@ -418,17 +545,34 @@ FindPeiCoreImageBaseInFv ( **/ VOID -EFIAPI FindPeiCoreImageBase ( IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv, OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase ) { + BOOLEAN S3Resume; + *PeiCoreImageBase = 0; - FindMainFv (BootFv); + S3Resume = IsS3Resume (); + if (S3Resume && !FeaturePcdGet (PcdSmmSmramRequire)) { + // + // A malicious runtime OS may have injected something into our previously + // decoded PEI FV, but we don't care about that unless SMM/SMRAM is required. + // + DEBUG ((EFI_D_VERBOSE, "SEC: S3 resume\n")); + GetS3ResumePeiFv (BootFv); + } else { + // + // We're either not resuming, or resuming "securely" -- we'll decompress + // both PEI FV and DXE FV from pristine flash. + // + DEBUG ((EFI_D_VERBOSE, "SEC: %a\n", + S3Resume ? "S3 resume (with PEI decompression)" : "Normal boot")); + FindMainFv (BootFv); - DecompressGuidedFv (BootFv); + DecompressMemFvs (BootFv); + } FindPeiCoreImageBaseInFv (*BootFv, PeiCoreImageBase); } @@ -438,7 +582,6 @@ FindPeiCoreImageBase ( **/ EFI_STATUS -EFIAPI FindImageBase ( IN EFI_FIRMWARE_VOLUME_HEADER *BootFirmwareVolumePtr, OUT EFI_PHYSICAL_ADDRESS *SecCoreImageBase @@ -526,12 +669,11 @@ FindImageBase ( /* Find and return Pei Core entry point. - It also find SEC and PEI Core file debug inforamtion. It will report them if + It also find SEC and PEI Core file debug information. It will report them if remote debug is enabled. **/ VOID -EFIAPI FindAndReportEntryPoints ( IN EFI_FIRMWARE_VOLUME_HEADER **BootFirmwareVolumePtr, OUT EFI_PEI_CORE_ENTRY_POINT *PeiCoreEntryPoint @@ -587,10 +729,23 @@ SecCoreStartupWithStack ( SEC_IDT_TABLE IdtTableInStack; IA32_DESCRIPTOR IdtDescriptor; UINT32 Index; + volatile UINT8 *Table; + + // + // To ensure SMM can't be compromised on S3 resume, we must force re-init of + // the BaseExtractGuidedSectionLib. Since this is before library contructors + // are called, we must use a loop rather than SetMem. + // + Table = (UINT8*)(UINTN)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress); + for (Index = 0; + Index < FixedPcdGet32 (PcdGuidedExtractHandlerTableSize); + ++Index) { + Table[Index] = 0; + } ProcessLibraryConstructorList (NULL, NULL); - DEBUG ((EFI_D_ERROR, + DEBUG ((EFI_D_INFO, "SecCoreStartupWithStack(0x%x, 0x%x)\n", (UINT32)(UINTN)BootFv, (UINT32)(UINTN)TopOfCurrentStack @@ -631,12 +786,16 @@ SecCoreStartupWithStack ( // |-------------| <-- SecCoreData.TemporaryRamBase // + ASSERT ((UINTN) (PcdGet32 (PcdOvmfSecPeiTempRamBase) + + PcdGet32 (PcdOvmfSecPeiTempRamSize)) == + (UINTN) TopOfCurrentStack); + // // Initialize SEC hand-off state // SecCoreData.DataSize = sizeof(EFI_SEC_PEI_HAND_OFF); - SecCoreData.TemporaryRamSize = SIZE_64KB; + SecCoreData.TemporaryRamSize = (UINTN) PcdGet32 (PcdOvmfSecPeiTempRamSize); SecCoreData.TemporaryRamBase = (VOID*)((UINT8 *)TopOfCurrentStack - SecCoreData.TemporaryRamSize); SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase; @@ -653,6 +812,14 @@ SecCoreStartupWithStack ( // IoWrite8 (0x21, 0xff); IoWrite8 (0xA1, 0xff); + + // + // Initialize Local APIC Timer hardware and disable Local APIC Timer + // interrupts before initializing the Debug Agent and the debug timer is + // enabled. + // + InitializeApicTimer (0, MAX_UINT32, TRUE, 5); + DisableApicTimerInterrupt (); // // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready. @@ -721,7 +888,12 @@ TemporaryRamMigration ( BOOLEAN OldStatus; BASE_LIBRARY_JUMP_BUFFER JumpBuffer; - DEBUG ((EFI_D_ERROR, "TemporaryRamMigration(0x%x, 0x%x, 0x%x)\n", (UINTN)TemporaryMemoryBase, (UINTN)PermanentMemoryBase, CopySize)); + DEBUG ((EFI_D_INFO, + "TemporaryRamMigration(0x%Lx, 0x%Lx, 0x%Lx)\n", + TemporaryMemoryBase, + PermanentMemoryBase, + (UINT64)CopySize + )); OldHeap = (VOID*)(UINTN)TemporaryMemoryBase; NewHeap = (VOID*)((UINTN)PermanentMemoryBase + (CopySize >> 1)); @@ -759,9 +931,11 @@ TemporaryRamMigration ( if (SetJump (&JumpBuffer) == 0) { #if defined (MDE_CPU_IA32) JumpBuffer.Esp = JumpBuffer.Esp + DebugAgentContext.StackMigrateOffset; + JumpBuffer.Ebp = JumpBuffer.Ebp + DebugAgentContext.StackMigrateOffset; #endif #if defined (MDE_CPU_X64) JumpBuffer.Rsp = JumpBuffer.Rsp + DebugAgentContext.StackMigrateOffset; + JumpBuffer.Rbp = JumpBuffer.Rbp + DebugAgentContext.StackMigrateOffset; #endif LongJump (&JumpBuffer, (UINTN)-1); }