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