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