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