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