]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Library / DxeCapsuleLibFmp / CapsuleOnDisk.c
CommitLineData
28889a78
WX
1/** @file\r
2 The implementation supports Capusle on Disk.\r
3\r
4 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "CapsuleOnDisk.h"\r
10\r
11/**\r
12 Return if this capsule is a capsule name capsule, based upon CapsuleHeader.\r
13\r
14 @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER\r
15\r
16 @retval TRUE It is a capsule name capsule.\r
17 @retval FALSE It is not a capsule name capsule.\r
18**/\r
19BOOLEAN\r
20IsCapsuleNameCapsule (\r
1436aea4 21 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
28889a78
WX
22 );\r
23\r
24/**\r
25 Check the integrity of the capsule name capsule.\r
26 If the capsule is vaild, return the physical address of each capsule name string.\r
27\r
fda8482d
WX
28 This routine assumes the capsule has been validated by IsValidCapsuleHeader(), so\r
29 capsule memory overflow is not going to happen in this routine.\r
30\r
28889a78
WX
31 @param[in] CapsuleHeader Pointer to the capsule header of a capsule name capsule.\r
32 @param[out] CapsuleNameNum Number of capsule name.\r
33\r
34 @retval NULL Capsule name capsule is not valid.\r
35 @retval CapsuleNameBuf Array of capsule name physical address.\r
36\r
37**/\r
38EFI_PHYSICAL_ADDRESS *\r
39ValidateCapsuleNameCapsuleIntegrity (\r
1436aea4
MK
40 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
41 OUT UINTN *CapsuleNameNum\r
28889a78
WX
42 )\r
43{\r
1436aea4
MK
44 UINT8 *CapsuleNamePtr;\r
45 UINT8 *CapsuleNameBufStart;\r
46 UINT8 *CapsuleNameBufEnd;\r
47 UINTN Index;\r
48 UINTN StringSize;\r
49 EFI_PHYSICAL_ADDRESS *CapsuleNameBuf;\r
28889a78
WX
50\r
51 if (!IsCapsuleNameCapsule (CapsuleHeader)) {\r
52 return NULL;\r
53 }\r
54\r
55 //\r
56 // Total string size must be even.\r
57 //\r
58 if (((CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize) & BIT0) != 0) {\r
59 return NULL;\r
60 }\r
61\r
1436aea4
MK
62 *CapsuleNameNum = 0;\r
63 Index = 0;\r
64 CapsuleNameBufStart = (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize;\r
28889a78
WX
65\r
66 //\r
67 // If strings are not aligned on a 16-bit boundary, reallocate memory for it.\r
68 //\r
1436aea4 69 if (((UINTN)CapsuleNameBufStart & BIT0) != 0) {\r
28889a78 70 CapsuleNameBufStart = AllocateCopyPool (CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize, CapsuleNameBufStart);\r
fda8482d
WX
71 if (CapsuleNameBufStart == NULL) {\r
72 return NULL;\r
73 }\r
28889a78
WX
74 }\r
75\r
76 CapsuleNameBufEnd = CapsuleNameBufStart + CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;\r
77\r
78 CapsuleNamePtr = CapsuleNameBufStart;\r
79 while (CapsuleNamePtr < CapsuleNameBufEnd) {\r
1436aea4 80 StringSize = StrnSizeS ((CHAR16 *)CapsuleNamePtr, (CapsuleNameBufEnd - CapsuleNamePtr)/sizeof (CHAR16));\r
28889a78 81 CapsuleNamePtr += StringSize;\r
1436aea4 82 (*CapsuleNameNum)++;\r
28889a78
WX
83 }\r
84\r
85 //\r
86 // Integrity check.\r
87 //\r
88 if (CapsuleNamePtr != CapsuleNameBufEnd) {\r
89 if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize) {\r
90 FreePool (CapsuleNameBufStart);\r
91 }\r
1436aea4 92\r
28889a78
WX
93 return NULL;\r
94 }\r
95\r
96 CapsuleNameBuf = AllocatePool (*CapsuleNameNum * sizeof (EFI_PHYSICAL_ADDRESS));\r
97 if (CapsuleNameBuf == NULL) {\r
98 if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize) {\r
99 FreePool (CapsuleNameBufStart);\r
100 }\r
1436aea4 101\r
28889a78
WX
102 return NULL;\r
103 }\r
104\r
105 CapsuleNamePtr = CapsuleNameBufStart;\r
106 while (CapsuleNamePtr < CapsuleNameBufEnd) {\r
1436aea4
MK
107 StringSize = StrnSizeS ((CHAR16 *)CapsuleNamePtr, (CapsuleNameBufEnd - CapsuleNamePtr)/sizeof (CHAR16));\r
108 CapsuleNameBuf[Index] = (EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleNamePtr;\r
109 CapsuleNamePtr += StringSize;\r
110 Index++;\r
28889a78
WX
111 }\r
112\r
113 return CapsuleNameBuf;\r
114}\r
115\r
116/**\r
117 This routine is called to upper case given unicode string.\r
118\r
119 @param[in] Str String to upper case\r
120\r
121 @retval upper cased string after process\r
122\r
123**/\r
124static\r
125CHAR16 *\r
126UpperCaseString (\r
1436aea4 127 IN CHAR16 *Str\r
28889a78
WX
128 )\r
129{\r
130 CHAR16 *Cptr;\r
131\r
f5892aa8 132 for (Cptr = Str; *Cptr != L'\0'; Cptr++) {\r
1436aea4 133 if ((L'a' <= *Cptr) && (*Cptr <= L'z')) {\r
28889a78
WX
134 *Cptr = *Cptr - L'a' + L'A';\r
135 }\r
136 }\r
137\r
138 return Str;\r
139}\r
140\r
141/**\r
142 This routine is used to return substring before period '.' or '\0'\r
143 Caller should respsonsible of substr space allocation & free\r
144\r
145 @param[in] Str String to check\r
146 @param[out] SubStr First part of string before period or '\0'\r
147 @param[out] SubStrLen Length of first part of string\r
148\r
149**/\r
150static\r
151VOID\r
152GetSubStringBeforePeriod (\r
1436aea4
MK
153 IN CHAR16 *Str,\r
154 OUT CHAR16 *SubStr,\r
155 OUT UINTN *SubStrLen\r
28889a78
WX
156 )\r
157{\r
1436aea4
MK
158 UINTN Index;\r
159\r
28889a78
WX
160 for (Index = 0; Str[Index] != L'.' && Str[Index] != L'\0'; Index++) {\r
161 SubStr[Index] = Str[Index];\r
162 }\r
163\r
164 SubStr[Index] = L'\0';\r
1436aea4 165 *SubStrLen = Index;\r
28889a78
WX
166}\r
167\r
168/**\r
169 This routine pad the string in tail with input character.\r
170\r
171 @param[in] StrBuf Str buffer to be padded, should be enough room for\r
172 @param[in] PadLen Expected padding length\r
173 @param[in] Character Character used to pad\r
174\r
175**/\r
176static\r
177VOID\r
178PadStrInTail (\r
1436aea4
MK
179 IN CHAR16 *StrBuf,\r
180 IN UINTN PadLen,\r
181 IN CHAR16 Character\r
28889a78
WX
182 )\r
183{\r
1436aea4 184 UINTN Index;\r
28889a78 185\r
1436aea4
MK
186 for (Index = 0; StrBuf[Index] != L'\0'; Index++) {\r
187 }\r
28889a78 188\r
1436aea4 189 while (PadLen != 0) {\r
28889a78
WX
190 StrBuf[Index] = Character;\r
191 Index++;\r
192 PadLen--;\r
193 }\r
194\r
195 StrBuf[Index] = L'\0';\r
196}\r
197\r
198/**\r
199 This routine find the offset of the last period '.' of string. If No period exists\r
200 function FileNameExtension is set to L'\0'\r
201\r
202 @param[in] FileName File name to split between last period\r
203 @param[out] FileNameFirst First FileName before last period\r
204 @param[out] FileNameExtension FileName after last period\r
205\r
206**/\r
207static\r
208VOID\r
209SplitFileNameExtension (\r
210 IN CHAR16 *FileName,\r
211 OUT CHAR16 *FileNameFirst,\r
212 OUT CHAR16 *FileNameExtension\r
213 )\r
214{\r
1436aea4
MK
215 UINTN Index;\r
216 UINTN StringLen;\r
28889a78 217\r
1436aea4
MK
218 StringLen = StrnLenS (FileName, MAX_FILE_NAME_SIZE);\r
219 for (Index = StringLen; Index > 0 && FileName[Index] != L'.'; Index--) {\r
220 }\r
28889a78
WX
221\r
222 //\r
223 // No period exists. No FileName Extension\r
224 //\r
1436aea4 225 if ((Index == 0) && (FileName[Index] != L'.')) {\r
28889a78 226 FileNameExtension[0] = L'\0';\r
1436aea4 227 Index = StringLen;\r
28889a78 228 } else {\r
1436aea4 229 StrCpyS (FileNameExtension, MAX_FILE_NAME_SIZE, &FileName[Index+1]);\r
28889a78
WX
230 }\r
231\r
232 //\r
233 // Copy First file name\r
234 //\r
1436aea4 235 StrnCpyS (FileNameFirst, MAX_FILE_NAME_SIZE, FileName, Index);\r
28889a78
WX
236 FileNameFirst[Index] = L'\0';\r
237}\r
238\r
239/**\r
240 This routine is called to get all boot options in the order determnined by:\r
241 1. "OptionBuf"\r
242 2. "BootOrder"\r
243\r
244 @param[out] OptionBuf BootList buffer to all boot options returned\r
245 @param[out] OptionCount BootList count of all boot options returned\r
246\r
247 @retval EFI_SUCCESS There is no error when processing capsule\r
248\r
249**/\r
250EFI_STATUS\r
1436aea4
MK
251GetBootOptionInOrder (\r
252 OUT EFI_BOOT_MANAGER_LOAD_OPTION **OptionBuf,\r
253 OUT UINTN *OptionCount\r
28889a78
WX
254 )\r
255{\r
1436aea4
MK
256 EFI_STATUS Status;\r
257 UINTN DataSize;\r
258 UINT16 BootNext;\r
259 CHAR16 BootOptionName[20];\r
260 EFI_BOOT_MANAGER_LOAD_OPTION *BootOrderOptionBuf;\r
261 UINTN BootOrderCount;\r
262 EFI_BOOT_MANAGER_LOAD_OPTION BootNextOptionEntry;\r
263 UINTN BootNextCount;\r
264 EFI_BOOT_MANAGER_LOAD_OPTION *TempBuf;\r
265\r
266 BootOrderOptionBuf = NULL;\r
267 TempBuf = NULL;\r
268 BootNextCount = 0;\r
269 BootOrderCount = 0;\r
270 *OptionBuf = NULL;\r
271 *OptionCount = 0;\r
28889a78
WX
272\r
273 //\r
274 // First Get BootOption from "BootNext"\r
275 //\r
1436aea4
MK
276 DataSize = sizeof (BootNext);\r
277 Status = gRT->GetVariable (\r
278 EFI_BOOT_NEXT_VARIABLE_NAME,\r
279 &gEfiGlobalVariableGuid,\r
280 NULL,\r
281 &DataSize,\r
282 (VOID *)&BootNext\r
283 );\r
28889a78
WX
284 //\r
285 // BootNext variable is a single UINT16\r
286 //\r
1436aea4 287 if (!EFI_ERROR (Status) && (DataSize == sizeof (UINT16))) {\r
28889a78
WX
288 //\r
289 // Add the boot next boot option\r
290 //\r
291 UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", BootNext);\r
1436aea4 292 ZeroMem (&BootNextOptionEntry, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
28889a78
WX
293 Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOptionEntry);\r
294\r
1436aea4 295 if (!EFI_ERROR (Status)) {\r
28889a78
WX
296 BootNextCount = 1;\r
297 }\r
298 }\r
299\r
300 //\r
301 // Second get BootOption from "BootOrder"\r
302 //\r
303 BootOrderOptionBuf = EfiBootManagerGetLoadOptions (&BootOrderCount, LoadOptionTypeBoot);\r
1436aea4 304 if ((BootNextCount == 0) && (BootOrderCount == 0)) {\r
28889a78
WX
305 return EFI_NOT_FOUND;\r
306 }\r
307\r
308 //\r
309 // At least one BootOption is found\r
310 //\r
1436aea4 311 TempBuf = AllocatePool (sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (BootNextCount + BootOrderCount));\r
28889a78
WX
312 if (TempBuf != NULL) {\r
313 if (BootNextCount == 1) {\r
1436aea4 314 CopyMem (TempBuf, &BootNextOptionEntry, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
28889a78
WX
315 }\r
316\r
317 if (BootOrderCount > 0) {\r
1436aea4 318 CopyMem (TempBuf + BootNextCount, BootOrderOptionBuf, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * BootOrderCount);\r
28889a78
WX
319 }\r
320\r
321 *OptionBuf = TempBuf;\r
322 *OptionCount = BootNextCount + BootOrderCount;\r
1436aea4 323 Status = EFI_SUCCESS;\r
28889a78
WX
324 } else {\r
325 Status = EFI_OUT_OF_RESOURCES;\r
326 }\r
327\r
1436aea4 328 FreePool (BootOrderOptionBuf);\r
28889a78
WX
329\r
330 return Status;\r
331}\r
332\r
333/**\r
334 This routine is called to get boot option by OptionNumber.\r
335\r
336 @param[in] Number The OptionNumber of boot option\r
337 @param[out] OptionBuf BootList buffer to all boot options returned\r
338\r
339 @retval EFI_SUCCESS There is no error when getting boot option\r
340\r
341**/\r
342EFI_STATUS\r
1436aea4
MK
343GetBootOptionByNumber (\r
344 IN UINT16 Number,\r
345 OUT EFI_BOOT_MANAGER_LOAD_OPTION **OptionBuf\r
28889a78
WX
346 )\r
347{\r
348 EFI_STATUS Status;\r
349 CHAR16 BootOptionName[20];\r
350 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
351\r
352 UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", Number);\r
353 ZeroMem (&BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
354 Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootOption);\r
355\r
356 if (!EFI_ERROR (Status)) {\r
357 *OptionBuf = AllocatePool (sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
358 if (*OptionBuf != NULL) {\r
359 CopyMem (*OptionBuf, &BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
360 Status = EFI_SUCCESS;\r
361 } else {\r
362 Status = EFI_OUT_OF_RESOURCES;\r
363 }\r
364 }\r
365\r
366 return Status;\r
367}\r
368\r
369/**\r
370 Get Active EFI System Partition within GPT based on device path.\r
371\r
372 @param[in] DevicePath Device path to find a active EFI System Partition\r
373 @param[out] FsHandle BootList points to all boot options returned\r
374\r
375 @retval EFI_SUCCESS Active EFI System Partition is succesfully found\r
376 @retval EFI_NOT_FOUND No Active EFI System Partition is found\r
377\r
378**/\r
379EFI_STATUS\r
1436aea4
MK
380GetEfiSysPartitionFromDevPath (\r
381 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
382 OUT EFI_HANDLE *FsHandle\r
28889a78
WX
383 )\r
384{\r
1436aea4
MK
385 EFI_STATUS Status;\r
386 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
387 HARDDRIVE_DEVICE_PATH *Hd;\r
388 EFI_HANDLE Handle;\r
389 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
28889a78
WX
390\r
391 //\r
392 // Check if the device path contains GPT node\r
393 //\r
394 TempDevicePath = DevicePath;\r
395 while (!IsDevicePathEnd (TempDevicePath)) {\r
396 if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) &&\r
1436aea4
MK
397 (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP))\r
398 {\r
28889a78
WX
399 Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;\r
400 if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) {\r
401 break;\r
402 }\r
403 }\r
1436aea4 404\r
28889a78
WX
405 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
406 }\r
407\r
408 if (!IsDevicePathEnd (TempDevicePath)) {\r
409 //\r
410 // Search for EFI system partition protocol on full device path in Boot Option\r
411 //\r
412 Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle);\r
413\r
414 //\r
415 // Search for simple file system on this handler\r
416 //\r
1436aea4
MK
417 if (!EFI_ERROR (Status)) {\r
418 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);\r
419 if (!EFI_ERROR (Status)) {\r
28889a78
WX
420 *FsHandle = Handle;\r
421 return EFI_SUCCESS;\r
422 }\r
423 }\r
424 }\r
425\r
426 return EFI_NOT_FOUND;\r
427}\r
428\r
429/**\r
430 This routine is called to get Simple File System protocol on the first EFI system partition found in\r
431 active boot option. The boot option list is detemined in order by\r
432 1. "BootNext"\r
433 2. "BootOrder"\r
434\r
435 @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure\r
436 device like USB can get enumerated.\r
437 @param[in, out] LoadOptionNumber On input, specify the boot option to get EFI system partition.\r
438 On output, return the OptionNumber of the boot option where EFI\r
439 system partition is got from.\r
440 @param[out] FsFsHandle Simple File System Protocol found on first active EFI system partition\r
441\r
442 @retval EFI_SUCCESS Simple File System protocol found for EFI system partition\r
443 @retval EFI_NOT_FOUND No Simple File System protocol found for EFI system partition\r
444\r
445**/\r
446EFI_STATUS\r
1436aea4
MK
447GetEfiSysPartitionFromActiveBootOption (\r
448 IN UINTN MaxRetry,\r
449 IN OUT UINT16 **LoadOptionNumber,\r
450 OUT EFI_HANDLE *FsHandle\r
28889a78
WX
451 )\r
452{\r
1436aea4
MK
453 EFI_STATUS Status;\r
454 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptionBuf;\r
455 UINTN BootOptionNum;\r
456 UINTN Index;\r
457 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
458 EFI_DEVICE_PATH_PROTOCOL *CurFullPath;\r
459 EFI_DEVICE_PATH_PROTOCOL *PreFullPath;\r
460\r
461 *FsHandle = NULL;\r
28889a78
WX
462 CurFullPath = NULL;\r
463\r
464 if (*LoadOptionNumber != NULL) {\r
465 BootOptionNum = 1;\r
1436aea4
MK
466 Status = GetBootOptionByNumber (**LoadOptionNumber, &BootOptionBuf);\r
467 if (EFI_ERROR (Status)) {\r
28889a78
WX
468 DEBUG ((DEBUG_ERROR, "GetBootOptionByIndex Failed %x! No BootOption available for connection\n", Status));\r
469 return Status;\r
470 }\r
471 } else {\r
1436aea4
MK
472 Status = GetBootOptionInOrder (&BootOptionBuf, &BootOptionNum);\r
473 if (EFI_ERROR (Status)) {\r
28889a78
WX
474 DEBUG ((DEBUG_ERROR, "GetBootOptionInOrder Failed %x! No BootOption available for connection\n", Status));\r
475 return Status;\r
476 }\r
477 }\r
478\r
479 //\r
480 // Search BootOptionList to check if it is an active boot option with EFI system partition\r
481 // 1. Connect device path\r
482 // 2. expend short/plug in devicepath\r
483 // 3. LoadImage\r
484 //\r
485 for (Index = 0; Index < BootOptionNum; Index++) {\r
486 //\r
487 // Get the boot option from the link list\r
488 //\r
1436aea4 489 DevicePath = BootOptionBuf[Index].FilePath;\r
28889a78
WX
490\r
491 //\r
492 // Skip inactive or legacy boot options\r
493 //\r
1436aea4
MK
494 if (((BootOptionBuf[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) ||\r
495 (DevicePathType (DevicePath) == BBS_DEVICE_PATH))\r
496 {\r
28889a78
WX
497 continue;\r
498 }\r
499\r
db52c7f7 500 DEBUG_CODE_BEGIN ();\r
1436aea4
MK
501 CHAR16 *DevicePathStr;\r
502\r
503 DevicePathStr = ConvertDevicePathToText (DevicePath, TRUE, TRUE);\r
504 if (DevicePathStr != NULL) {\r
505 DEBUG ((DEBUG_INFO, "Try BootOption %s\n", DevicePathStr));\r
506 FreePool (DevicePathStr);\r
507 } else {\r
508 DEBUG ((DEBUG_INFO, "DevicePathToStr failed\n"));\r
509 }\r
510\r
db52c7f7 511 DEBUG_CODE_END ();\r
28889a78
WX
512\r
513 CurFullPath = NULL;\r
514 //\r
515 // Try every full device Path generated from bootoption\r
516 //\r
517 do {\r
518 PreFullPath = CurFullPath;\r
1436aea4 519 CurFullPath = EfiBootManagerGetNextLoadOptionDevicePath (DevicePath, CurFullPath);\r
28889a78
WX
520\r
521 if (PreFullPath != NULL) {\r
522 FreePool (PreFullPath);\r
523 }\r
524\r
525 if (CurFullPath == NULL) {\r
526 //\r
527 // No Active EFI system partition is found in BootOption device path\r
528 //\r
529 Status = EFI_NOT_FOUND;\r
530 break;\r
531 }\r
532\r
db52c7f7 533 DEBUG_CODE_BEGIN ();\r
1436aea4
MK
534 CHAR16 *DevicePathStr1;\r
535\r
536 DevicePathStr1 = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);\r
537 if (DevicePathStr1 != NULL) {\r
538 DEBUG ((DEBUG_INFO, "Full device path %s\n", DevicePathStr1));\r
539 FreePool (DevicePathStr1);\r
540 }\r
28889a78 541\r
db52c7f7 542 DEBUG_CODE_END ();\r
28889a78
WX
543\r
544 //\r
545 // Make sure the boot option device path connected.\r
546 // Only handle first device in boot option. Other optional device paths are described as OSV specific\r
547 // FullDevice could contain extra directory & file info. So don't check connection status here.\r
548 //\r
549 EfiBootManagerConnectDevicePath (CurFullPath, NULL);\r
1436aea4 550 Status = GetEfiSysPartitionFromDevPath (CurFullPath, FsHandle);\r
28889a78
WX
551\r
552 //\r
553 // Some relocation device like USB need more time to get enumerated\r
554 //\r
1436aea4
MK
555 while (EFI_ERROR (Status) && MaxRetry > 0) {\r
556 EfiBootManagerConnectDevicePath (CurFullPath, NULL);\r
28889a78
WX
557\r
558 //\r
559 // Search for EFI system partition protocol on full device path in Boot Option\r
560 //\r
1436aea4
MK
561 Status = GetEfiSysPartitionFromDevPath (CurFullPath, FsHandle);\r
562 if (!EFI_ERROR (Status)) {\r
28889a78
WX
563 break;\r
564 }\r
1436aea4
MK
565\r
566 DEBUG ((DEBUG_ERROR, "GetEfiSysPartitionFromDevPath Loop %x\n", Status));\r
28889a78
WX
567 //\r
568 // Stall 100ms if connection failed to ensure USB stack is ready\r
569 //\r
1436aea4
MK
570 gBS->Stall (100000);\r
571 MaxRetry--;\r
28889a78 572 }\r
1436aea4 573 } while (EFI_ERROR (Status));\r
28889a78
WX
574\r
575 //\r
576 // Find a qualified Simple File System\r
577 //\r
1436aea4 578 if (!EFI_ERROR (Status)) {\r
28889a78
WX
579 break;\r
580 }\r
28889a78
WX
581 }\r
582\r
583 //\r
584 // Return the OptionNumber of the boot option where EFI system partition is got from\r
585 //\r
586 if (*LoadOptionNumber == NULL) {\r
1436aea4 587 *LoadOptionNumber = AllocateCopyPool (sizeof (UINT16), (UINT16 *)&BootOptionBuf[Index].OptionNumber);\r
28889a78
WX
588 if (*LoadOptionNumber == NULL) {\r
589 Status = EFI_OUT_OF_RESOURCES;\r
590 }\r
591 }\r
592\r
593 //\r
594 // No qualified EFI system partition found\r
595 //\r
596 if (*FsHandle == NULL) {\r
597 Status = EFI_NOT_FOUND;\r
598 }\r
599\r
db52c7f7 600 DEBUG_CODE_BEGIN ();\r
1436aea4
MK
601 CHAR16 *DevicePathStr2;\r
602\r
603 if (*FsHandle != NULL) {\r
604 DevicePathStr2 = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);\r
605 if (DevicePathStr2 != NULL) {\r
606 DEBUG ((DEBUG_INFO, "Found Active EFI System Partion on %s\n", DevicePathStr2));\r
607 FreePool (DevicePathStr2);\r
28889a78 608 }\r
1436aea4
MK
609 } else {\r
610 DEBUG ((DEBUG_INFO, "Failed to found Active EFI System Partion\n"));\r
611 }\r
612\r
db52c7f7 613 DEBUG_CODE_END ();\r
28889a78
WX
614\r
615 if (CurFullPath != NULL) {\r
1436aea4 616 FreePool (CurFullPath);\r
28889a78
WX
617 }\r
618\r
619 //\r
620 // Free BootOption Buffer\r
621 //\r
622 for (Index = 0; Index < BootOptionNum; Index++) {\r
623 if (BootOptionBuf[Index].Description != NULL) {\r
1436aea4 624 FreePool (BootOptionBuf[Index].Description);\r
28889a78
WX
625 }\r
626\r
627 if (BootOptionBuf[Index].FilePath != NULL) {\r
1436aea4 628 FreePool (BootOptionBuf[Index].FilePath);\r
28889a78
WX
629 }\r
630\r
631 if (BootOptionBuf[Index].OptionalData != NULL) {\r
1436aea4 632 FreePool (BootOptionBuf[Index].OptionalData);\r
28889a78
WX
633 }\r
634 }\r
635\r
1436aea4 636 FreePool (BootOptionBuf);\r
28889a78
WX
637\r
638 return Status;\r
639}\r
640\r
28889a78
WX
641/**\r
642 This routine is called to get all file infos with in a given dir & with given file attribute, the file info is listed in\r
643 alphabetical order described in UEFI spec.\r
644\r
645 @param[in] Dir Directory file handler\r
646 @param[in] FileAttr Attribute of file to be red from directory\r
647 @param[out] FileInfoList File images info list red from directory\r
648 @param[out] FileNum File images number red from directory\r
649\r
650 @retval EFI_SUCCESS File FileInfo list in the given\r
651\r
652**/\r
653EFI_STATUS\r
1436aea4 654GetFileInfoListInAlphabetFromDir (\r
28889a78
WX
655 IN EFI_FILE_HANDLE Dir,\r
656 IN UINT64 FileAttr,\r
657 OUT LIST_ENTRY *FileInfoList,\r
658 OUT UINTN *FileNum\r
659 )\r
660{\r
1436aea4
MK
661 EFI_STATUS Status;\r
662 FILE_INFO_ENTRY *NewFileInfoEntry;\r
663 FILE_INFO_ENTRY *TempFileInfoEntry;\r
664 EFI_FILE_INFO *FileInfo;\r
665 CHAR16 *NewFileName;\r
666 CHAR16 *ListedFileName;\r
667 CHAR16 *NewFileNameExtension;\r
668 CHAR16 *ListedFileNameExtension;\r
669 CHAR16 *TempNewSubStr;\r
670 CHAR16 *TempListedSubStr;\r
671 LIST_ENTRY *Link;\r
672 BOOLEAN NoFile;\r
673 UINTN FileCount;\r
674 UINTN IndexNew;\r
675 UINTN IndexListed;\r
676 UINTN NewSubStrLen;\r
677 UINTN ListedSubStrLen;\r
678 INTN SubStrCmpResult;\r
28889a78
WX
679\r
680 Status = EFI_SUCCESS;\r
681 NewFileName = NULL;\r
682 ListedFileName = NULL;\r
683 NewFileNameExtension = NULL;\r
684 ListedFileNameExtension = NULL;\r
685 TempNewSubStr = NULL;\r
686 TempListedSubStr = NULL;\r
687 FileInfo = NULL;\r
688 NoFile = FALSE;\r
689 FileCount = 0;\r
690\r
1436aea4 691 InitializeListHead (FileInfoList);\r
28889a78 692\r
1436aea4
MK
693 TempNewSubStr = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);\r
694 TempListedSubStr = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);\r
28889a78 695\r
1436aea4 696 if ((TempNewSubStr == NULL) || (TempListedSubStr == NULL)) {\r
28889a78
WX
697 Status = EFI_OUT_OF_RESOURCES;\r
698 goto EXIT;\r
699 }\r
700\r
1436aea4
MK
701 for ( Status = FileHandleFindFirstFile (Dir, &FileInfo)\r
702 ; !EFI_ERROR (Status) && !NoFile\r
703 ; Status = FileHandleFindNextFile (Dir, FileInfo, &NoFile)\r
704 )\r
705 {\r
28889a78
WX
706 if (FileInfo == NULL) {\r
707 goto EXIT;\r
708 }\r
709\r
710 //\r
711 // Skip file with mismatching File attribute\r
712 //\r
713 if ((FileInfo->Attribute & (FileAttr)) == 0) {\r
714 continue;\r
715 }\r
716\r
717 NewFileInfoEntry = NULL;\r
1436aea4 718 NewFileInfoEntry = (FILE_INFO_ENTRY *)AllocateZeroPool (sizeof (FILE_INFO_ENTRY));\r
28889a78
WX
719 if (NewFileInfoEntry == NULL) {\r
720 Status = EFI_OUT_OF_RESOURCES;\r
721 goto EXIT;\r
722 }\r
1436aea4 723\r
28889a78 724 NewFileInfoEntry->Signature = FILE_INFO_SIGNATURE;\r
1436aea4 725 NewFileInfoEntry->FileInfo = AllocateCopyPool ((UINTN)FileInfo->Size, FileInfo);\r
28889a78 726 if (NewFileInfoEntry->FileInfo == NULL) {\r
1436aea4 727 FreePool (NewFileInfoEntry);\r
28889a78
WX
728 Status = EFI_OUT_OF_RESOURCES;\r
729 goto EXIT;\r
730 }\r
731\r
1436aea4 732 NewFileInfoEntry->FileNameFirstPart = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);\r
28889a78 733 if (NewFileInfoEntry->FileNameFirstPart == NULL) {\r
1436aea4
MK
734 FreePool (NewFileInfoEntry->FileInfo);\r
735 FreePool (NewFileInfoEntry);\r
28889a78
WX
736 Status = EFI_OUT_OF_RESOURCES;\r
737 goto EXIT;\r
738 }\r
1436aea4
MK
739\r
740 NewFileInfoEntry->FileNameSecondPart = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);\r
28889a78 741 if (NewFileInfoEntry->FileNameSecondPart == NULL) {\r
1436aea4
MK
742 FreePool (NewFileInfoEntry->FileInfo);\r
743 FreePool (NewFileInfoEntry->FileNameFirstPart);\r
744 FreePool (NewFileInfoEntry);\r
28889a78
WX
745 Status = EFI_OUT_OF_RESOURCES;\r
746 goto EXIT;\r
747 }\r
748\r
749 //\r
750 // Splitter the whole New file name into 2 parts between the last period L'.' into NewFileName NewFileExtension\r
751 // If no period in the whole file name. NewFileExtension is set to L'\0'\r
752 //\r
753 NewFileName = NewFileInfoEntry->FileNameFirstPart;\r
754 NewFileNameExtension = NewFileInfoEntry->FileNameSecondPart;\r
1436aea4
MK
755 SplitFileNameExtension (FileInfo->FileName, NewFileName, NewFileNameExtension);\r
756 UpperCaseString (NewFileName);\r
757 UpperCaseString (NewFileNameExtension);\r
28889a78
WX
758\r
759 //\r
760 // Insert capsule file in alphabetical ordered list\r
761 //\r
762 for (Link = FileInfoList->ForwardLink; Link != FileInfoList; Link = Link->ForwardLink) {\r
763 //\r
764 // Get the FileInfo from the link list\r
765 //\r
1436aea4 766 TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);\r
28889a78
WX
767 ListedFileName = TempFileInfoEntry->FileNameFirstPart;\r
768 ListedFileNameExtension = TempFileInfoEntry->FileNameSecondPart;\r
769\r
770 //\r
771 // Follow rule in UEFI spec 8.5.5 to compare file name\r
772 //\r
773 IndexListed = 0;\r
774 IndexNew = 0;\r
1436aea4 775 while (TRUE) {\r
28889a78
WX
776 //\r
777 // First compare each substrings in NewFileName & ListedFileName between periods\r
778 //\r
1436aea4
MK
779 GetSubStringBeforePeriod (&NewFileName[IndexNew], TempNewSubStr, &NewSubStrLen);\r
780 GetSubStringBeforePeriod (&ListedFileName[IndexListed], TempListedSubStr, &ListedSubStrLen);\r
28889a78
WX
781 if (NewSubStrLen > ListedSubStrLen) {\r
782 //\r
783 // Substr in NewFileName is longer. Pad tail with SPACE\r
784 //\r
1436aea4
MK
785 PadStrInTail (TempListedSubStr, NewSubStrLen - ListedSubStrLen, L' ');\r
786 } else if (NewSubStrLen < ListedSubStrLen) {\r
28889a78
WX
787 //\r
788 // Substr in ListedFileName is longer. Pad tail with SPACE\r
789 //\r
1436aea4 790 PadStrInTail (TempNewSubStr, ListedSubStrLen - NewSubStrLen, L' ');\r
28889a78
WX
791 }\r
792\r
1436aea4 793 SubStrCmpResult = StrnCmp (TempNewSubStr, TempListedSubStr, MAX_FILE_NAME_LEN);\r
28889a78
WX
794 if (SubStrCmpResult != 0) {\r
795 break;\r
796 }\r
797\r
798 //\r
799 // Move to skip this substring\r
800 //\r
801 IndexNew += NewSubStrLen;\r
802 IndexListed += ListedSubStrLen;\r
803 //\r
804 // Reach File First Name end\r
805 //\r
1436aea4 806 if ((NewFileName[IndexNew] == L'\0') || (ListedFileName[IndexListed] == L'\0')) {\r
28889a78
WX
807 break;\r
808 }\r
809\r
810 //\r
811 // Skip the period L'.'\r
812 //\r
813 IndexNew++;\r
814 IndexListed++;\r
815 }\r
816\r
817 if (SubStrCmpResult < 0) {\r
818 //\r
819 // NewFileName is smaller. Find the right place to insert New file\r
820 //\r
821 break;\r
822 } else if (SubStrCmpResult == 0) {\r
823 //\r
824 // 2 cases whole NewFileName is smaller than ListedFileName\r
825 // 1. if NewFileName == ListedFileName. Continue to compare FileNameExtension\r
826 // 2. if NewFileName is shorter than ListedFileName\r
827 //\r
828 if (NewFileName[IndexNew] == L'\0') {\r
1436aea4 829 if ((ListedFileName[IndexListed] != L'\0') || (StrnCmp (NewFileNameExtension, ListedFileNameExtension, MAX_FILE_NAME_LEN) < 0)) {\r
28889a78
WX
830 break;\r
831 }\r
832 }\r
833 }\r
834\r
835 //\r
836 // Other case, ListedFileName is smaller. Continue to compare the next file in the list\r
837 //\r
838 }\r
839\r
840 //\r
841 // If Find an entry in the list whose name is bigger than new FileInfo in alphabet order\r
842 // Insert it before this entry\r
843 // else\r
844 // Insert at the tail of this list (Link = FileInfoList)\r
845 //\r
1436aea4 846 InsertTailList (Link, &NewFileInfoEntry->Link);\r
28889a78
WX
847\r
848 FileCount++;\r
849 }\r
850\r
851 *FileNum = FileCount;\r
852\r
853EXIT:\r
854\r
855 if (TempNewSubStr != NULL) {\r
1436aea4 856 FreePool (TempNewSubStr);\r
28889a78
WX
857 }\r
858\r
859 if (TempListedSubStr != NULL) {\r
1436aea4 860 FreePool (TempListedSubStr);\r
28889a78
WX
861 }\r
862\r
1436aea4
MK
863 if (EFI_ERROR (Status)) {\r
864 while (!IsListEmpty (FileInfoList)) {\r
28889a78 865 Link = FileInfoList->ForwardLink;\r
1436aea4 866 RemoveEntryList (Link);\r
28889a78
WX
867\r
868 TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);\r
869\r
1436aea4
MK
870 FreePool (TempFileInfoEntry->FileInfo);\r
871 FreePool (TempFileInfoEntry->FileNameFirstPart);\r
872 FreePool (TempFileInfoEntry->FileNameSecondPart);\r
873 FreePool (TempFileInfoEntry);\r
28889a78 874 }\r
1436aea4 875\r
28889a78
WX
876 *FileNum = 0;\r
877 }\r
878\r
879 return Status;\r
880}\r
881\r
28889a78
WX
882/**\r
883 This routine is called to get all qualified image from file from an given directory\r
884 in alphabetic order. All the file image is copied to allocated boottime memory.\r
885 Caller should free these memory\r
886\r
887 @param[in] Dir Directory file handler\r
888 @param[in] FileAttr Attribute of file to be red from directory\r
889 @param[out] FilePtr File images Info buffer red from directory\r
890 @param[out] FileNum File images number red from directory\r
891\r
892 @retval EFI_SUCCESS Succeed to get all capsules in alphabetic order.\r
893\r
894**/\r
895EFI_STATUS\r
1436aea4
MK
896GetFileImageInAlphabetFromDir (\r
897 IN EFI_FILE_HANDLE Dir,\r
898 IN UINT64 FileAttr,\r
899 OUT IMAGE_INFO **FilePtr,\r
900 OUT UINTN *FileNum\r
28889a78
WX
901 )\r
902{\r
1436aea4
MK
903 EFI_STATUS Status;\r
904 LIST_ENTRY *Link;\r
905 EFI_FILE_HANDLE FileHandle;\r
906 FILE_INFO_ENTRY *FileInfoEntry;\r
907 EFI_FILE_INFO *FileInfo;\r
908 UINTN FileCount;\r
909 IMAGE_INFO *TempFilePtrBuf;\r
910 UINTN Size;\r
911 LIST_ENTRY FileInfoList;\r
912\r
913 FileHandle = NULL;\r
914 FileCount = 0;\r
915 TempFilePtrBuf = NULL;\r
916 *FilePtr = NULL;\r
28889a78
WX
917\r
918 //\r
919 // Get file list in Dir in alphabetical order\r
920 //\r
1436aea4 921 Status = GetFileInfoListInAlphabetFromDir (\r
28889a78
WX
922 Dir,\r
923 FileAttr,\r
924 &FileInfoList,\r
925 &FileCount\r
926 );\r
1436aea4 927 if (EFI_ERROR (Status)) {\r
28889a78
WX
928 DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir Failed!\n"));\r
929 goto EXIT;\r
930 }\r
931\r
932 if (FileCount == 0) {\r
933 DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));\r
934 Status = EFI_NOT_FOUND;\r
935 goto EXIT;\r
936 }\r
937\r
1436aea4 938 TempFilePtrBuf = (IMAGE_INFO *)AllocateZeroPool (sizeof (IMAGE_INFO) * FileCount);\r
28889a78
WX
939 if (TempFilePtrBuf == NULL) {\r
940 Status = EFI_OUT_OF_RESOURCES;\r
941 goto EXIT;\r
942 }\r
943\r
944 //\r
945 // Read all files from FileInfoList to BS memory\r
946 //\r
947 FileCount = 0;\r
948 for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link->ForwardLink) {\r
949 //\r
950 // Get FileInfo from the link list\r
951 //\r
952 FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);\r
953 FileInfo = FileInfoEntry->FileInfo;\r
954\r
1436aea4 955 Status = Dir->Open (\r
28889a78
WX
956 Dir,\r
957 &FileHandle,\r
958 FileInfo->FileName,\r
959 EFI_FILE_MODE_READ,\r
960 0\r
961 );\r
1436aea4 962 if (EFI_ERROR (Status)) {\r
28889a78
WX
963 continue;\r
964 }\r
965\r
1436aea4
MK
966 Size = (UINTN)FileInfo->FileSize;\r
967 TempFilePtrBuf[FileCount].ImageAddress = AllocateZeroPool (Size);\r
28889a78 968 if (TempFilePtrBuf[FileCount].ImageAddress == NULL) {\r
1436aea4 969 DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsule. Stop processing the rest.\n"));\r
28889a78
WX
970 break;\r
971 }\r
972\r
1436aea4 973 Status = FileHandle->Read (\r
28889a78
WX
974 FileHandle,\r
975 &Size,\r
976 TempFilePtrBuf[FileCount].ImageAddress\r
977 );\r
978\r
1436aea4 979 FileHandle->Close (FileHandle);\r
28889a78
WX
980\r
981 //\r
982 // Skip read error file\r
983 //\r
1436aea4 984 if (EFI_ERROR (Status) || (Size != (UINTN)FileInfo->FileSize)) {\r
28889a78
WX
985 //\r
986 // Remove this error file info accordingly\r
987 // & move Link to BackLink\r
988 //\r
1436aea4 989 Link = RemoveEntryList (Link);\r
28889a78
WX
990 Link = Link->BackLink;\r
991\r
1436aea4
MK
992 FreePool (FileInfoEntry->FileInfo);\r
993 FreePool (FileInfoEntry->FileNameFirstPart);\r
994 FreePool (FileInfoEntry->FileNameSecondPart);\r
995 FreePool (FileInfoEntry);\r
28889a78 996\r
1436aea4 997 FreePool (TempFilePtrBuf[FileCount].ImageAddress);\r
28889a78
WX
998 TempFilePtrBuf[FileCount].ImageAddress = NULL;\r
999 TempFilePtrBuf[FileCount].FileInfo = NULL;\r
1000\r
1001 continue;\r
1002 }\r
1436aea4 1003\r
28889a78
WX
1004 TempFilePtrBuf[FileCount].FileInfo = FileInfo;\r
1005 FileCount++;\r
1006 }\r
1007\r
db52c7f7 1008 DEBUG_CODE_BEGIN ();\r
1436aea4
MK
1009 for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link->ForwardLink) {\r
1010 FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);\r
1011 FileInfo = FileInfoEntry->FileInfo;\r
1012 DEBUG ((DEBUG_INFO, "Successfully read capsule file %s from disk.\n", FileInfo->FileName));\r
1013 }\r
1014\r
db52c7f7 1015 DEBUG_CODE_END ();\r
28889a78
WX
1016\r
1017EXIT:\r
1018\r
1019 *FilePtr = TempFilePtrBuf;\r
1020 *FileNum = FileCount;\r
1021\r
1022 //\r
1023 // FileInfo will be freed by Calller\r
1024 //\r
1436aea4 1025 while (!IsListEmpty (&FileInfoList)) {\r
28889a78 1026 Link = FileInfoList.ForwardLink;\r
1436aea4 1027 RemoveEntryList (Link);\r
28889a78
WX
1028\r
1029 FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);\r
1030\r
1436aea4
MK
1031 FreePool (FileInfoEntry->FileNameFirstPart);\r
1032 FreePool (FileInfoEntry->FileNameSecondPart);\r
1033 FreePool (FileInfoEntry);\r
28889a78
WX
1034 }\r
1035\r
1036 return Status;\r
1037}\r
1038\r
1039/**\r
1040 This routine is called to remove all qualified image from file from an given directory.\r
1041\r
1042 @param[in] Dir Directory file handler\r
1043 @param[in] FileAttr Attribute of files to be deleted\r
1044\r
1045 @retval EFI_SUCCESS Succeed to remove all files from an given directory.\r
1046\r
1047**/\r
1048EFI_STATUS\r
1436aea4
MK
1049RemoveFileFromDir (\r
1050 IN EFI_FILE_HANDLE Dir,\r
1051 IN UINT64 FileAttr\r
28889a78
WX
1052 )\r
1053{\r
1436aea4
MK
1054 EFI_STATUS Status;\r
1055 LIST_ENTRY *Link;\r
1056 LIST_ENTRY FileInfoList;\r
1057 EFI_FILE_HANDLE FileHandle;\r
1058 FILE_INFO_ENTRY *FileInfoEntry;\r
1059 EFI_FILE_INFO *FileInfo;\r
1060 UINTN FileCount;\r
28889a78
WX
1061\r
1062 FileHandle = NULL;\r
1063\r
1064 //\r
1065 // Get file list in Dir in alphabetical order\r
1066 //\r
1436aea4 1067 Status = GetFileInfoListInAlphabetFromDir (\r
28889a78
WX
1068 Dir,\r
1069 FileAttr,\r
1070 &FileInfoList,\r
1071 &FileCount\r
1072 );\r
1436aea4 1073 if (EFI_ERROR (Status)) {\r
28889a78
WX
1074 DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir Failed!\n"));\r
1075 goto EXIT;\r
1076 }\r
1077\r
1078 if (FileCount == 0) {\r
1079 DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));\r
1080 Status = EFI_NOT_FOUND;\r
1081 goto EXIT;\r
1082 }\r
1083\r
1084 //\r
1085 // Delete all files with given attribute in Dir\r
1086 //\r
1087 for (Link = FileInfoList.ForwardLink; Link != &(FileInfoList); Link = Link->ForwardLink) {\r
1088 //\r
1089 // Get FileInfo from the link list\r
1090 //\r
1091 FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);\r
1092 FileInfo = FileInfoEntry->FileInfo;\r
1093\r
1436aea4 1094 Status = Dir->Open (\r
28889a78
WX
1095 Dir,\r
1096 &FileHandle,\r
1097 FileInfo->FileName,\r
1098 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,\r
1099 0\r
1100 );\r
1436aea4 1101 if (EFI_ERROR (Status)) {\r
28889a78
WX
1102 continue;\r
1103 }\r
1104\r
1436aea4 1105 Status = FileHandle->Delete (FileHandle);\r
28889a78
WX
1106 }\r
1107\r
1108EXIT:\r
1109\r
1436aea4 1110 while (!IsListEmpty (&FileInfoList)) {\r
28889a78 1111 Link = FileInfoList.ForwardLink;\r
1436aea4 1112 RemoveEntryList (Link);\r
28889a78
WX
1113\r
1114 FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);\r
1115\r
1436aea4
MK
1116 FreePool (FileInfoEntry->FileInfo);\r
1117 FreePool (FileInfoEntry);\r
28889a78
WX
1118 }\r
1119\r
1120 return Status;\r
1121}\r
1122\r
1123/**\r
1124 This routine is called to get all caspules from file. The capsule file image is\r
1125 copied to BS memory. Caller is responsible to free them.\r
1126\r
1127 @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure\r
1128 devices like USB can get enumerated.\r
1129 @param[out] CapsulePtr Copied Capsule file Image Info buffer\r
1130 @param[out] CapsuleNum CapsuleNumber\r
1131 @param[out] FsHandle File system handle\r
1132 @param[out] LoadOptionNumber OptionNumber of boot option\r
1133\r
1134 @retval EFI_SUCCESS Succeed to get all capsules.\r
1135\r
1136**/\r
1137EFI_STATUS\r
1436aea4
MK
1138GetAllCapsuleOnDisk (\r
1139 IN UINTN MaxRetry,\r
1140 OUT IMAGE_INFO **CapsulePtr,\r
1141 OUT UINTN *CapsuleNum,\r
1142 OUT EFI_HANDLE *FsHandle,\r
1143 OUT UINT16 *LoadOptionNumber\r
28889a78
WX
1144 )\r
1145{\r
1146 EFI_STATUS Status;\r
1147 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
1148 EFI_FILE_HANDLE RootDir;\r
1149 EFI_FILE_HANDLE FileDir;\r
1150 UINT16 *TempOptionNumber;\r
1151\r
1152 TempOptionNumber = NULL;\r
1153 *CapsuleNum = 0;\r
1154\r
1436aea4
MK
1155 Status = GetEfiSysPartitionFromActiveBootOption (MaxRetry, &TempOptionNumber, FsHandle);\r
1156 if (EFI_ERROR (Status)) {\r
28889a78
WX
1157 return Status;\r
1158 }\r
1159\r
1436aea4
MK
1160 Status = gBS->HandleProtocol (*FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);\r
1161 if (EFI_ERROR (Status)) {\r
28889a78
WX
1162 return Status;\r
1163 }\r
1164\r
1436aea4
MK
1165 Status = Fs->OpenVolume (Fs, &RootDir);\r
1166 if (EFI_ERROR (Status)) {\r
28889a78
WX
1167 return Status;\r
1168 }\r
1169\r
1436aea4 1170 Status = RootDir->Open (\r
28889a78
WX
1171 RootDir,\r
1172 &FileDir,\r
1173 EFI_CAPSULE_FILE_DIRECTORY,\r
1174 EFI_FILE_MODE_READ,\r
1175 0\r
1176 );\r
1436aea4
MK
1177 if (EFI_ERROR (Status)) {\r
1178 DEBUG ((DEBUG_ERROR, "CodLibGetAllCapsuleOnDisk fail to open RootDir!\n"));\r
28889a78
WX
1179 RootDir->Close (RootDir);\r
1180 return Status;\r
1181 }\r
1436aea4 1182\r
28889a78
WX
1183 RootDir->Close (RootDir);\r
1184\r
1185 //\r
1186 // Only Load files with EFI_FILE_SYSTEM or EFI_FILE_ARCHIVE attribute\r
1187 // ignore EFI_FILE_READ_ONLY, EFI_FILE_HIDDEN, EFI_FILE_RESERVED, EFI_FILE_DIRECTORY\r
1188 //\r
1436aea4 1189 Status = GetFileImageInAlphabetFromDir (\r
28889a78
WX
1190 FileDir,\r
1191 EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE,\r
1192 CapsulePtr,\r
1193 CapsuleNum\r
1194 );\r
1436aea4 1195 DEBUG ((DEBUG_INFO, "GetFileImageInAlphabetFromDir status %x\n", Status));\r
28889a78
WX
1196\r
1197 //\r
1198 // Always remove file to avoid deadloop in capsule process\r
1199 //\r
1436aea4
MK
1200 Status = RemoveFileFromDir (FileDir, EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE);\r
1201 DEBUG ((DEBUG_INFO, "RemoveFileFromDir status %x\n", Status));\r
28889a78
WX
1202\r
1203 FileDir->Close (FileDir);\r
1204\r
1205 if (LoadOptionNumber != NULL) {\r
1206 *LoadOptionNumber = *TempOptionNumber;\r
1207 }\r
1208\r
1209 return Status;\r
1210}\r
1211\r
1212/**\r
1213 Build Gather list for a list of capsule images.\r
1214\r
1215 @param[in] CapsuleBuffer An array of pointer to capsule images\r
1216 @param[in] CapsuleSize An array of UINTN to capsule images size\r
1217 @param[in] CapsuleNum The count of capsule images\r
1218 @param[out] BlockDescriptors The block descriptors for the capsule images\r
1219\r
1220 @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.\r
1221\r
1222**/\r
1223EFI_STATUS\r
1224BuildGatherList (\r
1436aea4
MK
1225 IN VOID **CapsuleBuffer,\r
1226 IN UINTN *CapsuleSize,\r
1227 IN UINTN CapsuleNum,\r
1228 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors\r
28889a78
WX
1229 )\r
1230{\r
1231 EFI_STATUS Status;\r
1232 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;\r
1233 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;\r
1234 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;\r
1235 UINTN Index;\r
1236\r
1237 BlockDescriptors1 = NULL;\r
1238 BlockDescriptorPre = NULL;\r
1239 BlockDescriptorsHeader = NULL;\r
1240\r
1241 for (Index = 0; Index < CapsuleNum; Index++) {\r
1242 //\r
1243 // Allocate memory for the descriptors.\r
1244 //\r
1436aea4 1245 BlockDescriptors1 = AllocateZeroPool (2 * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR));\r
28889a78
WX
1246 if (BlockDescriptors1 == NULL) {\r
1247 DEBUG ((DEBUG_ERROR, "BuildGatherList: failed to allocate memory for descriptors\n"));\r
1248 Status = EFI_OUT_OF_RESOURCES;\r
1249 goto ERREXIT;\r
1250 } else {\r
1436aea4 1251 DEBUG ((DEBUG_INFO, "BuildGatherList: creating capsule descriptors at 0x%X\n", (UINTN)BlockDescriptors1));\r
28889a78
WX
1252 }\r
1253\r
1254 //\r
1255 // Record descirptor header\r
1256 //\r
1257 if (Index == 0) {\r
1258 BlockDescriptorsHeader = BlockDescriptors1;\r
1259 }\r
1260\r
1261 if (BlockDescriptorPre != NULL) {\r
1436aea4
MK
1262 BlockDescriptorPre->Union.ContinuationPointer = (UINTN)BlockDescriptors1;\r
1263 BlockDescriptorPre->Length = 0;\r
28889a78
WX
1264 }\r
1265\r
1436aea4
MK
1266 BlockDescriptors1->Union.DataBlock = (UINTN)CapsuleBuffer[Index];\r
1267 BlockDescriptors1->Length = CapsuleSize[Index];\r
28889a78
WX
1268\r
1269 BlockDescriptorPre = BlockDescriptors1 + 1;\r
1436aea4 1270 BlockDescriptors1 = NULL;\r
28889a78
WX
1271 }\r
1272\r
1273 //\r
1274 // Null-terminate.\r
1275 //\r
1276 if (BlockDescriptorPre != NULL) {\r
1277 BlockDescriptorPre->Union.ContinuationPointer = (UINTN)NULL;\r
1436aea4
MK
1278 BlockDescriptorPre->Length = 0;\r
1279 *BlockDescriptors = BlockDescriptorsHeader;\r
28889a78
WX
1280 }\r
1281\r
1282 return EFI_SUCCESS;\r
1283\r
1284ERREXIT:\r
1285 if (BlockDescriptors1 != NULL) {\r
1286 FreePool (BlockDescriptors1);\r
1287 }\r
1288\r
1289 return Status;\r
1290}\r
1291\r
1292/**\r
1293 This routine is called to check if CapsuleOnDisk flag in OsIndications Variable\r
1294 is enabled.\r
1295\r
1296 @retval TRUE Flag is enabled\r
1297 @retval FALSE Flag is not enabled\r
1298\r
1299**/\r
1300BOOLEAN\r
1301EFIAPI\r
1436aea4 1302CoDCheckCapsuleOnDiskFlag (\r
28889a78
WX
1303 VOID\r
1304 )\r
1305{\r
1436aea4
MK
1306 EFI_STATUS Status;\r
1307 UINT64 OsIndication;\r
1308 UINTN DataSize;\r
28889a78
WX
1309\r
1310 //\r
1311 // Check File Capsule Delivery Supported Flag in OsIndication variable\r
1312 //\r
1313 OsIndication = 0;\r
1436aea4
MK
1314 DataSize = sizeof (UINT64);\r
1315 Status = gRT->GetVariable (\r
1316 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
1317 &gEfiGlobalVariableGuid,\r
1318 NULL,\r
1319 &DataSize,\r
1320 &OsIndication\r
1321 );\r
1322 if (!EFI_ERROR (Status) &&\r
1323 ((OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0))\r
1324 {\r
28889a78
WX
1325 return TRUE;\r
1326 }\r
1327\r
1328 return FALSE;\r
1329}\r
1330\r
28889a78
WX
1331/**\r
1332 This routine is called to clear CapsuleOnDisk flags including OsIndications and BootNext variable.\r
1333\r
1334 @retval EFI_SUCCESS All Capsule On Disk flags are cleared\r
1335\r
1336**/\r
1337EFI_STATUS\r
1338EFIAPI\r
1436aea4 1339CoDClearCapsuleOnDiskFlag (\r
28889a78
WX
1340 VOID\r
1341 )\r
1342{\r
1436aea4
MK
1343 EFI_STATUS Status;\r
1344 UINT64 OsIndication;\r
1345 UINTN DataSize;\r
28889a78
WX
1346\r
1347 //\r
1348 // Reset File Capsule Delivery Supported Flag in OsIndication variable\r
1349 //\r
1350 OsIndication = 0;\r
1436aea4
MK
1351 DataSize = sizeof (UINT64);\r
1352 Status = gRT->GetVariable (\r
1353 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
1354 &gEfiGlobalVariableGuid,\r
1355 NULL,\r
1356 &DataSize,\r
1357 &OsIndication\r
1358 );\r
1359 if (EFI_ERROR (Status) ||\r
1360 ((OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) == 0))\r
1361 {\r
28889a78
WX
1362 return Status;\r
1363 }\r
1364\r
1365 OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);\r
1436aea4
MK
1366 Status = gRT->SetVariable (\r
1367 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
1368 &gEfiGlobalVariableGuid,\r
1369 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1370 sizeof (UINT64),\r
1371 &OsIndication\r
1372 );\r
1373 ASSERT (!EFI_ERROR (Status));\r
28889a78
WX
1374\r
1375 //\r
1376 // Delete BootNext variable. Capsule Process may reset system, so can't rely on Bds to clear this variable\r
1377 //\r
1378 Status = gRT->SetVariable (\r
1379 EFI_BOOT_NEXT_VARIABLE_NAME,\r
1380 &gEfiGlobalVariableGuid,\r
1381 0,\r
1382 0,\r
1383 NULL\r
1384 );\r
1385 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);\r
1386\r
1387 return EFI_SUCCESS;\r
1388}\r
1389\r
1390/**\r
1391 This routine is called to clear CapsuleOnDisk Relocation Info variable.\r
1392 Total Capsule On Disk length is recorded in this variable\r
1393\r
1394 @retval EFI_SUCCESS Capsule On Disk flags are cleared\r
1395\r
1396**/\r
1397EFI_STATUS\r
1436aea4 1398CoDClearCapsuleRelocationInfo (\r
28889a78
WX
1399 VOID\r
1400 )\r
1401{\r
1402 return gRT->SetVariable (\r
1403 COD_RELOCATION_INFO_VAR_NAME,\r
1404 &gEfiCapsuleVendorGuid,\r
1405 0,\r
1406 0,\r
1407 NULL\r
1408 );\r
1409}\r
1410\r
1411/**\r
1412 Relocate Capsule on Disk from EFI system partition to a platform-specific NV storage device\r
1413 with BlockIo protocol. Relocation device path, identified by PcdCodRelocationDevPath, must\r
1414 be a full device path.\r
1415 Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.\r
1416 Function will stall 100ms between each retry.\r
1417\r
1418 Side Effects:\r
1419 Content corruption. Block IO write directly touches low level write. Orignal partitions, file systems\r
1420 of the relocation device will be corrupted.\r
1421\r
1422 @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure\r
1423 devices like USB can get enumerated.\r
1424\r
1425 @retval EFI_SUCCESS Capsule on Disk images are sucessfully relocated to the platform-specific device.\r
1426\r
1427**/\r
1428EFI_STATUS\r
1436aea4
MK
1429RelocateCapsuleToDisk (\r
1430 UINTN MaxRetry\r
28889a78
WX
1431 )\r
1432{\r
1436aea4
MK
1433 EFI_STATUS Status;\r
1434 UINTN CapsuleOnDiskNum;\r
1435 UINTN Index;\r
1436 UINTN DataSize;\r
1437 UINT64 TotalImageSize;\r
1438 UINT64 TotalImageNameSize;\r
1439 IMAGE_INFO *CapsuleOnDiskBuf;\r
1440 EFI_HANDLE Handle;\r
1441 EFI_HANDLE TempHandle;\r
1442 EFI_HANDLE *HandleBuffer;\r
1443 UINTN NumberOfHandles;\r
1444 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
1445 UINT8 *CapsuleDataBuf;\r
1446 UINT8 *CapsulePtr;\r
1447 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
1448 EFI_FILE_HANDLE RootDir;\r
1449 EFI_FILE_HANDLE TempCodFile;\r
1450 UINT64 TempCodFileSize;\r
1451 EFI_DEVICE_PATH *TempDevicePath;\r
1452 BOOLEAN RelocationInfo;\r
1453 UINT16 LoadOptionNumber;\r
1454 EFI_CAPSULE_HEADER FileNameCapsuleHeader;\r
28889a78
WX
1455\r
1456 RootDir = NULL;\r
1457 TempCodFile = NULL;\r
1458 HandleBuffer = NULL;\r
1459 CapsuleDataBuf = NULL;\r
1460 CapsuleOnDiskBuf = NULL;\r
1461 NumberOfHandles = 0;\r
1462\r
1463 DEBUG ((DEBUG_INFO, "CapsuleOnDisk RelocateCapsule Enter\n"));\r
1464\r
1465 //\r
1466 // 1. Load all Capsule On Disks in to memory\r
1467 //\r
1436aea4
MK
1468 Status = GetAllCapsuleOnDisk (MaxRetry, &CapsuleOnDiskBuf, &CapsuleOnDiskNum, &Handle, &LoadOptionNumber);\r
1469 if (EFI_ERROR (Status) || (CapsuleOnDiskNum == 0) || (CapsuleOnDiskBuf == NULL)) {\r
28889a78
WX
1470 DEBUG ((DEBUG_INFO, "RelocateCapsule: GetAllCapsuleOnDisk Status - 0x%x\n", Status));\r
1471 return EFI_NOT_FOUND;\r
1472 }\r
1473\r
1474 //\r
1475 // 2. Connect platform special device path as relocation device.\r
1476 // If no platform special device path specified or the device path is invalid, use the EFI system partition where\r
1477 // stores the capsules as relocation device.\r
1478 //\r
1436aea4
MK
1479 if (IsDevicePathValid ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath), PcdGetSize (PcdCodRelocationDevPath))) {\r
1480 Status = EfiBootManagerConnectDevicePath ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath), &TempHandle);\r
1481 if (EFI_ERROR (Status)) {\r
28889a78
WX
1482 DEBUG ((DEBUG_ERROR, "RelocateCapsule: EfiBootManagerConnectDevicePath Status - 0x%x\n", Status));\r
1483 goto EXIT;\r
1484 }\r
1485\r
1486 //\r
1487 // Connect all the child handle. Partition & FAT drivers are allowed in this case\r
1488 //\r
1489 gBS->ConnectController (TempHandle, NULL, NULL, TRUE);\r
1436aea4 1490 Status = gBS->LocateHandleBuffer (\r
28889a78
WX
1491 ByProtocol,\r
1492 &gEfiSimpleFileSystemProtocolGuid,\r
1493 NULL,\r
1494 &NumberOfHandles,\r
1495 &HandleBuffer\r
1496 );\r
1436aea4 1497 if (EFI_ERROR (Status)) {\r
28889a78
WX
1498 DEBUG ((DEBUG_ERROR, "RelocateCapsule: LocateHandleBuffer Status - 0x%x\n", Status));\r
1499 goto EXIT;\r
1500 }\r
1501\r
1502 //\r
1503 // Find first Simple File System Handle which can match PcdCodRelocationDevPath\r
1504 //\r
1505 for (Index = 0; Index < NumberOfHandles; Index++) {\r
1436aea4
MK
1506 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&TempDevicePath);\r
1507 if (EFI_ERROR (Status)) {\r
28889a78
WX
1508 continue;\r
1509 }\r
1510\r
1436aea4
MK
1511 DataSize = GetDevicePathSize ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath)) - sizeof (EFI_DEVICE_PATH);\r
1512 if (0 == CompareMem ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath), TempDevicePath, DataSize)) {\r
28889a78
WX
1513 Handle = HandleBuffer[Index];\r
1514 break;\r
1515 }\r
1516 }\r
1517\r
1436aea4 1518 FreePool (HandleBuffer);\r
28889a78
WX
1519\r
1520 if (Index == NumberOfHandles) {\r
1521 DEBUG ((DEBUG_ERROR, "RelocateCapsule: No simple file system protocol found.\n"));\r
1522 Status = EFI_NOT_FOUND;\r
1523 }\r
1524 }\r
1525\r
1436aea4
MK
1526 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);\r
1527 if (EFI_ERROR (Status) || BlockIo->Media->ReadOnly) {\r
1528 DEBUG ((DEBUG_ERROR, "Fail to find Capsule on Disk relocation BlockIo device or device is ReadOnly!\n"));\r
28889a78
WX
1529 goto EXIT;\r
1530 }\r
1531\r
1436aea4
MK
1532 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);\r
1533 if (EFI_ERROR (Status)) {\r
28889a78
WX
1534 goto EXIT;\r
1535 }\r
1536\r
1537 //\r
1538 // Check if device used to relocate Capsule On Disk is big enough\r
1539 //\r
1540 TotalImageSize = 0;\r
1541 TotalImageNameSize = 0;\r
1542 for (Index = 0; Index < CapsuleOnDiskNum; Index++) {\r
1543 //\r
1544 // Overflow check\r
1545 //\r
1546 if (MAX_ADDRESS - (UINTN)TotalImageSize <= CapsuleOnDiskBuf[Index].FileInfo->FileSize) {\r
1547 Status = EFI_INVALID_PARAMETER;\r
1548 goto EXIT;\r
1549 }\r
1550\r
1436aea4 1551 if (MAX_ADDRESS - (UINTN)TotalImageNameSize <= StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName)) {\r
28889a78
WX
1552 Status = EFI_INVALID_PARAMETER;\r
1553 goto EXIT;\r
1554 }\r
1555\r
1556 TotalImageSize += CapsuleOnDiskBuf[Index].FileInfo->FileSize;\r
1436aea4
MK
1557 TotalImageNameSize += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);\r
1558 DEBUG ((DEBUG_INFO, "RelocateCapsule: %x Size %x\n", CapsuleOnDiskBuf[Index].FileInfo->FileName, CapsuleOnDiskBuf[Index].FileInfo->FileSize));\r
28889a78
WX
1559 }\r
1560\r
1436aea4
MK
1561 DEBUG ((DEBUG_INFO, "RelocateCapsule: TotalImageSize %x\n", TotalImageSize));\r
1562 DEBUG ((DEBUG_INFO, "RelocateCapsule: TotalImageNameSize %x\n", TotalImageNameSize));\r
28889a78 1563\r
1436aea4
MK
1564 if ((MAX_ADDRESS - (UINTN)TotalImageNameSize <= sizeof (UINT64) * 2) ||\r
1565 (MAX_ADDRESS - (UINTN)TotalImageSize <= (UINTN)TotalImageNameSize + sizeof (UINT64) * 2))\r
1566 {\r
28889a78
WX
1567 Status = EFI_INVALID_PARAMETER;\r
1568 goto EXIT;\r
1569 }\r
1570\r
1436aea4 1571 TempCodFileSize = sizeof (UINT64) + TotalImageSize + sizeof (EFI_CAPSULE_HEADER) + TotalImageNameSize;\r
28889a78
WX
1572\r
1573 //\r
1574 // Check if CapsuleTotalSize. There could be reminder, so use LastBlock number directly\r
1575 //\r
1436aea4
MK
1576 if (DivU64x32 (TempCodFileSize, BlockIo->Media->BlockSize) > BlockIo->Media->LastBlock) {\r
1577 DEBUG ((DEBUG_ERROR, "RelocateCapsule: Relocation device isn't big enough to hold all Capsule on Disk!\n"));\r
1578 DEBUG ((DEBUG_ERROR, "TotalImageSize = %x\n", TotalImageSize));\r
1579 DEBUG ((DEBUG_ERROR, "TotalImageNameSize = %x\n", TotalImageNameSize));\r
1580 DEBUG ((DEBUG_ERROR, "RelocationDev BlockSize = %x LastBlock = %x\n", BlockIo->Media->BlockSize, BlockIo->Media->LastBlock));\r
28889a78
WX
1581 Status = EFI_OUT_OF_RESOURCES;\r
1582 goto EXIT;\r
1583 }\r
1584\r
1436aea4 1585 CapsuleDataBuf = AllocatePool ((UINTN)TempCodFileSize);\r
28889a78
WX
1586 if (CapsuleDataBuf == NULL) {\r
1587 Status = EFI_OUT_OF_RESOURCES;\r
1588 goto EXIT;\r
1589 }\r
1590\r
1591 //\r
1592 // First UINT64 reserved for total image size, including capsule name capsule.\r
1593 //\r
1436aea4 1594 *(UINT64 *)CapsuleDataBuf = TotalImageSize + sizeof (EFI_CAPSULE_HEADER) + TotalImageNameSize;\r
28889a78
WX
1595\r
1596 //\r
1597 // Line up all the Capsule on Disk and write to relocation disk at one time. It could save some time in disk write\r
1598 //\r
1436aea4
MK
1599 for (Index = 0, CapsulePtr = CapsuleDataBuf + sizeof (UINT64); Index < CapsuleOnDiskNum; Index++) {\r
1600 CopyMem (CapsulePtr, CapsuleOnDiskBuf[Index].ImageAddress, (UINTN)CapsuleOnDiskBuf[Index].FileInfo->FileSize);\r
28889a78
WX
1601 CapsulePtr += CapsuleOnDiskBuf[Index].FileInfo->FileSize;\r
1602 }\r
1603\r
1604 //\r
1605 // Line the capsule header for capsule name capsule.\r
1606 //\r
1436aea4
MK
1607 CopyGuid (&FileNameCapsuleHeader.CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);\r
1608 FileNameCapsuleHeader.CapsuleImageSize = (UINT32)TotalImageNameSize + sizeof (EFI_CAPSULE_HEADER);\r
28889a78 1609 FileNameCapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;\r
1436aea4
MK
1610 FileNameCapsuleHeader.HeaderSize = sizeof (EFI_CAPSULE_HEADER);\r
1611 CopyMem (CapsulePtr, &FileNameCapsuleHeader, FileNameCapsuleHeader.HeaderSize);\r
28889a78
WX
1612 CapsulePtr += FileNameCapsuleHeader.HeaderSize;\r
1613\r
1614 //\r
1615 // Line up all the Capsule file names.\r
1616 //\r
1617 for (Index = 0; Index < CapsuleOnDiskNum; Index++) {\r
1436aea4
MK
1618 CopyMem (CapsulePtr, CapsuleOnDiskBuf[Index].FileInfo->FileName, StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName));\r
1619 CapsulePtr += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);\r
28889a78
WX
1620 }\r
1621\r
1622 //\r
1623 // 5. Flash all Capsules on Disk to TempCoD.tmp under RootDir\r
1624 //\r
1436aea4
MK
1625 Status = Fs->OpenVolume (Fs, &RootDir);\r
1626 if (EFI_ERROR (Status)) {\r
1627 DEBUG ((DEBUG_ERROR, "RelocateCapsule: OpenVolume error. %x\n", Status));\r
28889a78
WX
1628 goto EXIT;\r
1629 }\r
1630\r
1436aea4 1631 Status = RootDir->Open (\r
28889a78
WX
1632 RootDir,\r
1633 &TempCodFile,\r
1436aea4 1634 (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName),\r
28889a78
WX
1635 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,\r
1636 0\r
1637 );\r
1436aea4 1638 if (!EFI_ERROR (Status)) {\r
28889a78
WX
1639 //\r
1640 // Error handling code to prevent malicious code to hold this file to block capsule on disk\r
1641 //\r
1436aea4 1642 TempCodFile->Delete (TempCodFile);\r
28889a78 1643 }\r
1436aea4
MK
1644\r
1645 Status = RootDir->Open (\r
28889a78
WX
1646 RootDir,\r
1647 &TempCodFile,\r
1436aea4 1648 (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName),\r
28889a78
WX
1649 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,\r
1650 0\r
1651 );\r
1436aea4
MK
1652 if (EFI_ERROR (Status)) {\r
1653 DEBUG ((DEBUG_ERROR, "RelocateCapsule: Open TemCoD.tmp error. %x\n", Status));\r
28889a78
WX
1654 goto EXIT;\r
1655 }\r
1656\r
1657 //\r
1658 // Always write at the begining of TempCap file\r
1659 //\r
1436aea4
MK
1660 DataSize = (UINTN)TempCodFileSize;\r
1661 Status = TempCodFile->Write (\r
1662 TempCodFile,\r
1663 &DataSize,\r
1664 CapsuleDataBuf\r
1665 );\r
1666 if (EFI_ERROR (Status)) {\r
1667 DEBUG ((DEBUG_ERROR, "RelocateCapsule: Write TemCoD.tmp error. %x\n", Status));\r
28889a78
WX
1668 goto EXIT;\r
1669 }\r
1670\r
1671 if (DataSize != TempCodFileSize) {\r
1672 Status = EFI_DEVICE_ERROR;\r
1673 goto EXIT;\r
1674 }\r
1675\r
1676 //\r
1677 // Save Capsule On Disk relocation info to "CodRelocationInfo" Var\r
1678 // It is used in next reboot by TCB\r
1679 //\r
1680 RelocationInfo = TRUE;\r
1436aea4
MK
1681 Status = gRT->SetVariable (\r
1682 COD_RELOCATION_INFO_VAR_NAME,\r
1683 &gEfiCapsuleVendorGuid,\r
1684 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1685 sizeof (BOOLEAN),\r
1686 &RelocationInfo\r
1687 );\r
28889a78
WX
1688 //\r
1689 // Save the LoadOptionNumber of the boot option, where the capsule is relocated,\r
1690 // into "CodRelocationLoadOption" var. It is used in next reboot after capsule is\r
1691 // updated out of TCB to remove the TempCoDFile.\r
1692 //\r
1436aea4
MK
1693 Status = gRT->SetVariable (\r
1694 COD_RELOCATION_LOAD_OPTION_VAR_NAME,\r
1695 &gEfiCapsuleVendorGuid,\r
1696 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1697 sizeof (UINT16),\r
1698 &LoadOptionNumber\r
1699 );\r
28889a78
WX
1700\r
1701EXIT:\r
1702\r
1703 if (CapsuleDataBuf != NULL) {\r
1436aea4 1704 FreePool (CapsuleDataBuf);\r
28889a78
WX
1705 }\r
1706\r
1707 if (CapsuleOnDiskBuf != NULL) {\r
1708 //\r
1709 // Free resources allocated by CodLibGetAllCapsuleOnDisk\r
1710 //\r
1711 for (Index = 0; Index < CapsuleOnDiskNum; Index++ ) {\r
1436aea4
MK
1712 FreePool (CapsuleOnDiskBuf[Index].ImageAddress);\r
1713 FreePool (CapsuleOnDiskBuf[Index].FileInfo);\r
28889a78 1714 }\r
1436aea4
MK
1715\r
1716 FreePool (CapsuleOnDiskBuf);\r
28889a78
WX
1717 }\r
1718\r
1719 if (TempCodFile != NULL) {\r
1436aea4 1720 if (EFI_ERROR (Status)) {\r
28889a78
WX
1721 TempCodFile->Delete (TempCodFile);\r
1722 } else {\r
1723 TempCodFile->Close (TempCodFile);\r
1724 }\r
1725 }\r
1726\r
1727 if (RootDir != NULL) {\r
1728 RootDir->Close (RootDir);\r
1729 }\r
1730\r
1731 return Status;\r
1732}\r
1733\r
1734/**\r
1735 For the platforms that support Capsule In Ram, reuse the Capsule In Ram to deliver capsule.\r
1736 Relocate Capsule On Disk to memory and call UpdateCapsule().\r
1737 Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.\r
1738 Function will stall 100ms between each retry.\r
1739\r
1740 @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure\r
1741 devices like USB can get enumerated.\r
1742\r
1743 @retval EFI_SUCCESS Deliver capsule through Capsule In Ram successfully.\r
1744\r
1745**/\r
1746EFI_STATUS\r
1747RelocateCapsuleToRam (\r
1436aea4 1748 UINTN MaxRetry\r
28889a78
WX
1749 )\r
1750{\r
1751 EFI_STATUS Status;\r
1752 UINTN CapsuleOnDiskNum;\r
1753 IMAGE_INFO *CapsuleOnDiskBuf;\r
1754 EFI_HANDLE Handle;\r
1755 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;\r
1756 VOID **CapsuleBuffer;\r
1757 UINTN *CapsuleSize;\r
1758 EFI_CAPSULE_HEADER *FileNameCapsule;\r
1759 UINTN Index;\r
1760 UINT8 *StringBuf;\r
1761 UINTN StringSize;\r
1762 UINTN TotalStringSize;\r
aab6bb3d 1763 UINTN CapsulesToProcess;\r
28889a78
WX
1764\r
1765 CapsuleOnDiskBuf = NULL;\r
1766 BlockDescriptors = NULL;\r
1767 CapsuleBuffer = NULL;\r
1768 CapsuleSize = NULL;\r
1769 FileNameCapsule = NULL;\r
1770 TotalStringSize = 0;\r
1771\r
1772 //\r
1773 // 1. Load all Capsule On Disks into memory\r
1774 //\r
1775 Status = GetAllCapsuleOnDisk (MaxRetry, &CapsuleOnDiskBuf, &CapsuleOnDiskNum, &Handle, NULL);\r
1436aea4 1776 if (EFI_ERROR (Status) || (CapsuleOnDiskNum == 0) || (CapsuleOnDiskBuf == NULL)) {\r
28889a78
WX
1777 DEBUG ((DEBUG_ERROR, "GetAllCapsuleOnDisk Status - 0x%x\n", Status));\r
1778 return EFI_NOT_FOUND;\r
1779 }\r
1780\r
1781 //\r
1782 // 2. Add a capsule for Capsule file name strings\r
1783 //\r
1784 CapsuleBuffer = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof (VOID *));\r
1785 if (CapsuleBuffer == NULL) {\r
1786 DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));\r
1787 return EFI_OUT_OF_RESOURCES;\r
1788 }\r
1789\r
1790 CapsuleSize = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof (UINTN));\r
1791 if (CapsuleSize == NULL) {\r
1792 DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));\r
1793 FreePool (CapsuleBuffer);\r
1794 return EFI_OUT_OF_RESOURCES;\r
1795 }\r
1796\r
1797 for (Index = 0; Index < CapsuleOnDiskNum; Index++) {\r
1436aea4
MK
1798 CapsuleBuffer[Index] = (VOID *)(UINTN)CapsuleOnDiskBuf[Index].ImageAddress;\r
1799 CapsuleSize[Index] = (UINTN)CapsuleOnDiskBuf[Index].FileInfo->FileSize;\r
1800 TotalStringSize += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);\r
28889a78
WX
1801 }\r
1802\r
aab6bb3d
BM
1803 // If Persist Across Reset isn't supported, skip the file name strings capsule\r
1804 if (!FeaturePcdGet (PcdSupportUpdateCapsuleReset)) {\r
1805 CapsulesToProcess = CapsuleOnDiskNum;\r
1806 goto BuildGather;\r
1807 }\r
1436aea4 1808\r
aab6bb3d
BM
1809 CapsulesToProcess = CapsuleOnDiskNum + 1;\r
1810\r
28889a78
WX
1811 FileNameCapsule = AllocateZeroPool (sizeof (EFI_CAPSULE_HEADER) + TotalStringSize);\r
1812 if (FileNameCapsule == NULL) {\r
1813 DEBUG ((DEBUG_ERROR, "Fail to allocate memory for name capsule.\n"));\r
1814 FreePool (CapsuleBuffer);\r
1815 FreePool (CapsuleSize);\r
1816 return EFI_OUT_OF_RESOURCES;\r
1817 }\r
1818\r
1436aea4
MK
1819 FileNameCapsule->CapsuleImageSize = (UINT32)(sizeof (EFI_CAPSULE_HEADER) + TotalStringSize);\r
1820 FileNameCapsule->Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;\r
1821 FileNameCapsule->HeaderSize = sizeof (EFI_CAPSULE_HEADER);\r
28889a78
WX
1822 CopyGuid (&(FileNameCapsule->CapsuleGuid), &gEdkiiCapsuleOnDiskNameGuid);\r
1823\r
1824 StringBuf = (UINT8 *)FileNameCapsule + FileNameCapsule->HeaderSize;\r
1436aea4 1825 for (Index = 0; Index < CapsuleOnDiskNum; Index++) {\r
28889a78
WX
1826 StringSize = StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);\r
1827 CopyMem (StringBuf, CapsuleOnDiskBuf[Index].FileInfo->FileName, StringSize);\r
1828 StringBuf += StringSize;\r
1829 }\r
1830\r
1831 CapsuleBuffer[CapsuleOnDiskNum] = FileNameCapsule;\r
1436aea4 1832 CapsuleSize[CapsuleOnDiskNum] = TotalStringSize + sizeof (EFI_CAPSULE_HEADER);\r
28889a78
WX
1833\r
1834 //\r
1835 // 3. Build Gather list for the capsules\r
1836 //\r
aab6bb3d
BM
1837BuildGather:\r
1838 Status = BuildGatherList (CapsuleBuffer, CapsuleSize, CapsulesToProcess, &BlockDescriptors);\r
1436aea4 1839 if (EFI_ERROR (Status) || (BlockDescriptors == NULL)) {\r
28889a78
WX
1840 FreePool (CapsuleBuffer);\r
1841 FreePool (CapsuleSize);\r
aab6bb3d
BM
1842 if (FileNameCapsule != NULL) {\r
1843 FreePool (FileNameCapsule);\r
1844 }\r
1436aea4 1845\r
28889a78
WX
1846 return EFI_OUT_OF_RESOURCES;\r
1847 }\r
1848\r
1849 //\r
1850 // 4. Call UpdateCapsule() service\r
1851 //\r
1436aea4
MK
1852 Status = gRT->UpdateCapsule (\r
1853 (EFI_CAPSULE_HEADER **)CapsuleBuffer,\r
1854 CapsulesToProcess,\r
1855 (UINTN)BlockDescriptors\r
1856 );\r
28889a78
WX
1857\r
1858 return Status;\r
1859}\r
1860\r
1861/**\r
1862 Relocate Capsule on Disk from EFI system partition.\r
1863\r
1864 Two solution to deliver Capsule On Disk:\r
1865 Solution A: If PcdCapsuleInRamSupport is enabled, relocate Capsule On Disk to memory and call UpdateCapsule().\r
1866 Solution B: If PcdCapsuleInRamSupport is disabled, relocate Capsule On Disk to a platform-specific NV storage\r
1867 device with BlockIo protocol.\r
1868\r
1869 Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.\r
1870 Function will stall 100ms between each retry.\r
1871\r
1872 Side Effects:\r
1873 Capsule Delivery Supported Flag in OsIndication variable and BootNext variable will be cleared.\r
1874 Solution B: Content corruption. Block IO write directly touches low level write. Orignal partitions, file\r
1875 systems of the relocation device will be corrupted.\r
1876\r
1877 @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure\r
1878 devices like USB can get enumerated. Input 0 means no retry.\r
1879\r
1880 @retval EFI_SUCCESS Capsule on Disk images are successfully relocated.\r
1881\r
1882**/\r
1883EFI_STATUS\r
1884EFIAPI\r
1436aea4
MK
1885CoDRelocateCapsule (\r
1886 UINTN MaxRetry\r
28889a78
WX
1887 )\r
1888{\r
1889 if (!PcdGetBool (PcdCapsuleOnDiskSupport)) {\r
1890 return EFI_UNSUPPORTED;\r
1891 }\r
1892\r
1893 //\r
1894 // Clear CapsuleOnDisk Flag firstly.\r
1895 //\r
1896 CoDClearCapsuleOnDiskFlag ();\r
1897\r
1898 //\r
1899 // If Capsule In Ram is supported, delivery capsules through memory\r
1900 //\r
1901 if (PcdGetBool (PcdCapsuleInRamSupport)) {\r
1902 DEBUG ((DEBUG_INFO, "Capsule In Ram is supported, call gRT->UpdateCapsule().\n"));\r
1903 return RelocateCapsuleToRam (MaxRetry);\r
1904 } else {\r
1436aea4 1905 DEBUG ((DEBUG_INFO, "Reallcoate all Capsule on Disks to %s in RootDir.\n", (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName)));\r
28889a78
WX
1906 return RelocateCapsuleToDisk (MaxRetry);\r
1907 }\r
1908}\r
1909\r
1910/**\r
1911 Remove the temp file from the root of EFI System Partition.\r
1912 Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.\r
1913 Function will stall 100ms between each retry.\r
1914\r
1915 @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure\r
1916 devices like USB can get enumerated. Input 0 means no retry.\r
1917\r
1918 @retval EFI_SUCCESS Remove the temp file successfully.\r
1919\r
1920**/\r
1921EFI_STATUS\r
1922EFIAPI\r
1923CoDRemoveTempFile (\r
1436aea4 1924 UINTN MaxRetry\r
28889a78
WX
1925 )\r
1926{\r
1927 EFI_STATUS Status;\r
1928 UINTN DataSize;\r
1929 UINT16 *LoadOptionNumber;\r
1930 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
1931 EFI_HANDLE FsHandle;\r
1932 EFI_FILE_HANDLE RootDir;\r
1933 EFI_FILE_HANDLE TempCodFile;\r
1934\r
1935 RootDir = NULL;\r
1936 TempCodFile = NULL;\r
1436aea4 1937 DataSize = sizeof (UINT16);\r
28889a78 1938\r
1436aea4 1939 LoadOptionNumber = AllocatePool (sizeof (UINT16));\r
28889a78
WX
1940 if (LoadOptionNumber == NULL) {\r
1941 return EFI_OUT_OF_RESOURCES;\r
1942 }\r
1943\r
1944 //\r
1945 // Check if capsule files are relocated\r
1946 //\r
1947 Status = gRT->GetVariable (\r
1948 COD_RELOCATION_LOAD_OPTION_VAR_NAME,\r
1949 &gEfiCapsuleVendorGuid,\r
1950 NULL,\r
1951 &DataSize,\r
1952 (VOID *)LoadOptionNumber\r
1953 );\r
1436aea4 1954 if (EFI_ERROR (Status) || (DataSize != sizeof (UINT16))) {\r
28889a78
WX
1955 goto EXIT;\r
1956 }\r
1957\r
1958 //\r
1959 // Get the EFI file system from the boot option where the capsules are relocated\r
1960 //\r
1436aea4
MK
1961 Status = GetEfiSysPartitionFromActiveBootOption (MaxRetry, &LoadOptionNumber, &FsHandle);\r
1962 if (EFI_ERROR (Status)) {\r
28889a78
WX
1963 goto EXIT;\r
1964 }\r
1965\r
1436aea4
MK
1966 Status = gBS->HandleProtocol (FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);\r
1967 if (EFI_ERROR (Status)) {\r
28889a78
WX
1968 goto EXIT;\r
1969 }\r
1970\r
1436aea4
MK
1971 Status = Fs->OpenVolume (Fs, &RootDir);\r
1972 if (EFI_ERROR (Status)) {\r
28889a78
WX
1973 goto EXIT;\r
1974 }\r
1975\r
1976 //\r
1977 // Delete the TempCoDFile\r
1978 //\r
1436aea4 1979 Status = RootDir->Open (\r
28889a78
WX
1980 RootDir,\r
1981 &TempCodFile,\r
1436aea4 1982 (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName),\r
28889a78
WX
1983 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,\r
1984 0\r
1985 );\r
1436aea4 1986 if (EFI_ERROR (Status)) {\r
28889a78
WX
1987 goto EXIT;\r
1988 }\r
1989\r
1436aea4 1990 TempCodFile->Delete (TempCodFile);\r
28889a78
WX
1991\r
1992 //\r
1993 // Clear "CoDRelocationLoadOption" variable\r
1994 //\r
1995 Status = gRT->SetVariable (\r
1436aea4
MK
1996 COD_RELOCATION_LOAD_OPTION_VAR_NAME,\r
1997 &gEfiCapsuleVendorGuid,\r
1998 0,\r
1999 0,\r
2000 NULL\r
2001 );\r
28889a78
WX
2002\r
2003EXIT:\r
2004 if (LoadOptionNumber != NULL) {\r
2005 FreePool (LoadOptionNumber);\r
2006 }\r
2007\r
2008 if (RootDir != NULL) {\r
1436aea4 2009 RootDir->Close (RootDir);\r
28889a78
WX
2010 }\r
2011\r
2012 return Status;\r
2013}\r