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