]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Sec/FindPeiCore.c
OVMF: Update OVMF FD/FV build to minimize ROM size
[mirror_edk2.git] / OvmfPkg / Sec / FindPeiCore.c
index 7d13ebb4bcb41645796d0851fdafcc9149e0d467..01cd70f5baf0dab6d3aa2b0c6ba5f616b36e8e62 100644 (file)
@@ -1,7 +1,7 @@
 /** @file
   Locate the entry point for the PEI Core
 
-  Copyright (c) 2008 - 2009, Intel Corporation
+  Copyright (c) 2008 - 2010, 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
 
 #include <PiPei.h>
 #include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/PcdLib.h>
 #include <Library/PeCoffGetEntryPointLib.h>
 
 #include "SecMain.h"
 
 
-VOID
+/**
+  Locates the main boot firmware volume.
+
+  @param[in,out]  BootFv  On input, the base of the BootFv
+                          On output, the decompressed main firmware volume
+
+  @retval EFI_SUCCESS    The main firmware volume was located and decompressed
+  @retval EFI_NOT_FOUND  The main firmware volume was not found
+
+**/
+EFI_STATUS
+FindMainFv (
+  IN OUT  EFI_FIRMWARE_VOLUME_HEADER   **BootFv
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER  *Fv;
+  UINTN                       Distance;
+  BOOLEAN                     Found;
+
+  ASSERT (((UINTN) *BootFv & EFI_PAGE_MASK) == 0);
+
+  Found = FALSE;
+  Fv = *BootFv;
+  Distance = (UINTN) (*BootFv)->FvLength;
+  do {
+    Fv = (EFI_FIRMWARE_VOLUME_HEADER*) ((UINT8*) Fv - EFI_PAGE_SIZE);
+    Distance += EFI_PAGE_SIZE;
+    if (Distance > SIZE_32MB) {
+      return EFI_NOT_FOUND;
+    }
+
+    if (Fv->Signature != EFI_FVH_SIGNATURE) {
+      continue;
+    }
+
+    if ((UINTN) Fv->FvLength > Distance) {
+      continue;
+    }
+
+    *BootFv = Fv;
+    return EFI_SUCCESS;
+
+  } while (TRUE);
+}
+
+
+/**
+  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
+  )
+{
+  EFI_PHYSICAL_ADDRESS        CurrentAddress;
+  UINT32                      Size;
+  EFI_PHYSICAL_ADDRESS        EndOfSections;
+  EFI_COMMON_SECTION_HEADER   *Section;
+  EFI_PHYSICAL_ADDRESS        EndOfSection;
+
+  //
+  // Loop through the FFS file sections within the PEI Core FFS file
+  //
+  EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) Sections;
+  EndOfSections = EndOfSection + SizeOfSections;
+  for (;;) {
+    if (EndOfSection == EndOfSections) {
+      break;
+    }
+    CurrentAddress = (EndOfSection + 3) & ~(3ULL);
+    if (CurrentAddress >= EndOfSections) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    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)) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    EndOfSection = CurrentAddress + Size;
+    if (EndOfSection > EndOfSections) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    //
+    // Look for the requested section type
+    //
+    if (Section->Type == SectionType) {
+      *FoundSection = Section;
+      return EFI_SUCCESS;
+    }
+    DEBUG ((EFI_D_INFO, "Section->Type (0x%x) != SectionType (0x%x)\n", Section->Type, SectionType));
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+
+/**
+  Locates a FFS file with the specified file type and a section
+  within that file with the specified section type.
+
+  @param[in]   Fv            The firmware volume to search
+  @param[in]   FileType      The file type to locate
+  @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
 EFIAPI
-FindPeiCoreEntryPoint (
-  IN  EFI_FIRMWARE_VOLUME_HEADER       *BootFirmwareVolumePtr,
-  OUT VOID                             **PeiCoreEntryPoint
+FindFfsFileAndSection (
+  IN  EFI_FIRMWARE_VOLUME_HEADER       *Fv,
+  IN  EFI_FV_FILETYPE                  FileType,
+  IN  EFI_SECTION_TYPE                 SectionType,
+  OUT EFI_COMMON_SECTION_HEADER        **FoundSection
   )
 {
   EFI_STATUS                  Status;
@@ -33,71 +168,219 @@ FindPeiCoreEntryPoint (
   EFI_FFS_FILE_HEADER         *File;
   UINT32                      Size;
   EFI_PHYSICAL_ADDRESS        EndOfFile;
-  EFI_COMMON_SECTION_HEADER   *Section;
-  EFI_PHYSICAL_ADDRESS        EndOfSection;
 
-  *PeiCoreEntryPoint = NULL;
+  if (Fv->Signature != EFI_FVH_SIGNATURE) {
+    DEBUG ((EFI_D_INFO, "FV at %p does not have FV header signature\n", Fv));
+    return EFI_VOLUME_CORRUPTED;
+  }
 
-  CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) BootFirmwareVolumePtr;
-  EndOfFirmwareVolume = CurrentAddress + BootFirmwareVolumePtr->FvLength;
+  CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Fv;
+  EndOfFirmwareVolume = CurrentAddress + Fv->FvLength;
 
   //
   // Loop through the FFS files in the Boot Firmware Volume
   //
-  for (EndOfFile = CurrentAddress + BootFirmwareVolumePtr->HeaderLength; ; ) {
+  for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {
 
-    CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;
+    CurrentAddress = (EndOfFile + 7) & ~(7ULL);
     if (CurrentAddress > EndOfFirmwareVolume) {
-      return;
+      return EFI_VOLUME_CORRUPTED;
     }
 
     File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
     Size = *(UINT32*) File->Size & 0xffffff;
-    if (Size < (sizeof (*File) + sizeof (*Section))) {
-      return;
+    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) {
-      return;
+      return EFI_VOLUME_CORRUPTED;
     }
 
     //
-    // Look for PEI Core files
+    // Look for the request file type
     //
-    if (File->Type != EFI_FV_FILETYPE_PEI_CORE) {
+    if (File->Type != FileType) {
+      DEBUG ((EFI_D_INFO, "File->Type (0x%x) != FileType (0x%x)\n", File->Type, FileType));
       continue;
     }
 
-    //
-    // Loop through the FFS file sections within the PEI Core FFS file
-    //
-    EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) (File + 1);
-    for (;;) {
-      CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL;
-      Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
-
-      Size = *(UINT32*) Section->Size & 0xffffff;
-      if (Size < sizeof (*Section)) {
-        return;
-      }
-
-      EndOfSection = CurrentAddress + Size;
-      if (EndOfSection > EndOfFile) {
-        return;
-      }
-
-      //
-      // Look for executable sections
-      //
-      if (Section->Type == EFI_SECTION_PE32) {
-        Status = PeCoffLoaderGetEntryPoint ((VOID*) (Section + 1), PeiCoreEntryPoint);
-        if (!EFI_ERROR (Status)) {
-          return;
-        }
-      }
+    Status = FindFfsSectionInSections (
+               (VOID*) (File + 1),
+               (UINTN) EndOfFile - (UINTN) (File + 1),
+               SectionType,
+               FoundSection
+               );
+    if (!EFI_ERROR (Status) || (Status == EFI_VOLUME_CORRUPTED)) {
+      return Status;
     }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+
+/**
+  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
+
+  @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
+EFIAPI
+DecompressGuidedFv (
+  IN OUT EFI_FIRMWARE_VOLUME_HEADER       **Fv
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_GUID_DEFINED_SECTION          *Section;
+  UINT32                            OutputBufferSize;
+  UINT32                            ScratchBufferSize;
+  UINT16                            SectionAttribute;
+  UINT32                            AuthenticationStatus;
+  VOID                              *OutputBuffer;
+  VOID                              *ScratchBuffer;
+  EFI_FIRMWARE_VOLUME_IMAGE_SECTION *NewFvSection;
+  EFI_FIRMWARE_VOLUME_HEADER        *NewFv;
 
+  NewFvSection = (EFI_FIRMWARE_VOLUME_IMAGE_SECTION*) NULL;
+
+  Status = FindFfsFileAndSection (
+             *Fv,
+             EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
+             EFI_SECTION_GUID_DEFINED,
+             (EFI_COMMON_SECTION_HEADER**) &Section
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Unable to find GUID defined section\n"));
+    return Status;
+  }
+
+  Status = ExtractGuidedSectionGetInfo (
+             Section,
+             &OutputBufferSize,
+             &ScratchBufferSize,
+             &SectionAttribute
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Unable to GetInfo for GUIDed section\n"));
+    return Status;
+  }
+
+  //PcdGet32 (PcdOvmfMemFvBase), PcdGet32 (PcdOvmfMemFvSize)
+  OutputBuffer = (VOID*) ((UINT8*)(UINTN) PcdGet32 (PcdOvmfMemFvBase) + SIZE_1MB);
+  ScratchBuffer = ALIGN_POINTER ((UINT8*) OutputBuffer + OutputBufferSize, SIZE_1MB);
+  Status = ExtractGuidedSectionDecode (
+             Section,
+             &OutputBuffer,
+             ScratchBuffer,
+             &AuthenticationStatus
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Error during GUID section decode\n"));
+    return Status;
+  }
+
+  Status = FindFfsSectionInSections (
+             OutputBuffer,
+             OutputBufferSize,
+             EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
+             (EFI_COMMON_SECTION_HEADER**) &NewFvSection
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Unable to find FV image in extracted data\n"));
+    return Status;
   }
+
+  NewFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfMemFvBase);
+  CopyMem (NewFv, (VOID*) (NewFvSection + 1), PcdGet32 (PcdOvmfMemFvSize));
+
+  if (NewFv->Signature != EFI_FVH_SIGNATURE) {
+    DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", NewFv));
+    CpuDeadLoop ();
+    return EFI_VOLUME_CORRUPTED;
+  }
+
+  *Fv = NewFv;
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Locates the PEI Core entry point address
+
+  @param[in]  Fv                 The firmware volume to search
+  @param[out] PeiCoreEntryPoint  The entry point of the PEI Core image
+
+  @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
+EFIAPI
+FindPeiCoreEntryPointInFv (
+  IN  EFI_FIRMWARE_VOLUME_HEADER       *Fv,
+  OUT VOID                             **PeiCoreEntryPoint
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_COMMON_SECTION_HEADER   *Section;
+
+  Status = FindFfsFileAndSection (
+             Fv,
+             EFI_FV_FILETYPE_PEI_CORE,
+             EFI_SECTION_PE32,
+             &Section
+             );
+  if (EFI_ERROR (Status)) {
+    Status = FindFfsFileAndSection (
+               Fv,
+               EFI_FV_FILETYPE_PEI_CORE,
+               EFI_SECTION_TE,
+               &Section
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "Unable to find PEI Core image\n"));
+      return Status;
+    }
+  }
+
+  return PeCoffLoaderGetEntryPoint ((VOID*) (Section + 1), PeiCoreEntryPoint);
+}
+
+
+/**
+  Locates the PEI Core entry point address
+
+  @param[in,out]  Fv                 The firmware volume to search
+  @param[out]     PeiCoreEntryPoint  The entry point of the PEI Core image
+
+  @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
+
+**/
+VOID
+EFIAPI
+FindPeiCoreEntryPoint (
+  IN OUT  EFI_FIRMWARE_VOLUME_HEADER       **BootFv,
+     OUT  VOID                             **PeiCoreEntryPoint
+  )
+{
+  *PeiCoreEntryPoint = NULL;
+
+  FindMainFv (BootFv);
+
+  DecompressGuidedFv (BootFv);
+
+  FindPeiCoreEntryPointInFv (*BootFv, PeiCoreEntryPoint);
 }