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