]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/CapsulePei/Common/CapsuleCoalesce.c
MdeModulePkg: Add missing header files in INF files
[mirror_edk2.git] / MdeModulePkg / Universal / CapsulePei / Common / CapsuleCoalesce.c
CommitLineData
ab7017fe 1/** @file\r
2 The logic to process capsule.\r
3\r
dc204d5a
JY
4 Caution: This module requires additional review when modified.\r
5 This driver will have external input - capsule image.\r
6 This external input must be validated carefully to avoid security issue like\r
7 buffer overflow, integer overflow.\r
8\r
9 CapsuleDataCoalesce() will do basic validation before coalesce capsule data\r
10 into memory.\r
11\r
35f910f0 12(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
d1102dba 13Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 14SPDX-License-Identifier: BSD-2-Clause-Patent\r
ab7017fe 15\r
16**/\r
17\r
18#include <Uefi.h>\r
19#include <PiPei.h>\r
20\r
21#include <Guid/CapsuleVendor.h>\r
22\r
23#include <Library/BaseMemoryLib.h>\r
24#include <Library/DebugLib.h>\r
25#include <Library/PrintLib.h>\r
26#include <Library/BaseLib.h>\r
27\r
ff284c56 28#include "CommonHeader.h"\r
ab7017fe 29\r
ff284c56 30#define MIN_COALESCE_ADDR (1024 * 1024)\r
ab7017fe 31\r
32/**\r
33 Given a pointer to the capsule block list, info on the available system\r
34 memory, and the size of a buffer, find a free block of memory where a\r
35 buffer of the given size can be copied to safely.\r
36\r
37 @param BlockList Pointer to head of capsule block descriptors\r
38 @param MemBase Pointer to the base of memory in which we want to find free space\r
39 @param MemSize The size of the block of memory pointed to by MemBase\r
40 @param DataSize How big a free block we want to find\r
41\r
d1102dba 42 @return A pointer to a memory block of at least DataSize that lies somewhere\r
ab7017fe 43 between MemBase and (MemBase + MemSize). The memory pointed to does not\r
44 contain any of the capsule block descriptors or capsule blocks pointed to\r
45 by the BlockList.\r
46\r
47**/\r
48UINT8 *\r
49FindFreeMem (\r
50 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,\r
51 UINT8 *MemBase,\r
52 UINTN MemSize,\r
53 UINTN DataSize\r
54 );\r
55\r
ab7017fe 56/**\r
57 The capsule block descriptors may be fragmented and spread all over memory.\r
58 To simplify the coalescing of capsule blocks, first coalesce all the\r
59 capsule block descriptors low in memory.\r
60\r
61 The descriptors passed in can be fragmented throughout memory. Here\r
62 they are relocated into memory to turn them into a contiguous (null\r
63 terminated) array.\r
64\r
ff284c56
JY
65 @param PeiServices pointer to PEI services table\r
66 @param BlockList pointer to the capsule block descriptors\r
67 @param NumDescriptors number of capsule data block descriptors, whose Length is non-zero.\r
68 @param MemBase base of system memory in which we can work\r
69 @param MemSize size of the system memory pointed to by MemBase\r
ab7017fe 70\r
71 @retval NULL could not relocate the descriptors\r
d1102dba 72 @retval Pointer to the base of the successfully-relocated block descriptors.\r
ab7017fe 73\r
74**/\r
75EFI_CAPSULE_BLOCK_DESCRIPTOR *\r
76RelocateBlockDescriptors (\r
77 IN EFI_PEI_SERVICES **PeiServices,\r
78 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,\r
ff284c56 79 IN UINTN NumDescriptors,\r
ab7017fe 80 IN UINT8 *MemBase,\r
81 IN UINTN MemSize\r
82 );\r
83\r
84/**\r
85 Check every capsule header.\r
86\r
87 @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER\r
88\r
89 @retval FALSE Capsule is OK\r
d1102dba 90 @retval TRUE Capsule is corrupted\r
ab7017fe 91\r
92**/\r
93BOOLEAN\r
94IsCapsuleCorrupted (\r
95 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
96 );\r
97\r
98/**\r
99 Determine if two buffers overlap in memory.\r
100\r
101 @param Buff1 pointer to first buffer\r
102 @param Size1 size of Buff1\r
103 @param Buff2 pointer to second buffer\r
104 @param Size2 size of Buff2\r
105\r
106 @retval TRUE Buffers overlap in memory.\r
107 @retval FALSE Buffer doesn't overlap.\r
108\r
109**/\r
110BOOLEAN\r
111IsOverlapped (\r
112 UINT8 *Buff1,\r
113 UINTN Size1,\r
114 UINT8 *Buff2,\r
115 UINTN Size2\r
116 );\r
117\r
118/**\r
119 Given a pointer to a capsule block descriptor, traverse the list to figure\r
120 out how many legitimate descriptors there are, and how big the capsule it\r
121 refers to is.\r
122\r
123 @param Desc Pointer to the capsule block descriptors\r
ff284c56
JY
124 @param NumDescriptors Optional pointer to where to return the number of capsule data descriptors, whose Length is non-zero.\r
125 @param CapsuleSize Optional pointer to where to return the capsule image size\r
126 @param CapsuleNumber Optional pointer to where to return the number of capsule\r
ab7017fe 127\r
128 @retval EFI_NOT_FOUND No descriptors containing data in the list\r
129 @retval EFI_SUCCESS Return data is valid\r
130\r
131**/\r
132EFI_STATUS\r
133GetCapsuleInfo (\r
134 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc,\r
135 IN OUT UINTN *NumDescriptors OPTIONAL,\r
ff284c56
JY
136 IN OUT UINTN *CapsuleSize OPTIONAL,\r
137 IN OUT UINTN *CapsuleNumber OPTIONAL\r
ab7017fe 138 );\r
139\r
140/**\r
141 Given a pointer to the capsule block list, info on the available system\r
142 memory, and the size of a buffer, find a free block of memory where a\r
143 buffer of the given size can be copied to safely.\r
144\r
145 @param BlockList Pointer to head of capsule block descriptors\r
146 @param MemBase Pointer to the base of memory in which we want to find free space\r
147 @param MemSize The size of the block of memory pointed to by MemBase\r
148 @param DataSize How big a free block we want to find\r
149\r
d1102dba 150 @return A pointer to a memory block of at least DataSize that lies somewhere\r
ab7017fe 151 between MemBase and (MemBase + MemSize). The memory pointed to does not\r
152 contain any of the capsule block descriptors or capsule blocks pointed to\r
153 by the BlockList.\r
154\r
155**/\r
156UINT8 *\r
157FindFreeMem (\r
158 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,\r
159 UINT8 *MemBase,\r
160 UINTN MemSize,\r
161 UINTN DataSize\r
162 )\r
163{\r
164 UINTN Size;\r
165 EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrDesc;\r
166 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempDesc;\r
167 UINT8 *MemEnd;\r
168 BOOLEAN Failed;\r
169\r
170 //\r
171 // Need at least enough to copy the data to at the end of the buffer, so\r
172 // say the end is less the data size for easy comparisons here.\r
173 //\r
174 MemEnd = MemBase + MemSize - DataSize;\r
175 CurrDesc = BlockList;\r
176 //\r
177 // Go through all the descriptor blocks and see if any obstruct the range\r
178 //\r
179 while (CurrDesc != NULL) {\r
180 //\r
181 // Get the size of this block list and see if it's in the way\r
182 //\r
183 Failed = FALSE;\r
184 TempDesc = CurrDesc;\r
185 Size = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
186 while (TempDesc->Length != 0) {\r
187 Size += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
188 TempDesc++;\r
189 }\r
190\r
191 if (IsOverlapped (MemBase, DataSize, (UINT8 *) CurrDesc, Size)) {\r
192 //\r
193 // Set our new base to the end of this block list and start all over\r
194 //\r
195 MemBase = (UINT8 *) CurrDesc + Size;\r
196 CurrDesc = BlockList;\r
197 if (MemBase > MemEnd) {\r
198 return NULL;\r
199 }\r
200\r
201 Failed = TRUE;\r
202 }\r
203 //\r
204 // Now go through all the blocks and make sure none are in the way\r
205 //\r
206 while ((CurrDesc->Length != 0) && (!Failed)) {\r
207 if (IsOverlapped (MemBase, DataSize, (UINT8 *) (UINTN) CurrDesc->Union.DataBlock, (UINTN) CurrDesc->Length)) {\r
208 //\r
209 // Set our new base to the end of this block and start all over\r
210 //\r
211 Failed = TRUE;\r
212 MemBase = (UINT8 *) ((UINTN) CurrDesc->Union.DataBlock) + CurrDesc->Length;\r
213 CurrDesc = BlockList;\r
214 if (MemBase > MemEnd) {\r
215 return NULL;\r
216 }\r
217 }\r
218 CurrDesc++;\r
219 }\r
220 //\r
221 // Normal continuation -- jump to next block descriptor list\r
222 //\r
223 if (!Failed) {\r
224 CurrDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) CurrDesc->Union.ContinuationPointer;\r
225 }\r
226 }\r
227 return MemBase;\r
228}\r
229\r
359cb1a3
SZ
230/**\r
231 Validate capsule by MemoryResource.\r
232\r
233 @param MemoryResource Pointer to the buffer of memory resource descriptor.\r
234 @param Address Address to be validated.\r
235 @param Size Size to be validated.\r
236\r
237 @retval TRUE No memory resource descriptor reported in HOB list before capsule Coalesce,\r
238 or it is valid in one MemoryResource.\r
239 FALSE It is not in any MemoryResource.\r
240\r
241**/\r
242BOOLEAN\r
243ValidateCapsuleByMemoryResource (\r
244 IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource,\r
245 IN EFI_PHYSICAL_ADDRESS Address,\r
246 IN UINT64 Size\r
247 )\r
248{\r
249 UINTN Index;\r
250\r
251 //\r
252 // Sanity Check\r
253 //\r
254 if (Size > MAX_ADDRESS) {\r
85b01932 255 DEBUG ((DEBUG_ERROR, "ERROR: Size(0x%lx) > MAX_ADDRESS\n", Size));\r
359cb1a3
SZ
256 return FALSE;\r
257 }\r
258\r
259 //\r
260 // Sanity Check\r
261 //\r
262 if (Address > (MAX_ADDRESS - Size)) {\r
85b01932 263 DEBUG ((DEBUG_ERROR, "ERROR: Address(0x%lx) > (MAX_ADDRESS - Size(0x%lx))\n", Address, Size));\r
359cb1a3
SZ
264 return FALSE;\r
265 }\r
266\r
267 if (MemoryResource == NULL) {\r
268 //\r
269 // No memory resource descriptor reported in HOB list before capsule Coalesce.\r
270 //\r
271 return TRUE;\r
272 }\r
273\r
274 for (Index = 0; MemoryResource[Index].ResourceLength != 0; Index++) {\r
275 if ((Address >= MemoryResource[Index].PhysicalStart) &&\r
276 ((Address + Size) <= (MemoryResource[Index].PhysicalStart + MemoryResource[Index].ResourceLength))) {\r
85b01932 277 DEBUG ((DEBUG_INFO, "Address(0x%lx) Size(0x%lx) in MemoryResource[0x%x] - Start(0x%lx) Length(0x%lx)\n",\r
359cb1a3
SZ
278 Address, Size,\r
279 Index, MemoryResource[Index].PhysicalStart, MemoryResource[Index].ResourceLength));\r
280 return TRUE;\r
281 }\r
282 }\r
283\r
85b01932 284 DEBUG ((DEBUG_ERROR, "ERROR: Address(0x%lx) Size(0x%lx) not in any MemoryResource\n", Address, Size));\r
359cb1a3
SZ
285 return FALSE;\r
286}\r
287\r
ab7017fe 288/**\r
289 Check the integrity of the capsule descriptors.\r
290\r
359cb1a3
SZ
291 @param BlockList Pointer to the capsule descriptors\r
292 @param MemoryResource Pointer to the buffer of memory resource descriptor.\r
ab7017fe 293\r
294 @retval NULL BlockList is not valid.\r
295 @retval LastBlockDesc Last one Block in BlockList\r
296\r
297**/\r
298EFI_CAPSULE_BLOCK_DESCRIPTOR *\r
299ValidateCapsuleIntegrity (\r
359cb1a3
SZ
300 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,\r
301 IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource\r
ab7017fe 302 )\r
303{\r
304 EFI_CAPSULE_HEADER *CapsuleHeader;\r
305 UINT64 CapsuleSize;\r
ff284c56 306 UINTN CapsuleCount;\r
ab7017fe 307 EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr;\r
308\r
85b01932 309 DEBUG ((DEBUG_INFO, "ValidateCapsuleIntegrity\n"));\r
ff284c56 310\r
ab7017fe 311 //\r
312 // Go through the list to look for inconsistencies. Check for:\r
313 // * misaligned block descriptors.\r
314 // * The first capsule header guid\r
315 // * The first capsule header flag\r
ff284c56 316 // * The first capsule header HeaderSize\r
359cb1a3 317 // * Below check will be done in ValidateCapsuleByMemoryResource()\r
d1102dba 318 // Length > MAX_ADDRESS\r
359cb1a3
SZ
319 // Ptr + sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR) > MAX_ADDRESS\r
320 // DataBlock + Length > MAX_ADDRESS\r
ff284c56 321 //\r
ab7017fe 322 CapsuleSize = 0;\r
323 CapsuleCount = 0;\r
324 Ptr = BlockList;\r
ff284c56 325\r
359cb1a3
SZ
326 if (!ValidateCapsuleByMemoryResource (MemoryResource, (EFI_PHYSICAL_ADDRESS) (UINTN) Ptr, sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR))) {\r
327 return NULL;\r
328 }\r
329\r
42d8be0e
BB
330 DEBUG ((DEBUG_INFO, "Ptr - 0x%p\n", Ptr));\r
331 DEBUG ((DEBUG_INFO, "Ptr->Length - 0x%lx\n", Ptr->Length));\r
332 DEBUG ((DEBUG_INFO, "Ptr->Union - 0x%lx\n", Ptr->Union.ContinuationPointer));\r
ab7017fe 333 while ((Ptr->Length != 0) || (Ptr->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {\r
334 //\r
335 // Make sure the descriptor is aligned at UINT64 in memory\r
336 //\r
ff284c56 337 if ((UINTN) Ptr & (sizeof(UINT64) - 1)) {\r
85b01932 338 DEBUG ((DEBUG_ERROR, "ERROR: BlockList address failed alignment check\n"));\r
ff284c56
JY
339 return NULL;\r
340 }\r
ab7017fe 341\r
342 if (Ptr->Length == 0) {\r
343 //\r
344 // Descriptor points to another list of block descriptors somewhere\r
345 // else.\r
346 //\r
347 Ptr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Ptr->Union.ContinuationPointer;\r
359cb1a3
SZ
348 if (!ValidateCapsuleByMemoryResource (MemoryResource, (EFI_PHYSICAL_ADDRESS) (UINTN) Ptr, sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR))) {\r
349 return NULL;\r
350 }\r
42d8be0e
BB
351 DEBUG ((DEBUG_INFO, "Ptr(C) - 0x%p\n", Ptr));\r
352 DEBUG ((DEBUG_INFO, "Ptr->Length - 0x%lx\n", Ptr->Length));\r
353 DEBUG ((DEBUG_INFO, "Ptr->Union - 0x%lx\n", Ptr->Union.ContinuationPointer));\r
ab7017fe 354 } else {\r
359cb1a3 355 if (!ValidateCapsuleByMemoryResource (MemoryResource, Ptr->Union.DataBlock, Ptr->Length)) {\r
ff284c56
JY
356 return NULL;\r
357 }\r
358\r
ab7017fe 359 //\r
360 //To enhance the reliability of check-up, the first capsule's header is checked here.\r
361 //More reliabilities check-up will do later.\r
362 //\r
363 if (CapsuleSize == 0) {\r
364 //\r
365 //Move to the first capsule to check its header.\r
366 //\r
367 CapsuleHeader = (EFI_CAPSULE_HEADER*)((UINTN)Ptr->Union.DataBlock);\r
ff284c56
JY
368 //\r
369 // Sanity check\r
370 //\r
371 if (Ptr->Length < sizeof(EFI_CAPSULE_HEADER)) {\r
85b01932 372 DEBUG ((DEBUG_ERROR, "ERROR: Ptr->Length(0x%lx) < sizeof(EFI_CAPSULE_HEADER)\n", Ptr->Length));\r
ff284c56
JY
373 return NULL;\r
374 }\r
375 //\r
376 // Make sure HeaderSize field is valid\r
377 //\r
378 if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) {\r
85b01932 379 DEBUG ((DEBUG_ERROR, "ERROR: CapsuleHeader->HeaderSize(0x%x) > CapsuleHeader->CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));\r
ff284c56
JY
380 return NULL;\r
381 }\r
ab7017fe 382 if (IsCapsuleCorrupted (CapsuleHeader)) {\r
383 return NULL;\r
384 }\r
385 CapsuleCount ++;\r
386 CapsuleSize = CapsuleHeader->CapsuleImageSize;\r
240bc4ee
SZ
387 }\r
388\r
389 if (CapsuleSize >= Ptr->Length) {\r
390 CapsuleSize = CapsuleSize - Ptr->Length;\r
ab7017fe 391 } else {\r
85b01932 392 DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize(0x%lx) < Ptr->Length(0x%lx)\n", CapsuleSize, Ptr->Length));\r
ff284c56
JY
393 //\r
394 // Sanity check\r
395 //\r
396 return NULL;\r
ab7017fe 397 }\r
240bc4ee 398\r
ab7017fe 399 //\r
400 // Move to next BLOCK descriptor\r
401 //\r
402 Ptr++;\r
359cb1a3
SZ
403 if (!ValidateCapsuleByMemoryResource (MemoryResource, (EFI_PHYSICAL_ADDRESS) (UINTN) Ptr, sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR))) {\r
404 return NULL;\r
405 }\r
42d8be0e
BB
406 DEBUG ((DEBUG_INFO, "Ptr(B) - 0x%p\n", Ptr));\r
407 DEBUG ((DEBUG_INFO, "Ptr->Length - 0x%lx\n", Ptr->Length));\r
408 DEBUG ((DEBUG_INFO, "Ptr->Union - 0x%lx\n", Ptr->Union.ContinuationPointer));\r
ab7017fe 409 }\r
410 }\r
411\r
ff284c56 412 if (CapsuleCount == 0) {\r
ab7017fe 413 //\r
ff284c56 414 // No any capsule is found in BlockList\r
ab7017fe 415 //\r
85b01932 416 DEBUG ((DEBUG_ERROR, "ERROR: CapsuleCount(0x%x) == 0\n", CapsuleCount));\r
ff284c56
JY
417 return NULL;\r
418 }\r
419\r
420 if (CapsuleSize != 0) {\r
421 //\r
422 // Capsule data is incomplete.\r
423 //\r
85b01932 424 DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize(0x%lx) != 0\n", CapsuleSize));\r
ab7017fe 425 return NULL;\r
426 }\r
427\r
428 return Ptr;\r
429}\r
430\r
431/**\r
432 The capsule block descriptors may be fragmented and spread all over memory.\r
433 To simplify the coalescing of capsule blocks, first coalesce all the\r
434 capsule block descriptors low in memory.\r
435\r
436 The descriptors passed in can be fragmented throughout memory. Here\r
437 they are relocated into memory to turn them into a contiguous (null\r
438 terminated) array.\r
439\r
ff284c56
JY
440 @param PeiServices pointer to PEI services table\r
441 @param BlockList pointer to the capsule block descriptors\r
442 @param NumDescriptors number of capsule data block descriptors, whose Length is non-zero.\r
443 @param MemBase base of system memory in which we can work\r
444 @param MemSize size of the system memory pointed to by MemBase\r
ab7017fe 445\r
446 @retval NULL could not relocate the descriptors\r
d1102dba 447 @retval Pointer to the base of the successfully-relocated block descriptors.\r
ab7017fe 448\r
449**/\r
450EFI_CAPSULE_BLOCK_DESCRIPTOR *\r
451RelocateBlockDescriptors (\r
452 IN EFI_PEI_SERVICES **PeiServices,\r
453 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,\r
ff284c56 454 IN UINTN NumDescriptors,\r
ab7017fe 455 IN UINT8 *MemBase,\r
456 IN UINTN MemSize\r
457 )\r
458{\r
459 EFI_CAPSULE_BLOCK_DESCRIPTOR *NewBlockList;\r
460 EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrBlockDescHead;\r
461 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc;\r
462 EFI_CAPSULE_BLOCK_DESCRIPTOR *PrevBlockDescTail;\r
ab7017fe 463 UINTN BufferSize;\r
464 UINT8 *RelocBuffer;\r
465 UINTN BlockListSize;\r
ff284c56 466\r
ab7017fe 467 //\r
468 // Get the info on the blocks and descriptors. Since we're going to move\r
469 // the descriptors low in memory, adjust the base/size values accordingly here.\r
ff284c56
JY
470 // NumDescriptors is the number of legit data descriptors, so add one for\r
471 // a terminator. (Already done by caller, no check is needed.)\r
ab7017fe 472 //\r
ab7017fe 473\r
ab7017fe 474 BufferSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
475 NewBlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) MemBase;\r
476 if (MemSize < BufferSize) {\r
477 return NULL;\r
478 }\r
479\r
480 MemSize -= BufferSize;\r
481 MemBase += BufferSize;\r
482 //\r
483 // Go through all the blocks and make sure none are in the way\r
484 //\r
485 TempBlockDesc = BlockList;\r
486 while (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {\r
487 if (TempBlockDesc->Length == 0) {\r
488 //\r
489 // Next block of descriptors\r
490 //\r
491 TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;\r
492 } else {\r
493 //\r
494 // If the capsule data pointed to by this descriptor is in the way,\r
495 // move it.\r
496 //\r
497 if (IsOverlapped (\r
498 (UINT8 *) NewBlockList,\r
499 BufferSize,\r
500 (UINT8 *) (UINTN) TempBlockDesc->Union.DataBlock,\r
501 (UINTN) TempBlockDesc->Length\r
502 )) {\r
503 //\r
504 // Relocate the block\r
505 //\r
506 RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, (UINTN) TempBlockDesc->Length);\r
507 if (RelocBuffer == NULL) {\r
508 return NULL;\r
509 }\r
510\r
511 CopyMem ((VOID *) RelocBuffer, (VOID *) (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) TempBlockDesc->Length);\r
85b01932 512 DEBUG ((DEBUG_INFO, "Capsule relocate descriptors from/to/size 0x%lX 0x%lX 0x%lX\n", TempBlockDesc->Union.DataBlock, (UINT64)(UINTN)RelocBuffer, TempBlockDesc->Length));\r
5d4f8cf3 513 TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocBuffer;\r
ab7017fe 514 }\r
5d4f8cf3 515 TempBlockDesc++;\r
ab7017fe 516 }\r
ab7017fe 517 }\r
518 //\r
519 // Now go through all the block descriptors to make sure that they're not\r
520 // in the memory region we want to copy them to.\r
521 //\r
522 CurrBlockDescHead = BlockList;\r
523 PrevBlockDescTail = NULL;\r
524 while ((CurrBlockDescHead != NULL) && (CurrBlockDescHead->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {\r
525 //\r
526 // Get the size of this list then see if it overlaps our low region\r
527 //\r
528 TempBlockDesc = CurrBlockDescHead;\r
529 BlockListSize = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
530 while (TempBlockDesc->Length != 0) {\r
531 BlockListSize += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
532 TempBlockDesc++;\r
533 }\r
534\r
535 if (IsOverlapped (\r
536 (UINT8 *) NewBlockList,\r
537 BufferSize,\r
538 (UINT8 *) CurrBlockDescHead,\r
539 BlockListSize\r
540 )) {\r
541 //\r
542 // Overlaps, so move it out of the way\r
543 //\r
544 RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, BlockListSize);\r
545 if (RelocBuffer == NULL) {\r
546 return NULL;\r
547 }\r
548 CopyMem ((VOID *) RelocBuffer, (VOID *) CurrBlockDescHead, BlockListSize);\r
85b01932 549 DEBUG ((DEBUG_INFO, "Capsule reloc descriptor block #2\n"));\r
ab7017fe 550 //\r
551 // Point the previous block's next point to this copied version. If\r
552 // the tail pointer is null, then this is the first descriptor block.\r
553 //\r
554 if (PrevBlockDescTail == NULL) {\r
555 BlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) RelocBuffer;\r
556 } else {\r
557 PrevBlockDescTail->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocBuffer;\r
558 }\r
559 }\r
560 //\r
561 // Save our new tail and jump to the next block list\r
562 //\r
563 PrevBlockDescTail = TempBlockDesc;\r
564 CurrBlockDescHead = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;\r
565 }\r
566 //\r
567 // Cleared out low memory. Now copy the descriptors down there.\r
568 //\r
569 TempBlockDesc = BlockList;\r
570 CurrBlockDescHead = NewBlockList;\r
571 while ((TempBlockDesc != NULL) && (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {\r
572 if (TempBlockDesc->Length != 0) {\r
573 CurrBlockDescHead->Union.DataBlock = TempBlockDesc->Union.DataBlock;\r
574 CurrBlockDescHead->Length = TempBlockDesc->Length;\r
575 CurrBlockDescHead++;\r
576 TempBlockDesc++;\r
577 } else {\r
578 TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;\r
579 }\r
580 }\r
581 //\r
582 // Null terminate\r
583 //\r
584 CurrBlockDescHead->Union.ContinuationPointer = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;\r
585 CurrBlockDescHead->Length = 0;\r
586 return NewBlockList;\r
587}\r
588\r
589/**\r
590 Determine if two buffers overlap in memory.\r
591\r
592 @param Buff1 pointer to first buffer\r
593 @param Size1 size of Buff1\r
594 @param Buff2 pointer to second buffer\r
595 @param Size2 size of Buff2\r
596\r
597 @retval TRUE Buffers overlap in memory.\r
598 @retval FALSE Buffer doesn't overlap.\r
599\r
600**/\r
601BOOLEAN\r
602IsOverlapped (\r
603 UINT8 *Buff1,\r
604 UINTN Size1,\r
605 UINT8 *Buff2,\r
606 UINTN Size2\r
607 )\r
608{\r
609 //\r
610 // If buff1's end is less than the start of buff2, then it's ok.\r
611 // Also, if buff1's start is beyond buff2's end, then it's ok.\r
612 //\r
613 if (((Buff1 + Size1) <= Buff2) || (Buff1 >= (Buff2 + Size2))) {\r
614 return FALSE;\r
615 }\r
616\r
617 return TRUE;\r
618}\r
619\r
620/**\r
621 Given a pointer to a capsule block descriptor, traverse the list to figure\r
622 out how many legitimate descriptors there are, and how big the capsule it\r
623 refers to is.\r
624\r
625 @param Desc Pointer to the capsule block descriptors\r
ff284c56
JY
626 @param NumDescriptors Optional pointer to where to return the number of capsule data descriptors, whose Length is non-zero.\r
627 @param CapsuleSize Optional pointer to where to return the capsule image size\r
628 @param CapsuleNumber Optional pointer to where to return the number of capsule\r
ab7017fe 629\r
630 @retval EFI_NOT_FOUND No descriptors containing data in the list\r
631 @retval EFI_SUCCESS Return data is valid\r
632\r
633**/\r
634EFI_STATUS\r
635GetCapsuleInfo (\r
636 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc,\r
637 IN OUT UINTN *NumDescriptors OPTIONAL,\r
ff284c56
JY
638 IN OUT UINTN *CapsuleSize OPTIONAL,\r
639 IN OUT UINTN *CapsuleNumber OPTIONAL\r
ab7017fe 640 )\r
641{\r
ff284c56
JY
642 UINTN Count;\r
643 UINTN Size;\r
644 UINTN Number;\r
645 UINTN ThisCapsuleImageSize;\r
646 EFI_CAPSULE_HEADER *CapsuleHeader;\r
647\r
85b01932 648 DEBUG ((DEBUG_INFO, "GetCapsuleInfo enter\n"));\r
ab7017fe 649\r
f63085f5 650 ASSERT (Desc != NULL);\r
651\r
ab7017fe 652 Count = 0;\r
653 Size = 0;\r
ff284c56
JY
654 Number = 0;\r
655 ThisCapsuleImageSize = 0;\r
ab7017fe 656\r
657 while (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {\r
658 if (Desc->Length == 0) {\r
659 //\r
660 // Descriptor points to another list of block descriptors somewhere\r
661 //\r
662 Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;\r
663 } else {\r
ff284c56
JY
664 //\r
665 // Sanity Check\r
666 // It is needed, because ValidateCapsuleIntegrity() only validate one individual capsule Size.\r
667 // While here we need check all capsules size.\r
668 //\r
669 if (Desc->Length >= (MAX_ADDRESS - Size)) {\r
85b01932 670 DEBUG ((DEBUG_ERROR, "ERROR: Desc->Length(0x%lx) >= (MAX_ADDRESS - Size(0x%x))\n", Desc->Length, Size));\r
ff284c56
JY
671 return EFI_OUT_OF_RESOURCES;\r
672 }\r
ab7017fe 673 Size += (UINTN) Desc->Length;\r
674 Count++;\r
ff284c56
JY
675\r
676 //\r
677 // See if this is first capsule's header\r
678 //\r
679 if (ThisCapsuleImageSize == 0) {\r
680 CapsuleHeader = (EFI_CAPSULE_HEADER*)((UINTN)Desc->Union.DataBlock);\r
681 //\r
682 // This has been checked in ValidateCapsuleIntegrity()\r
683 //\r
684 Number ++;\r
685 ThisCapsuleImageSize = CapsuleHeader->CapsuleImageSize;\r
686 }\r
687\r
688 //\r
689 // This has been checked in ValidateCapsuleIntegrity()\r
690 //\r
691 ASSERT (ThisCapsuleImageSize >= Desc->Length);\r
692 ThisCapsuleImageSize = (UINTN)(ThisCapsuleImageSize - Desc->Length);\r
693\r
694 //\r
695 // Move to next\r
696 //\r
ab7017fe 697 Desc++;\r
698 }\r
699 }\r
700 //\r
701 // If no descriptors, then fail\r
702 //\r
703 if (Count == 0) {\r
85b01932 704 DEBUG ((DEBUG_ERROR, "ERROR: Count == 0\n"));\r
ab7017fe 705 return EFI_NOT_FOUND;\r
706 }\r
707\r
ff284c56
JY
708 //\r
709 // checked in ValidateCapsuleIntegrity()\r
710 //\r
711 ASSERT (ThisCapsuleImageSize == 0);\r
712\r
ab7017fe 713 if (NumDescriptors != NULL) {\r
714 *NumDescriptors = Count;\r
715 }\r
716\r
717 if (CapsuleSize != NULL) {\r
718 *CapsuleSize = Size;\r
719 }\r
720\r
ff284c56
JY
721 if (CapsuleNumber != NULL) {\r
722 *CapsuleNumber = Number;\r
723 }\r
724\r
ab7017fe 725 return EFI_SUCCESS;\r
726}\r
727\r
728/**\r
729 Check every capsule header.\r
730\r
731 @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER\r
732\r
733 @retval FALSE Capsule is OK\r
d1102dba 734 @retval TRUE Capsule is corrupted\r
ab7017fe 735\r
736**/\r
737BOOLEAN\r
738IsCapsuleCorrupted (\r
739 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
740 )\r
741{\r
742 //\r
743 //A capsule to be updated across a system reset should contain CAPSULE_FLAGS_PERSIST_ACROSS_RESET.\r
744 //\r
745 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) {\r
746 return TRUE;\r
747 }\r
748 //\r
749 //Make sure the flags combination is supported by the platform.\r
750 //\r
751 if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {\r
752 return TRUE;\r
753 }\r
754 if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {\r
755 return TRUE;\r
756 }\r
757\r
758 return FALSE;\r
759}\r
760\r
761/**\r
762 Try to verify the integrity of a capsule test pattern before the\r
763 capsule gets coalesced. This can be useful in narrowing down\r
764 where capsule data corruption occurs.\r
765\r
d1102dba 766 The test pattern mode fills in memory with a counting UINT32 value.\r
ab7017fe 767 If the capsule is not divided up in a multiple of 4-byte blocks, then\r
768 things get messy doing the check. Therefore there are some cases\r
769 here where we just give up and skip the pre-coalesce check.\r
770\r
771 @param PeiServices PEI services table\r
772 @param Desc Pointer to capsule descriptors\r
773**/\r
774VOID\r
775CapsuleTestPatternPreCoalesce (\r
776 IN EFI_PEI_SERVICES **PeiServices,\r
777 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc\r
778 )\r
779{\r
780 UINT32 *TestPtr;\r
781 UINT32 TestCounter;\r
782 UINT32 TestSize;\r
ff284c56 783\r
85b01932 784 DEBUG ((DEBUG_INFO, "CapsuleTestPatternPreCoalesce\n"));\r
ff284c56 785\r
ab7017fe 786 //\r
787 // Find first data descriptor\r
788 //\r
789 while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {\r
790 Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;\r
791 }\r
792\r
793 if (Desc->Union.ContinuationPointer == 0) {\r
794 return ;\r
795 }\r
796 //\r
797 // First one better be long enough to at least hold the test signature\r
798 //\r
799 if (Desc->Length < sizeof (UINT32)) {\r
85b01932 800 DEBUG ((DEBUG_INFO, "Capsule test pattern pre-coalesce punted #1\n"));\r
ab7017fe 801 return ;\r
802 }\r
803\r
804 TestPtr = (UINT32 *) (UINTN) Desc->Union.DataBlock;\r
805 //\r
806 // 0x54534554 "TEST"\r
807 //\r
808 if (*TestPtr != 0x54534554) {\r
809 return ;\r
810 }\r
811\r
812 TestCounter = 0;\r
813 TestSize = (UINT32) Desc->Length - 2 * sizeof (UINT32);\r
814 //\r
815 // Skip over the signature and the size fields in the pattern data header\r
816 //\r
817 TestPtr += 2;\r
818 while (1) {\r
819 if ((TestSize & 0x03) != 0) {\r
85b01932 820 DEBUG ((DEBUG_INFO, "Capsule test pattern pre-coalesce punted #2\n"));\r
ab7017fe 821 return ;\r
822 }\r
823\r
824 while (TestSize > 0) {\r
825 if (*TestPtr != TestCounter) {\r
85b01932 826 DEBUG ((DEBUG_INFO, "Capsule test pattern pre-coalesce failed data corruption check\n"));\r
ab7017fe 827 return ;\r
828 }\r
829\r
830 TestSize -= sizeof (UINT32);\r
831 TestCounter++;\r
832 TestPtr++;\r
833 }\r
834 Desc++;\r
835 while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {\r
836 Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;\r
837 }\r
838\r
839 if (Desc->Union.ContinuationPointer == (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {\r
840 return ;\r
841 }\r
842 TestSize = (UINT32) Desc->Length;\r
843 TestPtr = (UINT32 *) (UINTN) Desc->Union.DataBlock;\r
844 }\r
845}\r
846\r
847/**\r
848 Checks for the presence of capsule descriptors.\r
849 Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...\r
850\r
851 @param BlockListBuffer Pointer to the buffer of capsule descriptors variables\r
359cb1a3 852 @param MemoryResource Pointer to the buffer of memory resource descriptor.\r
ab7017fe 853 @param BlockDescriptorList Pointer to the capsule descriptors list\r
854\r
855 @retval EFI_SUCCESS a valid capsule is present\r
856 @retval EFI_NOT_FOUND if a valid capsule is not present\r
857**/\r
858EFI_STATUS\r
859BuildCapsuleDescriptors (\r
860 IN EFI_PHYSICAL_ADDRESS *BlockListBuffer,\r
359cb1a3 861 IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource,\r
d1102dba 862 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptorList\r
ab7017fe 863 )\r
864{\r
865 UINTN Index;\r
866 EFI_CAPSULE_BLOCK_DESCRIPTOR *LastBlock;\r
867 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlock;\r
868 EFI_CAPSULE_BLOCK_DESCRIPTOR *HeadBlock;\r
869\r
85b01932 870 DEBUG ((DEBUG_INFO, "BuildCapsuleDescriptors enter\n"));\r
ff284c56 871\r
ab7017fe 872 LastBlock = NULL;\r
873 HeadBlock = NULL;\r
874 TempBlock = NULL;\r
875 Index = 0;\r
876\r
877 while (BlockListBuffer[Index] != 0) {\r
31abeada
SZ
878 //\r
879 // Test integrity of descriptors.\r
880 //\r
ff284c56 881 if (BlockListBuffer[Index] < MAX_ADDRESS) {\r
359cb1a3 882 TempBlock = ValidateCapsuleIntegrity ((EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index], MemoryResource);\r
ff284c56
JY
883 if (TempBlock != NULL) {\r
884 if (LastBlock == NULL) {\r
885 LastBlock = TempBlock;\r
31abeada 886\r
ff284c56
JY
887 //\r
888 // Return the base of the block descriptors\r
889 //\r
890 HeadBlock = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index];\r
891 } else {\r
892 //\r
893 // Combine the different BlockList into single BlockList.\r
894 //\r
895 LastBlock->Union.DataBlock = (EFI_PHYSICAL_ADDRESS)(UINTN)BlockListBuffer[Index];\r
896 LastBlock->Length = 0;\r
897 LastBlock = TempBlock;\r
898 }\r
ab7017fe 899 }\r
ff284c56 900 } else {\r
85b01932 901 DEBUG ((DEBUG_ERROR, "ERROR: BlockListBuffer[Index](0x%lx) < MAX_ADDRESS\n", BlockListBuffer[Index]));\r
ab7017fe 902 }\r
903 Index ++;\r
904 }\r
d1102dba 905\r
ab7017fe 906 if (HeadBlock != NULL) {\r
907 *BlockDescriptorList = HeadBlock;\r
908 return EFI_SUCCESS;\r
909 }\r
910 return EFI_NOT_FOUND;\r
911}\r
912\r
913/**\r
914 The function to coalesce a fragmented capsule in memory.\r
915\r
916 Memory Map for coalesced capsule:\r
917 MemBase + ---->+---------------------------+<-----------+\r
ff284c56
JY
918 MemSize | ------------------------- | |\r
919 | | Capsule [Num-1] | | |\r
920 | ------------------------- | |\r
921 | | ................ | | |\r
922 | ------------------------- | |\r
923 | | Capsule [1] | | |\r
924 | ------------------------- | |\r
925 | | Capsule [0] | | |\r
926 | ------------------------- | |\r
d1102dba 927 | Capsule Image | |\r
ff284c56
JY
928CapsuleImageBase-->+---------------------------+\r
929 | ------------------------- | |\r
930 | | CapsuleOffset[Num-1] | | |\r
931 | ------------------------- | |\r
932 | | ................ | | CapsuleSize\r
933 | ------------------------- | |\r
934 | | CapsuleOffset[1] | | |\r
935 | ------------------------- | |\r
936 | | CapsuleOffset[0] | | |\r
937 |---------------------------| |\r
938 | | CapsuleNumber | | |\r
939 | ------------------------- | |\r
940 | | CapsuleAllImageSize | | |\r
941 | ------------------------- | |\r
ab7017fe 942 | PrivateData | |\r
ff284c56 943 DestPtr ---->+---------------------------+<-----------+\r
ab7017fe 944 | | |\r
945 | FreeMem | FreeMemSize\r
946 | | |\r
947 FreeMemBase --->+---------------------------+<-----------+\r
948 | Terminator |\r
949 +---------------------------+\r
950 | BlockDescriptor n |\r
951 +---------------------------+\r
952 | ................. |\r
953 +---------------------------+\r
954 | BlockDescriptor 1 |\r
955 +---------------------------+\r
956 | BlockDescriptor 0 |\r
957 +---------------------------+\r
958 | PrivateDataDesc 0 |\r
959 MemBase ---->+---------------------------+<----- BlockList\r
960\r
dc204d5a
JY
961 Caution: This function may receive untrusted input.\r
962 The capsule data is external input, so this routine will do basic validation before\r
963 coalesce capsule data into memory.\r
964\r
ab7017fe 965 @param PeiServices General purpose services available to every PEIM.\r
359cb1a3
SZ
966 @param BlockListBuffer Pointer to the buffer of Capsule Descriptor Variables.\r
967 @param MemoryResource Pointer to the buffer of memory resource descriptor.\r
ab7017fe 968 @param MemoryBase Pointer to the base of a block of memory that we can walk\r
969 all over while trying to coalesce our buffers.\r
970 On output, this variable will hold the base address of\r
971 a coalesced capsule.\r
972 @param MemorySize Size of the memory region pointed to by MemoryBase.\r
973 On output, this variable will contain the size of the\r
974 coalesced capsule.\r
975\r
976 @retval EFI_NOT_FOUND If we could not find the capsule descriptors.\r
977\r
978 @retval EFI_BUFFER_TOO_SMALL\r
979 If we could not coalesce the capsule in the memory\r
980 region provided to us.\r
981\r
982 @retval EFI_SUCCESS Processed the capsule successfully.\r
983**/\r
984EFI_STATUS\r
985EFIAPI\r
986CapsuleDataCoalesce (\r
987 IN EFI_PEI_SERVICES **PeiServices,\r
988 IN EFI_PHYSICAL_ADDRESS *BlockListBuffer,\r
359cb1a3 989 IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource,\r
ab7017fe 990 IN OUT VOID **MemoryBase,\r
991 IN OUT UINTN *MemorySize\r
992 )\r
993{\r
994 VOID *NewCapsuleBase;\r
ff284c56
JY
995 VOID *CapsuleImageBase;\r
996 UINTN CapsuleIndex;\r
ab7017fe 997 UINT8 *FreeMemBase;\r
998 UINT8 *DestPtr;\r
ff284c56 999 UINTN DestLength;\r
ab7017fe 1000 UINT8 *RelocPtr;\r
d1102dba
LG
1001 UINTN CapsuleTimes;\r
1002 UINT64 SizeLeft;\r
1003 UINT64 CapsuleImageSize;\r
ab7017fe 1004 UINTN CapsuleSize;\r
ff284c56 1005 UINTN CapsuleNumber;\r
ab7017fe 1006 UINTN DescriptorsSize;\r
1007 UINTN FreeMemSize;\r
1008 UINTN NumDescriptors;\r
ab7017fe 1009 BOOLEAN CapsuleBeginFlag;\r
1010 EFI_STATUS Status;\r
1011 EFI_CAPSULE_HEADER *CapsuleHeader;\r
1012 EFI_CAPSULE_PEIM_PRIVATE_DATA PrivateData;\r
1013 EFI_CAPSULE_PEIM_PRIVATE_DATA *PrivateDataPtr;\r
1014 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList;\r
1015 EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrentBlockDesc;\r
1016 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc;\r
1017 EFI_CAPSULE_BLOCK_DESCRIPTOR PrivateDataDesc[2];\r
1018\r
85b01932 1019 DEBUG ((DEBUG_INFO, "CapsuleDataCoalesce enter\n"));\r
ff284c56 1020\r
ab7017fe 1021 CapsuleIndex = 0;\r
1022 SizeLeft = 0;\r
1023 CapsuleTimes = 0;\r
1024 CapsuleImageSize = 0;\r
1025 PrivateDataPtr = NULL;\r
ab7017fe 1026 CapsuleHeader = NULL;\r
1027 CapsuleBeginFlag = TRUE;\r
ab7017fe 1028 CapsuleSize = 0;\r
1029 NumDescriptors = 0;\r
ff284c56 1030\r
ab7017fe 1031 //\r
1032 // Build capsule descriptors list\r
1033 //\r
359cb1a3 1034 Status = BuildCapsuleDescriptors (BlockListBuffer, MemoryResource, &BlockList);\r
ab7017fe 1035 if (EFI_ERROR (Status)) {\r
1036 return Status;\r
1037 }\r
1038\r
1039 DEBUG_CODE (\r
1040 CapsuleTestPatternPreCoalesce (PeiServices, BlockList);\r
1041 );\r
1042\r
1043 //\r
1044 // Get the size of our descriptors and the capsule size. GetCapsuleInfo()\r
1045 // returns the number of descriptors that actually point to data, so add\r
1046 // one for a terminator. Do that below.\r
1047 //\r
ff284c56
JY
1048 Status = GetCapsuleInfo (BlockList, &NumDescriptors, &CapsuleSize, &CapsuleNumber);\r
1049 if (EFI_ERROR (Status)) {\r
1050 return Status;\r
1051 }\r
85b01932
ZG
1052 DEBUG ((DEBUG_INFO, "CapsuleSize - 0x%x\n", CapsuleSize));\r
1053 DEBUG ((DEBUG_INFO, "CapsuleNumber - 0x%x\n", CapsuleNumber));\r
1054 DEBUG ((DEBUG_INFO, "NumDescriptors - 0x%x\n", NumDescriptors));\r
ff284c56 1055 if ((CapsuleSize == 0) || (NumDescriptors == 0) || (CapsuleNumber == 0)) {\r
ab7017fe 1056 return EFI_NOT_FOUND;\r
1057 }\r
1058\r
ff284c56 1059 if (CapsuleNumber - 1 >= (MAX_ADDRESS - (sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + sizeof(UINT64))) / sizeof(UINT64)) {\r
85b01932 1060 DEBUG ((DEBUG_ERROR, "ERROR: CapsuleNumber - 0x%x\n", CapsuleNumber));\r
ff284c56
JY
1061 return EFI_BUFFER_TOO_SMALL;\r
1062 }\r
1063\r
ab7017fe 1064 //\r
1065 // Initialize our local copy of private data. When we're done, we'll create a\r
1066 // descriptor for it as well so that it can be put into free memory without\r
1067 // trashing anything.\r
1068 //\r
ff284c56
JY
1069 PrivateData.Signature = EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE;\r
1070 PrivateData.CapsuleAllImageSize = (UINT64) CapsuleSize;\r
1071 PrivateData.CapsuleNumber = (UINT64) CapsuleNumber;\r
1072 PrivateData.CapsuleOffset[0] = 0;\r
1073 //\r
ed3ff1ac 1074 // NOTE: Only data in sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) is valid, CapsuleOffset field is uninitialized at this moment.\r
ff284c56
JY
1075 // The code sets partial length here for Descriptor.Length check, but later it will use full length to reserve those PrivateData region.\r
1076 //\r
ab7017fe 1077 PrivateDataDesc[0].Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) &PrivateData;\r
1078 PrivateDataDesc[0].Length = sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA);\r
1079 PrivateDataDesc[1].Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) BlockList;\r
1080 PrivateDataDesc[1].Length = 0;\r
1081 //\r
ed3ff1ac 1082 // Add PrivateDataDesc[0] in beginning, as it is new descriptor. PrivateDataDesc[1] is NOT needed.\r
ff284c56
JY
1083 // In addition, one NULL terminator is added in the end. See RelocateBlockDescriptors().\r
1084 //\r
1085 NumDescriptors += 2;\r
ab7017fe 1086 //\r
ed3ff1ac 1087 // Sanity check\r
ff284c56
JY
1088 //\r
1089 if (CapsuleSize >= (MAX_ADDRESS - (sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64) + sizeof(UINT64)))) {\r
85b01932 1090 DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize - 0x%x\n", CapsuleSize));\r
ff284c56
JY
1091 return EFI_BUFFER_TOO_SMALL;\r
1092 }\r
1093 //\r
1094 // Need add sizeof(UINT64) for PrivateData alignment\r
1095 //\r
1096 CapsuleSize += sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64) + sizeof(UINT64);\r
ab7017fe 1097 BlockList = PrivateDataDesc;\r
ff284c56 1098 //\r
ed3ff1ac 1099 // Sanity check\r
ff284c56
JY
1100 //\r
1101 if (NumDescriptors >= (MAX_ADDRESS / sizeof(EFI_CAPSULE_BLOCK_DESCRIPTOR))) {\r
85b01932 1102 DEBUG ((DEBUG_ERROR, "ERROR: NumDescriptors - 0x%x\n", NumDescriptors));\r
ff284c56
JY
1103 return EFI_BUFFER_TOO_SMALL;\r
1104 }\r
ab7017fe 1105 DescriptorsSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
ff284c56 1106 //\r
ed3ff1ac 1107 // Sanity check\r
ff284c56
JY
1108 //\r
1109 if (DescriptorsSize >= (MAX_ADDRESS - CapsuleSize)) {\r
85b01932 1110 DEBUG ((DEBUG_ERROR, "ERROR: DescriptorsSize - 0x%lx, CapsuleSize - 0x%lx\n", (UINT64)DescriptorsSize, (UINT64)CapsuleSize));\r
ff284c56
JY
1111 return EFI_BUFFER_TOO_SMALL;\r
1112 }\r
ab7017fe 1113\r
1114 //\r
1115 // Don't go below some min address. If the base is below it,\r
1116 // then move it up and adjust the size accordingly.\r
1117 //\r
85b01932 1118 DEBUG ((DEBUG_INFO, "Capsule Memory range from 0x%8X to 0x%8X\n", (UINTN) *MemoryBase, (UINTN)*MemoryBase + *MemorySize));\r
ab7017fe 1119 if ((UINTN)*MemoryBase < (UINTN) MIN_COALESCE_ADDR) {\r
1120 if (((UINTN)*MemoryBase + *MemorySize) < (UINTN) MIN_COALESCE_ADDR) {\r
85b01932 1121 DEBUG ((DEBUG_ERROR, "ERROR: *MemoryBase + *MemorySize - 0x%x\n", (UINTN)*MemoryBase + *MemorySize));\r
ab7017fe 1122 return EFI_BUFFER_TOO_SMALL;\r
1123 } else {\r
1124 *MemorySize = *MemorySize - ((UINTN) MIN_COALESCE_ADDR - (UINTN) *MemoryBase);\r
1125 *MemoryBase = (VOID *) (UINTN) MIN_COALESCE_ADDR;\r
1126 }\r
1127 }\r
1128\r
1129 if (*MemorySize <= (CapsuleSize + DescriptorsSize)) {\r
85b01932 1130 DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize + DescriptorsSize - 0x%x\n", CapsuleSize + DescriptorsSize));\r
ab7017fe 1131 return EFI_BUFFER_TOO_SMALL;\r
1132 }\r
1133\r
1134 FreeMemBase = *MemoryBase;\r
1135 FreeMemSize = *MemorySize;\r
85b01932 1136 DEBUG ((DEBUG_INFO, "Capsule Free Memory from 0x%8X to 0x%8X\n", (UINTN) FreeMemBase, (UINTN) FreeMemBase + FreeMemSize));\r
ab7017fe 1137\r
1138 //\r
1139 // Relocate all the block descriptors to low memory to make further\r
1140 // processing easier.\r
1141 //\r
ff284c56 1142 BlockList = RelocateBlockDescriptors (PeiServices, BlockList, NumDescriptors, FreeMemBase, FreeMemSize);\r
ab7017fe 1143 if (BlockList == NULL) {\r
1144 //\r
1145 // Not enough room to relocate the descriptors\r
1146 //\r
1147 return EFI_BUFFER_TOO_SMALL;\r
1148 }\r
1149\r
1150 //\r
ff284c56 1151 // Take the top of memory for the capsule. UINT64 align up.\r
ab7017fe 1152 //\r
1153 DestPtr = FreeMemBase + FreeMemSize - CapsuleSize;\r
ff284c56 1154 DestPtr = (UINT8 *) (((UINTN)DestPtr + sizeof (UINT64) - 1) & ~(sizeof (UINT64) - 1));\r
ab7017fe 1155 FreeMemBase = (UINT8 *) BlockList + DescriptorsSize;\r
4694dd1b 1156 FreeMemSize = (UINTN) DestPtr - (UINTN) FreeMemBase;\r
ab7017fe 1157 NewCapsuleBase = (VOID *) DestPtr;\r
ff284c56
JY
1158 CapsuleImageBase = (UINT8 *)NewCapsuleBase + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64);\r
1159\r
1160 PrivateDataPtr = (EFI_CAPSULE_PEIM_PRIVATE_DATA *) NewCapsuleBase;\r
ab7017fe 1161\r
1162 //\r
1163 // Move all the blocks to the top (high) of memory.\r
1164 // Relocate all the obstructing blocks. Note that the block descriptors\r
1165 // were coalesced when they were relocated, so we can just ++ the pointer.\r
1166 //\r
1167 CurrentBlockDesc = BlockList;\r
1168 while ((CurrentBlockDesc->Length != 0) || (CurrentBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {\r
ff284c56
JY
1169 if (CapsuleTimes == 0) {\r
1170 //\r
1171 // The first entry is the block descriptor for EFI_CAPSULE_PEIM_PRIVATE_DATA.\r
1172 // CapsuleOffset field is uninitialized at this time. No need copy it, but need to reserve for future use.\r
1173 //\r
1174 ASSERT (CurrentBlockDesc->Union.DataBlock == (UINT64)(UINTN)&PrivateData);\r
1175 DestLength = sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64);\r
1176 } else {\r
1177 DestLength = (UINTN)CurrentBlockDesc->Length;\r
1178 }\r
ab7017fe 1179 //\r
1180 // See if any of the remaining capsule blocks are in the way\r
1181 //\r
1182 TempBlockDesc = CurrentBlockDesc;\r
1183 while (TempBlockDesc->Length != 0) {\r
1184 //\r
1185 // Is this block in the way of where we want to copy the current descriptor to?\r
1186 //\r
1187 if (IsOverlapped (\r
1188 (UINT8 *) DestPtr,\r
ff284c56 1189 (UINTN) DestLength,\r
ab7017fe 1190 (UINT8 *) (UINTN) TempBlockDesc->Union.DataBlock,\r
1191 (UINTN) TempBlockDesc->Length\r
1192 )) {\r
1193 //\r
1194 // Relocate the block\r
1195 //\r
1196 RelocPtr = FindFreeMem (BlockList, FreeMemBase, FreeMemSize, (UINTN) TempBlockDesc->Length);\r
1197 if (RelocPtr == NULL) {\r
1198 return EFI_BUFFER_TOO_SMALL;\r
1199 }\r
1200\r
1201 CopyMem ((VOID *) RelocPtr, (VOID *) (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) TempBlockDesc->Length);\r
85b01932 1202 DEBUG ((DEBUG_INFO, "Capsule reloc data block from 0x%8X to 0x%8X with size 0x%8X\n",\r
ab7017fe 1203 (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) RelocPtr, (UINTN) TempBlockDesc->Length));\r
1204\r
1205 TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocPtr;\r
1206 }\r
1207 //\r
1208 // Next descriptor\r
1209 //\r
1210 TempBlockDesc++;\r
1211 }\r
1212 //\r
1213 // Ok, we made it through. Copy the block.\r
1214 // we just support greping one capsule from the lists of block descs list.\r
1215 //\r
1216 CapsuleTimes ++;\r
1217 //\r
1218 //Skip the first block descriptor that filled with EFI_CAPSULE_PEIM_PRIVATE_DATA\r
1219 //\r
1220 if (CapsuleTimes > 1) {\r
1221 //\r
1222 //For every capsule entry point, check its header to determine whether to relocate it.\r
1223 //If it is invalid, skip it and move on to the next capsule. If it is valid, relocate it.\r
1224 //\r
1225 if (CapsuleBeginFlag) {\r
1226 CapsuleBeginFlag = FALSE;\r
1227 CapsuleHeader = (EFI_CAPSULE_HEADER*)(UINTN)CurrentBlockDesc->Union.DataBlock;\r
1228 SizeLeft = CapsuleHeader->CapsuleImageSize;\r
ab7017fe 1229\r
ff284c56
JY
1230 //\r
1231 // No more check here is needed, because IsCapsuleCorrupted() already in ValidateCapsuleIntegrity()\r
1232 //\r
1233 ASSERT (CapsuleIndex < CapsuleNumber);\r
ab7017fe 1234\r
ff284c56
JY
1235 //\r
1236 // Relocate this capsule\r
1237 //\r
1238 CapsuleImageSize += SizeLeft;\r
1239 //\r
1240 // Cache the begin offset of this capsule\r
1241 //\r
1242 ASSERT (PrivateDataPtr->Signature == EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE);\r
1243 ASSERT ((UINTN)DestPtr >= (UINTN)CapsuleImageBase);\r
16f69227 1244 PrivateDataPtr->CapsuleOffset[CapsuleIndex++] = (UINTN)DestPtr - (UINTN)CapsuleImageBase;\r
240bc4ee
SZ
1245 }\r
1246\r
ff284c56
JY
1247 //\r
1248 // Below ASSERT is checked in ValidateCapsuleIntegrity()\r
1249 //\r
1250 ASSERT (CurrentBlockDesc->Length <= SizeLeft);\r
1251\r
1252 CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) (CurrentBlockDesc->Union.DataBlock), (UINTN)CurrentBlockDesc->Length);\r
85b01932 1253 DEBUG ((DEBUG_INFO, "Capsule coalesce block no.0x%lX from 0x%lX to 0x%lX with size 0x%lX\n",(UINT64)CapsuleTimes,\r
ff284c56
JY
1254 CurrentBlockDesc->Union.DataBlock, (UINT64)(UINTN)DestPtr, CurrentBlockDesc->Length));\r
1255 DestPtr += CurrentBlockDesc->Length;\r
1256 SizeLeft -= CurrentBlockDesc->Length;\r
1257\r
1258 if (SizeLeft == 0) {\r
ab7017fe 1259 //\r
240bc4ee 1260 //Here is the end of the current capsule image.\r
ab7017fe 1261 //\r
d1102dba 1262 CapsuleBeginFlag = TRUE;\r
ab7017fe 1263 }\r
1264 } else {\r
1265 //\r
ff284c56
JY
1266 // The first entry is the block descriptor for EFI_CAPSULE_PEIM_PRIVATE_DATA.\r
1267 // CapsuleOffset field is uninitialized at this time. No need copy it, but need to reserve for future use.\r
ab7017fe 1268 //\r
ff284c56
JY
1269 ASSERT (CurrentBlockDesc->Length == sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA));\r
1270 ASSERT ((UINTN)DestPtr == (UINTN)NewCapsuleBase);\r
ab7017fe 1271 CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) CurrentBlockDesc->Union.DataBlock, (UINTN) CurrentBlockDesc->Length);\r
ff284c56 1272 DestPtr += sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64);\r
ab7017fe 1273 }\r
1274 //\r
1275 //Walk through the block descriptor list.\r
1276 //\r
1277 CurrentBlockDesc++;\r
1278 }\r
1279 //\r
1280 // We return the base of memory we want reserved, and the size.\r
1281 // The memory peim should handle it appropriately from there.\r
1282 //\r
2e4c9e01 1283 *MemorySize = (UINTN) CapsuleSize;\r
ab7017fe 1284 *MemoryBase = (VOID *) NewCapsuleBase;\r
1285\r
ff284c56
JY
1286 ASSERT (PrivateDataPtr->Signature == EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE);\r
1287 ASSERT (PrivateDataPtr->CapsuleAllImageSize == CapsuleImageSize);\r
1288 ASSERT (PrivateDataPtr->CapsuleNumber == CapsuleIndex);\r
ab7017fe 1289\r
1290 return EFI_SUCCESS;\r
1291}\r