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