Home | History | Annotate | Download | only in CapsulePei
      1 /** @file
      2   Capsule update PEIM for UEFI2.0
      3 
      4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      5 
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions
      8 of the BSD License which accompanies this distribution.  The
      9 full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "Capsule.h"
     18 
     19 #ifdef MDE_CPU_IA32
     20 //
     21 // Global Descriptor Table (GDT)
     22 //
     23 GLOBAL_REMOVE_IF_UNREFERENCED IA32_SEGMENT_DESCRIPTOR mGdtEntries[] = {
     24 /* selector { Global Segment Descriptor                              } */
     25 /* 0x00 */  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}}, //null descriptor
     26 /* 0x08 */  {{0xffff, 0,  0,  0x3,  1,  0,  1,  0xf,  0,  0, 1,  1,  0}}, //linear data segment descriptor
     27 /* 0x10 */  {{0xffff, 0,  0,  0xf,  1,  0,  1,  0xf,  0,  0, 1,  1,  0}}, //linear code segment descriptor
     28 /* 0x18 */  {{0xffff, 0,  0,  0x3,  1,  0,  1,  0xf,  0,  0, 1,  1,  0}}, //system data segment descriptor
     29 /* 0x20 */  {{0xffff, 0,  0,  0xb,  1,  0,  1,  0xf,  0,  0, 1,  1,  0}}, //system code segment descriptor
     30 /* 0x28 */  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}}, //spare segment descriptor
     31 /* 0x30 */  {{0xffff, 0,  0,  0x3,  1,  0,  1,  0xf,  0,  0, 1,  1,  0}}, //system data segment descriptor
     32 /* 0x38 */  {{0xffff, 0,  0,  0xb,  1,  0,  1,  0xf,  0,  1, 0,  1,  0}}, //system code segment descriptor
     33 /* 0x40 */  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}}, //spare segment descriptor
     34 };
     35 
     36 //
     37 // IA32 Gdt register
     38 //
     39 GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR mGdt = {
     40   sizeof (mGdtEntries) - 1,
     41   (UINTN) mGdtEntries
     42   };
     43 
     44 /**
     45   The function will check if 1G page is supported.
     46 
     47   @retval TRUE   1G page is supported.
     48   @retval FALSE  1G page is not supported.
     49 
     50 **/
     51 BOOLEAN
     52 IsPage1GSupport (
     53   VOID
     54   )
     55 {
     56   UINT32                                        RegEax;
     57   UINT32                                        RegEdx;
     58   BOOLEAN                                       Page1GSupport;
     59 
     60   Page1GSupport = FALSE;
     61   if (PcdGetBool(PcdUse1GPageTable)) {
     62     AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
     63     if (RegEax >= 0x80000001) {
     64       AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
     65       if ((RegEdx & BIT26) != 0) {
     66         Page1GSupport = TRUE;
     67       }
     68     }
     69   }
     70 
     71   return Page1GSupport;
     72 }
     73 
     74 /**
     75   Calculate the total size of page table.
     76 
     77   @param[in] Page1GSupport      1G page support or not.
     78 
     79   @return The size of page table.
     80 
     81 **/
     82 UINTN
     83 CalculatePageTableSize (
     84   IN BOOLEAN                                    Page1GSupport
     85   )
     86 {
     87   UINTN                                         ExtraPageTablePages;
     88   UINTN                                         TotalPagesNum;
     89   UINT8                                         PhysicalAddressBits;
     90   UINT32                                        NumberOfPml4EntriesNeeded;
     91   UINT32                                        NumberOfPdpEntriesNeeded;
     92 
     93   //
     94   // Create 4G page table by default,
     95   // and let PF handler to handle > 4G request.
     96   //
     97   PhysicalAddressBits = 32;
     98   ExtraPageTablePages = EXTRA_PAGE_TABLE_PAGES;
     99 
    100   //
    101   // Calculate the table entries needed.
    102   //
    103   if (PhysicalAddressBits <= 39 ) {
    104     NumberOfPml4EntriesNeeded = 1;
    105     NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
    106   } else {
    107     NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
    108     NumberOfPdpEntriesNeeded = 512;
    109   }
    110 
    111   if (!Page1GSupport) {
    112     TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;
    113   } else {
    114     TotalPagesNum = NumberOfPml4EntriesNeeded + 1;
    115   }
    116   TotalPagesNum += ExtraPageTablePages;
    117 
    118   return EFI_PAGES_TO_SIZE (TotalPagesNum);
    119 }
    120 
    121 /**
    122   Allocates and fills in the Page Directory and Page Table Entries to
    123   establish a 4G page table.
    124 
    125   @param[in] PageTablesAddress  The base address of page table.
    126   @param[in] Page1GSupport      1G page support or not.
    127 
    128 **/
    129 VOID
    130 Create4GPageTables (
    131   IN EFI_PHYSICAL_ADDRESS   PageTablesAddress,
    132   IN BOOLEAN                Page1GSupport
    133   )
    134 {
    135   UINT8                                         PhysicalAddressBits;
    136   EFI_PHYSICAL_ADDRESS                          PageAddress;
    137   UINTN                                         IndexOfPml4Entries;
    138   UINTN                                         IndexOfPdpEntries;
    139   UINTN                                         IndexOfPageDirectoryEntries;
    140   UINT32                                        NumberOfPml4EntriesNeeded;
    141   UINT32                                        NumberOfPdpEntriesNeeded;
    142   PAGE_MAP_AND_DIRECTORY_POINTER                *PageMapLevel4Entry;
    143   PAGE_MAP_AND_DIRECTORY_POINTER                *PageMap;
    144   PAGE_MAP_AND_DIRECTORY_POINTER                *PageDirectoryPointerEntry;
    145   PAGE_TABLE_ENTRY                              *PageDirectoryEntry;
    146   UINTN                                         BigPageAddress;
    147   PAGE_TABLE_1G_ENTRY                           *PageDirectory1GEntry;
    148 
    149   //
    150   // Create 4G page table by default,
    151   // and let PF handler to handle > 4G request.
    152   //
    153   PhysicalAddressBits = 32;
    154 
    155   //
    156   // Calculate the table entries needed.
    157   //
    158   if (PhysicalAddressBits <= 39 ) {
    159     NumberOfPml4EntriesNeeded = 1;
    160     NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
    161   } else {
    162     NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
    163     NumberOfPdpEntriesNeeded = 512;
    164   }
    165 
    166   //
    167   // Pre-allocate big pages to avoid later allocations.
    168   //
    169   BigPageAddress = (UINTN) PageTablesAddress;
    170 
    171   //
    172   // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
    173   //
    174   PageMap         = (VOID *) BigPageAddress;
    175   BigPageAddress += SIZE_4KB;
    176 
    177   PageMapLevel4Entry = PageMap;
    178   PageAddress        = 0;
    179   for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {
    180     //
    181     // Each PML4 entry points to a page of Page Directory Pointer entires.
    182     // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.
    183     //
    184     PageDirectoryPointerEntry = (VOID *) BigPageAddress;
    185     BigPageAddress += SIZE_4KB;
    186 
    187     //
    188     // Make a PML4 Entry
    189     //
    190     PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry;
    191     PageMapLevel4Entry->Bits.ReadWrite = 1;
    192     PageMapLevel4Entry->Bits.Present = 1;
    193 
    194     if (Page1GSupport) {
    195       PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
    196 
    197       for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
    198         //
    199         // Fill in the Page Directory entries
    200         //
    201         PageDirectory1GEntry->Uint64 = (UINT64)PageAddress;
    202         PageDirectory1GEntry->Bits.ReadWrite = 1;
    203         PageDirectory1GEntry->Bits.Present = 1;
    204         PageDirectory1GEntry->Bits.MustBe1 = 1;
    205       }
    206     } else {
    207       for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
    208         //
    209         // Each Directory Pointer entries points to a page of Page Directory entires.
    210         // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
    211         //
    212         PageDirectoryEntry = (VOID *) BigPageAddress;
    213         BigPageAddress += SIZE_4KB;
    214 
    215         //
    216         // Fill in a Page Directory Pointer Entries
    217         //
    218         PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry;
    219         PageDirectoryPointerEntry->Bits.ReadWrite = 1;
    220         PageDirectoryPointerEntry->Bits.Present = 1;
    221 
    222         for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
    223           //
    224           // Fill in the Page Directory entries
    225           //
    226           PageDirectoryEntry->Uint64 = (UINT64)PageAddress;
    227           PageDirectoryEntry->Bits.ReadWrite = 1;
    228           PageDirectoryEntry->Bits.Present = 1;
    229           PageDirectoryEntry->Bits.MustBe1 = 1;
    230         }
    231       }
    232 
    233       for (; IndexOfPdpEntries < 512; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
    234         ZeroMem (
    235           PageDirectoryPointerEntry,
    236           sizeof(PAGE_MAP_AND_DIRECTORY_POINTER)
    237           );
    238       }
    239     }
    240   }
    241 
    242   //
    243   // For the PML4 entries we are not using fill in a null entry.
    244   //
    245   for (; IndexOfPml4Entries < 512; IndexOfPml4Entries++, PageMapLevel4Entry++) {
    246     ZeroMem (
    247       PageMapLevel4Entry,
    248       sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
    249       );
    250   }
    251 }
    252 
    253 /**
    254   Return function from long mode to 32-bit mode.
    255 
    256   @param  EntrypointContext  Context for mode switching
    257   @param  ReturnContext      Context for mode switching
    258 
    259 **/
    260 VOID
    261 ReturnFunction (
    262   SWITCH_32_TO_64_CONTEXT  *EntrypointContext,
    263   SWITCH_64_TO_32_CONTEXT  *ReturnContext
    264   )
    265 {
    266   //
    267   // Restore original GDT
    268   //
    269   AsmWriteGdtr (&ReturnContext->Gdtr);
    270 
    271   //
    272   // return to original caller
    273   //
    274   LongJump ((BASE_LIBRARY_JUMP_BUFFER  *)(UINTN)EntrypointContext->JumpBuffer, 1);
    275 
    276   //
    277   // never be here
    278   //
    279   ASSERT (FALSE);
    280 }
    281 
    282 /**
    283   Thunk function from 32-bit protection mode to long mode.
    284 
    285   @param  PageTableAddress  Page table base address
    286   @param  Context           Context for mode switching
    287   @param  ReturnContext     Context for mode switching
    288 
    289   @retval EFI_SUCCESS  Function successfully executed.
    290 
    291 **/
    292 EFI_STATUS
    293 Thunk32To64 (
    294   EFI_PHYSICAL_ADDRESS          PageTableAddress,
    295   SWITCH_32_TO_64_CONTEXT       *Context,
    296   SWITCH_64_TO_32_CONTEXT       *ReturnContext
    297   )
    298 {
    299   UINTN                       SetJumpFlag;
    300   EFI_STATUS                  Status;
    301 
    302   //
    303   // Save return address, LongJump will return here then
    304   //
    305   SetJumpFlag = SetJump ((BASE_LIBRARY_JUMP_BUFFER  *) (UINTN) Context->JumpBuffer);
    306 
    307   if (SetJumpFlag == 0) {
    308 
    309     //
    310     // Build 4G Page Tables.
    311     //
    312     Create4GPageTables (PageTableAddress, Context->Page1GSupport);
    313 
    314     //
    315     // Create 64-bit GDT
    316     //
    317     AsmWriteGdtr (&mGdt);
    318 
    319     //
    320     // Write CR3
    321     //
    322     AsmWriteCr3 ((UINTN) PageTableAddress);
    323 
    324     //
    325     // Disable interrupt of Debug timer, since the IDT table cannot work in long mode
    326     //
    327     SaveAndSetDebugTimerInterrupt (FALSE);
    328     //
    329     // Transfer to long mode
    330     //
    331     AsmEnablePaging64 (
    332        0x38,
    333       (UINT64) Context->EntryPoint,
    334       (UINT64)(UINTN) Context,
    335       (UINT64)(UINTN) ReturnContext,
    336       Context->StackBufferBase + Context->StackBufferLength
    337       );
    338   }
    339 
    340   //
    341   // Convert to 32-bit Status and return
    342   //
    343   Status = EFI_SUCCESS;
    344   if ((UINTN) ReturnContext->ReturnStatus != 0) {
    345     Status = ENCODE_ERROR ((UINTN) ReturnContext->ReturnStatus);
    346   }
    347 
    348   return Status;
    349 }
    350 
    351 /**
    352   If in 32 bit protection mode, and coalesce image is of X64, switch to long mode.
    353 
    354   @param  LongModeBuffer            The context of long mode.
    355   @param  CoalesceEntry             Entry of coalesce image.
    356   @param  BlockListAddr             Address of block list.
    357   @param  MemoryBase                Base of memory range.
    358   @param  MemorySize                Size of memory range.
    359 
    360   @retval EFI_SUCCESS               Successfully switched to long mode and execute coalesce.
    361   @retval Others                    Failed to execute coalesce in long mode.
    362 
    363 **/
    364 EFI_STATUS
    365 ModeSwitch (
    366   IN EFI_CAPSULE_LONG_MODE_BUFFER   *LongModeBuffer,
    367   IN COALESCE_ENTRY                 CoalesceEntry,
    368   IN EFI_PHYSICAL_ADDRESS           BlockListAddr,
    369   IN OUT VOID                       **MemoryBase,
    370   IN OUT UINTN                      *MemorySize
    371   )
    372 {
    373   EFI_STATUS                           Status;
    374   EFI_PHYSICAL_ADDRESS                 MemoryBase64;
    375   UINT64                               MemorySize64;
    376   EFI_PHYSICAL_ADDRESS                 MemoryEnd64;
    377   SWITCH_32_TO_64_CONTEXT              Context;
    378   SWITCH_64_TO_32_CONTEXT              ReturnContext;
    379   BASE_LIBRARY_JUMP_BUFFER             JumpBuffer;
    380   EFI_PHYSICAL_ADDRESS                 ReservedRangeBase;
    381   EFI_PHYSICAL_ADDRESS                 ReservedRangeEnd;
    382   BOOLEAN                              Page1GSupport;
    383 
    384   ZeroMem (&Context, sizeof (SWITCH_32_TO_64_CONTEXT));
    385   ZeroMem (&ReturnContext, sizeof (SWITCH_64_TO_32_CONTEXT));
    386 
    387   MemoryBase64  = (UINT64) (UINTN) *MemoryBase;
    388   MemorySize64  = (UINT64) (UINTN) *MemorySize;
    389   MemoryEnd64   = MemoryBase64 + MemorySize64;
    390 
    391   Page1GSupport = IsPage1GSupport ();
    392 
    393   //
    394   // Merge memory range reserved for stack and page table
    395   //
    396   if (LongModeBuffer->StackBaseAddress < LongModeBuffer->PageTableAddress) {
    397     ReservedRangeBase = LongModeBuffer->StackBaseAddress;
    398     ReservedRangeEnd  = LongModeBuffer->PageTableAddress + CalculatePageTableSize (Page1GSupport);
    399   } else {
    400     ReservedRangeBase = LongModeBuffer->PageTableAddress;
    401     ReservedRangeEnd  = LongModeBuffer->StackBaseAddress + LongModeBuffer->StackSize;
    402   }
    403 
    404   //
    405   // Check if memory range reserved is overlap with MemoryBase ~ MemoryBase + MemorySize.
    406   // If they are overlapped, get a larger range to process capsule data.
    407   //
    408   if (ReservedRangeBase <= MemoryBase64) {
    409     if (ReservedRangeEnd < MemoryEnd64) {
    410       MemoryBase64 = ReservedRangeEnd;
    411     } else {
    412       DEBUG ((EFI_D_ERROR, "Memory is not enough to process capsule!\n"));
    413       return EFI_OUT_OF_RESOURCES;
    414     }
    415   } else if (ReservedRangeBase < MemoryEnd64) {
    416     if (ReservedRangeEnd < MemoryEnd64   &&
    417         ReservedRangeBase - MemoryBase64 < MemoryEnd64 - ReservedRangeEnd) {
    418       MemoryBase64 = ReservedRangeEnd;
    419     } else {
    420       MemorySize64 = (UINT64)(UINTN)(ReservedRangeBase - MemoryBase64);
    421     }
    422   }
    423 
    424   //
    425   // Initialize context jumping to 64-bit enviroment
    426   //
    427   Context.JumpBuffer            = (EFI_PHYSICAL_ADDRESS)(UINTN)&JumpBuffer;
    428   Context.StackBufferBase       = LongModeBuffer->StackBaseAddress;
    429   Context.StackBufferLength     = LongModeBuffer->StackSize;
    430   Context.EntryPoint            = (EFI_PHYSICAL_ADDRESS)(UINTN)CoalesceEntry;
    431   Context.BlockListAddr         = BlockListAddr;
    432   Context.MemoryBase64Ptr       = (EFI_PHYSICAL_ADDRESS)(UINTN)&MemoryBase64;
    433   Context.MemorySize64Ptr       = (EFI_PHYSICAL_ADDRESS)(UINTN)&MemorySize64;
    434   Context.Page1GSupport         = Page1GSupport;
    435 
    436   //
    437   // Prepare data for return back
    438   //
    439   ReturnContext.ReturnCs           = 0x10;
    440   ReturnContext.ReturnEntryPoint   = (EFI_PHYSICAL_ADDRESS)(UINTN)ReturnFunction;
    441   //
    442   // Will save the return status of processing capsule
    443   //
    444   ReturnContext.ReturnStatus       = 0;
    445 
    446   //
    447   // Save original GDT
    448   //
    449   AsmReadGdtr ((IA32_DESCRIPTOR *)&ReturnContext.Gdtr);
    450 
    451   Status = Thunk32To64 (LongModeBuffer->PageTableAddress, &Context, &ReturnContext);
    452 
    453   if (!EFI_ERROR (Status)) {
    454     *MemoryBase = (VOID *) (UINTN) MemoryBase64;
    455     *MemorySize = (UINTN) MemorySize64;
    456   }
    457 
    458   return Status;
    459 
    460 }
    461 
    462 /**
    463   Locates the coalesce image entry point, and detects its machine type.
    464 
    465   @param CoalesceImageEntryPoint   Pointer to coalesce image entry point for output.
    466   @param CoalesceImageMachineType  Pointer to machine type of coalesce image.
    467 
    468   @retval EFI_SUCCESS     Coalesce image successfully located.
    469   @retval Others          Failed to locate the coalesce image.
    470 
    471 **/
    472 EFI_STATUS
    473 FindCapsuleCoalesceImage (
    474   OUT EFI_PHYSICAL_ADDRESS    *CoalesceImageEntryPoint,
    475   OUT UINT16                  *CoalesceImageMachineType
    476   )
    477 {
    478   EFI_STATUS                           Status;
    479   UINTN                                Instance;
    480   EFI_PEI_LOAD_FILE_PPI                *LoadFile;
    481   EFI_PEI_FV_HANDLE                    VolumeHandle;
    482   EFI_PEI_FILE_HANDLE                  FileHandle;
    483   EFI_PHYSICAL_ADDRESS                 CoalesceImageAddress;
    484   UINT64                               CoalesceImageSize;
    485   UINT32                               AuthenticationState;
    486 
    487   Instance = 0;
    488 
    489   while (TRUE) {
    490     Status = PeiServicesFfsFindNextVolume (Instance++, &VolumeHandle);
    491     if (EFI_ERROR (Status)) {
    492       return Status;
    493     }
    494     Status = PeiServicesFfsFindFileByName (PcdGetPtr(PcdCapsuleCoalesceFile), VolumeHandle, &FileHandle);
    495     if (!EFI_ERROR (Status)) {
    496       Status = PeiServicesLocatePpi (&gEfiPeiLoadFilePpiGuid, 0, NULL, (VOID **) &LoadFile);
    497       ASSERT_EFI_ERROR (Status);
    498 
    499       Status = LoadFile->LoadFile (
    500                            LoadFile,
    501                            FileHandle,
    502                            &CoalesceImageAddress,
    503                            &CoalesceImageSize,
    504                            CoalesceImageEntryPoint,
    505                            &AuthenticationState
    506                            );
    507       if (EFI_ERROR (Status)) {
    508         DEBUG ((EFI_D_ERROR, "Unable to find PE32 section in CapsuleX64 image ffs %r!\n", Status));
    509         return Status;
    510       }
    511       *CoalesceImageMachineType = PeCoffLoaderGetMachineType ((VOID *) (UINTN) CoalesceImageAddress);
    512       break;
    513     } else {
    514       continue;
    515     }
    516   }
    517 
    518   return Status;
    519 }
    520 
    521 /**
    522   Gets the reserved long mode buffer.
    523 
    524   @param  LongModeBuffer  Pointer to the long mode buffer for output.
    525 
    526   @retval EFI_SUCCESS     Long mode buffer successfully retrieved.
    527   @retval Others          Variable storing long mode buffer not found.
    528 
    529 **/
    530 EFI_STATUS
    531 GetLongModeContext (
    532   OUT EFI_CAPSULE_LONG_MODE_BUFFER *LongModeBuffer
    533   )
    534 {
    535   EFI_STATUS   Status;
    536   UINTN        Size;
    537   EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;
    538 
    539   Status = PeiServicesLocatePpi (
    540              &gEfiPeiReadOnlyVariable2PpiGuid,
    541              0,
    542              NULL,
    543              (VOID **) &PPIVariableServices
    544              );
    545   ASSERT_EFI_ERROR (Status);
    546 
    547   Size = sizeof (EFI_CAPSULE_LONG_MODE_BUFFER);
    548   Status = PPIVariableServices->GetVariable (
    549                                   PPIVariableServices,
    550                                   EFI_CAPSULE_LONG_MODE_BUFFER_NAME,
    551                                   &gEfiCapsuleVendorGuid,
    552                                   NULL,
    553                                   &Size,
    554                                   LongModeBuffer
    555                                   );
    556   if (EFI_ERROR (Status)) {
    557     DEBUG (( EFI_D_ERROR, "Error Get LongModeBuffer variable %r!\n", Status));
    558   }
    559   return Status;
    560 }
    561 #endif
    562 
    563 /**
    564   Checks for the presence of capsule descriptors.
    565   Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
    566   and save to DescriptorBuffer.
    567 
    568   @param DescriptorBuffer        Pointer to the capsule descriptors
    569 
    570   @retval EFI_SUCCESS     a valid capsule is present
    571   @retval EFI_NOT_FOUND   if a valid capsule is not present
    572 **/
    573 EFI_STATUS
    574 GetCapsuleDescriptors (
    575   IN EFI_PHYSICAL_ADDRESS     *DescriptorBuffer
    576   )
    577 {
    578   EFI_STATUS                       Status;
    579   UINTN                            Size;
    580   UINTN                            Index;
    581   UINTN                            TempIndex;
    582   UINTN                            ValidIndex;
    583   BOOLEAN                          Flag;
    584   CHAR16                           CapsuleVarName[30];
    585   CHAR16                           *TempVarName;
    586   EFI_PHYSICAL_ADDRESS             CapsuleDataPtr64;
    587   EFI_PEI_READ_ONLY_VARIABLE2_PPI  *PPIVariableServices;
    588 
    589   Index             = 0;
    590   TempVarName       = NULL;
    591   CapsuleVarName[0] = 0;
    592   ValidIndex        = 0;
    593   CapsuleDataPtr64  = 0;
    594 
    595   Status = PeiServicesLocatePpi (
    596               &gEfiPeiReadOnlyVariable2PpiGuid,
    597               0,
    598               NULL,
    599               (VOID **) &PPIVariableServices
    600               );
    601   if (Status == EFI_SUCCESS) {
    602     StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME);
    603     TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
    604     Size = sizeof (CapsuleDataPtr64);
    605     while (1) {
    606       if (Index == 0) {
    607         //
    608         // For the first Capsule Image
    609         //
    610         Status = PPIVariableServices->GetVariable (
    611                                         PPIVariableServices,
    612                                         CapsuleVarName,
    613                                         &gEfiCapsuleVendorGuid,
    614                                         NULL,
    615                                         &Size,
    616                                         (VOID *) &CapsuleDataPtr64
    617                                         );
    618         if (EFI_ERROR (Status)) {
    619           DEBUG ((EFI_D_ERROR, "Capsule -- capsule variable not set\n"));
    620           return EFI_NOT_FOUND;
    621         }
    622         //
    623         // We have a chicken/egg situation where the memory init code needs to
    624         // know the boot mode prior to initializing memory. For this case, our
    625         // validate function will fail. We can detect if this is the case if blocklist
    626         // pointer is null. In that case, return success since we know that the
    627         // variable is set.
    628         //
    629         if (DescriptorBuffer == NULL) {
    630           return EFI_SUCCESS;
    631         }
    632       } else {
    633         UnicodeValueToString (TempVarName, 0, Index, 0);
    634         Status = PPIVariableServices->GetVariable (
    635                                         PPIVariableServices,
    636                                         CapsuleVarName,
    637                                         &gEfiCapsuleVendorGuid,
    638                                         NULL,
    639                                         &Size,
    640                                         (VOID *) &CapsuleDataPtr64
    641                                         );
    642         if (EFI_ERROR (Status)) {
    643           break;
    644         }
    645 
    646         //
    647         // If this BlockList has been linked before, skip this variable
    648         //
    649         Flag = FALSE;
    650         for (TempIndex = 0; TempIndex < ValidIndex; TempIndex++) {
    651           if (DescriptorBuffer[TempIndex] == CapsuleDataPtr64)  {
    652             Flag = TRUE;
    653             break;
    654           }
    655         }
    656         if (Flag) {
    657           Index ++;
    658           continue;
    659         }
    660       }
    661 
    662       //
    663       // Cache BlockList which has been processed
    664       //
    665       DescriptorBuffer[ValidIndex++] = CapsuleDataPtr64;
    666       Index ++;
    667     }
    668   }
    669 
    670   return EFI_SUCCESS;
    671 }
    672 
    673 /**
    674   Capsule PPI service to coalesce a fragmented capsule in memory.
    675 
    676   @param PeiServices  General purpose services available to every PEIM.
    677   @param MemoryBase   Pointer to the base of a block of memory that we can walk
    678                       all over while trying to coalesce our buffers.
    679                       On output, this variable will hold the base address of
    680                       a coalesced capsule.
    681   @param MemorySize   Size of the memory region pointed to by MemoryBase.
    682                       On output, this variable will contain the size of the
    683                       coalesced capsule.
    684 
    685   @retval EFI_NOT_FOUND   if we can't determine the boot mode
    686                           if the boot mode is not flash-update
    687                           if we could not find the capsule descriptors
    688 
    689   @retval EFI_BUFFER_TOO_SMALL
    690                           if we could not coalesce the capsule in the memory
    691                           region provided to us
    692 
    693   @retval EFI_SUCCESS     if there's no capsule, or if we processed the
    694                           capsule successfully.
    695 **/
    696 EFI_STATUS
    697 EFIAPI
    698 CapsuleCoalesce (
    699   IN     EFI_PEI_SERVICES            **PeiServices,
    700   IN OUT VOID                        **MemoryBase,
    701   IN OUT UINTN                       *MemorySize
    702   )
    703 {
    704   UINTN                                Index;
    705   UINTN                                Size;
    706   UINTN                                VariableCount;
    707   CHAR16                               CapsuleVarName[30];
    708   CHAR16                               *TempVarName;
    709   EFI_PHYSICAL_ADDRESS                 CapsuleDataPtr64;
    710   EFI_STATUS                           Status;
    711   EFI_BOOT_MODE                        BootMode;
    712   EFI_PEI_READ_ONLY_VARIABLE2_PPI      *PPIVariableServices;
    713   EFI_PHYSICAL_ADDRESS                 *VariableArrayAddress;
    714 #ifdef MDE_CPU_IA32
    715   UINT16                               CoalesceImageMachineType;
    716   EFI_PHYSICAL_ADDRESS                 CoalesceImageEntryPoint;
    717   COALESCE_ENTRY                       CoalesceEntry;
    718   EFI_CAPSULE_LONG_MODE_BUFFER         LongModeBuffer;
    719 #endif
    720 
    721   Index                   = 0;
    722   VariableCount           = 0;
    723   CapsuleVarName[0]       = 0;
    724   CapsuleDataPtr64        = 0;
    725 
    726   //
    727   // Someone should have already ascertained the boot mode. If it's not
    728   // capsule update, then return normally.
    729   //
    730   Status = PeiServicesGetBootMode (&BootMode);
    731   if (EFI_ERROR (Status) || (BootMode != BOOT_ON_FLASH_UPDATE)) {
    732     DEBUG ((EFI_D_ERROR, "Boot mode is not correct for capsule update path.\n"));
    733     Status = EFI_NOT_FOUND;
    734     goto Done;
    735   }
    736 
    737   //
    738   // User may set the same ScatterGatherList with several different variables,
    739   // so cache all ScatterGatherList for check later.
    740   //
    741   Status = PeiServicesLocatePpi (
    742               &gEfiPeiReadOnlyVariable2PpiGuid,
    743               0,
    744               NULL,
    745               (VOID **) &PPIVariableServices
    746               );
    747   if (EFI_ERROR (Status)) {
    748     goto Done;
    749   }
    750   Size = sizeof (CapsuleDataPtr64);
    751   StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME);
    752   TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
    753   while (TRUE) {
    754     if (Index > 0) {
    755       UnicodeValueToString (TempVarName, 0, Index, 0);
    756     }
    757     Status = PPIVariableServices->GetVariable (
    758                                     PPIVariableServices,
    759                                     CapsuleVarName,
    760                                     &gEfiCapsuleVendorGuid,
    761                                     NULL,
    762                                     &Size,
    763                                     (VOID *) &CapsuleDataPtr64
    764                                     );
    765     if (EFI_ERROR (Status)) {
    766       //
    767       // There is no capsule variables, quit
    768       //
    769       DEBUG ((EFI_D_INFO,"Capsule variable Index = %d\n", Index));
    770       break;
    771     }
    772     VariableCount++;
    773     Index++;
    774   }
    775 
    776   DEBUG ((EFI_D_INFO,"Capsule variable count = %d\n", VariableCount));
    777 
    778   //
    779   // The last entry is the end flag.
    780   //
    781   Status = PeiServicesAllocatePool (
    782              (VariableCount + 1) * sizeof (EFI_PHYSICAL_ADDRESS),
    783              (VOID **)&VariableArrayAddress
    784              );
    785 
    786   if (Status != EFI_SUCCESS) {
    787     DEBUG ((EFI_D_ERROR, "AllocatePages Failed!, Status = %x\n", Status));
    788     goto Done;
    789   }
    790 
    791   ZeroMem (VariableArrayAddress, (VariableCount + 1) * sizeof (EFI_PHYSICAL_ADDRESS));
    792 
    793   //
    794   // Find out if we actually have a capsule.
    795   // GetCapsuleDescriptors depends on variable PPI, so it should run in 32-bit environment.
    796   //
    797   Status = GetCapsuleDescriptors (VariableArrayAddress);
    798   if (EFI_ERROR (Status)) {
    799     DEBUG ((EFI_D_ERROR, "Fail to find capsule variables.\n"));
    800     goto Done;
    801   }
    802 
    803 #ifdef MDE_CPU_IA32
    804   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
    805     //
    806     // Switch to 64-bit mode to process capsule data when:
    807     // 1. When DXE phase is 64-bit
    808     // 2. When the buffer for 64-bit transition exists
    809     // 3. When Capsule X64 image is built in BIOS image
    810     // In 64-bit mode, we can process capsule data above 4GB.
    811     //
    812     CoalesceImageEntryPoint = 0;
    813     Status = GetLongModeContext (&LongModeBuffer);
    814     if (EFI_ERROR (Status)) {
    815       DEBUG ((EFI_D_ERROR, "Fail to find the variable for long mode context!\n"));
    816       Status = EFI_NOT_FOUND;
    817       goto Done;
    818     }
    819 
    820     Status = FindCapsuleCoalesceImage (&CoalesceImageEntryPoint, &CoalesceImageMachineType);
    821     if ((EFI_ERROR (Status)) || (CoalesceImageMachineType != EFI_IMAGE_MACHINE_X64)) {
    822       DEBUG ((EFI_D_ERROR, "Fail to find CapsuleX64 module in FV!\n"));
    823       Status = EFI_NOT_FOUND;
    824       goto Done;
    825     }
    826     ASSERT (CoalesceImageEntryPoint != 0);
    827     CoalesceEntry = (COALESCE_ENTRY) (UINTN) CoalesceImageEntryPoint;
    828     Status = ModeSwitch (&LongModeBuffer, CoalesceEntry, (EFI_PHYSICAL_ADDRESS)(UINTN)VariableArrayAddress, MemoryBase, MemorySize);
    829   } else {
    830     //
    831     // Capsule is processed in IA32 mode.
    832     //
    833     Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryBase, MemorySize);
    834   }
    835 #else
    836   //
    837   // Process capsule directly.
    838   //
    839   Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryBase, MemorySize);
    840 #endif
    841 
    842   DEBUG ((EFI_D_INFO, "Capsule Coalesce Status = %r!\n", Status));
    843 
    844   if (Status == EFI_BUFFER_TOO_SMALL) {
    845     DEBUG ((EFI_D_ERROR, "There is not enough memory to process capsule!\n"));
    846   }
    847 
    848   if (Status == EFI_NOT_FOUND) {
    849     DEBUG ((EFI_D_ERROR, "Fail to parse capsule descriptor in memory!\n"));
    850     REPORT_STATUS_CODE (
    851       EFI_ERROR_CODE | EFI_ERROR_MAJOR,
    852       (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_INVALID_CAPSULE_DESCRIPTOR)
    853       );
    854   }
    855 
    856 Done:
    857   return Status;
    858 }
    859 
    860 /**
    861   Determine if we're in capsule update boot mode.
    862 
    863   @param PeiServices  PEI services table
    864 
    865   @retval EFI_SUCCESS   if we have a capsule available
    866   @retval EFI_NOT_FOUND no capsule detected
    867 
    868 **/
    869 EFI_STATUS
    870 EFIAPI
    871 CheckCapsuleUpdate (
    872   IN EFI_PEI_SERVICES           **PeiServices
    873   )
    874 {
    875   EFI_STATUS  Status;
    876   Status = GetCapsuleDescriptors (NULL);
    877   return Status;
    878 }
    879 /**
    880   This function will look at a capsule and determine if it's a test pattern.
    881   If it is, then it will verify it and emit an error message if corruption is detected.
    882 
    883   @param PeiServices   Standard pei services pointer
    884   @param CapsuleBase   Base address of coalesced capsule, which is preceeded
    885                        by private data. Very implementation specific.
    886 
    887   @retval TRUE    Capsule image is the test image
    888   @retval FALSE   Capsule image is not the test image.
    889 
    890 **/
    891 BOOLEAN
    892 CapsuleTestPattern (
    893   IN EFI_PEI_SERVICES                 **PeiServices,
    894   IN VOID                             *CapsuleBase
    895   )
    896 {
    897   UINT32  *TestPtr;
    898   UINT32  TestCounter;
    899   UINT32  TestSize;
    900   BOOLEAN RetValue;
    901 
    902   RetValue = FALSE;
    903 
    904   //
    905   // Look at the capsule data and determine if it's a test pattern. If it
    906   // is, then test it now.
    907   //
    908   TestPtr = (UINT32 *) CapsuleBase;
    909   //
    910   // 0x54534554 "TEST"
    911   //
    912   if (*TestPtr == 0x54534554) {
    913     RetValue = TRUE;
    914     DEBUG ((EFI_D_INFO, "Capsule test pattern mode activated...\n"));
    915     TestSize = TestPtr[1] / sizeof (UINT32);
    916     //
    917     // Skip over the signature and the size fields in the pattern data header
    918     //
    919     TestPtr += 2;
    920     TestCounter = 0;
    921     while (TestSize > 0) {
    922       if (*TestPtr != TestCounter) {
    923         DEBUG ((EFI_D_INFO, "Capsule test pattern mode FAILED: BaseAddr/FailAddr 0x%X 0x%X\n", (UINT32)(UINTN)(EFI_CAPSULE_PEIM_PRIVATE_DATA *)CapsuleBase, (UINT32)(UINTN)TestPtr));
    924         return TRUE;
    925       }
    926 
    927       TestPtr++;
    928       TestCounter++;
    929       TestSize--;
    930     }
    931 
    932     DEBUG ((EFI_D_INFO, "Capsule test pattern mode SUCCESS\n"));
    933   }
    934 
    935   return RetValue;
    936 }
    937 
    938 /**
    939   Capsule PPI service that gets called after memory is available. The
    940   capsule coalesce function, which must be called first, returns a base
    941   address and size, which can be anything actually. Once the memory init
    942   PEIM has discovered memory, then it should call this function and pass in
    943   the base address and size returned by the coalesce function. Then this
    944   function can create a capsule HOB and return.
    945 
    946   @param PeiServices   standard pei services pointer
    947   @param CapsuleBase   address returned by the capsule coalesce function. Most
    948                        likely this will actually be a pointer to private data.
    949   @param CapsuleSize   value returned by the capsule coalesce function.
    950 
    951   @retval EFI_VOLUME_CORRUPTED  CapsuleBase does not appear to point to a
    952                                 coalesced capsule
    953   @retval EFI_SUCCESS           if all goes well.
    954 **/
    955 EFI_STATUS
    956 EFIAPI
    957 CreateState (
    958   IN EFI_PEI_SERVICES                 **PeiServices,
    959   IN VOID                             *CapsuleBase,
    960   IN UINTN                            CapsuleSize
    961   )
    962 {
    963   EFI_STATUS                    Status;
    964   EFI_CAPSULE_PEIM_PRIVATE_DATA *PrivateData;
    965   UINTN                         Size;
    966   EFI_PHYSICAL_ADDRESS          NewBuffer;
    967   UINTN                         CapsuleNumber;
    968   UINT32                        Index;
    969   EFI_PHYSICAL_ADDRESS          BaseAddress;
    970   UINT64                        Length;
    971 
    972   PrivateData    = (EFI_CAPSULE_PEIM_PRIVATE_DATA *) CapsuleBase;
    973   if (PrivateData->Signature != EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE) {
    974     return EFI_VOLUME_CORRUPTED;
    975   }
    976   if (PrivateData->CapsuleAllImageSize >= MAX_ADDRESS) {
    977     DEBUG ((EFI_D_ERROR, "CapsuleAllImageSize too big - 0x%lx\n", PrivateData->CapsuleAllImageSize));
    978     return EFI_OUT_OF_RESOURCES;
    979   }
    980   if (PrivateData->CapsuleNumber >= MAX_ADDRESS) {
    981     DEBUG ((EFI_D_ERROR, "CapsuleNumber too big - 0x%lx\n", PrivateData->CapsuleNumber));
    982     return EFI_OUT_OF_RESOURCES;
    983   }
    984   //
    985   // Capsule Number and Capsule Offset is in the tail of Capsule data.
    986   //
    987   Size          = (UINTN)PrivateData->CapsuleAllImageSize;
    988   CapsuleNumber = (UINTN)PrivateData->CapsuleNumber;
    989   //
    990   // Allocate the memory so that it gets preserved into DXE
    991   //
    992   Status = PeiServicesAllocatePages (
    993              EfiRuntimeServicesData,
    994              EFI_SIZE_TO_PAGES (Size),
    995              &NewBuffer
    996              );
    997 
    998   if (Status != EFI_SUCCESS) {
    999     DEBUG ((EFI_D_ERROR, "AllocatePages Failed!\n"));
   1000     return Status;
   1001   }
   1002   //
   1003   // Copy to our new buffer for DXE
   1004   //
   1005   DEBUG ((EFI_D_INFO, "Capsule copy from 0x%8X to 0x%8X with size 0x%8X\n", (UINTN)((UINT8 *)PrivateData + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64)), (UINTN) NewBuffer, Size));
   1006   CopyMem ((VOID *) (UINTN) NewBuffer, (VOID *) (UINTN) ((UINT8 *)PrivateData + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64)), Size);
   1007   //
   1008   // Check for test data pattern. If it is the test pattern, then we'll
   1009   // test it ans still create the HOB so that it can be used to verify
   1010   // that capsules don't get corrupted all the way into BDS. BDS will
   1011   // still try to turn it into a firmware volume, but will think it's
   1012   // corrupted so nothing will happen.
   1013   //
   1014   DEBUG_CODE (
   1015     CapsuleTestPattern (PeiServices, (VOID *) (UINTN) NewBuffer);
   1016   );
   1017 
   1018   //
   1019   // Build the UEFI Capsule Hob for each capsule image.
   1020   //
   1021   for (Index = 0; Index < CapsuleNumber; Index ++) {
   1022     BaseAddress = NewBuffer + PrivateData->CapsuleOffset[Index];
   1023     Length      = ((EFI_CAPSULE_HEADER *)((UINTN) BaseAddress))->CapsuleImageSize;
   1024 
   1025     BuildCvHob (BaseAddress, Length);
   1026   }
   1027 
   1028   return EFI_SUCCESS;
   1029 }
   1030 
   1031 CONST EFI_PEI_CAPSULE_PPI        mCapsulePpi = {
   1032   CapsuleCoalesce,
   1033   CheckCapsuleUpdate,
   1034   CreateState
   1035 };
   1036 
   1037 CONST EFI_PEI_PPI_DESCRIPTOR mUefiPpiListCapsule = {
   1038   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
   1039   &gEfiPeiCapsulePpiGuid,
   1040   (EFI_PEI_CAPSULE_PPI *) &mCapsulePpi
   1041 };
   1042 
   1043 /**
   1044   Entry point function for the PEIM
   1045 
   1046   @param FileHandle      Handle of the file being invoked.
   1047   @param PeiServices     Describes the list of possible PEI Services.
   1048 
   1049   @return EFI_SUCCESS    If we installed our PPI
   1050 
   1051 **/
   1052 EFI_STATUS
   1053 EFIAPI
   1054 CapsuleMain (
   1055   IN       EFI_PEI_FILE_HANDLE  FileHandle,
   1056   IN CONST EFI_PEI_SERVICES     **PeiServices
   1057   )
   1058 {
   1059   //
   1060   // Just produce our PPI
   1061   //
   1062   return PeiServicesInstallPpi (&mUefiPpiListCapsule);
   1063 }
   1064