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