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