]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/CapsulePei/UefiCapsule.c
MdeModulePkg/Ip4Dxe: Add wrong/invalid subnet check
[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
6fb389d0
JF
324 DEBUG ((\r
325 DEBUG_INFO,\r
326 "%a() Stack Base: 0x%lx, Stack Size: 0x%lx\n",\r
327 __FUNCTION__,\r
328 Context->StackBufferBase,\r
329 Context->StackBufferLength\r
330 ));\r
331\r
933d80a1 332 //\r
333 // Disable interrupt of Debug timer, since the IDT table cannot work in long mode\r
334 //\r
335 SaveAndSetDebugTimerInterrupt (FALSE);\r
ab7017fe 336 //\r
337 // Transfer to long mode\r
338 //\r
339 AsmEnablePaging64 (\r
340 0x38,\r
341 (UINT64) Context->EntryPoint,\r
342 (UINT64)(UINTN) Context,\r
343 (UINT64)(UINTN) ReturnContext,\r
344 Context->StackBufferBase + Context->StackBufferLength\r
345 );\r
346 }\r
716087e2 347\r
ab7017fe 348 //\r
349 // Convert to 32-bit Status and return\r
350 //\r
351 Status = EFI_SUCCESS;\r
352 if ((UINTN) ReturnContext->ReturnStatus != 0) {\r
353 Status = ENCODE_ERROR ((UINTN) ReturnContext->ReturnStatus);\r
354 }\r
355 \r
356 return Status;\r
da58b0db 357}\r
358\r
ab7017fe 359/**\r
360 If in 32 bit protection mode, and coalesce image is of X64, switch to long mode.\r
361\r
362 @param LongModeBuffer The context of long mode.\r
363 @param CoalesceEntry Entry of coalesce image.\r
364 @param BlockListAddr Address of block list.\r
359cb1a3 365 @param MemoryResource Pointer to the buffer of memory resource descriptor.\r
ab7017fe 366 @param MemoryBase Base of memory range.\r
367 @param MemorySize Size of memory range.\r
368\r
369 @retval EFI_SUCCESS Successfully switched to long mode and execute coalesce.\r
370 @retval Others Failed to execute coalesce in long mode.\r
371\r
372**/\r
373EFI_STATUS\r
374ModeSwitch (\r
375 IN EFI_CAPSULE_LONG_MODE_BUFFER *LongModeBuffer,\r
376 IN COALESCE_ENTRY CoalesceEntry,\r
377 IN EFI_PHYSICAL_ADDRESS BlockListAddr,\r
359cb1a3 378 IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource,\r
ab7017fe 379 IN OUT VOID **MemoryBase,\r
380 IN OUT UINTN *MemorySize\r
381 )\r
382{\r
383 EFI_STATUS Status;\r
384 EFI_PHYSICAL_ADDRESS MemoryBase64;\r
385 UINT64 MemorySize64;\r
386 EFI_PHYSICAL_ADDRESS MemoryEnd64;\r
387 SWITCH_32_TO_64_CONTEXT Context;\r
388 SWITCH_64_TO_32_CONTEXT ReturnContext;\r
389 BASE_LIBRARY_JUMP_BUFFER JumpBuffer;\r
390 EFI_PHYSICAL_ADDRESS ReservedRangeBase;\r
391 EFI_PHYSICAL_ADDRESS ReservedRangeEnd;\r
716087e2 392 BOOLEAN Page1GSupport;\r
ab7017fe 393\r
394 ZeroMem (&Context, sizeof (SWITCH_32_TO_64_CONTEXT));\r
395 ZeroMem (&ReturnContext, sizeof (SWITCH_64_TO_32_CONTEXT));\r
396 \r
397 MemoryBase64 = (UINT64) (UINTN) *MemoryBase;\r
398 MemorySize64 = (UINT64) (UINTN) *MemorySize;\r
399 MemoryEnd64 = MemoryBase64 + MemorySize64;\r
400\r
716087e2
SZ
401 Page1GSupport = IsPage1GSupport ();\r
402\r
ab7017fe 403 //\r
404 // Merge memory range reserved for stack and page table \r
405 //\r
406 if (LongModeBuffer->StackBaseAddress < LongModeBuffer->PageTableAddress) {\r
407 ReservedRangeBase = LongModeBuffer->StackBaseAddress;\r
716087e2 408 ReservedRangeEnd = LongModeBuffer->PageTableAddress + CalculatePageTableSize (Page1GSupport);\r
ab7017fe 409 } else {\r
410 ReservedRangeBase = LongModeBuffer->PageTableAddress;\r
411 ReservedRangeEnd = LongModeBuffer->StackBaseAddress + LongModeBuffer->StackSize;\r
412 }\r
716087e2 413\r
ab7017fe 414 //\r
415 // Check if memory range reserved is overlap with MemoryBase ~ MemoryBase + MemorySize.\r
416 // If they are overlapped, get a larger range to process capsule data.\r
417 //\r
418 if (ReservedRangeBase <= MemoryBase64) {\r
419 if (ReservedRangeEnd < MemoryEnd64) {\r
420 MemoryBase64 = ReservedRangeEnd;\r
421 } else {\r
422 DEBUG ((EFI_D_ERROR, "Memory is not enough to process capsule!\n"));\r
423 return EFI_OUT_OF_RESOURCES;\r
424 }\r
425 } else if (ReservedRangeBase < MemoryEnd64) {\r
426 if (ReservedRangeEnd < MemoryEnd64 &&\r
427 ReservedRangeBase - MemoryBase64 < MemoryEnd64 - ReservedRangeEnd) {\r
428 MemoryBase64 = ReservedRangeEnd;\r
429 } else {\r
430 MemorySize64 = (UINT64)(UINTN)(ReservedRangeBase - MemoryBase64);\r
431 }\r
716087e2
SZ
432 }\r
433\r
ab7017fe 434 //\r
435 // Initialize context jumping to 64-bit enviroment\r
436 //\r
437 Context.JumpBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)&JumpBuffer;\r
438 Context.StackBufferBase = LongModeBuffer->StackBaseAddress;\r
439 Context.StackBufferLength = LongModeBuffer->StackSize;\r
440 Context.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)CoalesceEntry;\r
441 Context.BlockListAddr = BlockListAddr;\r
359cb1a3 442 Context.MemoryResource = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryResource;\r
ab7017fe 443 Context.MemoryBase64Ptr = (EFI_PHYSICAL_ADDRESS)(UINTN)&MemoryBase64;\r
444 Context.MemorySize64Ptr = (EFI_PHYSICAL_ADDRESS)(UINTN)&MemorySize64;\r
716087e2 445 Context.Page1GSupport = Page1GSupport;\r
ab7017fe 446\r
447 //\r
448 // Prepare data for return back\r
449 //\r
450 ReturnContext.ReturnCs = 0x10;\r
451 ReturnContext.ReturnEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)ReturnFunction;\r
452 //\r
453 // Will save the return status of processing capsule\r
454 //\r
455 ReturnContext.ReturnStatus = 0;\r
456 \r
457 //\r
458 // Save original GDT\r
459 //\r
460 AsmReadGdtr ((IA32_DESCRIPTOR *)&ReturnContext.Gdtr);\r
461 \r
462 Status = Thunk32To64 (LongModeBuffer->PageTableAddress, &Context, &ReturnContext);\r
463 \r
464 if (!EFI_ERROR (Status)) {\r
465 *MemoryBase = (VOID *) (UINTN) MemoryBase64;\r
466 *MemorySize = (UINTN) MemorySize64;\r
467 }\r
468\r
469 return Status;\r
470\r
471}\r
da58b0db 472\r
4e4f13d2 473/**\r
474 Locates the coalesce image entry point, and detects its machine type.\r
475\r
476 @param CoalesceImageEntryPoint Pointer to coalesce image entry point for output.\r
477 @param CoalesceImageMachineType Pointer to machine type of coalesce image.\r
478\r
479 @retval EFI_SUCCESS Coalesce image successfully located.\r
480 @retval Others Failed to locate the coalesce image.\r
481\r
482**/\r
483EFI_STATUS\r
484FindCapsuleCoalesceImage (\r
485 OUT EFI_PHYSICAL_ADDRESS *CoalesceImageEntryPoint,\r
486 OUT UINT16 *CoalesceImageMachineType\r
487 )\r
488{\r
489 EFI_STATUS Status;\r
490 UINTN Instance;\r
491 EFI_PEI_LOAD_FILE_PPI *LoadFile;\r
492 EFI_PEI_FV_HANDLE VolumeHandle;\r
493 EFI_PEI_FILE_HANDLE FileHandle;\r
494 EFI_PHYSICAL_ADDRESS CoalesceImageAddress;\r
495 UINT64 CoalesceImageSize;\r
496 UINT32 AuthenticationState;\r
497\r
498 Instance = 0;\r
499\r
500 while (TRUE) {\r
501 Status = PeiServicesFfsFindNextVolume (Instance++, &VolumeHandle);\r
502 if (EFI_ERROR (Status)) {\r
503 return Status;\r
504 }\r
505 Status = PeiServicesFfsFindFileByName (PcdGetPtr(PcdCapsuleCoalesceFile), VolumeHandle, &FileHandle);\r
506 if (!EFI_ERROR (Status)) {\r
507 Status = PeiServicesLocatePpi (&gEfiPeiLoadFilePpiGuid, 0, NULL, (VOID **) &LoadFile);\r
508 ASSERT_EFI_ERROR (Status);\r
509\r
510 Status = LoadFile->LoadFile (\r
511 LoadFile,\r
512 FileHandle,\r
513 &CoalesceImageAddress,\r
514 &CoalesceImageSize,\r
515 CoalesceImageEntryPoint,\r
516 &AuthenticationState\r
517 );\r
518 if (EFI_ERROR (Status)) {\r
716087e2 519 DEBUG ((EFI_D_ERROR, "Unable to find PE32 section in CapsuleX64 image ffs %r!\n", Status));\r
4e4f13d2 520 return Status;\r
521 }\r
522 *CoalesceImageMachineType = PeCoffLoaderGetMachineType ((VOID *) (UINTN) CoalesceImageAddress);\r
523 break;\r
524 } else {\r
525 continue;\r
526 }\r
527 }\r
528\r
529 return Status;\r
530}\r
531\r
716087e2
SZ
532/**\r
533 Gets the reserved long mode buffer.\r
534\r
535 @param LongModeBuffer Pointer to the long mode buffer for output.\r
536\r
537 @retval EFI_SUCCESS Long mode buffer successfully retrieved.\r
538 @retval Others Variable storing long mode buffer not found.\r
539\r
540**/\r
541EFI_STATUS\r
542GetLongModeContext (\r
543 OUT EFI_CAPSULE_LONG_MODE_BUFFER *LongModeBuffer\r
544 )\r
545{\r
546 EFI_STATUS Status;\r
547 UINTN Size;\r
548 EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;\r
549\r
550 Status = PeiServicesLocatePpi (\r
551 &gEfiPeiReadOnlyVariable2PpiGuid,\r
552 0,\r
553 NULL,\r
554 (VOID **) &PPIVariableServices\r
555 );\r
556 ASSERT_EFI_ERROR (Status);\r
557\r
558 Size = sizeof (EFI_CAPSULE_LONG_MODE_BUFFER);\r
559 Status = PPIVariableServices->GetVariable (\r
560 PPIVariableServices,\r
561 EFI_CAPSULE_LONG_MODE_BUFFER_NAME,\r
562 &gEfiCapsuleVendorGuid,\r
563 NULL,\r
564 &Size,\r
565 LongModeBuffer\r
566 );\r
567 if (EFI_ERROR (Status)) {\r
568 DEBUG (( EFI_D_ERROR, "Error Get LongModeBuffer variable %r!\n", Status));\r
569 }\r
570 return Status;\r
571}\r
4e4f13d2 572#endif\r
573\r
359cb1a3
SZ
574#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)\r
575/**\r
576 Get physical address bits.\r
577\r
578 @return Physical address bits.\r
579\r
580**/\r
581UINT8\r
582GetPhysicalAddressBits (\r
583 VOID\r
584 )\r
585{\r
586 UINT32 RegEax;\r
587 UINT8 PhysicalAddressBits;\r
588 VOID *Hob;\r
589\r
590 //\r
591 // Get physical address bits supported.\r
592 //\r
593 Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
594 if (Hob != NULL) {\r
595 PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;\r
596 } else {\r
597 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
598 if (RegEax >= 0x80000008) {\r
599 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
600 PhysicalAddressBits = (UINT8) RegEax;\r
601 } else {\r
602 PhysicalAddressBits = 36;\r
603 }\r
604 }\r
605\r
606 //\r
607 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.\r
608 //\r
609 ASSERT (PhysicalAddressBits <= 52);\r
610 if (PhysicalAddressBits > 48) {\r
611 PhysicalAddressBits = 48;\r
612 }\r
613\r
614 return PhysicalAddressBits;\r
615}\r
616#endif\r
617\r
618/**\r
619 Build memory resource descriptor from resource descriptor in HOB list.\r
620\r
621 @return Pointer to the buffer of memory resource descriptor.\r
622 NULL if no memory resource descriptor reported in HOB list\r
623 before capsule Coalesce.\r
624\r
625**/\r
626MEMORY_RESOURCE_DESCRIPTOR *\r
627BuildMemoryResourceDescriptor (\r
628 VOID\r
629 )\r
630{\r
631 EFI_PEI_HOB_POINTERS Hob;\r
632 UINTN Index;\r
633 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor;\r
634 MEMORY_RESOURCE_DESCRIPTOR *MemoryResource;\r
635 EFI_STATUS Status;\r
636\r
637 //\r
638 // Get the count of memory resource descriptor.\r
639 //\r
640 Index = 0;\r
641 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);\r
642 while (Hob.Raw != NULL) {\r
643 ResourceDescriptor = (EFI_HOB_RESOURCE_DESCRIPTOR *) Hob.Raw;\r
644 if (ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {\r
645 Index++;\r
646 }\r
647 Hob.Raw = GET_NEXT_HOB (Hob);\r
648 Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);\r
649 }\r
650\r
651 if (Index == 0) {\r
652 DEBUG ((EFI_D_INFO | EFI_D_WARN, "No memory resource descriptor reported in HOB list before capsule Coalesce\n"));\r
653#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)\r
654 //\r
655 // Allocate memory to hold memory resource descriptor,\r
656 // include extra one NULL terminate memory resource descriptor.\r
657 //\r
658 Status = PeiServicesAllocatePool ((1 + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR), (VOID **) &MemoryResource);\r
659 ASSERT_EFI_ERROR (Status);\r
660 ZeroMem (MemoryResource, (1 + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR));\r
661 \r
662 MemoryResource[0].PhysicalStart = 0;\r
663 MemoryResource[0].ResourceLength = LShiftU64 (1, GetPhysicalAddressBits ());\r
664 DEBUG ((EFI_D_INFO, "MemoryResource[0x0] - Start(0x%0lx) Length(0x%0lx)\n",\r
665 MemoryResource[0x0].PhysicalStart, MemoryResource[0x0].ResourceLength));\r
666 return MemoryResource;\r
667#else\r
668 return NULL;\r
669#endif\r
670 }\r
671\r
672 //\r
673 // Allocate memory to hold memory resource descriptor,\r
674 // include extra one NULL terminate memory resource descriptor.\r
675 //\r
676 Status = PeiServicesAllocatePool ((Index + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR), (VOID **) &MemoryResource);\r
677 ASSERT_EFI_ERROR (Status);\r
678 ZeroMem (MemoryResource, (Index + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR));\r
679\r
680 //\r
681 // Get the content of memory resource descriptor.\r
682 //\r
683 Index = 0;\r
684 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);\r
685 while (Hob.Raw != NULL) {\r
686 ResourceDescriptor = (EFI_HOB_RESOURCE_DESCRIPTOR *) Hob.Raw;\r
687 if (ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {\r
688 DEBUG ((EFI_D_INFO, "MemoryResource[0x%x] - Start(0x%0lx) Length(0x%0lx)\n",\r
689 Index, ResourceDescriptor->PhysicalStart, ResourceDescriptor->ResourceLength));\r
690 MemoryResource[Index].PhysicalStart = ResourceDescriptor->PhysicalStart;\r
691 MemoryResource[Index].ResourceLength = ResourceDescriptor->ResourceLength;\r
692 Index++;\r
693 }\r
694 Hob.Raw = GET_NEXT_HOB (Hob);\r
695 Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);\r
696 }\r
697\r
698 return MemoryResource;\r
699}\r
700\r
da58b0db 701/**\r
702 Checks for the presence of capsule descriptors.\r
703 Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...\r
ab7017fe 704 and save to DescriptorBuffer.\r
da58b0db 705\r
ab7017fe 706 @param DescriptorBuffer Pointer to the capsule descriptors\r
da58b0db 707\r
708 @retval EFI_SUCCESS a valid capsule is present\r
709 @retval EFI_NOT_FOUND if a valid capsule is not present\r
710**/\r
711EFI_STATUS\r
712GetCapsuleDescriptors (\r
ab7017fe 713 IN EFI_PHYSICAL_ADDRESS *DescriptorBuffer\r
da58b0db 714 )\r
715{\r
716 EFI_STATUS Status;\r
717 UINTN Size;\r
718 UINTN Index;\r
719 UINTN TempIndex;\r
720 UINTN ValidIndex;\r
721 BOOLEAN Flag;\r
722 CHAR16 CapsuleVarName[30];\r
723 CHAR16 *TempVarName;\r
724 EFI_PHYSICAL_ADDRESS CapsuleDataPtr64;\r
da58b0db 725 EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;\r
726\r
da58b0db 727 Index = 0;\r
728 TempVarName = NULL;\r
729 CapsuleVarName[0] = 0;\r
730 ValidIndex = 0;\r
34717ef0 731 CapsuleDataPtr64 = 0;\r
da58b0db 732 \r
733 Status = PeiServicesLocatePpi (\r
734 &gEfiPeiReadOnlyVariable2PpiGuid,\r
735 0,\r
736 NULL,\r
737 (VOID **) &PPIVariableServices\r
738 );\r
739 if (Status == EFI_SUCCESS) {\r
59d1f4f0 740 StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME);\r
da58b0db 741 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
742 Size = sizeof (CapsuleDataPtr64);\r
743 while (1) {\r
744 if (Index == 0) {\r
745 //\r
746 // For the first Capsule Image\r
747 //\r
748 Status = PPIVariableServices->GetVariable (\r
749 PPIVariableServices,\r
750 CapsuleVarName,\r
751 &gEfiCapsuleVendorGuid,\r
752 NULL,\r
753 &Size,\r
754 (VOID *) &CapsuleDataPtr64\r
755 );\r
756 if (EFI_ERROR (Status)) {\r
757 DEBUG ((EFI_D_ERROR, "Capsule -- capsule variable not set\n"));\r
758 return EFI_NOT_FOUND;\r
759 }\r
760 //\r
761 // We have a chicken/egg situation where the memory init code needs to\r
762 // know the boot mode prior to initializing memory. For this case, our\r
763 // validate function will fail. We can detect if this is the case if blocklist\r
764 // pointer is null. In that case, return success since we know that the\r
765 // variable is set.\r
766 //\r
ab7017fe 767 if (DescriptorBuffer == NULL) {\r
da58b0db 768 return EFI_SUCCESS;\r
769 }\r
da58b0db 770 } else {\r
771 UnicodeValueToString (TempVarName, 0, Index, 0);\r
772 Status = PPIVariableServices->GetVariable (\r
773 PPIVariableServices,\r
774 CapsuleVarName,\r
775 &gEfiCapsuleVendorGuid,\r
776 NULL,\r
777 &Size,\r
778 (VOID *) &CapsuleDataPtr64\r
779 );\r
780 if (EFI_ERROR (Status)) {\r
781 break;\r
782 }\r
783 \r
784 //\r
785 // If this BlockList has been linked before, skip this variable\r
786 //\r
787 Flag = FALSE;\r
788 for (TempIndex = 0; TempIndex < ValidIndex; TempIndex++) {\r
ab7017fe 789 if (DescriptorBuffer[TempIndex] == CapsuleDataPtr64) {\r
da58b0db 790 Flag = TRUE;\r
791 break;\r
792 }\r
793 }\r
794 if (Flag) {\r
795 Index ++;\r
796 continue;\r
797 }\r
da58b0db 798 }\r
799 \r
800 //\r
801 // Cache BlockList which has been processed\r
802 //\r
ab7017fe 803 DescriptorBuffer[ValidIndex++] = CapsuleDataPtr64;\r
da58b0db 804 Index ++;\r
805 }\r
806 }\r
807 \r
da58b0db 808 return EFI_SUCCESS;\r
809}\r
810\r
da58b0db 811/**\r
812 Capsule PPI service to coalesce a fragmented capsule in memory.\r
813\r
da58b0db 814 @param PeiServices General purpose services available to every PEIM.\r
815 @param MemoryBase Pointer to the base of a block of memory that we can walk\r
816 all over while trying to coalesce our buffers.\r
817 On output, this variable will hold the base address of\r
818 a coalesced capsule.\r
819 @param MemorySize Size of the memory region pointed to by MemoryBase.\r
820 On output, this variable will contain the size of the\r
821 coalesced capsule.\r
822\r
823 @retval EFI_NOT_FOUND if we can't determine the boot mode\r
824 if the boot mode is not flash-update\r
825 if we could not find the capsule descriptors\r
826\r
827 @retval EFI_BUFFER_TOO_SMALL\r
828 if we could not coalesce the capsule in the memory\r
829 region provided to us\r
830\r
831 @retval EFI_SUCCESS if there's no capsule, or if we processed the\r
832 capsule successfully.\r
833**/\r
834EFI_STATUS\r
835EFIAPI\r
836CapsuleCoalesce (\r
837 IN EFI_PEI_SERVICES **PeiServices,\r
838 IN OUT VOID **MemoryBase,\r
839 IN OUT UINTN *MemorySize\r
840 )\r
841{\r
ab7017fe 842 UINTN Index;\r
843 UINTN Size;\r
844 UINTN VariableCount;\r
845 CHAR16 CapsuleVarName[30];\r
846 CHAR16 *TempVarName;\r
847 EFI_PHYSICAL_ADDRESS CapsuleDataPtr64; \r
848 EFI_STATUS Status;\r
849 EFI_BOOT_MODE BootMode;\r
850 EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;\r
851 EFI_PHYSICAL_ADDRESS *VariableArrayAddress;\r
359cb1a3 852 MEMORY_RESOURCE_DESCRIPTOR *MemoryResource;\r
ab7017fe 853#ifdef MDE_CPU_IA32\r
854 UINT16 CoalesceImageMachineType;\r
855 EFI_PHYSICAL_ADDRESS CoalesceImageEntryPoint;\r
856 COALESCE_ENTRY CoalesceEntry;\r
857 EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer;\r
858#endif\r
859\r
860 Index = 0;\r
861 VariableCount = 0;\r
862 CapsuleVarName[0] = 0;\r
34717ef0 863 CapsuleDataPtr64 = 0;\r
da58b0db 864\r
865 //\r
866 // Someone should have already ascertained the boot mode. If it's not\r
867 // capsule update, then return normally.\r
868 //\r
869 Status = PeiServicesGetBootMode (&BootMode);\r
870 if (EFI_ERROR (Status) || (BootMode != BOOT_ON_FLASH_UPDATE)) {\r
ab7017fe 871 DEBUG ((EFI_D_ERROR, "Boot mode is not correct for capsule update path.\n")); \r
872 Status = EFI_NOT_FOUND;\r
873 goto Done;\r
da58b0db 874 }\r
875 \r
876 //\r
877 // User may set the same ScatterGatherList with several different variables,\r
878 // so cache all ScatterGatherList for check later.\r
879 //\r
880 Status = PeiServicesLocatePpi (\r
881 &gEfiPeiReadOnlyVariable2PpiGuid,\r
882 0,\r
883 NULL,\r
884 (VOID **) &PPIVariableServices\r
885 );\r
886 if (EFI_ERROR (Status)) {\r
ab7017fe 887 goto Done;\r
da58b0db 888 }\r
889 Size = sizeof (CapsuleDataPtr64);\r
59d1f4f0 890 StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME);\r
da58b0db 891 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
892 while (TRUE) {\r
893 if (Index > 0) {\r
894 UnicodeValueToString (TempVarName, 0, Index, 0);\r
895 }\r
896 Status = PPIVariableServices->GetVariable (\r
897 PPIVariableServices,\r
898 CapsuleVarName,\r
899 &gEfiCapsuleVendorGuid,\r
900 NULL,\r
901 &Size,\r
902 (VOID *) &CapsuleDataPtr64\r
903 );\r
904 if (EFI_ERROR (Status)) {\r
905 //\r
906 // There is no capsule variables, quit\r
907 //\r
ab7017fe 908 DEBUG ((EFI_D_INFO,"Capsule variable Index = %d\n", Index));\r
da58b0db 909 break;\r
910 }\r
911 VariableCount++;\r
912 Index++;\r
913 }\r
914 \r
ab7017fe 915 DEBUG ((EFI_D_INFO,"Capsule variable count = %d\n", VariableCount));\r
da58b0db 916 \r
ab7017fe 917 //\r
918 // The last entry is the end flag.\r
919 //\r
da58b0db 920 Status = PeiServicesAllocatePool (\r
ab7017fe 921 (VariableCount + 1) * sizeof (EFI_PHYSICAL_ADDRESS),\r
922 (VOID **)&VariableArrayAddress\r
da58b0db 923 );\r
924\r
925 if (Status != EFI_SUCCESS) {\r
926 DEBUG ((EFI_D_ERROR, "AllocatePages Failed!, Status = %x\n", Status));\r
ab7017fe 927 goto Done;\r
da58b0db 928 }\r
929 \r
ab7017fe 930 ZeroMem (VariableArrayAddress, (VariableCount + 1) * sizeof (EFI_PHYSICAL_ADDRESS));\r
931 \r
da58b0db 932 //\r
933 // Find out if we actually have a capsule.\r
ab7017fe 934 // GetCapsuleDescriptors depends on variable PPI, so it should run in 32-bit environment.\r
da58b0db 935 //\r
ab7017fe 936 Status = GetCapsuleDescriptors (VariableArrayAddress);\r
da58b0db 937 if (EFI_ERROR (Status)) {\r
ab7017fe 938 DEBUG ((EFI_D_ERROR, "Fail to find capsule variables.\n"));\r
939 goto Done;\r
da58b0db 940 }\r
941\r
359cb1a3
SZ
942 MemoryResource = BuildMemoryResourceDescriptor ();\r
943\r
ab7017fe 944#ifdef MDE_CPU_IA32\r
945 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
da58b0db 946 //\r
ab7017fe 947 // Switch to 64-bit mode to process capsule data when:\r
948 // 1. When DXE phase is 64-bit\r
949 // 2. When the buffer for 64-bit transition exists\r
950 // 3. When Capsule X64 image is built in BIOS image\r
951 // In 64-bit mode, we can process capsule data above 4GB.\r
da58b0db 952 //\r
ab7017fe 953 CoalesceImageEntryPoint = 0;\r
954 Status = GetLongModeContext (&LongModeBuffer);\r
955 if (EFI_ERROR (Status)) {\r
716087e2 956 DEBUG ((EFI_D_ERROR, "Fail to find the variable for long mode context!\n"));\r
ab7017fe 957 Status = EFI_NOT_FOUND;\r
958 goto Done;\r
da58b0db 959 }\r
ab7017fe 960 \r
961 Status = FindCapsuleCoalesceImage (&CoalesceImageEntryPoint, &CoalesceImageMachineType);\r
962 if ((EFI_ERROR (Status)) || (CoalesceImageMachineType != EFI_IMAGE_MACHINE_X64)) {\r
963 DEBUG ((EFI_D_ERROR, "Fail to find CapsuleX64 module in FV!\n"));\r
964 Status = EFI_NOT_FOUND;\r
965 goto Done;\r
da58b0db 966 }\r
ab7017fe 967 ASSERT (CoalesceImageEntryPoint != 0);\r
968 CoalesceEntry = (COALESCE_ENTRY) (UINTN) CoalesceImageEntryPoint;\r
359cb1a3 969 Status = ModeSwitch (&LongModeBuffer, CoalesceEntry, (EFI_PHYSICAL_ADDRESS)(UINTN)VariableArrayAddress, MemoryResource, MemoryBase, MemorySize);\r
ab7017fe 970 } else {\r
da58b0db 971 //\r
ab7017fe 972 // Capsule is processed in IA32 mode.\r
da58b0db 973 //\r
359cb1a3 974 Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryResource, MemoryBase, MemorySize);\r
da58b0db 975 }\r
ab7017fe 976#else\r
da58b0db 977 //\r
ab7017fe 978 // Process capsule directly.\r
da58b0db 979 //\r
359cb1a3 980 Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryResource, MemoryBase, MemorySize);\r
ab7017fe 981#endif\r
982 \r
983 DEBUG ((EFI_D_INFO, "Capsule Coalesce Status = %r!\n", Status));\r
da58b0db 984\r
ab7017fe 985 if (Status == EFI_BUFFER_TOO_SMALL) {\r
986 DEBUG ((EFI_D_ERROR, "There is not enough memory to process capsule!\n"));\r
987 }\r
988 \r
989 if (Status == EFI_NOT_FOUND) {\r
990 DEBUG ((EFI_D_ERROR, "Fail to parse capsule descriptor in memory!\n"));\r
991 REPORT_STATUS_CODE (\r
992 EFI_ERROR_CODE | EFI_ERROR_MAJOR,\r
993 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_INVALID_CAPSULE_DESCRIPTOR)\r
994 );\r
995 }\r
da58b0db 996\r
ab7017fe 997Done:\r
da58b0db 998 return Status;\r
999}\r
1000\r
1001/**\r
1002 Determine if we're in capsule update boot mode.\r
1003\r
1004 @param PeiServices PEI services table\r
1005\r
1006 @retval EFI_SUCCESS if we have a capsule available\r
1007 @retval EFI_NOT_FOUND no capsule detected\r
1008\r
1009**/\r
1010EFI_STATUS\r
1011EFIAPI\r
1012CheckCapsuleUpdate (\r
1013 IN EFI_PEI_SERVICES **PeiServices\r
1014 )\r
1015{\r
1016 EFI_STATUS Status;\r
1017 Status = GetCapsuleDescriptors (NULL);\r
1018 return Status;\r
1019}\r
1020/**\r
1021 This function will look at a capsule and determine if it's a test pattern. \r
1022 If it is, then it will verify it and emit an error message if corruption is detected.\r
1023 \r
1024 @param PeiServices Standard pei services pointer\r
1025 @param CapsuleBase Base address of coalesced capsule, which is preceeded\r
1026 by private data. Very implementation specific.\r
1027\r
1028 @retval TRUE Capsule image is the test image\r
1029 @retval FALSE Capsule image is not the test image.\r
1030\r
1031**/\r
1032BOOLEAN\r
1033CapsuleTestPattern (\r
1034 IN EFI_PEI_SERVICES **PeiServices,\r
1035 IN VOID *CapsuleBase\r
1036 )\r
1037{\r
1038 UINT32 *TestPtr;\r
1039 UINT32 TestCounter;\r
1040 UINT32 TestSize;\r
1041 BOOLEAN RetValue;\r
1042\r
1043 RetValue = FALSE;\r
1044\r
1045 //\r
1046 // Look at the capsule data and determine if it's a test pattern. If it\r
1047 // is, then test it now.\r
1048 //\r
1049 TestPtr = (UINT32 *) CapsuleBase;\r
ab7017fe 1050 //\r
1051 // 0x54534554 "TEST"\r
1052 //\r
1053 if (*TestPtr == 0x54534554) {\r
da58b0db 1054 RetValue = TRUE;\r
1055 DEBUG ((EFI_D_INFO, "Capsule test pattern mode activated...\n"));\r
1056 TestSize = TestPtr[1] / sizeof (UINT32);\r
1057 //\r
1058 // Skip over the signature and the size fields in the pattern data header\r
1059 //\r
1060 TestPtr += 2;\r
1061 TestCounter = 0;\r
1062 while (TestSize > 0) {\r
1063 if (*TestPtr != TestCounter) {\r
1064 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
1065 return TRUE;\r
1066 }\r
1067\r
1068 TestPtr++;\r
1069 TestCounter++;\r
1070 TestSize--;\r
1071 }\r
1072\r
1073 DEBUG ((EFI_D_INFO, "Capsule test pattern mode SUCCESS\n"));\r
1074 }\r
1075\r
1076 return RetValue;\r
1077}\r
1078\r
1079/**\r
1080 Capsule PPI service that gets called after memory is available. The\r
1081 capsule coalesce function, which must be called first, returns a base\r
1082 address and size, which can be anything actually. Once the memory init\r
1083 PEIM has discovered memory, then it should call this function and pass in\r
1084 the base address and size returned by the coalesce function. Then this\r
1085 function can create a capsule HOB and return.\r
1086\r
1087 @param PeiServices standard pei services pointer\r
1088 @param CapsuleBase address returned by the capsule coalesce function. Most\r
1089 likely this will actually be a pointer to private data.\r
1090 @param CapsuleSize value returned by the capsule coalesce function.\r
1091\r
1092 @retval EFI_VOLUME_CORRUPTED CapsuleBase does not appear to point to a\r
1093 coalesced capsule\r
1094 @retval EFI_SUCCESS if all goes well.\r
1095**/\r
1096EFI_STATUS\r
1097EFIAPI\r
1098CreateState (\r
1099 IN EFI_PEI_SERVICES **PeiServices,\r
1100 IN VOID *CapsuleBase,\r
1101 IN UINTN CapsuleSize\r
1102 )\r
1103{\r
1104 EFI_STATUS Status;\r
1105 EFI_CAPSULE_PEIM_PRIVATE_DATA *PrivateData;\r
1106 UINTN Size;\r
1107 EFI_PHYSICAL_ADDRESS NewBuffer;\r
ff284c56 1108 UINTN CapsuleNumber;\r
da58b0db 1109 UINT32 Index;\r
1110 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1111 UINT64 Length;\r
1112 \r
da58b0db 1113 PrivateData = (EFI_CAPSULE_PEIM_PRIVATE_DATA *) CapsuleBase;\r
1114 if (PrivateData->Signature != EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE) {\r
1115 return EFI_VOLUME_CORRUPTED;\r
1116 }\r
ff284c56
JY
1117 if (PrivateData->CapsuleAllImageSize >= MAX_ADDRESS) {\r
1118 DEBUG ((EFI_D_ERROR, "CapsuleAllImageSize too big - 0x%lx\n", PrivateData->CapsuleAllImageSize));\r
1119 return EFI_OUT_OF_RESOURCES;\r
1120 }\r
1121 if (PrivateData->CapsuleNumber >= MAX_ADDRESS) {\r
1122 DEBUG ((EFI_D_ERROR, "CapsuleNumber too big - 0x%lx\n", PrivateData->CapsuleNumber));\r
1123 return EFI_OUT_OF_RESOURCES;\r
1124 }\r
da58b0db 1125 //\r
1126 // Capsule Number and Capsule Offset is in the tail of Capsule data.\r
1127 //\r
ff284c56
JY
1128 Size = (UINTN)PrivateData->CapsuleAllImageSize;\r
1129 CapsuleNumber = (UINTN)PrivateData->CapsuleNumber;\r
da58b0db 1130 //\r
1131 // Allocate the memory so that it gets preserved into DXE\r
1132 //\r
1133 Status = PeiServicesAllocatePages (\r
1134 EfiRuntimeServicesData,\r
1135 EFI_SIZE_TO_PAGES (Size),\r
1136 &NewBuffer\r
1137 );\r
1138\r
1139 if (Status != EFI_SUCCESS) {\r
1140 DEBUG ((EFI_D_ERROR, "AllocatePages Failed!\n"));\r
1141 return Status;\r
1142 }\r
1143 //\r
1144 // Copy to our new buffer for DXE\r
1145 //\r
ff284c56
JY
1146 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
1147 CopyMem ((VOID *) (UINTN) NewBuffer, (VOID *) (UINTN) ((UINT8 *)PrivateData + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64)), Size);\r
da58b0db 1148 //\r
1149 // Check for test data pattern. If it is the test pattern, then we'll\r
ed3ff1ac 1150 // test it and still create the HOB so that it can be used to verify\r
da58b0db 1151 // that capsules don't get corrupted all the way into BDS. BDS will\r
1152 // still try to turn it into a firmware volume, but will think it's\r
1153 // corrupted so nothing will happen.\r
1154 //\r
1155 DEBUG_CODE (\r
1156 CapsuleTestPattern (PeiServices, (VOID *) (UINTN) NewBuffer);\r
1157 );\r
1158\r
1159 //\r
1160 // Build the UEFI Capsule Hob for each capsule image.\r
1161 //\r
1162 for (Index = 0; Index < CapsuleNumber; Index ++) {\r
ff284c56 1163 BaseAddress = NewBuffer + PrivateData->CapsuleOffset[Index];\r
da58b0db 1164 Length = ((EFI_CAPSULE_HEADER *)((UINTN) BaseAddress))->CapsuleImageSize;\r
1165\r
1166 BuildCvHob (BaseAddress, Length);\r
1167 }\r
1168 \r
1169 return EFI_SUCCESS;\r
1170}\r
1171\r
09d46995 1172CONST EFI_PEI_CAPSULE_PPI mCapsulePpi = {\r
da58b0db 1173 CapsuleCoalesce,\r
1174 CheckCapsuleUpdate,\r
1175 CreateState\r
1176};\r
1177\r
1178CONST EFI_PEI_PPI_DESCRIPTOR mUefiPpiListCapsule = {\r
1179 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
09d46995
LG
1180 &gEfiPeiCapsulePpiGuid,\r
1181 (EFI_PEI_CAPSULE_PPI *) &mCapsulePpi\r
da58b0db 1182};\r
1183\r
1184/**\r
1185 Entry point function for the PEIM\r
1186\r
1187 @param FileHandle Handle of the file being invoked.\r
1188 @param PeiServices Describes the list of possible PEI Services.\r
1189\r
1190 @return EFI_SUCCESS If we installed our PPI\r
1191\r
1192**/\r
1193EFI_STATUS\r
1194EFIAPI\r
1195CapsuleMain (\r
1196 IN EFI_PEI_FILE_HANDLE FileHandle,\r
1197 IN CONST EFI_PEI_SERVICES **PeiServices\r
1198 )\r
1199{\r
1200 //\r
1201 // Just produce our PPI\r
1202 //\r
1203 return PeiServicesInstallPpi (&mUefiPpiListCapsule);\r
1204}\r