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