Coverage Report

Created: 2025-12-09 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}