]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/GenFv/GenFvInternalLib.c
BaseTools GenFv: Report the correct spare FV image size
[mirror_edk2.git] / BaseTools / Source / C / GenFv / GenFvInternalLib.c
index 818c46407beb755c8ad59378b2cc388d69a46de6..b5ffed93a9747b2d7a08e77716f6e19dacb9fb5f 100644 (file)
@@ -4,13 +4,8 @@ This file contains the internal functions required to generate a Firmware Volume
 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
 Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>\r
 Portions Copyright (c) 2016 HP Development Company, L.P.<BR>\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
+Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -43,6 +38,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define ARM64_UNCONDITIONAL_JUMP_INSTRUCTION      0x14000000\r
 \r
 BOOLEAN mArm = FALSE;\r
+BOOLEAN mRiscV = FALSE;\r
 STATIC UINT32   MaxFfsAlignment = 0;\r
 BOOLEAN VtfFileFlag = FALSE;\r
 \r
@@ -797,6 +793,7 @@ Returns:
   FILE                                *PeMapFile;\r
   CHAR8                               Line [MAX_LINE_LEN];\r
   CHAR8                               KeyWord [MAX_LINE_LEN];\r
+  CHAR8                               KeyWord2 [MAX_LINE_LEN];\r
   CHAR8                               FunctionName [MAX_LINE_LEN];\r
   EFI_PHYSICAL_ADDRESS                FunctionAddress;\r
   UINT32                              FunctionType;\r
@@ -811,6 +808,7 @@ Returns:
   UINT32                              TextVirtualAddress;\r
   UINT32                              DataVirtualAddress;\r
   EFI_PHYSICAL_ADDRESS                LinkTimeBaseAddress;\r
+  BOOLEAN                             IsUseClang;\r
 \r
   //\r
   // Init local variable\r
@@ -938,6 +936,7 @@ Returns:
   // Output Functions information into Fv Map file\r
   //\r
   LinkTimeBaseAddress = 0;\r
+  IsUseClang = FALSE;\r
   while (fgets (Line, MAX_LINE_LEN, PeMapFile) != NULL) {\r
     //\r
     // Skip blank line\r
@@ -952,6 +951,12 @@ Returns:
     if (FunctionType == 0) {\r
       sscanf (Line, "%s", KeyWord);\r
       if (stricmp (KeyWord, "Address") == 0) {\r
+        sscanf (Line, "%s %s", KeyWord, KeyWord2);\r
+        if (stricmp (KeyWord2, "Size") == 0) {\r
+          IsUseClang = TRUE;\r
+          FunctionType = 1;\r
+          continue;\r
+        }\r
         //\r
         // function list\r
         //\r
@@ -973,11 +978,20 @@ Returns:
     // Printf Function Information\r
     //\r
     if (FunctionType == 1) {\r
-      sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);\r
-      FunctionAddress = (UINT64) TempLongAddress;\r
-      if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {\r
-        fprintf (FvMapFile, "  0x%010llx    ", (unsigned long long) (ImageBaseAddress + FunctionAddress - LinkTimeBaseAddress));\r
-        fprintf (FvMapFile, "%s\n", FunctionName);\r
+      if (IsUseClang) {\r
+        sscanf (Line, "%llx %s %s %s", &TempLongAddress, KeyWord, KeyWord2, FunctionTypeName);\r
+        FunctionAddress = (UINT64) TempLongAddress;\r
+        if (FunctionTypeName [0] == '_' ) {\r
+          fprintf (FvMapFile, "  0x%010llx    ", (unsigned long long) (ImageBaseAddress + FunctionAddress - LinkTimeBaseAddress));\r
+          fprintf (FvMapFile, "%s\n", FunctionTypeName);\r
+        }\r
+      } else {\r
+        sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);\r
+        FunctionAddress = (UINT64) TempLongAddress;\r
+        if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {\r
+          fprintf (FvMapFile, "  0x%010llx    ", (unsigned long long) (ImageBaseAddress + FunctionAddress - LinkTimeBaseAddress));\r
+          fprintf (FvMapFile, "%s\n", FunctionName);\r
+        }\r
       }\r
     } else if (FunctionType == 2) {\r
       sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);\r
@@ -2279,6 +2293,104 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
+EFI_STATUS\r
+UpdateRiscvResetVectorIfNeeded (\r
+  MEMORY_FILE            *FvImage,\r
+  FV_INFO                *FvInfo\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  This parses the FV looking for SEC and patches that address into the\r
+  beginning of the FV header.\r
+\r
+  For RISC-V ISA, the reset vector is at 0xfff~ff00h or 200h\r
+\r
+Arguments:\r
+  FvImage       Memory file for the FV memory image/\r
+  FvInfo        Information read from INF file.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS             Function Completed successfully.\r
+  EFI_ABORTED             Error encountered.\r
+  EFI_INVALID_PARAMETER   A required parameter was NULL.\r
+  EFI_NOT_FOUND           PEI Core file not found.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT16                    MachineType;\r
+  EFI_FILE_SECTION_POINTER  SecPe32;\r
+  EFI_PHYSICAL_ADDRESS      SecCoreEntryAddress;\r
+\r
+  UINT32 bSecCore;\r
+  UINT32 tmp;\r
+\r
+\r
+  //\r
+  // Verify input parameters\r
+  //\r
+  if (FvImage == NULL || FvInfo == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Initialize FV library\r
+  //\r
+  InitializeFvLib (FvImage->FileImage, FvInfo->Size);\r
+\r
+  //\r
+  // Find the Sec Core\r
+  //\r
+  Status = FindCorePeSection(FvImage->FileImage, FvInfo->Size, EFI_FV_FILETYPE_SECURITY_CORE, &SecPe32);\r
+  if(EFI_ERROR(Status)) {\r
+    printf("skip because Secutiry Core not found\n");\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  DebugMsg (NULL, 0, 9, "Update SEC core in FV Header", NULL);\r
+\r
+  Status = GetCoreMachineType(SecPe32, &MachineType);\r
+  if(EFI_ERROR(Status)) {\r
+    Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 machine type for SEC core.");\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  if (MachineType != EFI_IMAGE_MACHINE_RISCV64) {\r
+    Error(NULL, 0, 3000, "Invalid", "Could not update SEC core because Machine type is not RiscV.");\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  Status = GetCoreEntryPointAddress(FvImage->FileImage, FvInfo, SecPe32, &SecCoreEntryAddress);\r
+  if(EFI_ERROR(Status)) {\r
+    Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 entry point address for SEC Core.");\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  VerboseMsg("SecCore entry point Address = 0x%llX", (unsigned long long) SecCoreEntryAddress);\r
+  VerboseMsg("BaseAddress = 0x%llX", (unsigned long long) FvInfo->BaseAddress);\r
+  bSecCore = (UINT32)(SecCoreEntryAddress - FvInfo->BaseAddress);\r
+  VerboseMsg("offset = 0x%llX", bSecCore);\r
+\r
+  if(bSecCore > 0x0fffff) {\r
+    Error(NULL, 0, 3000, "Invalid", "SEC Entry point must be within 1MB of start of the FV");\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  tmp = bSecCore;\r
+  bSecCore = 0;\r
+  //J-type\r
+  bSecCore  = (tmp&0x100000)<<11; //imm[20]    at bit[31]\r
+  bSecCore |= (tmp&0x0007FE)<<20; //imm[10:1]  at bit[30:21]\r
+  bSecCore |= (tmp&0x000800)<<9;  //imm[11]    at bit[20]\r
+  bSecCore |= (tmp&0x0FF000);     //imm[19:12] at bit[19:12]\r
+  bSecCore |= 0x6F; //JAL opcode\r
+\r
+  memcpy(FvImage->FileImage, &bSecCore, sizeof(bSecCore));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 EFI_STATUS\r
 GetPe32Info (\r
   IN UINT8                  *Pe32,\r
@@ -2371,7 +2483,8 @@ Returns:
   // Verify machine type is supported\r
   //\r
   if ((*MachineType != EFI_IMAGE_MACHINE_IA32) &&  (*MachineType != EFI_IMAGE_MACHINE_X64) && (*MachineType != EFI_IMAGE_MACHINE_EBC) &&\r
-      (*MachineType != EFI_IMAGE_MACHINE_ARMT) && (*MachineType != EFI_IMAGE_MACHINE_AARCH64)) {\r
+      (*MachineType != EFI_IMAGE_MACHINE_ARMT) && (*MachineType != EFI_IMAGE_MACHINE_AARCH64) &&\r
+      (*MachineType != EFI_IMAGE_MACHINE_RISCV64)) {\r
     Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");\r
     return EFI_UNSUPPORTED;\r
   }\r
@@ -2814,7 +2927,8 @@ Returns:
       Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add pad file between the last file and the VTF file.");\r
       goto Finish;\r
     }\r
-    if (!mArm) {\r
+\r
+    if (!mArm && !mRiscV) {\r
       //\r
       // Update reset vector (SALE_ENTRY for IPF)\r
       // Now for IA32 and IA64 platform, the fv which has bsf file must have the\r
@@ -2849,6 +2963,22 @@ Returns:
     FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
   }\r
 \r
+  if (mRiscV) {\r
+     //\r
+     // Update RISCV reset vector.\r
+     //\r
+     Status = UpdateRiscvResetVectorIfNeeded (&FvImageMemoryFile, &mFvDataInfo);\r
+     if (EFI_ERROR (Status)) {\r
+       Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector for RISC-V.");\r
+       goto Finish;\r
+    }\r
+    //\r
+    // Update Checksum for FvHeader\r
+    //\r
+    FvHeader->Checksum = 0;\r
+    FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
+  }\r
+\r
   //\r
   // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV\r
   //\r
@@ -3010,6 +3140,7 @@ Returns:
 --*/\r
 {\r
   UINTN               CurrentOffset;\r
+  UINTN               OrigOffset;\r
   UINTN               Index;\r
   FILE                *fpin;\r
   UINTN               FfsFileSize;\r
@@ -3018,8 +3149,10 @@ Returns:
   UINT32              FfsHeaderSize;\r
   EFI_FFS_FILE_HEADER FfsHeader;\r
   UINTN               VtfFileSize;\r
+  UINTN               MaxPadFileSize;\r
 \r
   FvExtendHeaderSize = 0;\r
+  MaxPadFileSize = 0;\r
   VtfFileSize = 0;\r
   fpin  = NULL;\r
   Index = 0;\r
@@ -3128,8 +3261,12 @@ Returns:
         //\r
         // Only EFI_FFS_FILE_HEADER is needed for a pad section.\r
         //\r
+        OrigOffset    = CurrentOffset;\r
         CurrentOffset = (CurrentOffset + FfsHeaderSize + sizeof(EFI_FFS_FILE_HEADER) + FfsAlignment - 1) & ~(FfsAlignment - 1);\r
         CurrentOffset -= FfsHeaderSize;\r
+        if ((CurrentOffset - OrigOffset) > MaxPadFileSize) {\r
+          MaxPadFileSize = CurrentOffset - OrigOffset;\r
+        }\r
       }\r
     }\r
 \r
@@ -3173,6 +3310,12 @@ Returns:
   //\r
   mFvTotalSize = FvInfoPtr->Size;\r
   mFvTakenSize = CurrentOffset;\r
+  if ((mFvTakenSize == mFvTotalSize) && (MaxPadFileSize > 0)) {\r
+    //\r
+    // This FV means TOP FFS has been taken. Then, check whether there is padding data for use.\r
+    //\r
+    mFvTakenSize = mFvTakenSize - MaxPadFileSize;\r
+  }\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -3436,6 +3579,10 @@ Returns:
       mArm = TRUE;\r
     }\r
 \r
+    if (ImageContext.Machine == EFI_IMAGE_MACHINE_RISCV64) {\r
+      mRiscV = TRUE;\r
+    }\r
+\r
     //\r
     // Keep Image Context for PE image in FV\r
     //\r
@@ -3589,7 +3736,7 @@ Returns:
     ImageContext.DestinationAddress = NewPe32BaseAddress;\r
     Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
     if (EFI_ERROR (Status)) {\r
-      Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);\r
+      Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s Status=%d", FileName, Status);\r
       free ((VOID *) MemoryImagePointer);\r
       return Status;\r
     }\r