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