From 37905818f622641cf89642c5d7584c871c27d090 Mon Sep 17 00:00:00 2001
From: Kenji Chen <kenji.chen@intel.com>
Date: Tue, 5 Nov 2019 11:01:32 +0800
Subject: [PATCH] FitGen: Add FitGen feature to support uCode Capsule Update

Add slot mode handling with header array.

Change-Id: Icee955a8cb4456ceb233e7a068fa7db733464626
Signed-off-by: Kenji Chen <kenji.chen@intel.com>
---
 Silicon/Intel/Tools/FitGen/FitGen.c | 76 +++++++++++++++++++++++++++++++++----
 1 file changed, 69 insertions(+), 7 deletions(-)

diff --git a/Silicon/Intel/Tools/FitGen/FitGen.c b/Silicon/Intel/Tools/FitGen/FitGen.c
index faf98800..94a1e58c 100644
--- a/Silicon/Intel/Tools/FitGen/FitGen.c
+++ b/Silicon/Intel/Tools/FitGen/FitGen.c
@@ -765,6 +765,7 @@ Returns:
 {
   EFI_GUID  Guid;
   INTN      Index;
+  UINTN     MicrocodeIndex;
   UINT8     *FileBuffer;
   UINT32    FileSize;
   UINT32    Type;
@@ -774,8 +775,10 @@ Returns:
   UINT32    MicrocodeBase;
   UINT32    MicrocodeSize;
   UINT8     *MicrocodeBuffer;
+  UINT8     *MicrocodeBufferEnd;
   UINT32    MicrocodeRegionOffset;
   UINT32    MicrocodeRegionSize;
+  UINT32    SlotSize;
   STATUS    Status;
   EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;
   UINTN                       FitEntryNumber;
@@ -783,6 +786,7 @@ Returns:
   BIOS_INFO_HEADER            *BiosInfo;
   BIOS_INFO_STRUCT            *BiosInfoStruct;
   UINTN                       BiosInfoIndex;
+  UINT32                      AlignmentByte;
 
   //
   // Init index
@@ -900,7 +904,22 @@ Returns:
   }
 
   //
-  // 0.5 BiosInfo
+  // 0.5 SlotSize
+  //
+  if ((Index + 1 >= argc) ||
+      ((strcmp (argv[Index], "-S") != 0) &&
+       (strcmp (argv[Index], "-s") != 0)) ) {
+    //
+    // Bypass
+    //
+    SlotSize = 0;
+  } else {
+    SlotSize = xtoi (argv[Index + 1]);
+    Index += 2;
+  }
+
+  //
+  // 0.6 BiosInfo
   //
   if ((Index + 1 >= argc) ||
       ((strcmp (argv[Index], "-I") != 0) &&
@@ -998,6 +1017,7 @@ Returns:
 
             MicrocodeFileBuffer = FLASH_TO_MEMORY (MicrocodeRegionOffset, FdBuffer, FdSize);
             MicrocodeFileSize = MicrocodeRegionSize;
+            MicrocodeBufferEnd = MicrocodeFileBuffer + MicrocodeFileSize;
             MicrocodeBase = MicrocodeRegionOffset;
 
             FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer;
@@ -1007,13 +1027,26 @@ Returns:
             } else {
               MicrocodeBuffer = MicrocodeFileBuffer;
             }
+
+            AlignmentByte = 1;
+            AlignmentByte = AlignmentByte << ((FvHeader->Attributes&0x000F0000) >> 16);
+
+            ///
+            /// Make MicrocodeBuffer address to alignment.
+            ///
+            if ((UINT32)MicrocodeBuffer % AlignmentByte != 0) {
+              MicrocodeBuffer = (UINT8 *)((UINT32)MicrocodeBuffer &~(AlignmentByte - 1));
+              MicrocodeBuffer += AlignmentByte;
+            }
+
             while ((UINT32)(MicrocodeBuffer - MicrocodeFileBuffer) < MicrocodeFileSize) {
-              if (*(UINT32 *)(MicrocodeBuffer) != 0x1) { // HeaderVersion
-                break;
-              }
-              if (*(UINT32 *)(MicrocodeBuffer + 20) != 0x1) { // LoaderVersion
-                break;
+              if (*(UINT32 *)(MicrocodeBuffer) != 0x1 ||
+                  *(UINT32 *)(MicrocodeBuffer + 20) != 0x1
+                 ) { // HeaderVersion
+                MicrocodeBuffer += 1024;
+                continue;
               }
+
               if (*(UINT32 *)(MicrocodeBuffer + 28) == 0) { // DataSize
                 MicrocodeSize = 2048;
               } else {
@@ -1036,12 +1069,41 @@ Returns:
               }
               gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE;
               gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = MicrocodeBase + ((UINT32) (UINTN) MicrocodeBuffer - (UINT32) (UINTN) MicrocodeFileBuffer);
-              gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = MicrocodeSize;
+              //
+              // No longer use.
+              //
+              //gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = MicrocodeSize;
               gFitTableContext.MicrocodeNumber++;
               gFitTableContext.FitEntryNumber++;
 
               MicrocodeBuffer += MicrocodeSize;
             }
+
+            if (SlotSize != 0) {
+              ///
+              /// Check whether each uCode is alignment with SlotSize bytes.
+              ///
+              for (MicrocodeIndex = 1; MicrocodeIndex < (INTN)gFitTableContext.MicrocodeNumber; MicrocodeIndex++) {
+                if (gFitTableContext.Microcode[MicrocodeIndex].Address - gFitTableContext.Microcode[MicrocodeIndex - 1].Address != SlotSize) {
+                  printf ("uCode must be follow SlotSize(%lu) alignment.\n", SlotSize);
+                  ASSERT (FALSE);
+                }
+              }
+
+              ///
+              /// Assume the empty space follows the uCode array.
+              ///
+              MicrocodeBuffer = (UINT8 *)(gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber - 1].Address - MicrocodeBase + MicrocodeFileBuffer);
+              MicrocodeBuffer += SlotSize;
+              while (MicrocodeBuffer + SlotSize <= MicrocodeBufferEnd) {
+                gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE;
+                gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = MicrocodeBase + ((UINT32) (UINTN) MicrocodeBuffer - (UINT32) (UINTN) MicrocodeFileBuffer);
+                gFitTableContext.MicrocodeNumber++;
+                gFitTableContext.FitEntryNumber++;
+
+                MicrocodeBuffer += SlotSize;
+              }
+            }
           }
           break;
         case FIT_TABLE_TYPE_TPM_POLICY:
-- 
2.16.2.windows.1

