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