]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
MdeModulePkg/CapsuleLib: Support result rolling over.
[mirror_edk2.git] / MdeModulePkg / Library / DxeCapsuleLibFmp / DxeCapsuleReportLib.c
CommitLineData
d2a16030
JY
1/** @file\r
2 DXE capsule report related function.\r
3\r
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <PiDxe.h>\r
16#include <Protocol/FirmwareManagement.h>\r
17#include <Protocol/VariableLock.h>\r
18#include <Guid/CapsuleReport.h>\r
19#include <Guid/FmpCapsule.h>\r
20#include <Guid/CapsuleVendor.h>\r
21\r
22#include <Library/BaseLib.h>\r
23#include <Library/DebugLib.h>\r
24#include <Library/BaseMemoryLib.h>\r
25#include <Library/UefiBootServicesTableLib.h>\r
26#include <Library/UefiRuntimeServicesTableLib.h>\r
27#include <Library/MemoryAllocationLib.h>\r
28#include <Library/UefiLib.h>\r
29#include <Library/PcdLib.h>\r
30#include <Library/HobLib.h>\r
31#include <Library/PrintLib.h>\r
32#include <Library/ReportStatusCodeLib.h>\r
8f6db161 33#include <Library/DevicePathLib.h>\r
d2a16030
JY
34#include <Library/CapsuleLib.h>\r
35\r
36#include <IndustryStandard/WindowsUxCapsule.h>\r
37\r
38typedef struct {\r
39 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultHeader;\r
40 EFI_CAPSULE_RESULT_VARIABLE_FMP CapsuleResultFmp;\r
41} CAPSULE_RESULT_VARIABLE_CACHE;\r
42\r
43#define CAPSULE_RESULT_VARIABLE_CACHE_COUNT 0x10\r
44\r
45CAPSULE_RESULT_VARIABLE_CACHE *mCapsuleResultVariableCache;\r
46UINTN mCapsuleResultVariableCacheMaxCount;\r
47UINTN mCapsuleResultVariableCacheCount;\r
48\r
49/**\r
50 Get current capsule last variable index.\r
51\r
52 @return Current capsule last variable index.\r
53 @retval -1 No current capsule last variable.\r
54**/\r
55INTN\r
56GetCurrentCapsuleLastIndex (\r
57 VOID\r
58 )\r
59{\r
60 UINTN Size;\r
61 CHAR16 CapsuleLastStr[sizeof("Capsule####")];\r
62 EFI_STATUS Status;\r
63 UINT16 CurrentIndex;\r
64\r
65 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
66 Status = gRT->GetVariable(\r
67 L"CapsuleLast",\r
68 &gEfiCapsuleReportGuid,\r
69 NULL,\r
70 &Size,\r
71 CapsuleLastStr\r
72 );\r
73 if (EFI_ERROR(Status)) {\r
74 return -1;\r
75 }\r
76 CurrentIndex = (UINT16)StrHexToUintn(&CapsuleLastStr[sizeof("Capsule") - 1]);\r
77 return CurrentIndex;\r
78}\r
79\r
80/**\r
81 Check if this FMP capsule is processed.\r
82\r
83 @param[in] CapsuleHeader The capsule image header\r
84 @param[in] PayloadIndex FMP payload index\r
85 @param[in] ImageHeader FMP image header\r
86\r
87 @retval TRUE This FMP capsule is processed.\r
88 @retval FALSE This FMP capsule is not processed.\r
89**/\r
90BOOLEAN\r
91IsFmpCapsuleProcessed (\r
92 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
93 IN UINTN PayloadIndex,\r
94 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader\r
95 )\r
96{\r
97 UINTN Index;\r
98 EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResult;\r
99 EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultFmp;\r
100\r
101 for (Index = 0; Index < mCapsuleResultVariableCacheCount; Index++) {\r
102 //\r
103 // Check\r
104 //\r
105 CapsuleResult = &mCapsuleResultVariableCache[Index].CapsuleResultHeader;\r
106 if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)) {\r
107 if (CompareGuid(&CapsuleResult->CapsuleGuid, &gEfiFmpCapsuleGuid)) {\r
d8487a34 108 if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + sizeof(CHAR16) * 2) {\r
d2a16030
JY
109 CapsuleResultFmp = (EFI_CAPSULE_RESULT_VARIABLE_FMP *)(CapsuleResult + 1);\r
110 if (CompareGuid(&CapsuleResultFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId) &&\r
111 (CapsuleResultFmp->UpdateImageIndex == ImageHeader->UpdateImageIndex) &&\r
112 (CapsuleResultFmp->PayloadIndex == PayloadIndex) ) {\r
113 return TRUE;\r
114 }\r
115 }\r
116 }\r
117 }\r
118 }\r
119\r
120 return FALSE;\r
121}\r
122\r
123/**\r
124 Write a new capsule status variable cache.\r
125\r
126 @param[in] CapsuleResult The capsule status variable\r
127 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes\r
128\r
129 @retval EFI_SUCCESS The capsule status variable is cached.\r
130 @retval EFI_OUT_OF_RESOURCES No resource to cache the capsule status variable.\r
131**/\r
132EFI_STATUS\r
133WriteNewCapsuleResultVariableCache (\r
134 IN VOID *CapsuleResult,\r
135 IN UINTN CapsuleResultSize\r
136 )\r
137{\r
138 if (CapsuleResultSize > sizeof(CAPSULE_RESULT_VARIABLE_CACHE)) {\r
139 CapsuleResultSize = sizeof(CAPSULE_RESULT_VARIABLE_CACHE);\r
140 }\r
141\r
142 if (mCapsuleResultVariableCacheCount == mCapsuleResultVariableCacheMaxCount) {\r
143 mCapsuleResultVariableCache = ReallocatePool(\r
144 mCapsuleResultVariableCacheMaxCount * sizeof(CAPSULE_RESULT_VARIABLE_CACHE),\r
145 (mCapsuleResultVariableCacheMaxCount + CAPSULE_RESULT_VARIABLE_CACHE_COUNT) * sizeof(CAPSULE_RESULT_VARIABLE_CACHE),\r
146 mCapsuleResultVariableCache\r
147 );\r
148 if (mCapsuleResultVariableCache == NULL) {\r
149 return EFI_OUT_OF_RESOURCES;\r
150 }\r
151 mCapsuleResultVariableCacheMaxCount += CAPSULE_RESULT_VARIABLE_CACHE_COUNT;\r
152 }\r
153\r
154 ASSERT(mCapsuleResultVariableCacheCount < mCapsuleResultVariableCacheMaxCount);\r
155 ASSERT(mCapsuleResultVariableCache != NULL);\r
156 CopyMem(\r
157 &mCapsuleResultVariableCache[mCapsuleResultVariableCacheCount],\r
158 CapsuleResult,\r
159 CapsuleResultSize\r
160 );\r
161 mCapsuleResultVariableCacheCount++;\r
162\r
163 return EFI_SUCCESS;\r
164}\r
165\r
166/**\r
167 Get a new capsule status variable index.\r
168\r
169 @return A new capsule status variable index.\r
777034ce 170 @retval 0 No new capsule status variable index. Rolling over.\r
d2a16030
JY
171**/\r
172INTN\r
173GetNewCapsuleResultIndex (\r
174 VOID\r
175 )\r
176{\r
177 INTN CurrentIndex;\r
178\r
179 CurrentIndex = GetCurrentCapsuleLastIndex();\r
180 if (CurrentIndex >= PcdGet16(PcdCapsuleMax)) {\r
777034ce
JY
181 DEBUG((DEBUG_INFO, " CapsuleResult variable Rolling Over!\n"));\r
182 return 0;\r
d2a16030
JY
183 }\r
184\r
185 return CurrentIndex + 1;\r
186}\r
187\r
188/**\r
189 Write a new capsule status variable.\r
190\r
191 @param[in] CapsuleResult The capsule status variable\r
192 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes\r
193\r
194 @retval EFI_SUCCESS The capsule status variable is recorded.\r
195 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
196**/\r
197EFI_STATUS\r
198WriteNewCapsuleResultVariable (\r
199 IN VOID *CapsuleResult,\r
200 IN UINTN CapsuleResultSize\r
201 )\r
202{\r
203 INTN CapsuleResultIndex;\r
204 CHAR16 CapsuleResultStr[sizeof("Capsule####")];\r
205 UINTN Size;\r
206 EFI_STATUS Status;\r
207\r
208 CapsuleResultIndex = GetNewCapsuleResultIndex();\r
209 DEBUG((DEBUG_INFO, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex));\r
777034ce 210\r
d2a16030
JY
211 UnicodeSPrint(\r
212 CapsuleResultStr,\r
213 sizeof(CapsuleResultStr),\r
214 L"Capsule%04x",\r
215 CapsuleResultIndex\r
216 );\r
217\r
218 Status = gRT->SetVariable(\r
219 CapsuleResultStr,\r
220 &gEfiCapsuleReportGuid,\r
221 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
222 CapsuleResultSize,\r
223 CapsuleResult\r
224 );\r
225 if (!EFI_ERROR(Status)) {\r
226 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
227 DEBUG((DEBUG_INFO, "Set CapsuleLast - %s\n", CapsuleResultStr));\r
228 Status = gRT->SetVariable(\r
229 L"CapsuleLast",\r
230 &gEfiCapsuleReportGuid,\r
231 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
232 Size,\r
233 CapsuleResultStr\r
234 );\r
235 }\r
236\r
237 return Status;\r
238}\r
239\r
240/**\r
241 Record capsule status variable and to local cache.\r
242\r
243 @param[in] CapsuleHeader The capsule image header\r
244 @param[in] CapsuleStatus The capsule process stauts\r
245\r
246 @retval EFI_SUCCESS The capsule status variable is recorded.\r
247 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
248**/\r
249EFI_STATUS\r
250RecordCapsuleStatusVariable (\r
251 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
252 IN EFI_STATUS CapsuleStatus\r
253 )\r
254{\r
255 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable;\r
256 EFI_STATUS Status;\r
257\r
258 CapsuleResultVariable.VariableTotalSize = sizeof(CapsuleResultVariable);\r
d8487a34 259 CapsuleResultVariable.Reserved = 0;\r
d2a16030
JY
260 CopyGuid (&CapsuleResultVariable.CapsuleGuid, &CapsuleHeader->CapsuleGuid);\r
261 ZeroMem(&CapsuleResultVariable.CapsuleProcessed, sizeof(CapsuleResultVariable.CapsuleProcessed));\r
262 gRT->GetTime(&CapsuleResultVariable.CapsuleProcessed, NULL);\r
263 CapsuleResultVariable.CapsuleStatus = CapsuleStatus;\r
264\r
265 //\r
266 // Save Local Cache\r
267 //\r
268 Status = WriteNewCapsuleResultVariableCache(&CapsuleResultVariable, sizeof(CapsuleResultVariable));\r
269\r
270 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
271 Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable));\r
272 }\r
273 return Status;\r
274}\r
275\r
276/**\r
277 Record FMP capsule status variable and to local cache.\r
278\r
279 @param[in] CapsuleHeader The capsule image header\r
280 @param[in] CapsuleStatus The capsule process stauts\r
281 @param[in] PayloadIndex FMP payload index\r
282 @param[in] ImageHeader FMP image header\r
8f6db161 283 @param[in] FmpDevicePath DevicePath associated with the FMP producer\r
d2a16030
JY
284\r
285 @retval EFI_SUCCESS The capsule status variable is recorded.\r
286 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
287**/\r
288EFI_STATUS\r
289RecordFmpCapsuleStatusVariable (\r
290 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
291 IN EFI_STATUS CapsuleStatus,\r
292 IN UINTN PayloadIndex,\r
8f6db161
JY
293 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,\r
294 IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL\r
d2a16030
JY
295 )\r
296{\r
d2a16030
JY
297 EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResultVariableHeader;\r
298 EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultVariableFmp;\r
299 EFI_STATUS Status;\r
b857bf48 300 UINT8 *CapsuleResultVariable;\r
8f6db161
JY
301 UINTN CapsuleResultVariableSize;\r
302 CHAR16 *DevicePathStr;\r
303 UINTN DevicePathStrSize;\r
d2a16030 304\r
8f6db161
JY
305 DevicePathStr = NULL;\r
306 if (FmpDevicePath != NULL) {\r
307 DevicePathStr = ConvertDevicePathToText (FmpDevicePath, FALSE, FALSE);\r
308 }\r
309 if (DevicePathStr != NULL) {\r
310 DevicePathStrSize = StrSize(DevicePathStr);\r
311 } else {\r
312 DevicePathStrSize = sizeof(CHAR16);\r
313 }\r
d8487a34 314 //\r
8f6db161 315 // Allocate zero CHAR16 for CapsuleFileName.\r
d8487a34 316 //\r
8f6db161 317 CapsuleResultVariableSize = sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + sizeof(CHAR16) + DevicePathStrSize;\r
d8487a34 318 CapsuleResultVariable = AllocateZeroPool (CapsuleResultVariableSize);\r
b857bf48
DB
319 if (CapsuleResultVariable == NULL) {\r
320 return EFI_OUT_OF_RESOURCES;\r
321 }\r
322 CapsuleResultVariableHeader = (VOID *)CapsuleResultVariable;\r
8f6db161 323 CapsuleResultVariableHeader->VariableTotalSize = (UINT32)CapsuleResultVariableSize;\r
d8487a34 324 CapsuleResultVariableHeader->Reserved = 0;\r
d2a16030
JY
325 CopyGuid(&CapsuleResultVariableHeader->CapsuleGuid, &CapsuleHeader->CapsuleGuid);\r
326 ZeroMem(&CapsuleResultVariableHeader->CapsuleProcessed, sizeof(CapsuleResultVariableHeader->CapsuleProcessed));\r
327 gRT->GetTime(&CapsuleResultVariableHeader->CapsuleProcessed, NULL);\r
328 CapsuleResultVariableHeader->CapsuleStatus = CapsuleStatus;\r
329\r
b857bf48 330 CapsuleResultVariableFmp = (VOID *)(CapsuleResultVariable + sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER));\r
d2a16030
JY
331 CapsuleResultVariableFmp->Version = 0x1;\r
332 CapsuleResultVariableFmp->PayloadIndex = (UINT8)PayloadIndex;\r
333 CapsuleResultVariableFmp->UpdateImageIndex = ImageHeader->UpdateImageIndex;\r
334 CopyGuid (&CapsuleResultVariableFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId);\r
8f6db161
JY
335 if (DevicePathStr != NULL) {\r
336 CopyMem ((UINT8 *)CapsuleResultVariableFmp + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + sizeof(CHAR16), DevicePathStr, DevicePathStrSize);\r
337 FreePool (DevicePathStr);\r
338 DevicePathStr = NULL;\r
339 }\r
d2a16030
JY
340\r
341 //\r
342 // Save Local Cache\r
343 //\r
b857bf48 344 Status = WriteNewCapsuleResultVariableCache(CapsuleResultVariable, CapsuleResultVariableSize);\r
d2a16030
JY
345\r
346 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
b857bf48 347 Status = WriteNewCapsuleResultVariable(CapsuleResultVariable, CapsuleResultVariableSize);\r
d2a16030 348 }\r
b857bf48 349 FreePool (CapsuleResultVariable);\r
d2a16030
JY
350 return Status;\r
351}\r
352\r
353/**\r
354 Initialize CapsuleMax variables.\r
355**/\r
356VOID\r
357InitCapsuleMaxVariable (\r
358 VOID\r
359 )\r
360{\r
361 EFI_STATUS Status;\r
362 UINTN Size;\r
363 CHAR16 CapsuleMaxStr[sizeof("Capsule####")];\r
364 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
365\r
366 UnicodeSPrint(\r
367 CapsuleMaxStr,\r
368 sizeof(CapsuleMaxStr),\r
369 L"Capsule%04x",\r
370 PcdGet16(PcdCapsuleMax)\r
371 );\r
372\r
373 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
374 Status = gRT->SetVariable(\r
375 L"CapsuleMax",\r
376 &gEfiCapsuleReportGuid,\r
377 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
378 Size,\r
379 CapsuleMaxStr\r
380 );\r
381 if (!EFI_ERROR(Status)) {\r
382 // Lock it per UEFI spec.\r
383 Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);\r
384 if (!EFI_ERROR(Status)) {\r
385 Status = VariableLock->RequestToLock(VariableLock, L"CapsuleMax", &gEfiCapsuleReportGuid);\r
386 ASSERT_EFI_ERROR(Status);\r
387 }\r
388 }\r
389}\r
390\r
391/**\r
392 Initialize CapsuleLast variables.\r
393**/\r
394VOID\r
395InitCapsuleLastVariable (\r
396 VOID\r
397 )\r
398{\r
399 EFI_STATUS Status;\r
400 EFI_BOOT_MODE BootMode;\r
401 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
402 VOID *CapsuleResult;\r
403 UINTN Size;\r
404 CHAR16 CapsuleLastStr[sizeof("Capsule####")];\r
405\r
406 BootMode = GetBootModeHob();\r
407 if (BootMode == BOOT_ON_FLASH_UPDATE) {\r
408 Status = gRT->SetVariable(\r
409 L"CapsuleLast",\r
410 &gEfiCapsuleReportGuid,\r
411 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
412 0,\r
413 NULL\r
414 );\r
415 // Do not lock it because it will be updated later.\r
416 } else {\r
417 //\r
418 // Check if OS/APP cleared L"Capsule####"\r
419 //\r
420 ZeroMem(CapsuleLastStr, sizeof(CapsuleLastStr));\r
421 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
422 Status = gRT->GetVariable(\r
423 L"CapsuleLast",\r
424 &gEfiCapsuleReportGuid,\r
425 NULL,\r
426 &Size,\r
427 CapsuleLastStr\r
428 );\r
429 if (!EFI_ERROR(Status)) {\r
430 //\r
431 // L"CapsuleLast" is got, check if data is there.\r
432 //\r
433 Status = GetVariable2 (\r
434 CapsuleLastStr,\r
435 &gEfiCapsuleReportGuid,\r
436 (VOID **) &CapsuleResult,\r
437 NULL\r
438 );\r
439 if (EFI_ERROR(Status)) {\r
440 //\r
441 // If no data, delete L"CapsuleLast"\r
442 //\r
443 Status = gRT->SetVariable(\r
444 L"CapsuleLast",\r
445 &gEfiCapsuleReportGuid,\r
446 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
447 0,\r
448 NULL\r
449 );\r
450 }\r
451 }\r
452\r
453 // Lock it in normal boot path per UEFI spec.\r
454 Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);\r
455 if (!EFI_ERROR(Status)) {\r
456 Status = VariableLock->RequestToLock(VariableLock, L"CapsuleLast", &gEfiCapsuleReportGuid);\r
457 ASSERT_EFI_ERROR(Status);\r
458 }\r
459 }\r
460}\r
461\r
462/**\r
463 Initialize capsule update variables.\r
464**/\r
465VOID\r
466InitCapsuleUpdateVariable (\r
467 VOID\r
468 )\r
469{\r
470 EFI_STATUS Status;\r
471 UINTN Index;\r
472 CHAR16 CapsuleVarName[30];\r
473 CHAR16 *TempVarName;\r
474\r
475 //\r
476 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...\r
477 // as early as possible which will avoid the next time boot after the capsule update\r
478 // will still into the capsule loop\r
479 //\r
480 StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), EFI_CAPSULE_VARIABLE_NAME);\r
481 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
482 Index = 0;\r
483 while (TRUE) {\r
484 if (Index > 0) {\r
485 UnicodeValueToString (TempVarName, 0, Index, 0);\r
486 }\r
487 Status = gRT->SetVariable (\r
488 CapsuleVarName,\r
489 &gEfiCapsuleVendorGuid,\r
490 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
491 0,\r
492 (VOID *)NULL\r
493 );\r
494 if (EFI_ERROR (Status)) {\r
495 //\r
496 // There is no capsule variables, quit\r
497 //\r
498 break;\r
499 }\r
500 Index++;\r
501 }\r
502}\r
503\r
504/**\r
505 Initialize capsule related variables.\r
506**/\r
507VOID\r
508InitCapsuleVariable (\r
509 VOID\r
510 )\r
511{\r
512 InitCapsuleUpdateVariable();\r
513 InitCapsuleMaxVariable();\r
514 InitCapsuleLastVariable();\r
515 //\r
516 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"\r
517 // to check status and delete them.\r
518 //\r
519}\r