]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c
MdeModulePkg/CapsuleApp: Improve comparisons in CapsuleOnDisk.c
[mirror_edk2.git] / MdeModulePkg / Application / CapsuleApp / CapsuleOnDisk.c
1 /** @file
2 Process Capsule 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 "CapsuleApp.h"
10
11 EFI_GUID mCapsuleOnDiskBootOptionGuid = { 0x4CC29BB7, 0x2413, 0x40A2, { 0xB0, 0x6D, 0x25, 0x3E, 0x37, 0x10, 0xF5, 0x32 } };
12
13 /**
14 Get file name from file path.
15
16 @param FilePath File path.
17
18 @return Pointer to file name.
19
20 **/
21 CHAR16 *
22 GetFileNameFromPath (
23 CHAR16 *FilePath
24 )
25 {
26 EFI_STATUS Status;
27 EFI_SHELL_PROTOCOL *ShellProtocol;
28 SHELL_FILE_HANDLE Handle;
29 EFI_FILE_INFO *FileInfo;
30
31 ShellProtocol = GetShellProtocol ();
32 if (ShellProtocol == NULL) {
33 return NULL;
34 }
35
36 //
37 // Open file by FileName.
38 //
39 Status = ShellProtocol->OpenFileByName (
40 FilePath,
41 &Handle,
42 EFI_FILE_MODE_READ
43 );
44 if (EFI_ERROR (Status)) {
45 return NULL;
46 }
47
48 //
49 // Get file name from EFI_FILE_INFO.
50 //
51 FileInfo = ShellProtocol->GetFileInfo (Handle);
52 ShellProtocol->CloseFile (Handle);
53 if (FileInfo == NULL) {
54 return NULL;
55 }
56
57 return FileInfo->FileName;
58 }
59
60 /**
61 Check if the device path is EFI system Partition.
62
63 @param DevicePath The ESP device path.
64
65 @retval TRUE DevicePath is a device path for ESP.
66 @retval FALSE DevicePath is not a device path for ESP.
67
68 **/
69 BOOLEAN
70 IsEfiSysPartitionDevicePath (
71 EFI_DEVICE_PATH_PROTOCOL *DevicePath
72 )
73 {
74 EFI_STATUS Status;
75 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
76 HARDDRIVE_DEVICE_PATH *Hd;
77 EFI_HANDLE Handle;
78
79 //
80 // Check if the device path contains GPT node
81 //
82 TempDevicePath = DevicePath;
83
84 while (!IsDevicePathEnd (TempDevicePath)) {
85 if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) &&
86 (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP)) {
87 Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
88 if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) {
89 break;
90 }
91 }
92 TempDevicePath = NextDevicePathNode (TempDevicePath);
93 }
94
95 if (!IsDevicePathEnd (TempDevicePath)) {
96 //
97 // Search for EFI system partition protocol on full device path in Boot Option
98 //
99 Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle);
100 return EFI_ERROR (Status) ? FALSE : TRUE;
101 } else {
102 return FALSE;
103 }
104 }
105
106 /**
107 Dump all EFI System Partition.
108
109 **/
110 VOID
111 DumpAllEfiSysPartition (
112 VOID
113 )
114 {
115 EFI_HANDLE *SimpleFileSystemHandles;
116 UINTN NumberSimpleFileSystemHandles;
117 UINTN Index;
118 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
119 UINTN NumberEfiSystemPartitions;
120 EFI_SHELL_PROTOCOL *ShellProtocol;
121
122 NumberEfiSystemPartitions = 0;
123
124 ShellProtocol = GetShellProtocol ();
125 if (ShellProtocol == NULL) {
126 Print (L"Get Shell Protocol Fail\n");;
127 return ;
128 }
129
130 Print (L"EFI System Partition list:\n");
131
132 gBS->LocateHandleBuffer (
133 ByProtocol,
134 &gEfiSimpleFileSystemProtocolGuid,
135 NULL,
136 &NumberSimpleFileSystemHandles,
137 &SimpleFileSystemHandles
138 );
139
140 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
141 DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
142 if (IsEfiSysPartitionDevicePath (DevicePath)) {
143 NumberEfiSystemPartitions++;
144 Print(L" %s\n %s\n", ShellProtocol->GetMapFromDevicePath (&DevicePath), ConvertDevicePathToText (DevicePath, TRUE, TRUE));
145 }
146 }
147
148 if (NumberEfiSystemPartitions == 0) {
149 Print(L" No ESP found.\n");
150 }
151 }
152
153 /**
154 Check if capsule is provisioned.
155
156 @retval TRUE Capsule is provisioned previously.
157 @retval FALSE No capsule is provisioned.
158
159 **/
160 BOOLEAN
161 IsCapsuleProvisioned (
162 VOID
163 )
164 {
165 EFI_STATUS Status;
166 UINT64 OsIndication;
167 UINTN DataSize;
168
169 OsIndication = 0;
170 DataSize = sizeof(UINT64);
171 Status = gRT->GetVariable (
172 L"OsIndications",
173 &gEfiGlobalVariableGuid,
174 NULL,
175 &DataSize,
176 &OsIndication
177 );
178 if (!EFI_ERROR (Status) &&
179 (OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) {
180 return TRUE;
181 }
182
183 return FALSE;
184 }
185
186 /**
187 Get one active Efi System Partition.
188
189 @param[out] FsDevicePath The device path of Fs
190 @param[out] Fs The file system within EfiSysPartition
191
192 @retval EFI_SUCCESS Get file system successfully
193 @retval EFI_NOT_FOUND No valid file system found
194
195 **/
196 EFI_STATUS
197 GetEfiSysPartition (
198 OUT EFI_DEVICE_PATH_PROTOCOL **FsDevicePath,
199 OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
200 )
201 {
202 EFI_HANDLE *SimpleFileSystemHandles;
203 UINTN NumberSimpleFileSystemHandles;
204 UINTN Index;
205 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
206 EFI_STATUS Status;
207
208 Status = gBS->LocateHandleBuffer (
209 ByProtocol,
210 &gEfiSimpleFileSystemProtocolGuid,
211 NULL,
212 &NumberSimpleFileSystemHandles,
213 &SimpleFileSystemHandles
214 );
215
216 if (EFI_ERROR (Status)) {
217 return EFI_NOT_FOUND;
218 }
219
220 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
221 DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
222 if (IsEfiSysPartitionDevicePath (DevicePath)) {
223 Status = gBS->HandleProtocol (SimpleFileSystemHandles[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)Fs);
224 if (!EFI_ERROR (Status)) {
225 *FsDevicePath = DevicePath;
226 return EFI_SUCCESS;
227 }
228 }
229 }
230
231 return EFI_NOT_FOUND;
232 }
233
234 /**
235 Check if Active Efi System Partition within GPT is in the device path.
236
237 @param[in] DevicePath The device path
238 @param[out] FsDevicePath The device path of Fs
239 @param[out] Fs The file system within EfiSysPartition
240
241 @retval EFI_SUCCESS Get file system successfully
242 @retval EFI_NOT_FOUND No valid file system found
243 @retval others Get file system failed
244
245 **/
246 EFI_STATUS
247 GetEfiSysPartitionFromDevPath (
248 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
249 OUT EFI_DEVICE_PATH_PROTOCOL **FsDevicePath,
250 OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
251 )
252 {
253 EFI_STATUS Status;
254 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
255 HARDDRIVE_DEVICE_PATH *Hd;
256 EFI_HANDLE Handle;
257
258 //
259 // Check if the device path contains GPT node
260 //
261 TempDevicePath = DevicePath;
262 while (!IsDevicePathEnd (TempDevicePath)) {
263 if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) &&
264 (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP)) {
265 Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
266 if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) {
267 break;
268 }
269 }
270 TempDevicePath = NextDevicePathNode (TempDevicePath);
271 }
272
273 if (!IsDevicePathEnd (TempDevicePath)) {
274 //
275 // Search for EFI system partition protocol on full device path in Boot Option
276 //
277 Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle);
278
279 //
280 // Search for simple file system on this handler
281 //
282 if (!EFI_ERROR (Status)) {
283 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)Fs);
284 if (!EFI_ERROR (Status)) {
285 *FsDevicePath = DevicePathFromHandle (Handle);
286 return EFI_SUCCESS;
287 }
288 }
289 }
290
291 return EFI_NOT_FOUND;
292 }
293
294 /**
295 Get SimpleFileSystem from boot option file path.
296
297 @param[in] DevicePath The file path of boot option
298 @param[out] FullPath The full device path of boot device
299 @param[out] Fs The file system within EfiSysPartition
300
301 @retval EFI_SUCCESS Get file system successfully
302 @retval EFI_NOT_FOUND No valid file system found
303 @retval others Get file system failed
304
305 **/
306 EFI_STATUS
307 GetEfiSysPartitionFromBootOptionFilePath (
308 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
309 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
310 OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
311 )
312 {
313 EFI_STATUS Status;
314 EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
315 EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
316 EFI_DEVICE_PATH_PROTOCOL *FsFullPath;
317
318 CurFullPath = NULL;
319 FsFullPath = NULL;
320 //
321 // Try every full device Path generated from bootoption
322 //
323 do {
324 PreFullPath = CurFullPath;
325 CurFullPath = EfiBootManagerGetNextLoadOptionDevicePath (DevicePath, CurFullPath);
326
327 if (PreFullPath != NULL) {
328 FreePool (PreFullPath);
329 }
330
331 if (CurFullPath == NULL) {
332 //
333 // No Active EFI system partition is found in BootOption device path
334 //
335 Status = EFI_NOT_FOUND;
336 break;
337 }
338
339 DEBUG_CODE (
340 CHAR16 *DevicePathStr;
341
342 DevicePathStr = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);
343 if (DevicePathStr != NULL){
344 DEBUG ((DEBUG_INFO, "Full device path %s\n", DevicePathStr));
345 FreePool (DevicePathStr);
346 }
347 );
348
349 Status = GetEfiSysPartitionFromDevPath (CurFullPath, &FsFullPath, Fs);
350 } while (EFI_ERROR (Status));
351
352 if (*Fs != NULL) {
353 *FullPath = FsFullPath;
354 return EFI_SUCCESS;
355 } else {
356 return EFI_NOT_FOUND;
357 }
358 }
359
360 /**
361 Get a valid SimpleFileSystem within EFI system partition.
362
363 @param[in] Map The FS mapping capsule write to
364 @param[out] BootNext The value of BootNext Variable
365 @param[out] Fs The file system within EfiSysPartition
366 @param[out] UpdateBootNext The flag to indicate whether update BootNext Variable
367
368 @retval EFI_SUCCESS Get FS successfully
369 @retval EFI_NOT_FOUND No valid FS found
370 @retval others Get FS failed
371
372 **/
373 EFI_STATUS
374 GetUpdateFileSystem (
375 IN CHAR16 *Map,
376 OUT UINT16 *BootNext,
377 OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs,
378 OUT BOOLEAN *UpdateBootNext
379 )
380 {
381 EFI_STATUS Status;
382 CHAR16 BootOptionName[20];
383 UINTN Index;
384 CONST EFI_DEVICE_PATH_PROTOCOL *MappedDevicePath;
385 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
386 EFI_DEVICE_PATH_PROTOCOL *FullPath;
387 UINT16 *BootNextData;
388 EFI_BOOT_MANAGER_LOAD_OPTION BootNextOption;
389 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptionBuffer;
390 UINTN BootOptionCount;
391 EFI_SHELL_PROTOCOL *ShellProtocol;
392 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
393
394 MappedDevicePath = NULL;
395 BootOptionBuffer = NULL;
396
397 ShellProtocol = GetShellProtocol ();
398 if (ShellProtocol == NULL) {
399 Print (L"Get Shell Protocol Fail\n");;
400 return EFI_NOT_FOUND;
401 }
402
403 //
404 // 1. If Fs is not assigned and there are capsule provisioned before,
405 // Get EFI system partition from BootNext.
406 //
407 if (IsCapsuleProvisioned () && Map == NULL) {
408 Status = GetVariable2 (
409 L"BootNext",
410 &gEfiGlobalVariableGuid,
411 (VOID **)&BootNextData,
412 NULL
413 );
414 if (EFI_ERROR (Status) || BootNextData == NULL) {
415 Print (L"Get Boot Next Data Fail. Status = %r\n", Status);
416 return EFI_NOT_FOUND;
417 } else {
418 UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", *BootNextData);
419 Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOption);
420 if (!EFI_ERROR (Status)) {
421 DevicePath = BootNextOption.FilePath;
422 Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs);
423 if (!EFI_ERROR (Status)) {
424 *UpdateBootNext = FALSE;
425 Print(L"Get EFI system partition from BootNext : %s\n", BootNextOption.Description);
426 Print(L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE));
427 return EFI_SUCCESS;
428 }
429 }
430 }
431 }
432
433 //
434 // Check if Map is valid.
435 //
436 if (Map != NULL) {
437 MappedDevicePath = ShellProtocol->GetDevicePathFromMap (Map);
438 if (MappedDevicePath == NULL) {
439 Print(L"'%s' is not a valid mapping.\n", Map);
440 return EFI_INVALID_PARAMETER;
441 } else if (!IsEfiSysPartitionDevicePath (DuplicateDevicePath (MappedDevicePath))) {
442 Print(L"'%s' is not a EFI System Partition.\n", Map);
443 return EFI_INVALID_PARAMETER;
444 }
445 }
446
447 //
448 // 2. Get EFI system partition form boot options.
449 //
450 BootOptionBuffer = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
451 if ( (BootOptionBuffer == NULL) ||
452 (BootOptionCount == 0 && Map == NULL)
453 ) {
454 return EFI_NOT_FOUND;
455 }
456
457 for (Index = 0; Index < BootOptionCount; Index++) {
458 //
459 // Get the boot option from the link list
460 //
461 DevicePath = BootOptionBuffer[Index].FilePath;
462
463 //
464 // Skip inactive or legacy boot options
465 //
466 if ((BootOptionBuffer[Index].Attributes & LOAD_OPTION_ACTIVE) == 0 ||
467 DevicePathType (DevicePath) == BBS_DEVICE_PATH) {
468 continue;
469 }
470
471 DEBUG_CODE (
472 CHAR16 *DevicePathStr;
473
474 DevicePathStr = ConvertDevicePathToText (DevicePath, TRUE, TRUE);
475 if (DevicePathStr != NULL){
476 DEBUG ((DEBUG_INFO, "Try BootOption %s\n", DevicePathStr));
477 FreePool (DevicePathStr);
478 } else {
479 DEBUG ((DEBUG_INFO, "DevicePathToStr failed\n"));
480 }
481 );
482
483 Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs);
484 if (!EFI_ERROR (Status)) {
485 if (Map == NULL) {
486 *BootNext = (UINT16) BootOptionBuffer[Index].OptionNumber;
487 *UpdateBootNext = TRUE;
488 Print (L"Found EFI system partition on Boot%04x: %s\n", *BootNext, BootOptionBuffer[Index].Description);
489 Print (L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE));
490 return EFI_SUCCESS;
491 }
492
493 if (StrnCmp (Map, ShellProtocol->GetMapFromDevicePath (&FullPath), StrLen (Map)) == 0) {
494 *BootNext = (UINT16) BootOptionBuffer[Index].OptionNumber;
495 *UpdateBootNext = TRUE;
496 Print (L"Found Boot Option on %s : %s\n", Map, BootOptionBuffer[Index].Description);
497 return EFI_SUCCESS;
498 }
499 }
500 }
501
502 //
503 // 3. If no ESP is found on boot option, try to find a ESP and create boot option for it.
504 //
505 if (Map != NULL) {
506 //
507 // If map is assigned, try to get ESP from mapped Fs.
508 //
509 DevicePath = DuplicateDevicePath (MappedDevicePath);
510 Status = GetEfiSysPartitionFromDevPath (DevicePath, &FullPath, Fs);
511 if (EFI_ERROR (Status)) {
512 Print (L"Error: Cannot get EFI system partiion from '%s' - %r\n", Map, Status);
513 return EFI_NOT_FOUND;
514 }
515 Print (L"Warning: Cannot find Boot Option on '%s'!\n", Map);
516 } else {
517 Status = GetEfiSysPartition (&DevicePath, Fs);
518 if (EFI_ERROR (Status)) {
519 Print (L"Error: Cannot find a EFI system partition!\n");
520 return EFI_NOT_FOUND;
521 }
522 }
523
524 Print (L"Create Boot option for capsule on disk:\n");
525 Status = EfiBootManagerInitializeLoadOption (
526 &NewOption,
527 LoadOptionNumberUnassigned,
528 LoadOptionTypeBoot,
529 LOAD_OPTION_ACTIVE,
530 L"UEFI Capsule On Disk",
531 DevicePath,
532 (UINT8 *) &mCapsuleOnDiskBootOptionGuid,
533 sizeof(EFI_GUID)
534 );
535 if (!EFI_ERROR (Status)) {
536 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN) -1); {
537 if (!EFI_ERROR (Status)) {
538 *UpdateBootNext = TRUE;
539 *BootNext = (UINT16) NewOption.OptionNumber;
540 Print (L" Boot%04x: %s\n", *BootNext, ConvertDevicePathToText(DevicePath, TRUE, TRUE));
541 return EFI_SUCCESS;
542 }
543 }
544 }
545
546 Print (L"ERROR: Cannot create boot option! - %r\n", Status);
547
548 return EFI_NOT_FOUND;
549 }
550
551 /**
552 Write files to a given SimpleFileSystem.
553
554 @param[in] Buffer The buffer array
555 @param[in] BufferSize The buffer size array
556 @param[in] FileName The file name array
557 @param[in] BufferNum The buffer number
558 @param[in] Fs The SimpleFileSystem handle to be written
559
560 @retval EFI_SUCCESS Write file successfully
561 @retval EFI_NOT_FOUND SFS protocol not found
562 @retval others Write file failed
563
564 **/
565 EFI_STATUS
566 WriteUpdateFile (
567 IN VOID **Buffer,
568 IN UINTN *BufferSize,
569 IN CHAR16 **FileName,
570 IN UINTN BufferNum,
571 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs
572 )
573 {
574 EFI_STATUS Status;
575 EFI_FILE *Root;
576 EFI_FILE *FileHandle;
577 EFI_FILE_PROTOCOL *DirHandle;
578 UINT64 FileInfo;
579 VOID *Filebuffer;
580 UINTN FileSize;
581 UINTN Index;
582
583 DirHandle = NULL;
584 FileHandle = NULL;
585 Index = 0;
586
587 //
588 // Open Root from SFS
589 //
590 Status = Fs->OpenVolume (Fs, &Root);
591 if (EFI_ERROR (Status)) {
592 Print (L"Cannot open volume. Status = %r\n", Status);
593 return EFI_NOT_FOUND;
594 }
595
596 //
597 // Ensure that efi and updatecapsule directories exist
598 //
599 Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
600 if (EFI_ERROR (Status)) {
601 Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
602 if (EFI_ERROR (Status)) {
603 Print(L"Unable to create %s directory\n", L"\\EFI");
604 return EFI_NOT_FOUND;
605 }
606 }
607 Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0);
608 if (EFI_ERROR (Status)) {
609 Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
610 if (EFI_ERROR (Status)) {
611 Print(L"Unable to create %s directory\n", EFI_CAPSULE_FILE_DIRECTORY);
612 return EFI_NOT_FOUND;
613 }
614 }
615
616 for (Index = 0; Index < BufferNum; Index++) {
617 FileHandle = NULL;
618
619 //
620 // Open UpdateCapsule file
621 //
622 Status = DirHandle->Open (DirHandle, &FileHandle, FileName[Index], EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
623 if (EFI_ERROR (Status)) {
624 Print (L"Unable to create %s file\n", FileName[Index]);
625 return EFI_NOT_FOUND;
626 }
627
628 //
629 // Empty the file contents
630 //
631 Status = FileHandleGetSize (FileHandle, &FileInfo);
632 if (EFI_ERROR (Status)) {
633 FileHandleClose (FileHandle);
634 Print (L"Error Reading %s\n", FileName[Index]);
635 return EFI_DEVICE_ERROR;
636 }
637
638 //
639 // If the file size is already 0, then it has been empty.
640 //
641 if (FileInfo != 0) {
642 //
643 // Set the file size to 0.
644 //
645 FileInfo = 0;
646 Status = FileHandleSetSize (FileHandle, FileInfo);
647 if (EFI_ERROR (Status)) {
648 Print (L"Error Deleting %s\n", FileName[Index]);
649 FileHandleClose (FileHandle);
650 return Status;
651 }
652 }
653
654 //
655 // Write Filebuffer to file
656 //
657 Filebuffer = Buffer[Index];
658 FileSize = BufferSize[Index];
659 Status = FileHandleWrite (FileHandle, &FileSize, Filebuffer);
660 if (EFI_ERROR (Status)) {
661 Print (L"Unable to write Capsule Update to %s, Status = %r\n", FileName[Index], Status);
662 return EFI_NOT_FOUND;
663 }
664
665 Print (L"Succeed to write %s\n", FileName[Index]);
666 FileHandleClose (FileHandle);
667 }
668
669 return EFI_SUCCESS;
670 }
671
672 /**
673 Set capsule status variable.
674
675 @param[in] SetCap Set or clear the capsule flag.
676
677 @retval EFI_SUCCESS Succeed to set SetCap variable.
678 @retval others Fail to set the variable.
679
680 **/
681 EFI_STATUS
682 SetCapsuleStatusVariable (
683 BOOLEAN SetCap
684 )
685 {
686 EFI_STATUS Status;
687 UINT64 OsIndication;
688 UINTN DataSize;
689
690 OsIndication = 0;
691 DataSize = sizeof(UINT64);
692 Status = gRT->GetVariable (
693 L"OsIndications",
694 &gEfiGlobalVariableGuid,
695 NULL,
696 &DataSize,
697 &OsIndication
698 );
699 if (EFI_ERROR (Status)) {
700 OsIndication = 0;
701 }
702 if (SetCap) {
703 OsIndication |= ((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
704 }
705 else {
706 OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
707 }
708 Status = gRT->SetVariable (
709 L"OsIndications",
710 &gEfiGlobalVariableGuid,
711 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
712 sizeof(UINT64),
713 &OsIndication
714 );
715
716 return Status;
717 }
718
719 /**
720 Check if Capsule On Disk is supported.
721
722 @retval TRUE Capsule On Disk is supported.
723 @retval FALSE Capsule On Disk is not supported.
724
725 **/
726 BOOLEAN
727 IsCapsuleOnDiskSupported (
728 VOID
729 )
730 {
731 EFI_STATUS Status;
732 UINT64 OsIndicationsSupported;
733 UINTN DataSize;
734
735 DataSize = sizeof(UINT64);
736 Status = gRT->GetVariable (
737 L"OsIndicationsSupported",
738 &gEfiGlobalVariableGuid,
739 NULL,
740 &DataSize,
741 &OsIndicationsSupported
742 );
743 if (EFI_ERROR (Status)) {
744 return FALSE;
745 }
746
747 if ((OsIndicationsSupported & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) {
748 return TRUE;
749 }
750
751 return FALSE;
752 }
753
754 /**
755 Process Capsule On Disk.
756
757 @param[in] CapsuleBuffer An array of pointer to capsule images
758 @param[in] CapsuleBufferSize An array of UINTN to capsule images size
759 @param[in] FilePath An array of capsule images file path
760 @param[in] Map File system mapping string
761 @param[in] CapsuleNum The count of capsule images
762
763 @retval EFI_SUCCESS Capsule on disk success.
764 @retval others Capsule on disk fail.
765
766 **/
767 EFI_STATUS
768 ProcessCapsuleOnDisk (
769 IN VOID **CapsuleBuffer,
770 IN UINTN *CapsuleBufferSize,
771 IN CHAR16 **FilePath,
772 IN CHAR16 *Map,
773 IN UINTN CapsuleNum
774 )
775 {
776 EFI_STATUS Status;
777 UINT16 BootNext;
778 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
779 BOOLEAN UpdateBootNext;
780 CHAR16 *FileName[MAX_CAPSULE_NUM];
781 UINTN Index;
782
783 //
784 // Check if Capsule On Disk is supported
785 //
786 if (!IsCapsuleOnDiskSupported ()) {
787 Print (L"CapsuleApp: Capsule On Disk is not supported.\n");
788 return EFI_UNSUPPORTED;
789 }
790
791 //
792 // Get a valid file system from boot path
793 //
794 Fs = NULL;
795
796 Status = GetUpdateFileSystem (Map, &BootNext, &Fs, &UpdateBootNext);
797 if (EFI_ERROR (Status)) {
798 Print (L"CapsuleApp: cannot find a valid file system on boot devies. Status = %r\n", Status);
799 return Status;
800 }
801
802 //
803 // Get file name from file path
804 //
805 for (Index = 0; Index < CapsuleNum; Index ++) {
806 FileName[Index] = GetFileNameFromPath (FilePath[Index]);
807 }
808
809 //
810 // Copy capsule image to '\efi\UpdateCapsule\'
811 //
812 Status = WriteUpdateFile (CapsuleBuffer, CapsuleBufferSize, FileName, CapsuleNum, Fs);
813 if (EFI_ERROR (Status)) {
814 Print (L"CapsuleApp: capsule image could not be copied for update.\n");
815 return Status;
816 }
817
818 //
819 // Set variable then reset
820 //
821 Status = SetCapsuleStatusVariable (TRUE);
822 if (EFI_ERROR (Status)) {
823 Print (L"CapsuleApp: unable to set OSIndication variable.\n");
824 return Status;
825 }
826
827 if (UpdateBootNext) {
828 Status = gRT->SetVariable (
829 L"BootNext",
830 &gEfiGlobalVariableGuid,
831 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
832 sizeof(UINT16),
833 &BootNext
834 );
835 if (EFI_ERROR (Status)){
836 Print (L"CapsuleApp: unable to set BootNext variable.\n");
837 return Status;
838 }
839 }
840
841 return EFI_SUCCESS;
842 }