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