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