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