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