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