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