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