]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c
MdeModulePkg/CapsuleApp: Fix potential NULL pointer dereference issue
[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 = EfiBootManagerGetNextFullDevicePath (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)) {
449 UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", *BootNextData);
450 Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOption);
451 if (!EFI_ERROR (Status)) {
452 DevicePath = BootNextOption.FilePath;
453 Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs);
454 if (!EFI_ERROR (Status)) {
455 *UpdateBootNext = FALSE;
456 Print(L"Get EFI system partition from BootNext : %s\n", BootNextOption.Description);
457 Print(L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE));
458 return EFI_SUCCESS;
459 }
460 }
461 }
462 }
463
464 //
465 // Check if Map is valid.
466 //
467 if (Map != NULL) {
468 MappedDevicePath = ShellProtocol->GetDevicePathFromMap (Map);
469 if (MappedDevicePath == NULL) {
470 Print(L"'%s' is not a valid mapping.\n", Map);
471 return EFI_INVALID_PARAMETER;
472 } else if (!IsEfiSysPartitionDevicePath (DuplicateDevicePath (MappedDevicePath))) {
473 Print(L"'%s' is not a EFI System Partition.\n", Map);
474 return EFI_INVALID_PARAMETER;
475 }
476 }
477
478 //
479 // 2. Get EFI system partition form boot options.
480 //
481 BootOptionBuffer = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
482 if ( (BootOptionBuffer == NULL) ||
483 (BootOptionCount == 0 && Map == NULL)
484 ) {
485 return EFI_NOT_FOUND;
486 }
487
488 for (Index = 0; Index < BootOptionCount; Index++) {
489 //
490 // Get the boot option from the link list
491 //
492 DevicePath = BootOptionBuffer[Index].FilePath;
493
494 //
495 // Skip inactive or legacy boot options
496 //
497 if ((BootOptionBuffer[Index].Attributes & LOAD_OPTION_ACTIVE) == 0 ||
498 DevicePathType (DevicePath) == BBS_DEVICE_PATH) {
499 continue;
500 }
501
502 DEBUG_CODE (
503 CHAR16 *DevicePathStr;
504
505 DevicePathStr = ConvertDevicePathToText (DevicePath, TRUE, TRUE);
506 if (DevicePathStr != NULL){
507 DEBUG ((DEBUG_INFO, "Try BootOption %s\n", DevicePathStr));
508 FreePool (DevicePathStr);
509 } else {
510 DEBUG ((DEBUG_INFO, "DevicePathToStr failed\n"));
511 }
512 );
513
514 Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs);
515 if (!EFI_ERROR (Status)) {
516 if (Map == NULL) {
517 *BootNext = (UINT16) BootOptionBuffer[Index].OptionNumber;
518 *UpdateBootNext = TRUE;
519 Print (L"Found EFI system partition on Boot%04x: %s\n", *BootNext, BootOptionBuffer[Index].Description);
520 Print (L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE));
521 return EFI_SUCCESS;
522 }
523
524 if (StrnCmp (Map, ShellProtocol->GetMapFromDevicePath (&FullPath), StrLen (Map)) == 0) {
525 *BootNext = (UINT16) BootOptionBuffer[Index].OptionNumber;
526 *UpdateBootNext = TRUE;
527 Print (L"Found Boot Option on %s : %s\n", Map, BootOptionBuffer[Index].Description);
528 return EFI_SUCCESS;
529 }
530 }
531 }
532
533 //
534 // 3. If no ESP is found on boot option, try to find a ESP and create boot option for it.
535 //
536 if (Map != NULL) {
537 //
538 // If map is assigned, try to get ESP from mapped Fs.
539 //
540 DevicePath = DuplicateDevicePath (MappedDevicePath);
541 Status = GetEfiSysPartitionFromDevPath (DevicePath, &FullPath, Fs);
542 if (EFI_ERROR (Status)) {
543 Print (L"Error: Cannot get EFI system partiion from '%s' - %r\n", Map, Status);
544 return EFI_NOT_FOUND;
545 }
546 Print (L"Warning: Cannot find Boot Option on '%s'!\n", Map);
547 } else {
548 Status = GetEfiSysPartition (&DevicePath, Fs);
549 if (EFI_ERROR (Status)) {
550 Print (L"Error: Cannot find a EFI system partition!\n");
551 return EFI_NOT_FOUND;
552 }
553 }
554
555 Print (L"Create Boot option for capsule on disk:\n");
556 Status = EfiBootManagerInitializeLoadOption (
557 &NewOption,
558 LoadOptionNumberUnassigned,
559 LoadOptionTypeBoot,
560 LOAD_OPTION_ACTIVE,
561 L"UEFI Capsule On Disk",
562 DevicePath,
563 (UINT8 *) &mCapsuleOnDiskBootOptionGuid,
564 sizeof(EFI_GUID)
565 );
566 if (!EFI_ERROR (Status)) {
567 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN) -1); {
568 if (!EFI_ERROR (Status)) {
569 *UpdateBootNext = TRUE;
570 *BootNext = (UINT16) NewOption.OptionNumber;
571 Print (L" Boot%04x: %s\n", *BootNext, ConvertDevicePathToText(DevicePath, TRUE, TRUE));
572 return EFI_SUCCESS;
573 }
574 }
575 }
576
577 Print (L"ERROR: Cannot create boot option! - %r\n", Status);
578
579 return EFI_NOT_FOUND;
580 }
581
582 /**
583 Write files to a given SimpleFileSystem.
584
585 @param[in] Buffer The buffer array
586 @param[in] BufferSize The buffer size array
587 @param[in] FileName The file name array
588 @param[in] BufferNum The buffer number
589 @param[in] Fs The SimpleFileSystem handle to be written
590
591 @retval EFI_SUCCESS Write file successfully
592 @retval EFI_NOT_FOUND SFS protocol not found
593 @retval others Write file failed
594
595 **/
596 EFI_STATUS
597 WriteUpdateFile (
598 IN VOID **Buffer,
599 IN UINTN *BufferSize,
600 IN CHAR16 **FileName,
601 IN UINTN BufferNum,
602 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs
603 )
604 {
605 EFI_STATUS Status;
606 EFI_FILE *Root;
607 EFI_FILE *FileHandle;
608 EFI_FILE_PROTOCOL *DirHandle;
609 UINT64 FileInfo;
610 VOID *Filebuffer;
611 UINTN FileSize;
612 UINTN Index;
613
614 DirHandle = NULL;
615 FileHandle = NULL;
616 Index = 0;
617
618 //
619 // Open Root from SFS
620 //
621 Status = Fs->OpenVolume (Fs, &Root);
622 if (EFI_ERROR (Status)) {
623 Print (L"Cannot open volume. Status = %r\n", Status);
624 return EFI_NOT_FOUND;
625 }
626
627 //
628 // Ensure that efi and updatecapsule directories exist
629 //
630 Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
631 if (EFI_ERROR (Status)) {
632 Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
633 if (EFI_ERROR (Status)) {
634 Print(L"Unable to create %s directory\n", L"\\EFI");
635 return EFI_NOT_FOUND;
636 }
637 }
638 Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0);
639 if (EFI_ERROR (Status)) {
640 Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
641 if (EFI_ERROR (Status)) {
642 Print(L"Unable to create %s directory\n", EFI_CAPSULE_FILE_DIRECTORY);
643 return EFI_NOT_FOUND;
644 }
645 }
646
647 for (Index = 0; Index < BufferNum; Index++) {
648 FileHandle = NULL;
649
650 //
651 // Open UpdateCapsule file
652 //
653 Status = DirHandle->Open (DirHandle, &FileHandle, FileName[Index], EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
654 if (EFI_ERROR (Status)) {
655 Print (L"Unable to create %s file\n", FileName[Index]);
656 return EFI_NOT_FOUND;
657 }
658
659 //
660 // Empty the file contents
661 //
662 Status = FileHandleGetSize (FileHandle, &FileInfo);
663 if (EFI_ERROR (Status)) {
664 FileHandleClose (FileHandle);
665 Print (L"Error Reading %s\n", FileName[Index]);
666 return EFI_DEVICE_ERROR;
667 }
668
669 //
670 // If the file size is already 0, then it has been empty.
671 //
672 if (FileInfo != 0) {
673 //
674 // Set the file size to 0.
675 //
676 FileInfo = 0;
677 Status = FileHandleSetSize (FileHandle, FileInfo);
678 if (EFI_ERROR (Status)) {
679 Print (L"Error Deleting %s\n", FileName[Index]);
680 FileHandleClose (FileHandle);
681 return Status;
682 }
683 }
684
685 //
686 // Write Filebuffer to file
687 //
688 Filebuffer = Buffer[Index];
689 FileSize = BufferSize[Index];
690 Status = FileHandleWrite (FileHandle, &FileSize, Filebuffer);
691 if (EFI_ERROR (Status)) {
692 Print (L"Unable to write Capsule Update to %s, Status = %r\n", FileName[Index], Status);
693 return EFI_NOT_FOUND;
694 }
695
696 Print (L"Succeed to write %s\n", FileName[Index]);
697 FileHandleClose (FileHandle);
698 }
699
700 return EFI_SUCCESS;
701 }
702
703 /**
704 Set capsule status variable.
705
706 @param[in] SetCap Set or clear the capsule flag.
707
708 @retval EFI_SUCCESS Succeed to set SetCap variable.
709 @retval others Fail to set the variable.
710
711 **/
712 EFI_STATUS
713 SetCapsuleStatusVariable (
714 BOOLEAN SetCap
715 )
716 {
717 EFI_STATUS Status;
718 UINT64 OsIndication;
719 UINTN DataSize;
720
721 OsIndication = 0;
722 DataSize = sizeof(UINT64);
723 Status = gRT->GetVariable (
724 L"OsIndications",
725 &gEfiGlobalVariableGuid,
726 NULL,
727 &DataSize,
728 &OsIndication
729 );
730 if (EFI_ERROR (Status)) {
731 OsIndication = 0;
732 }
733 if (SetCap) {
734 OsIndication |= ((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
735 }
736 else {
737 OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
738 }
739 Status = gRT->SetVariable (
740 L"OsIndications",
741 &gEfiGlobalVariableGuid,
742 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
743 sizeof(UINT64),
744 &OsIndication
745 );
746
747 return Status;
748 }
749
750 /**
751 Process Capsule On Disk.
752
753 @param[in] CapsuleBuffer An array of pointer to capsule images
754 @param[in] CapsuleBufferSize An array of UINTN to capsule images size
755 @param[in] FilePath An array of capsule images file path
756 @param[in] Map File system mapping string
757 @param[in] CapsuleNum The count of capsule images
758
759 @retval EFI_SUCCESS Capsule on disk success.
760 @retval others Capsule on disk fail.
761
762 **/
763 EFI_STATUS
764 ProcessCapsuleOnDisk (
765 IN VOID **CapsuleBuffer,
766 IN UINTN *CapsuleBufferSize,
767 IN CHAR16 **FilePath,
768 IN CHAR16 *Map,
769 IN UINTN CapsuleNum
770 )
771 {
772 EFI_STATUS Status;
773 UINT16 BootNext;
774 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
775 BOOLEAN UpdateBootNext;
776
777 //
778 // Get a valid file system from boot path
779 //
780 Fs = NULL;
781
782 Status = GetUpdateFileSystem (Map, &BootNext, &Fs, &UpdateBootNext);
783 if (EFI_ERROR (Status)) {
784 Print (L"CapsuleApp: cannot find a valid file system on boot devies. Status = %r\n", Status);
785 return Status;
786 }
787
788 //
789 // Copy capsule image to '\efi\UpdateCapsule\'
790 //
791 Status = WriteUpdateFile (CapsuleBuffer, CapsuleBufferSize, FilePath, CapsuleNum, Fs);
792 if (EFI_ERROR (Status)) {
793 Print (L"CapsuleApp: capsule image could not be copied for update.\n");
794 return Status;
795 }
796
797 //
798 // Set variable then reset
799 //
800 Status = SetCapsuleStatusVariable (TRUE);
801 if (EFI_ERROR (Status)) {
802 Print (L"CapsuleApp: unable to set OSIndication variable.\n");
803 return Status;
804 }
805
806 if (UpdateBootNext) {
807 Status = gRT->SetVariable (
808 L"BootNext",
809 &gEfiGlobalVariableGuid,
810 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
811 sizeof(UINT16),
812 &BootNext
813 );
814 if (EFI_ERROR (Status)){
815 Print (L"CapsuleApp: unable to set BootNext variable.\n");
816 return Status;
817 }
818 }
819
820 return EFI_SUCCESS;
821 }