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