]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c
MdeModulePkg/DxeCapsuleLibFmp: Improve comparisons in CapsuleOnDisk.c
[mirror_edk2.git] / MdeModulePkg / Library / DxeCapsuleLibFmp / CapsuleOnDisk.c
1 /** @file
2 The implementation supports Capusle on Disk.
3
4 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "CapsuleOnDisk.h"
10
11 /**
12 Return if this capsule is a capsule name capsule, based upon CapsuleHeader.
13
14 @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
15
16 @retval TRUE It is a capsule name capsule.
17 @retval FALSE It is not a capsule name capsule.
18 **/
19 BOOLEAN
20 IsCapsuleNameCapsule (
21 IN EFI_CAPSULE_HEADER *CapsuleHeader
22 );
23
24 /**
25 Check the integrity of the capsule name capsule.
26 If the capsule is vaild, return the physical address of each capsule name string.
27
28 This routine assumes the capsule has been validated by IsValidCapsuleHeader(), so
29 capsule memory overflow is not going to happen in this routine.
30
31 @param[in] CapsuleHeader Pointer to the capsule header of a capsule name capsule.
32 @param[out] CapsuleNameNum Number of capsule name.
33
34 @retval NULL Capsule name capsule is not valid.
35 @retval CapsuleNameBuf Array of capsule name physical address.
36
37 **/
38 EFI_PHYSICAL_ADDRESS *
39 ValidateCapsuleNameCapsuleIntegrity (
40 IN EFI_CAPSULE_HEADER *CapsuleHeader,
41 OUT UINTN *CapsuleNameNum
42 )
43 {
44 UINT8 *CapsuleNamePtr;
45 UINT8 *CapsuleNameBufStart;
46 UINT8 *CapsuleNameBufEnd;
47 UINTN Index;
48 UINTN StringSize;
49 EFI_PHYSICAL_ADDRESS *CapsuleNameBuf;
50
51 if (!IsCapsuleNameCapsule (CapsuleHeader)) {
52 return NULL;
53 }
54
55 //
56 // Total string size must be even.
57 //
58 if (((CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize) & BIT0) != 0) {
59 return NULL;
60 }
61
62 *CapsuleNameNum = 0;
63 Index = 0;
64 CapsuleNameBufStart = (UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize;
65
66 //
67 // If strings are not aligned on a 16-bit boundary, reallocate memory for it.
68 //
69 if (((UINTN) CapsuleNameBufStart & BIT0) != 0) {
70 CapsuleNameBufStart = AllocateCopyPool (CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize, CapsuleNameBufStart);
71 if (CapsuleNameBufStart == NULL) {
72 return NULL;
73 }
74 }
75
76 CapsuleNameBufEnd = CapsuleNameBufStart + CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
77
78 CapsuleNamePtr = CapsuleNameBufStart;
79 while (CapsuleNamePtr < CapsuleNameBufEnd) {
80 StringSize= StrnSizeS ((CHAR16 *) CapsuleNamePtr, (CapsuleNameBufEnd - CapsuleNamePtr)/sizeof(CHAR16));
81 CapsuleNamePtr += StringSize;
82 (*CapsuleNameNum) ++;
83 }
84
85 //
86 // Integrity check.
87 //
88 if (CapsuleNamePtr != CapsuleNameBufEnd) {
89 if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize) {
90 FreePool (CapsuleNameBufStart);
91 }
92 return NULL;
93 }
94
95 CapsuleNameBuf = AllocatePool (*CapsuleNameNum * sizeof (EFI_PHYSICAL_ADDRESS));
96 if (CapsuleNameBuf == NULL) {
97 if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize) {
98 FreePool (CapsuleNameBufStart);
99 }
100 return NULL;
101 }
102
103 CapsuleNamePtr = CapsuleNameBufStart;
104 while (CapsuleNamePtr < CapsuleNameBufEnd) {
105 StringSize= StrnSizeS ((CHAR16 *) CapsuleNamePtr, (CapsuleNameBufEnd - CapsuleNamePtr)/sizeof(CHAR16));
106 CapsuleNameBuf[Index] = (EFI_PHYSICAL_ADDRESS)(UINTN) CapsuleNamePtr;
107 CapsuleNamePtr += StringSize;
108 Index ++;
109 }
110
111 return CapsuleNameBuf;
112 }
113
114 /**
115 This routine is called to upper case given unicode string.
116
117 @param[in] Str String to upper case
118
119 @retval upper cased string after process
120
121 **/
122 static
123 CHAR16 *
124 UpperCaseString (
125 IN CHAR16 *Str
126 )
127 {
128 CHAR16 *Cptr;
129
130 for (Cptr = Str; *Cptr != L'\0'; Cptr++) {
131 if (L'a' <= *Cptr && *Cptr <= L'z') {
132 *Cptr = *Cptr - L'a' + L'A';
133 }
134 }
135
136 return Str;
137 }
138
139 /**
140 This routine is used to return substring before period '.' or '\0'
141 Caller should respsonsible of substr space allocation & free
142
143 @param[in] Str String to check
144 @param[out] SubStr First part of string before period or '\0'
145 @param[out] SubStrLen Length of first part of string
146
147 **/
148 static
149 VOID
150 GetSubStringBeforePeriod (
151 IN CHAR16 *Str,
152 OUT CHAR16 *SubStr,
153 OUT UINTN *SubStrLen
154 )
155 {
156 UINTN Index;
157 for (Index = 0; Str[Index] != L'.' && Str[Index] != L'\0'; Index++) {
158 SubStr[Index] = Str[Index];
159 }
160
161 SubStr[Index] = L'\0';
162 *SubStrLen = Index;
163 }
164
165 /**
166 This routine pad the string in tail with input character.
167
168 @param[in] StrBuf Str buffer to be padded, should be enough room for
169 @param[in] PadLen Expected padding length
170 @param[in] Character Character used to pad
171
172 **/
173 static
174 VOID
175 PadStrInTail (
176 IN CHAR16 *StrBuf,
177 IN UINTN PadLen,
178 IN CHAR16 Character
179 )
180 {
181 UINTN Index;
182
183 for (Index = 0; StrBuf[Index] != L'\0'; Index++);
184
185 while(PadLen != 0) {
186 StrBuf[Index] = Character;
187 Index++;
188 PadLen--;
189 }
190
191 StrBuf[Index] = L'\0';
192 }
193
194 /**
195 This routine find the offset of the last period '.' of string. If No period exists
196 function FileNameExtension is set to L'\0'
197
198 @param[in] FileName File name to split between last period
199 @param[out] FileNameFirst First FileName before last period
200 @param[out] FileNameExtension FileName after last period
201
202 **/
203 static
204 VOID
205 SplitFileNameExtension (
206 IN CHAR16 *FileName,
207 OUT CHAR16 *FileNameFirst,
208 OUT CHAR16 *FileNameExtension
209 )
210 {
211 UINTN Index;
212 UINTN StringLen;
213
214 StringLen = StrnLenS(FileName, MAX_FILE_NAME_SIZE);
215 for (Index = StringLen; Index > 0 && FileName[Index] != L'.'; Index--);
216
217 //
218 // No period exists. No FileName Extension
219 //
220 if (Index == 0 && FileName[Index] != L'.') {
221 FileNameExtension[0] = L'\0';
222 Index = StringLen;
223 } else {
224 StrCpyS(FileNameExtension, MAX_FILE_NAME_SIZE, &FileName[Index+1]);
225 }
226
227 //
228 // Copy First file name
229 //
230 StrnCpyS(FileNameFirst, MAX_FILE_NAME_SIZE, FileName, Index);
231 FileNameFirst[Index] = L'\0';
232 }
233
234 /**
235 This routine is called to get all boot options in the order determnined by:
236 1. "OptionBuf"
237 2. "BootOrder"
238
239 @param[out] OptionBuf BootList buffer to all boot options returned
240 @param[out] OptionCount BootList count of all boot options returned
241
242 @retval EFI_SUCCESS There is no error when processing capsule
243
244 **/
245 EFI_STATUS
246 GetBootOptionInOrder(
247 OUT EFI_BOOT_MANAGER_LOAD_OPTION **OptionBuf,
248 OUT UINTN *OptionCount
249 )
250 {
251 EFI_STATUS Status;
252 UINTN DataSize;
253 UINT16 BootNext;
254 CHAR16 BootOptionName[20];
255 EFI_BOOT_MANAGER_LOAD_OPTION *BootOrderOptionBuf;
256 UINTN BootOrderCount;
257 EFI_BOOT_MANAGER_LOAD_OPTION BootNextOptionEntry;
258 UINTN BootNextCount;
259 EFI_BOOT_MANAGER_LOAD_OPTION *TempBuf;
260
261 BootOrderOptionBuf = NULL;
262 TempBuf = NULL;
263 BootNextCount = 0;
264 BootOrderCount = 0;
265 *OptionBuf = NULL;
266 *OptionCount = 0;
267
268 //
269 // First Get BootOption from "BootNext"
270 //
271 DataSize = sizeof(BootNext);
272 Status = gRT->GetVariable (
273 EFI_BOOT_NEXT_VARIABLE_NAME,
274 &gEfiGlobalVariableGuid,
275 NULL,
276 &DataSize,
277 (VOID *)&BootNext
278 );
279 //
280 // BootNext variable is a single UINT16
281 //
282 if (!EFI_ERROR(Status) && DataSize == sizeof(UINT16)) {
283 //
284 // Add the boot next boot option
285 //
286 UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", BootNext);
287 ZeroMem(&BootNextOptionEntry, sizeof(EFI_BOOT_MANAGER_LOAD_OPTION));
288 Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOptionEntry);
289
290 if (!EFI_ERROR(Status)) {
291 BootNextCount = 1;
292 }
293 }
294
295 //
296 // Second get BootOption from "BootOrder"
297 //
298 BootOrderOptionBuf = EfiBootManagerGetLoadOptions (&BootOrderCount, LoadOptionTypeBoot);
299 if (BootNextCount == 0 && BootOrderCount == 0) {
300 return EFI_NOT_FOUND;
301 }
302
303 //
304 // At least one BootOption is found
305 //
306 TempBuf = AllocatePool(sizeof(EFI_BOOT_MANAGER_LOAD_OPTION) * (BootNextCount + BootOrderCount));
307 if (TempBuf != NULL) {
308 if (BootNextCount == 1) {
309 CopyMem(TempBuf, &BootNextOptionEntry, sizeof(EFI_BOOT_MANAGER_LOAD_OPTION));
310 }
311
312 if (BootOrderCount > 0) {
313 CopyMem(TempBuf + BootNextCount, BootOrderOptionBuf, sizeof(EFI_BOOT_MANAGER_LOAD_OPTION) * BootOrderCount);
314 }
315
316 *OptionBuf = TempBuf;
317 *OptionCount = BootNextCount + BootOrderCount;
318 Status = EFI_SUCCESS;
319 } else {
320 Status = EFI_OUT_OF_RESOURCES;
321 }
322
323 FreePool(BootOrderOptionBuf);
324
325 return Status;
326 }
327
328 /**
329 This routine is called to get boot option by OptionNumber.
330
331 @param[in] Number The OptionNumber of boot option
332 @param[out] OptionBuf BootList buffer to all boot options returned
333
334 @retval EFI_SUCCESS There is no error when getting boot option
335
336 **/
337 EFI_STATUS
338 GetBootOptionByNumber(
339 IN UINT16 Number,
340 OUT EFI_BOOT_MANAGER_LOAD_OPTION **OptionBuf
341 )
342 {
343 EFI_STATUS Status;
344 CHAR16 BootOptionName[20];
345 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
346
347 UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", Number);
348 ZeroMem (&BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
349 Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootOption);
350
351 if (!EFI_ERROR (Status)) {
352 *OptionBuf = AllocatePool (sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
353 if (*OptionBuf != NULL) {
354 CopyMem (*OptionBuf, &BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
355 Status = EFI_SUCCESS;
356 } else {
357 Status = EFI_OUT_OF_RESOURCES;
358 }
359 }
360
361 return Status;
362 }
363
364 /**
365 Get Active EFI System Partition within GPT based on device path.
366
367 @param[in] DevicePath Device path to find a active EFI System Partition
368 @param[out] FsHandle BootList points to all boot options returned
369
370 @retval EFI_SUCCESS Active EFI System Partition is succesfully found
371 @retval EFI_NOT_FOUND No Active EFI System Partition is found
372
373 **/
374 EFI_STATUS
375 GetEfiSysPartitionFromDevPath(
376 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
377 OUT EFI_HANDLE *FsHandle
378 )
379 {
380 EFI_STATUS Status;
381 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
382 HARDDRIVE_DEVICE_PATH *Hd;
383 EFI_HANDLE Handle;
384 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
385
386 //
387 // Check if the device path contains GPT node
388 //
389 TempDevicePath = DevicePath;
390 while (!IsDevicePathEnd (TempDevicePath)) {
391 if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) &&
392 (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP)) {
393 Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
394 if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) {
395 break;
396 }
397 }
398 TempDevicePath = NextDevicePathNode (TempDevicePath);
399 }
400
401 if (!IsDevicePathEnd (TempDevicePath)) {
402 //
403 // Search for EFI system partition protocol on full device path in Boot Option
404 //
405 Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle);
406
407 //
408 // Search for simple file system on this handler
409 //
410 if (!EFI_ERROR(Status)) {
411 Status = gBS->HandleProtocol(Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
412 if (!EFI_ERROR(Status)) {
413 *FsHandle = Handle;
414 return EFI_SUCCESS;
415 }
416 }
417 }
418
419 return EFI_NOT_FOUND;
420 }
421
422 /**
423 This routine is called to get Simple File System protocol on the first EFI system partition found in
424 active boot option. The boot option list is detemined in order by
425 1. "BootNext"
426 2. "BootOrder"
427
428 @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
429 device like USB can get enumerated.
430 @param[in, out] LoadOptionNumber On input, specify the boot option to get EFI system partition.
431 On output, return the OptionNumber of the boot option where EFI
432 system partition is got from.
433 @param[out] FsFsHandle Simple File System Protocol found on first active EFI system partition
434
435 @retval EFI_SUCCESS Simple File System protocol found for EFI system partition
436 @retval EFI_NOT_FOUND No Simple File System protocol found for EFI system partition
437
438 **/
439 EFI_STATUS
440 GetEfiSysPartitionFromActiveBootOption(
441 IN UINTN MaxRetry,
442 IN OUT UINT16 **LoadOptionNumber,
443 OUT EFI_HANDLE *FsHandle
444 )
445 {
446 EFI_STATUS Status;
447 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptionBuf;
448 UINTN BootOptionNum;
449 UINTN Index;
450 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
451 EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
452 EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
453
454 *FsHandle = NULL;
455 CurFullPath = NULL;
456
457 if (*LoadOptionNumber != NULL) {
458 BootOptionNum = 1;
459 Status = GetBootOptionByNumber(**LoadOptionNumber, &BootOptionBuf);
460 if (EFI_ERROR(Status)) {
461 DEBUG ((DEBUG_ERROR, "GetBootOptionByIndex Failed %x! No BootOption available for connection\n", Status));
462 return Status;
463 }
464 } else {
465 Status = GetBootOptionInOrder(&BootOptionBuf, &BootOptionNum);
466 if (EFI_ERROR(Status)) {
467 DEBUG ((DEBUG_ERROR, "GetBootOptionInOrder Failed %x! No BootOption available for connection\n", Status));
468 return Status;
469 }
470 }
471
472 //
473 // Search BootOptionList to check if it is an active boot option with EFI system partition
474 // 1. Connect device path
475 // 2. expend short/plug in devicepath
476 // 3. LoadImage
477 //
478 for (Index = 0; Index < BootOptionNum; Index++) {
479 //
480 // Get the boot option from the link list
481 //
482 DevicePath = BootOptionBuf[Index].FilePath;
483
484 //
485 // Skip inactive or legacy boot options
486 //
487 if ((BootOptionBuf[Index].Attributes & LOAD_OPTION_ACTIVE) == 0 ||
488 DevicePathType (DevicePath) == BBS_DEVICE_PATH) {
489 continue;
490 }
491
492 DEBUG_CODE (
493 CHAR16 *DevicePathStr;
494
495 DevicePathStr = ConvertDevicePathToText(DevicePath, TRUE, TRUE);
496 if (DevicePathStr != NULL){
497 DEBUG((DEBUG_INFO, "Try BootOption %s\n", DevicePathStr));
498 FreePool(DevicePathStr);
499 } else {
500 DEBUG((DEBUG_INFO, "DevicePathToStr failed\n"));
501 }
502 );
503
504 CurFullPath = NULL;
505 //
506 // Try every full device Path generated from bootoption
507 //
508 do {
509 PreFullPath = CurFullPath;
510 CurFullPath = EfiBootManagerGetNextLoadOptionDevicePath(DevicePath, CurFullPath);
511
512 if (PreFullPath != NULL) {
513 FreePool (PreFullPath);
514 }
515
516 if (CurFullPath == NULL) {
517 //
518 // No Active EFI system partition is found in BootOption device path
519 //
520 Status = EFI_NOT_FOUND;
521 break;
522 }
523
524 DEBUG_CODE (
525 CHAR16 *DevicePathStr1;
526
527 DevicePathStr1 = ConvertDevicePathToText(CurFullPath, TRUE, TRUE);
528 if (DevicePathStr1 != NULL){
529 DEBUG((DEBUG_INFO, "Full device path %s\n", DevicePathStr1));
530 FreePool(DevicePathStr1);
531 }
532 );
533
534 //
535 // Make sure the boot option device path connected.
536 // Only handle first device in boot option. Other optional device paths are described as OSV specific
537 // FullDevice could contain extra directory & file info. So don't check connection status here.
538 //
539 EfiBootManagerConnectDevicePath (CurFullPath, NULL);
540 Status = GetEfiSysPartitionFromDevPath(CurFullPath, FsHandle);
541
542 //
543 // Some relocation device like USB need more time to get enumerated
544 //
545 while (EFI_ERROR(Status) && MaxRetry > 0) {
546 EfiBootManagerConnectDevicePath(CurFullPath, NULL);
547
548 //
549 // Search for EFI system partition protocol on full device path in Boot Option
550 //
551 Status = GetEfiSysPartitionFromDevPath(CurFullPath, FsHandle);
552 if (!EFI_ERROR(Status)) {
553 break;
554 }
555 DEBUG((DEBUG_ERROR, "GetEfiSysPartitionFromDevPath Loop %x\n", Status));
556 //
557 // Stall 100ms if connection failed to ensure USB stack is ready
558 //
559 gBS->Stall(100000);
560 MaxRetry --;
561 }
562 } while(EFI_ERROR(Status));
563
564 //
565 // Find a qualified Simple File System
566 //
567 if (!EFI_ERROR(Status)) {
568 break;
569 }
570
571 }
572
573 //
574 // Return the OptionNumber of the boot option where EFI system partition is got from
575 //
576 if (*LoadOptionNumber == NULL) {
577 *LoadOptionNumber = AllocateCopyPool (sizeof(UINT16), (UINT16 *) &BootOptionBuf[Index].OptionNumber);
578 if (*LoadOptionNumber == NULL) {
579 Status = EFI_OUT_OF_RESOURCES;
580 }
581 }
582
583 //
584 // No qualified EFI system partition found
585 //
586 if (*FsHandle == NULL) {
587 Status = EFI_NOT_FOUND;
588 }
589
590 DEBUG_CODE (
591 CHAR16 *DevicePathStr2;
592 if (*FsHandle != NULL) {
593 DevicePathStr2 = ConvertDevicePathToText(CurFullPath, TRUE, TRUE);
594 if (DevicePathStr2 != NULL){
595 DEBUG((DEBUG_INFO, "Found Active EFI System Partion on %s\n", DevicePathStr2));
596 FreePool(DevicePathStr2);
597 }
598 } else {
599 DEBUG((DEBUG_INFO, "Failed to found Active EFI System Partion\n"));
600 }
601 );
602
603 if (CurFullPath != NULL) {
604 FreePool(CurFullPath);
605 }
606
607 //
608 // Free BootOption Buffer
609 //
610 for (Index = 0; Index < BootOptionNum; Index++) {
611 if (BootOptionBuf[Index].Description != NULL) {
612 FreePool(BootOptionBuf[Index].Description);
613 }
614
615 if (BootOptionBuf[Index].FilePath != NULL) {
616 FreePool(BootOptionBuf[Index].FilePath);
617 }
618
619 if (BootOptionBuf[Index].OptionalData != NULL) {
620 FreePool(BootOptionBuf[Index].OptionalData);
621 }
622 }
623
624 FreePool(BootOptionBuf);
625
626 return Status;
627 }
628
629
630 /**
631 This routine is called to get all file infos with in a given dir & with given file attribute, the file info is listed in
632 alphabetical order described in UEFI spec.
633
634 @param[in] Dir Directory file handler
635 @param[in] FileAttr Attribute of file to be red from directory
636 @param[out] FileInfoList File images info list red from directory
637 @param[out] FileNum File images number red from directory
638
639 @retval EFI_SUCCESS File FileInfo list in the given
640
641 **/
642 EFI_STATUS
643 GetFileInfoListInAlphabetFromDir(
644 IN EFI_FILE_HANDLE Dir,
645 IN UINT64 FileAttr,
646 OUT LIST_ENTRY *FileInfoList,
647 OUT UINTN *FileNum
648 )
649 {
650 EFI_STATUS Status;
651 FILE_INFO_ENTRY *NewFileInfoEntry;
652 FILE_INFO_ENTRY *TempFileInfoEntry;
653 EFI_FILE_INFO *FileInfo;
654 CHAR16 *NewFileName;
655 CHAR16 *ListedFileName;
656 CHAR16 *NewFileNameExtension;
657 CHAR16 *ListedFileNameExtension;
658 CHAR16 *TempNewSubStr;
659 CHAR16 *TempListedSubStr;
660 LIST_ENTRY *Link;
661 BOOLEAN NoFile;
662 UINTN FileCount;
663 UINTN IndexNew;
664 UINTN IndexListed;
665 UINTN NewSubStrLen;
666 UINTN ListedSubStrLen;
667 INTN SubStrCmpResult;
668
669 Status = EFI_SUCCESS;
670 NewFileName = NULL;
671 ListedFileName = NULL;
672 NewFileNameExtension = NULL;
673 ListedFileNameExtension = NULL;
674 TempNewSubStr = NULL;
675 TempListedSubStr = NULL;
676 FileInfo = NULL;
677 NoFile = FALSE;
678 FileCount = 0;
679
680 InitializeListHead(FileInfoList);
681
682 TempNewSubStr = (CHAR16 *) AllocateZeroPool(MAX_FILE_NAME_SIZE);
683 TempListedSubStr = (CHAR16 *) AllocateZeroPool(MAX_FILE_NAME_SIZE);
684
685 if (TempNewSubStr == NULL || TempListedSubStr == NULL ) {
686 Status = EFI_OUT_OF_RESOURCES;
687 goto EXIT;
688 }
689
690 for ( Status = FileHandleFindFirstFile(Dir, &FileInfo)
691 ; !EFI_ERROR(Status) && !NoFile
692 ; Status = FileHandleFindNextFile(Dir, FileInfo, &NoFile)
693 ){
694 if (FileInfo == NULL) {
695 goto EXIT;
696 }
697
698 //
699 // Skip file with mismatching File attribute
700 //
701 if ((FileInfo->Attribute & (FileAttr)) == 0) {
702 continue;
703 }
704
705 NewFileInfoEntry = NULL;
706 NewFileInfoEntry = (FILE_INFO_ENTRY*)AllocateZeroPool(sizeof(FILE_INFO_ENTRY));
707 if (NewFileInfoEntry == NULL) {
708 Status = EFI_OUT_OF_RESOURCES;
709 goto EXIT;
710 }
711 NewFileInfoEntry->Signature = FILE_INFO_SIGNATURE;
712 NewFileInfoEntry->FileInfo = AllocateCopyPool((UINTN) FileInfo->Size, FileInfo);
713 if (NewFileInfoEntry->FileInfo == NULL) {
714 FreePool(NewFileInfoEntry);
715 Status = EFI_OUT_OF_RESOURCES;
716 goto EXIT;
717 }
718
719 NewFileInfoEntry->FileNameFirstPart = (CHAR16 *) AllocateZeroPool(MAX_FILE_NAME_SIZE);
720 if (NewFileInfoEntry->FileNameFirstPart == NULL) {
721 FreePool(NewFileInfoEntry->FileInfo);
722 FreePool(NewFileInfoEntry);
723 Status = EFI_OUT_OF_RESOURCES;
724 goto EXIT;
725 }
726 NewFileInfoEntry->FileNameSecondPart = (CHAR16 *) AllocateZeroPool(MAX_FILE_NAME_SIZE);
727 if (NewFileInfoEntry->FileNameSecondPart == NULL) {
728 FreePool(NewFileInfoEntry->FileInfo);
729 FreePool(NewFileInfoEntry->FileNameFirstPart);
730 FreePool(NewFileInfoEntry);
731 Status = EFI_OUT_OF_RESOURCES;
732 goto EXIT;
733 }
734
735 //
736 // Splitter the whole New file name into 2 parts between the last period L'.' into NewFileName NewFileExtension
737 // If no period in the whole file name. NewFileExtension is set to L'\0'
738 //
739 NewFileName = NewFileInfoEntry->FileNameFirstPart;
740 NewFileNameExtension = NewFileInfoEntry->FileNameSecondPart;
741 SplitFileNameExtension(FileInfo->FileName, NewFileName, NewFileNameExtension);
742 UpperCaseString(NewFileName);
743 UpperCaseString(NewFileNameExtension);
744
745 //
746 // Insert capsule file in alphabetical ordered list
747 //
748 for (Link = FileInfoList->ForwardLink; Link != FileInfoList; Link = Link->ForwardLink) {
749 //
750 // Get the FileInfo from the link list
751 //
752 TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
753 ListedFileName = TempFileInfoEntry->FileNameFirstPart;
754 ListedFileNameExtension = TempFileInfoEntry->FileNameSecondPart;
755
756 //
757 // Follow rule in UEFI spec 8.5.5 to compare file name
758 //
759 IndexListed = 0;
760 IndexNew = 0;
761 while (TRUE){
762 //
763 // First compare each substrings in NewFileName & ListedFileName between periods
764 //
765 GetSubStringBeforePeriod(&NewFileName[IndexNew], TempNewSubStr, &NewSubStrLen);
766 GetSubStringBeforePeriod(&ListedFileName[IndexListed], TempListedSubStr, &ListedSubStrLen);
767 if (NewSubStrLen > ListedSubStrLen) {
768 //
769 // Substr in NewFileName is longer. Pad tail with SPACE
770 //
771 PadStrInTail(TempListedSubStr, NewSubStrLen - ListedSubStrLen, L' ');
772 } else if (NewSubStrLen < ListedSubStrLen){
773 //
774 // Substr in ListedFileName is longer. Pad tail with SPACE
775 //
776 PadStrInTail(TempNewSubStr, ListedSubStrLen - NewSubStrLen, L' ');
777 }
778
779 SubStrCmpResult = StrnCmp(TempNewSubStr, TempListedSubStr, MAX_FILE_NAME_LEN);
780 if (SubStrCmpResult != 0) {
781 break;
782 }
783
784 //
785 // Move to skip this substring
786 //
787 IndexNew += NewSubStrLen;
788 IndexListed += ListedSubStrLen;
789 //
790 // Reach File First Name end
791 //
792 if (NewFileName[IndexNew] == L'\0' || ListedFileName[IndexListed] == L'\0') {
793 break;
794 }
795
796 //
797 // Skip the period L'.'
798 //
799 IndexNew++;
800 IndexListed++;
801 }
802
803 if (SubStrCmpResult < 0) {
804 //
805 // NewFileName is smaller. Find the right place to insert New file
806 //
807 break;
808 } else if (SubStrCmpResult == 0) {
809 //
810 // 2 cases whole NewFileName is smaller than ListedFileName
811 // 1. if NewFileName == ListedFileName. Continue to compare FileNameExtension
812 // 2. if NewFileName is shorter than ListedFileName
813 //
814 if (NewFileName[IndexNew] == L'\0') {
815 if (ListedFileName[IndexListed] != L'\0' || (StrnCmp(NewFileNameExtension, ListedFileNameExtension, MAX_FILE_NAME_LEN) < 0)) {
816 break;
817 }
818 }
819 }
820
821 //
822 // Other case, ListedFileName is smaller. Continue to compare the next file in the list
823 //
824 }
825
826 //
827 // If Find an entry in the list whose name is bigger than new FileInfo in alphabet order
828 // Insert it before this entry
829 // else
830 // Insert at the tail of this list (Link = FileInfoList)
831 //
832 InsertTailList(Link, &NewFileInfoEntry->Link);
833
834 FileCount++;
835 }
836
837 *FileNum = FileCount;
838
839 EXIT:
840
841 if (TempNewSubStr != NULL) {
842 FreePool(TempNewSubStr);
843 }
844
845 if (TempListedSubStr != NULL) {
846 FreePool(TempListedSubStr);
847 }
848
849 if (EFI_ERROR(Status)) {
850 while(!IsListEmpty(FileInfoList)) {
851 Link = FileInfoList->ForwardLink;
852 RemoveEntryList(Link);
853
854 TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
855
856 FreePool(TempFileInfoEntry->FileInfo);
857 FreePool(TempFileInfoEntry->FileNameFirstPart);
858 FreePool(TempFileInfoEntry->FileNameSecondPart);
859 FreePool(TempFileInfoEntry);
860 }
861 *FileNum = 0;
862 }
863
864 return Status;
865 }
866
867
868 /**
869 This routine is called to get all qualified image from file from an given directory
870 in alphabetic order. All the file image is copied to allocated boottime memory.
871 Caller should free these memory
872
873 @param[in] Dir Directory file handler
874 @param[in] FileAttr Attribute of file to be red from directory
875 @param[out] FilePtr File images Info buffer red from directory
876 @param[out] FileNum File images number red from directory
877
878 @retval EFI_SUCCESS Succeed to get all capsules in alphabetic order.
879
880 **/
881 EFI_STATUS
882 GetFileImageInAlphabetFromDir(
883 IN EFI_FILE_HANDLE Dir,
884 IN UINT64 FileAttr,
885 OUT IMAGE_INFO **FilePtr,
886 OUT UINTN *FileNum
887 )
888 {
889 EFI_STATUS Status;
890 LIST_ENTRY *Link;
891 EFI_FILE_HANDLE FileHandle;
892 FILE_INFO_ENTRY *FileInfoEntry;
893 EFI_FILE_INFO *FileInfo;
894 UINTN FileCount;
895 IMAGE_INFO *TempFilePtrBuf;
896 UINTN Size;
897 LIST_ENTRY FileInfoList;
898
899 FileHandle = NULL;
900 FileCount = 0;
901 TempFilePtrBuf = NULL;
902 *FilePtr = NULL;
903
904 //
905 // Get file list in Dir in alphabetical order
906 //
907 Status = GetFileInfoListInAlphabetFromDir(
908 Dir,
909 FileAttr,
910 &FileInfoList,
911 &FileCount
912 );
913 if (EFI_ERROR(Status)) {
914 DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir Failed!\n"));
915 goto EXIT;
916 }
917
918 if (FileCount == 0) {
919 DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));
920 Status = EFI_NOT_FOUND;
921 goto EXIT;
922 }
923
924 TempFilePtrBuf = (IMAGE_INFO *)AllocateZeroPool(sizeof(IMAGE_INFO) * FileCount);
925 if (TempFilePtrBuf == NULL) {
926 Status = EFI_OUT_OF_RESOURCES;
927 goto EXIT;
928 }
929
930 //
931 // Read all files from FileInfoList to BS memory
932 //
933 FileCount = 0;
934 for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link->ForwardLink) {
935 //
936 // Get FileInfo from the link list
937 //
938 FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
939 FileInfo = FileInfoEntry->FileInfo;
940
941 Status = Dir->Open(
942 Dir,
943 &FileHandle,
944 FileInfo->FileName,
945 EFI_FILE_MODE_READ,
946 0
947 );
948 if (EFI_ERROR(Status)){
949 continue;
950 }
951
952 Size = (UINTN)FileInfo->FileSize;
953 TempFilePtrBuf[FileCount].ImageAddress = AllocateZeroPool(Size);
954 if (TempFilePtrBuf[FileCount].ImageAddress == NULL) {
955 DEBUG((DEBUG_ERROR, "Fail to allocate memory for capsule. Stop processing the rest.\n"));
956 break;
957 }
958
959 Status = FileHandle->Read(
960 FileHandle,
961 &Size,
962 TempFilePtrBuf[FileCount].ImageAddress
963 );
964
965 FileHandle->Close(FileHandle);
966
967 //
968 // Skip read error file
969 //
970 if (EFI_ERROR(Status) || Size != (UINTN)FileInfo->FileSize) {
971 //
972 // Remove this error file info accordingly
973 // & move Link to BackLink
974 //
975 Link = RemoveEntryList(Link);
976 Link = Link->BackLink;
977
978 FreePool(FileInfoEntry->FileInfo);
979 FreePool(FileInfoEntry->FileNameFirstPart);
980 FreePool(FileInfoEntry->FileNameSecondPart);
981 FreePool(FileInfoEntry);
982
983 FreePool(TempFilePtrBuf[FileCount].ImageAddress);
984 TempFilePtrBuf[FileCount].ImageAddress = NULL;
985 TempFilePtrBuf[FileCount].FileInfo = NULL;
986
987 continue;
988 }
989 TempFilePtrBuf[FileCount].FileInfo = FileInfo;
990 FileCount++;
991 }
992
993 DEBUG_CODE (
994 for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link->ForwardLink) {
995 FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
996 FileInfo = FileInfoEntry->FileInfo;
997 DEBUG((DEBUG_INFO, "Successfully read capsule file %s from disk.\n", FileInfo->FileName));
998 }
999 );
1000
1001 EXIT:
1002
1003 *FilePtr = TempFilePtrBuf;
1004 *FileNum = FileCount;
1005
1006 //
1007 // FileInfo will be freed by Calller
1008 //
1009 while(!IsListEmpty(&FileInfoList)) {
1010 Link = FileInfoList.ForwardLink;
1011 RemoveEntryList(Link);
1012
1013 FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
1014
1015 FreePool(FileInfoEntry->FileNameFirstPart);
1016 FreePool(FileInfoEntry->FileNameSecondPart);
1017 FreePool(FileInfoEntry);
1018 }
1019
1020 return Status;
1021 }
1022
1023 /**
1024 This routine is called to remove all qualified image from file from an given directory.
1025
1026 @param[in] Dir Directory file handler
1027 @param[in] FileAttr Attribute of files to be deleted
1028
1029 @retval EFI_SUCCESS Succeed to remove all files from an given directory.
1030
1031 **/
1032 EFI_STATUS
1033 RemoveFileFromDir(
1034 IN EFI_FILE_HANDLE Dir,
1035 IN UINT64 FileAttr
1036 )
1037 {
1038 EFI_STATUS Status;
1039 LIST_ENTRY *Link;
1040 LIST_ENTRY FileInfoList;
1041 EFI_FILE_HANDLE FileHandle;
1042 FILE_INFO_ENTRY *FileInfoEntry;
1043 EFI_FILE_INFO *FileInfo;
1044 UINTN FileCount;
1045
1046 FileHandle = NULL;
1047
1048 //
1049 // Get file list in Dir in alphabetical order
1050 //
1051 Status = GetFileInfoListInAlphabetFromDir(
1052 Dir,
1053 FileAttr,
1054 &FileInfoList,
1055 &FileCount
1056 );
1057 if (EFI_ERROR(Status)) {
1058 DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir Failed!\n"));
1059 goto EXIT;
1060 }
1061
1062 if (FileCount == 0) {
1063 DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));
1064 Status = EFI_NOT_FOUND;
1065 goto EXIT;
1066 }
1067
1068 //
1069 // Delete all files with given attribute in Dir
1070 //
1071 for (Link = FileInfoList.ForwardLink; Link != &(FileInfoList); Link = Link->ForwardLink) {
1072 //
1073 // Get FileInfo from the link list
1074 //
1075 FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
1076 FileInfo = FileInfoEntry->FileInfo;
1077
1078 Status = Dir->Open(
1079 Dir,
1080 &FileHandle,
1081 FileInfo->FileName,
1082 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
1083 0
1084 );
1085 if (EFI_ERROR(Status)){
1086 continue;
1087 }
1088
1089 Status = FileHandle->Delete(FileHandle);
1090 }
1091
1092 EXIT:
1093
1094 while(!IsListEmpty(&FileInfoList)) {
1095 Link = FileInfoList.ForwardLink;
1096 RemoveEntryList(Link);
1097
1098 FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
1099
1100 FreePool(FileInfoEntry->FileInfo);
1101 FreePool(FileInfoEntry);
1102 }
1103
1104 return Status;
1105 }
1106
1107 /**
1108 This routine is called to get all caspules from file. The capsule file image is
1109 copied to BS memory. Caller is responsible to free them.
1110
1111 @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
1112 devices like USB can get enumerated.
1113 @param[out] CapsulePtr Copied Capsule file Image Info buffer
1114 @param[out] CapsuleNum CapsuleNumber
1115 @param[out] FsHandle File system handle
1116 @param[out] LoadOptionNumber OptionNumber of boot option
1117
1118 @retval EFI_SUCCESS Succeed to get all capsules.
1119
1120 **/
1121 EFI_STATUS
1122 GetAllCapsuleOnDisk(
1123 IN UINTN MaxRetry,
1124 OUT IMAGE_INFO **CapsulePtr,
1125 OUT UINTN *CapsuleNum,
1126 OUT EFI_HANDLE *FsHandle,
1127 OUT UINT16 *LoadOptionNumber
1128 )
1129 {
1130 EFI_STATUS Status;
1131 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
1132 EFI_FILE_HANDLE RootDir;
1133 EFI_FILE_HANDLE FileDir;
1134 UINT16 *TempOptionNumber;
1135
1136 TempOptionNumber = NULL;
1137 *CapsuleNum = 0;
1138
1139 Status = GetEfiSysPartitionFromActiveBootOption(MaxRetry, &TempOptionNumber, FsHandle);
1140 if (EFI_ERROR(Status)) {
1141 return Status;
1142 }
1143
1144 Status = gBS->HandleProtocol(*FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
1145 if (EFI_ERROR(Status)) {
1146 return Status;
1147 }
1148
1149 Status = Fs->OpenVolume(Fs, &RootDir);
1150 if (EFI_ERROR(Status)) {
1151 return Status;
1152 }
1153
1154 Status = RootDir->Open(
1155 RootDir,
1156 &FileDir,
1157 EFI_CAPSULE_FILE_DIRECTORY,
1158 EFI_FILE_MODE_READ,
1159 0
1160 );
1161 if (EFI_ERROR(Status)) {
1162 DEBUG((DEBUG_ERROR, "CodLibGetAllCapsuleOnDisk fail to open RootDir!\n"));
1163 RootDir->Close (RootDir);
1164 return Status;
1165 }
1166 RootDir->Close (RootDir);
1167
1168 //
1169 // Only Load files with EFI_FILE_SYSTEM or EFI_FILE_ARCHIVE attribute
1170 // ignore EFI_FILE_READ_ONLY, EFI_FILE_HIDDEN, EFI_FILE_RESERVED, EFI_FILE_DIRECTORY
1171 //
1172 Status = GetFileImageInAlphabetFromDir(
1173 FileDir,
1174 EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE,
1175 CapsulePtr,
1176 CapsuleNum
1177 );
1178 DEBUG((DEBUG_INFO, "GetFileImageInAlphabetFromDir status %x\n", Status));
1179
1180 //
1181 // Always remove file to avoid deadloop in capsule process
1182 //
1183 Status = RemoveFileFromDir(FileDir, EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE);
1184 DEBUG((DEBUG_INFO, "RemoveFileFromDir status %x\n", Status));
1185
1186 FileDir->Close (FileDir);
1187
1188 if (LoadOptionNumber != NULL) {
1189 *LoadOptionNumber = *TempOptionNumber;
1190 }
1191
1192 return Status;
1193 }
1194
1195 /**
1196 Build Gather list for a list of capsule images.
1197
1198 @param[in] CapsuleBuffer An array of pointer to capsule images
1199 @param[in] CapsuleSize An array of UINTN to capsule images size
1200 @param[in] CapsuleNum The count of capsule images
1201 @param[out] BlockDescriptors The block descriptors for the capsule images
1202
1203 @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
1204
1205 **/
1206 EFI_STATUS
1207 BuildGatherList (
1208 IN VOID **CapsuleBuffer,
1209 IN UINTN *CapsuleSize,
1210 IN UINTN CapsuleNum,
1211 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors
1212 )
1213 {
1214 EFI_STATUS Status;
1215 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;
1216 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;
1217 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;
1218 UINTN Index;
1219
1220 BlockDescriptors1 = NULL;
1221 BlockDescriptorPre = NULL;
1222 BlockDescriptorsHeader = NULL;
1223
1224 for (Index = 0; Index < CapsuleNum; Index++) {
1225 //
1226 // Allocate memory for the descriptors.
1227 //
1228 BlockDescriptors1 = AllocateZeroPool (2 * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR));
1229 if (BlockDescriptors1 == NULL) {
1230 DEBUG ((DEBUG_ERROR, "BuildGatherList: failed to allocate memory for descriptors\n"));
1231 Status = EFI_OUT_OF_RESOURCES;
1232 goto ERREXIT;
1233 } else {
1234 DEBUG ((DEBUG_INFO, "BuildGatherList: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1));
1235 }
1236
1237 //
1238 // Record descirptor header
1239 //
1240 if (Index == 0) {
1241 BlockDescriptorsHeader = BlockDescriptors1;
1242 }
1243
1244 if (BlockDescriptorPre != NULL) {
1245 BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1;
1246 BlockDescriptorPre->Length = 0;
1247 }
1248
1249 BlockDescriptors1->Union.DataBlock = (UINTN) CapsuleBuffer[Index];
1250 BlockDescriptors1->Length = CapsuleSize[Index];
1251
1252 BlockDescriptorPre = BlockDescriptors1 + 1;
1253 BlockDescriptors1 = NULL;
1254 }
1255
1256 //
1257 // Null-terminate.
1258 //
1259 if (BlockDescriptorPre != NULL) {
1260 BlockDescriptorPre->Union.ContinuationPointer = (UINTN)NULL;
1261 BlockDescriptorPre->Length = 0;
1262 *BlockDescriptors = BlockDescriptorsHeader;
1263 }
1264
1265 return EFI_SUCCESS;
1266
1267 ERREXIT:
1268 if (BlockDescriptors1 != NULL) {
1269 FreePool (BlockDescriptors1);
1270 }
1271
1272 return Status;
1273 }
1274
1275 /**
1276 This routine is called to check if CapsuleOnDisk flag in OsIndications Variable
1277 is enabled.
1278
1279 @retval TRUE Flag is enabled
1280 @retval FALSE Flag is not enabled
1281
1282 **/
1283 BOOLEAN
1284 EFIAPI
1285 CoDCheckCapsuleOnDiskFlag(
1286 VOID
1287 )
1288 {
1289 EFI_STATUS Status;
1290 UINT64 OsIndication;
1291 UINTN DataSize;
1292
1293 //
1294 // Check File Capsule Delivery Supported Flag in OsIndication variable
1295 //
1296 OsIndication = 0;
1297 DataSize = sizeof(UINT64);
1298 Status = gRT->GetVariable (
1299 EFI_OS_INDICATIONS_VARIABLE_NAME,
1300 &gEfiGlobalVariableGuid,
1301 NULL,
1302 &DataSize,
1303 &OsIndication
1304 );
1305 if (!EFI_ERROR(Status) &&
1306 (OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) {
1307 return TRUE;
1308 }
1309
1310 return FALSE;
1311 }
1312
1313
1314 /**
1315 This routine is called to clear CapsuleOnDisk flags including OsIndications and BootNext variable.
1316
1317 @retval EFI_SUCCESS All Capsule On Disk flags are cleared
1318
1319 **/
1320 EFI_STATUS
1321 EFIAPI
1322 CoDClearCapsuleOnDiskFlag(
1323 VOID
1324 )
1325 {
1326 EFI_STATUS Status;
1327 UINT64 OsIndication;
1328 UINTN DataSize;
1329
1330 //
1331 // Reset File Capsule Delivery Supported Flag in OsIndication variable
1332 //
1333 OsIndication = 0;
1334 DataSize = sizeof(UINT64);
1335 Status = gRT->GetVariable (
1336 EFI_OS_INDICATIONS_VARIABLE_NAME,
1337 &gEfiGlobalVariableGuid,
1338 NULL,
1339 &DataSize,
1340 &OsIndication
1341 );
1342 if (EFI_ERROR(Status) ||
1343 (OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) == 0) {
1344 return Status;
1345 }
1346
1347 OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
1348 Status = gRT->SetVariable (
1349 EFI_OS_INDICATIONS_VARIABLE_NAME,
1350 &gEfiGlobalVariableGuid,
1351 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1352 sizeof(UINT64),
1353 &OsIndication
1354 );
1355 ASSERT(!EFI_ERROR(Status));
1356
1357 //
1358 // Delete BootNext variable. Capsule Process may reset system, so can't rely on Bds to clear this variable
1359 //
1360 Status = gRT->SetVariable (
1361 EFI_BOOT_NEXT_VARIABLE_NAME,
1362 &gEfiGlobalVariableGuid,
1363 0,
1364 0,
1365 NULL
1366 );
1367 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
1368
1369 return EFI_SUCCESS;
1370 }
1371
1372 /**
1373 This routine is called to clear CapsuleOnDisk Relocation Info variable.
1374 Total Capsule On Disk length is recorded in this variable
1375
1376 @retval EFI_SUCCESS Capsule On Disk flags are cleared
1377
1378 **/
1379 EFI_STATUS
1380 CoDClearCapsuleRelocationInfo(
1381 VOID
1382 )
1383 {
1384 return gRT->SetVariable (
1385 COD_RELOCATION_INFO_VAR_NAME,
1386 &gEfiCapsuleVendorGuid,
1387 0,
1388 0,
1389 NULL
1390 );
1391 }
1392
1393 /**
1394 Relocate Capsule on Disk from EFI system partition to a platform-specific NV storage device
1395 with BlockIo protocol. Relocation device path, identified by PcdCodRelocationDevPath, must
1396 be a full device path.
1397 Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
1398 Function will stall 100ms between each retry.
1399
1400 Side Effects:
1401 Content corruption. Block IO write directly touches low level write. Orignal partitions, file systems
1402 of the relocation device will be corrupted.
1403
1404 @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
1405 devices like USB can get enumerated.
1406
1407 @retval EFI_SUCCESS Capsule on Disk images are sucessfully relocated to the platform-specific device.
1408
1409 **/
1410 EFI_STATUS
1411 RelocateCapsuleToDisk(
1412 UINTN MaxRetry
1413 )
1414 {
1415 EFI_STATUS Status;
1416 UINTN CapsuleOnDiskNum;
1417 UINTN Index;
1418 UINTN DataSize;
1419 UINT64 TotalImageSize;
1420 UINT64 TotalImageNameSize;
1421 IMAGE_INFO *CapsuleOnDiskBuf;
1422 EFI_HANDLE Handle;
1423 EFI_HANDLE TempHandle;
1424 EFI_HANDLE *HandleBuffer;
1425 UINTN NumberOfHandles;
1426 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1427 UINT8 *CapsuleDataBuf;
1428 UINT8 *CapsulePtr;
1429 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
1430 EFI_FILE_HANDLE RootDir;
1431 EFI_FILE_HANDLE TempCodFile;
1432 UINT64 TempCodFileSize;
1433 EFI_DEVICE_PATH *TempDevicePath;
1434 BOOLEAN RelocationInfo;
1435 UINT16 LoadOptionNumber;
1436 EFI_CAPSULE_HEADER FileNameCapsuleHeader;
1437
1438 RootDir = NULL;
1439 TempCodFile = NULL;
1440 HandleBuffer = NULL;
1441 CapsuleDataBuf = NULL;
1442 CapsuleOnDiskBuf = NULL;
1443 NumberOfHandles = 0;
1444
1445 DEBUG ((DEBUG_INFO, "CapsuleOnDisk RelocateCapsule Enter\n"));
1446
1447 //
1448 // 1. Load all Capsule On Disks in to memory
1449 //
1450 Status = GetAllCapsuleOnDisk(MaxRetry, &CapsuleOnDiskBuf, &CapsuleOnDiskNum, &Handle, &LoadOptionNumber);
1451 if (EFI_ERROR(Status) || CapsuleOnDiskNum == 0 || CapsuleOnDiskBuf == NULL) {
1452 DEBUG ((DEBUG_INFO, "RelocateCapsule: GetAllCapsuleOnDisk Status - 0x%x\n", Status));
1453 return EFI_NOT_FOUND;
1454 }
1455
1456 //
1457 // 2. Connect platform special device path as relocation device.
1458 // If no platform special device path specified or the device path is invalid, use the EFI system partition where
1459 // stores the capsules as relocation device.
1460 //
1461 if (IsDevicePathValid ((EFI_DEVICE_PATH *)PcdGetPtr(PcdCodRelocationDevPath), PcdGetSize(PcdCodRelocationDevPath))) {
1462 Status = EfiBootManagerConnectDevicePath ((EFI_DEVICE_PATH *)PcdGetPtr(PcdCodRelocationDevPath), &TempHandle);
1463 if (EFI_ERROR(Status)) {
1464 DEBUG ((DEBUG_ERROR, "RelocateCapsule: EfiBootManagerConnectDevicePath Status - 0x%x\n", Status));
1465 goto EXIT;
1466 }
1467
1468 //
1469 // Connect all the child handle. Partition & FAT drivers are allowed in this case
1470 //
1471 gBS->ConnectController (TempHandle, NULL, NULL, TRUE);
1472 Status = gBS->LocateHandleBuffer(
1473 ByProtocol,
1474 &gEfiSimpleFileSystemProtocolGuid,
1475 NULL,
1476 &NumberOfHandles,
1477 &HandleBuffer
1478 );
1479 if (EFI_ERROR(Status)) {
1480 DEBUG ((DEBUG_ERROR, "RelocateCapsule: LocateHandleBuffer Status - 0x%x\n", Status));
1481 goto EXIT;
1482 }
1483
1484 //
1485 // Find first Simple File System Handle which can match PcdCodRelocationDevPath
1486 //
1487 for (Index = 0; Index < NumberOfHandles; Index++) {
1488 Status = gBS->HandleProtocol(HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&TempDevicePath);
1489 if (EFI_ERROR(Status)) {
1490 continue;
1491 }
1492
1493 DataSize = GetDevicePathSize((EFI_DEVICE_PATH *)PcdGetPtr(PcdCodRelocationDevPath)) - sizeof(EFI_DEVICE_PATH);
1494 if (0 == CompareMem((EFI_DEVICE_PATH *)PcdGetPtr(PcdCodRelocationDevPath), TempDevicePath, DataSize)) {
1495 Handle = HandleBuffer[Index];
1496 break;
1497 }
1498 }
1499
1500 FreePool(HandleBuffer);
1501
1502 if (Index == NumberOfHandles) {
1503 DEBUG ((DEBUG_ERROR, "RelocateCapsule: No simple file system protocol found.\n"));
1504 Status = EFI_NOT_FOUND;
1505 }
1506 }
1507
1508 Status = gBS->HandleProtocol(Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
1509 if (EFI_ERROR(Status) || BlockIo->Media->ReadOnly) {
1510 DEBUG((DEBUG_ERROR, "Fail to find Capsule on Disk relocation BlockIo device or device is ReadOnly!\n"));
1511 goto EXIT;
1512 }
1513
1514 Status = gBS->HandleProtocol(Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
1515 if (EFI_ERROR(Status)) {
1516 goto EXIT;
1517 }
1518
1519 //
1520 // Check if device used to relocate Capsule On Disk is big enough
1521 //
1522 TotalImageSize = 0;
1523 TotalImageNameSize = 0;
1524 for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
1525 //
1526 // Overflow check
1527 //
1528 if (MAX_ADDRESS - (UINTN)TotalImageSize <= CapsuleOnDiskBuf[Index].FileInfo->FileSize) {
1529 Status = EFI_INVALID_PARAMETER;
1530 goto EXIT;
1531 }
1532
1533 if (MAX_ADDRESS - (UINTN)TotalImageNameSize <= StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName)) {
1534 Status = EFI_INVALID_PARAMETER;
1535 goto EXIT;
1536 }
1537
1538 TotalImageSize += CapsuleOnDiskBuf[Index].FileInfo->FileSize;
1539 TotalImageNameSize += StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName);
1540 DEBUG((DEBUG_INFO, "RelocateCapsule: %x Size %x\n",CapsuleOnDiskBuf[Index].FileInfo->FileName, CapsuleOnDiskBuf[Index].FileInfo->FileSize));
1541 }
1542
1543 DEBUG((DEBUG_INFO, "RelocateCapsule: TotalImageSize %x\n", TotalImageSize));
1544 DEBUG((DEBUG_INFO, "RelocateCapsule: TotalImageNameSize %x\n", TotalImageNameSize));
1545
1546 if (MAX_ADDRESS - (UINTN)TotalImageNameSize <= sizeof(UINT64) * 2 ||
1547 MAX_ADDRESS - (UINTN)TotalImageSize <= (UINTN)TotalImageNameSize + sizeof(UINT64) * 2) {
1548 Status = EFI_INVALID_PARAMETER;
1549 goto EXIT;
1550 }
1551
1552 TempCodFileSize = sizeof(UINT64) + TotalImageSize + sizeof(EFI_CAPSULE_HEADER) + TotalImageNameSize;
1553
1554 //
1555 // Check if CapsuleTotalSize. There could be reminder, so use LastBlock number directly
1556 //
1557 if (DivU64x32(TempCodFileSize, BlockIo->Media->BlockSize) > BlockIo->Media->LastBlock) {
1558 DEBUG((DEBUG_ERROR, "RelocateCapsule: Relocation device isn't big enough to hold all Capsule on Disk!\n"));
1559 DEBUG((DEBUG_ERROR, "TotalImageSize = %x\n", TotalImageSize));
1560 DEBUG((DEBUG_ERROR, "TotalImageNameSize = %x\n", TotalImageNameSize));
1561 DEBUG((DEBUG_ERROR, "RelocationDev BlockSize = %x LastBlock = %x\n", BlockIo->Media->BlockSize, BlockIo->Media->LastBlock));
1562 Status = EFI_OUT_OF_RESOURCES;
1563 goto EXIT;
1564 }
1565
1566 CapsuleDataBuf = AllocatePool((UINTN) TempCodFileSize);
1567 if (CapsuleDataBuf == NULL) {
1568 Status = EFI_OUT_OF_RESOURCES;
1569 goto EXIT;
1570 }
1571
1572 //
1573 // First UINT64 reserved for total image size, including capsule name capsule.
1574 //
1575 *(UINT64 *) CapsuleDataBuf = TotalImageSize + sizeof(EFI_CAPSULE_HEADER) + TotalImageNameSize;
1576
1577 //
1578 // Line up all the Capsule on Disk and write to relocation disk at one time. It could save some time in disk write
1579 //
1580 for (Index = 0, CapsulePtr = CapsuleDataBuf + sizeof(UINT64); Index < CapsuleOnDiskNum; Index++) {
1581 CopyMem(CapsulePtr, CapsuleOnDiskBuf[Index].ImageAddress, (UINTN) CapsuleOnDiskBuf[Index].FileInfo->FileSize);
1582 CapsulePtr += CapsuleOnDiskBuf[Index].FileInfo->FileSize;
1583 }
1584
1585 //
1586 // Line the capsule header for capsule name capsule.
1587 //
1588 CopyGuid(&FileNameCapsuleHeader.CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);
1589 FileNameCapsuleHeader.CapsuleImageSize = (UINT32) TotalImageNameSize + sizeof(EFI_CAPSULE_HEADER);
1590 FileNameCapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
1591 FileNameCapsuleHeader.HeaderSize = sizeof(EFI_CAPSULE_HEADER);
1592 CopyMem(CapsulePtr, &FileNameCapsuleHeader, FileNameCapsuleHeader.HeaderSize);
1593 CapsulePtr += FileNameCapsuleHeader.HeaderSize;
1594
1595 //
1596 // Line up all the Capsule file names.
1597 //
1598 for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
1599 CopyMem(CapsulePtr, CapsuleOnDiskBuf[Index].FileInfo->FileName, StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName));
1600 CapsulePtr += StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName);
1601 }
1602
1603 //
1604 // 5. Flash all Capsules on Disk to TempCoD.tmp under RootDir
1605 //
1606 Status = Fs->OpenVolume(Fs, &RootDir);
1607 if (EFI_ERROR(Status)) {
1608 DEBUG((DEBUG_ERROR, "RelocateCapsule: OpenVolume error. %x\n", Status));
1609 goto EXIT;
1610 }
1611
1612 Status = RootDir->Open(
1613 RootDir,
1614 &TempCodFile,
1615 (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName),
1616 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
1617 0
1618 );
1619 if (!EFI_ERROR(Status)) {
1620 //
1621 // Error handling code to prevent malicious code to hold this file to block capsule on disk
1622 //
1623 TempCodFile->Delete(TempCodFile);
1624 }
1625 Status = RootDir->Open(
1626 RootDir,
1627 &TempCodFile,
1628 (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName),
1629 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
1630 0
1631 );
1632 if (EFI_ERROR(Status)) {
1633 DEBUG((DEBUG_ERROR, "RelocateCapsule: Open TemCoD.tmp error. %x\n", Status));
1634 goto EXIT;
1635 }
1636
1637 //
1638 // Always write at the begining of TempCap file
1639 //
1640 DataSize = (UINTN) TempCodFileSize;
1641 Status = TempCodFile->Write(
1642 TempCodFile,
1643 &DataSize,
1644 CapsuleDataBuf
1645 );
1646 if (EFI_ERROR(Status)) {
1647 DEBUG((DEBUG_ERROR, "RelocateCapsule: Write TemCoD.tmp error. %x\n", Status));
1648 goto EXIT;
1649 }
1650
1651 if (DataSize != TempCodFileSize) {
1652 Status = EFI_DEVICE_ERROR;
1653 goto EXIT;
1654 }
1655
1656 //
1657 // Save Capsule On Disk relocation info to "CodRelocationInfo" Var
1658 // It is used in next reboot by TCB
1659 //
1660 RelocationInfo = TRUE;
1661 Status = gRT->SetVariable(
1662 COD_RELOCATION_INFO_VAR_NAME,
1663 &gEfiCapsuleVendorGuid,
1664 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1665 sizeof (BOOLEAN),
1666 &RelocationInfo
1667 );
1668 //
1669 // Save the LoadOptionNumber of the boot option, where the capsule is relocated,
1670 // into "CodRelocationLoadOption" var. It is used in next reboot after capsule is
1671 // updated out of TCB to remove the TempCoDFile.
1672 //
1673 Status = gRT->SetVariable(
1674 COD_RELOCATION_LOAD_OPTION_VAR_NAME,
1675 &gEfiCapsuleVendorGuid,
1676 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1677 sizeof (UINT16),
1678 &LoadOptionNumber
1679 );
1680
1681 EXIT:
1682
1683 if (CapsuleDataBuf != NULL) {
1684 FreePool(CapsuleDataBuf);
1685 }
1686
1687 if (CapsuleOnDiskBuf != NULL) {
1688 //
1689 // Free resources allocated by CodLibGetAllCapsuleOnDisk
1690 //
1691 for (Index = 0; Index < CapsuleOnDiskNum; Index++ ) {
1692 FreePool(CapsuleOnDiskBuf[Index].ImageAddress);
1693 FreePool(CapsuleOnDiskBuf[Index].FileInfo);
1694 }
1695 FreePool(CapsuleOnDiskBuf);
1696 }
1697
1698 if (TempCodFile != NULL) {
1699 if (EFI_ERROR(Status)) {
1700 TempCodFile->Delete (TempCodFile);
1701 } else {
1702 TempCodFile->Close (TempCodFile);
1703 }
1704 }
1705
1706 if (RootDir != NULL) {
1707 RootDir->Close (RootDir);
1708 }
1709
1710 return Status;
1711 }
1712
1713 /**
1714 For the platforms that support Capsule In Ram, reuse the Capsule In Ram to deliver capsule.
1715 Relocate Capsule On Disk to memory and call UpdateCapsule().
1716 Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
1717 Function will stall 100ms between each retry.
1718
1719 @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
1720 devices like USB can get enumerated.
1721
1722 @retval EFI_SUCCESS Deliver capsule through Capsule In Ram successfully.
1723
1724 **/
1725 EFI_STATUS
1726 RelocateCapsuleToRam (
1727 UINTN MaxRetry
1728 )
1729 {
1730 EFI_STATUS Status;
1731 UINTN CapsuleOnDiskNum;
1732 IMAGE_INFO *CapsuleOnDiskBuf;
1733 EFI_HANDLE Handle;
1734 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;
1735 VOID **CapsuleBuffer;
1736 UINTN *CapsuleSize;
1737 EFI_CAPSULE_HEADER *FileNameCapsule;
1738 UINTN Index;
1739 UINT8 *StringBuf;
1740 UINTN StringSize;
1741 UINTN TotalStringSize;
1742
1743 CapsuleOnDiskBuf = NULL;
1744 BlockDescriptors = NULL;
1745 CapsuleBuffer = NULL;
1746 CapsuleSize = NULL;
1747 FileNameCapsule = NULL;
1748 TotalStringSize = 0;
1749
1750 //
1751 // 1. Load all Capsule On Disks into memory
1752 //
1753 Status = GetAllCapsuleOnDisk (MaxRetry, &CapsuleOnDiskBuf, &CapsuleOnDiskNum, &Handle, NULL);
1754 if (EFI_ERROR (Status) || CapsuleOnDiskNum == 0 || CapsuleOnDiskBuf == NULL) {
1755 DEBUG ((DEBUG_ERROR, "GetAllCapsuleOnDisk Status - 0x%x\n", Status));
1756 return EFI_NOT_FOUND;
1757 }
1758
1759 //
1760 // 2. Add a capsule for Capsule file name strings
1761 //
1762 CapsuleBuffer = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof (VOID *));
1763 if (CapsuleBuffer == NULL) {
1764 DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));
1765 return EFI_OUT_OF_RESOURCES;
1766 }
1767
1768 CapsuleSize = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof (UINTN));
1769 if (CapsuleSize == NULL) {
1770 DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));
1771 FreePool (CapsuleBuffer);
1772 return EFI_OUT_OF_RESOURCES;
1773 }
1774
1775 for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
1776 CapsuleBuffer[Index] = (VOID *)(UINTN) CapsuleOnDiskBuf[Index].ImageAddress;
1777 CapsuleSize[Index] = (UINTN) CapsuleOnDiskBuf[Index].FileInfo->FileSize;
1778 TotalStringSize += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
1779 }
1780
1781 FileNameCapsule = AllocateZeroPool (sizeof (EFI_CAPSULE_HEADER) + TotalStringSize);
1782 if (FileNameCapsule == NULL) {
1783 DEBUG ((DEBUG_ERROR, "Fail to allocate memory for name capsule.\n"));
1784 FreePool (CapsuleBuffer);
1785 FreePool (CapsuleSize);
1786 return EFI_OUT_OF_RESOURCES;
1787 }
1788
1789 FileNameCapsule->CapsuleImageSize = (UINT32) (sizeof (EFI_CAPSULE_HEADER) + TotalStringSize);
1790 FileNameCapsule->Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
1791 FileNameCapsule->HeaderSize = sizeof (EFI_CAPSULE_HEADER);
1792 CopyGuid (&(FileNameCapsule->CapsuleGuid), &gEdkiiCapsuleOnDiskNameGuid);
1793
1794 StringBuf = (UINT8 *)FileNameCapsule + FileNameCapsule->HeaderSize;
1795 for (Index = 0; Index < CapsuleOnDiskNum; Index ++) {
1796 StringSize = StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
1797 CopyMem (StringBuf, CapsuleOnDiskBuf[Index].FileInfo->FileName, StringSize);
1798 StringBuf += StringSize;
1799 }
1800
1801 CapsuleBuffer[CapsuleOnDiskNum] = FileNameCapsule;
1802 CapsuleSize[CapsuleOnDiskNum] = TotalStringSize + sizeof (EFI_CAPSULE_HEADER);
1803
1804 //
1805 // 3. Build Gather list for the capsules
1806 //
1807 Status = BuildGatherList (CapsuleBuffer, CapsuleSize, CapsuleOnDiskNum + 1, &BlockDescriptors);
1808 if (EFI_ERROR (Status) || BlockDescriptors == NULL) {
1809 FreePool (CapsuleBuffer);
1810 FreePool (CapsuleSize);
1811 FreePool (FileNameCapsule);
1812 return EFI_OUT_OF_RESOURCES;
1813 }
1814
1815 //
1816 // 4. Call UpdateCapsule() service
1817 //
1818 Status = gRT->UpdateCapsule((EFI_CAPSULE_HEADER **) CapsuleBuffer, CapsuleOnDiskNum + 1, (UINTN) BlockDescriptors);
1819
1820 return Status;
1821 }
1822
1823 /**
1824 Relocate Capsule on Disk from EFI system partition.
1825
1826 Two solution to deliver Capsule On Disk:
1827 Solution A: If PcdCapsuleInRamSupport is enabled, relocate Capsule On Disk to memory and call UpdateCapsule().
1828 Solution B: If PcdCapsuleInRamSupport is disabled, relocate Capsule On Disk to a platform-specific NV storage
1829 device with BlockIo protocol.
1830
1831 Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
1832 Function will stall 100ms between each retry.
1833
1834 Side Effects:
1835 Capsule Delivery Supported Flag in OsIndication variable and BootNext variable will be cleared.
1836 Solution B: Content corruption. Block IO write directly touches low level write. Orignal partitions, file
1837 systems of the relocation device will be corrupted.
1838
1839 @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
1840 devices like USB can get enumerated. Input 0 means no retry.
1841
1842 @retval EFI_SUCCESS Capsule on Disk images are successfully relocated.
1843
1844 **/
1845 EFI_STATUS
1846 EFIAPI
1847 CoDRelocateCapsule(
1848 UINTN MaxRetry
1849 )
1850 {
1851 if (!PcdGetBool (PcdCapsuleOnDiskSupport)) {
1852 return EFI_UNSUPPORTED;
1853 }
1854
1855 //
1856 // Clear CapsuleOnDisk Flag firstly.
1857 //
1858 CoDClearCapsuleOnDiskFlag ();
1859
1860 //
1861 // If Capsule In Ram is supported, delivery capsules through memory
1862 //
1863 if (PcdGetBool (PcdCapsuleInRamSupport)) {
1864 DEBUG ((DEBUG_INFO, "Capsule In Ram is supported, call gRT->UpdateCapsule().\n"));
1865 return RelocateCapsuleToRam (MaxRetry);
1866 } else {
1867 DEBUG ((DEBUG_INFO, "Reallcoate all Capsule on Disks to %s in RootDir.\n", (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName)));
1868 return RelocateCapsuleToDisk (MaxRetry);
1869 }
1870 }
1871
1872 /**
1873 Remove the temp file from the root of EFI System Partition.
1874 Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
1875 Function will stall 100ms between each retry.
1876
1877 @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
1878 devices like USB can get enumerated. Input 0 means no retry.
1879
1880 @retval EFI_SUCCESS Remove the temp file successfully.
1881
1882 **/
1883 EFI_STATUS
1884 EFIAPI
1885 CoDRemoveTempFile (
1886 UINTN MaxRetry
1887 )
1888 {
1889 EFI_STATUS Status;
1890 UINTN DataSize;
1891 UINT16 *LoadOptionNumber;
1892 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
1893 EFI_HANDLE FsHandle;
1894 EFI_FILE_HANDLE RootDir;
1895 EFI_FILE_HANDLE TempCodFile;
1896
1897 RootDir = NULL;
1898 TempCodFile = NULL;
1899 DataSize = sizeof(UINT16);
1900
1901 LoadOptionNumber = AllocatePool (sizeof(UINT16));
1902 if (LoadOptionNumber == NULL) {
1903 return EFI_OUT_OF_RESOURCES;
1904 }
1905
1906 //
1907 // Check if capsule files are relocated
1908 //
1909 Status = gRT->GetVariable (
1910 COD_RELOCATION_LOAD_OPTION_VAR_NAME,
1911 &gEfiCapsuleVendorGuid,
1912 NULL,
1913 &DataSize,
1914 (VOID *)LoadOptionNumber
1915 );
1916 if (EFI_ERROR(Status) || DataSize != sizeof(UINT16)) {
1917 goto EXIT;
1918 }
1919
1920 //
1921 // Get the EFI file system from the boot option where the capsules are relocated
1922 //
1923 Status = GetEfiSysPartitionFromActiveBootOption(MaxRetry, &LoadOptionNumber, &FsHandle);
1924 if (EFI_ERROR(Status)) {
1925 goto EXIT;
1926 }
1927
1928 Status = gBS->HandleProtocol(FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
1929 if (EFI_ERROR(Status)) {
1930 goto EXIT;
1931 }
1932
1933 Status = Fs->OpenVolume(Fs, &RootDir);
1934 if (EFI_ERROR(Status)) {
1935 goto EXIT;
1936 }
1937
1938 //
1939 // Delete the TempCoDFile
1940 //
1941 Status = RootDir->Open(
1942 RootDir,
1943 &TempCodFile,
1944 (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName),
1945 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
1946 0
1947 );
1948 if (EFI_ERROR(Status)) {
1949 goto EXIT;
1950 }
1951
1952 TempCodFile->Delete(TempCodFile);
1953
1954 //
1955 // Clear "CoDRelocationLoadOption" variable
1956 //
1957 Status = gRT->SetVariable (
1958 COD_RELOCATION_LOAD_OPTION_VAR_NAME,
1959 &gEfiCapsuleVendorGuid,
1960 0,
1961 0,
1962 NULL
1963 );
1964
1965 EXIT:
1966 if (LoadOptionNumber != NULL) {
1967 FreePool (LoadOptionNumber);
1968 }
1969
1970 if (RootDir != NULL) {
1971 RootDir->Close(RootDir);
1972 }
1973
1974 return Status;
1975 }