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