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