]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
MdeModulePkg/CapsuleLib: Fix runtime issue
[mirror_edk2.git] / MdeModulePkg / Library / DxeCapsuleLibFmp / DxeCapsuleReportLib.c
CommitLineData
d2a16030
JY
1/** @file\r
2 DXE capsule report related function.\r
3\r
9f4048f7 4 Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>\r
d2a16030
JY
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
d2a16030
JY
38/**\r
39 Get current capsule last variable index.\r
40\r
41 @return Current capsule last variable index.\r
42 @retval -1 No current capsule last variable.\r
43**/\r
44INTN\r
45GetCurrentCapsuleLastIndex (\r
46 VOID\r
47 )\r
48{\r
49 UINTN Size;\r
50 CHAR16 CapsuleLastStr[sizeof("Capsule####")];\r
51 EFI_STATUS Status;\r
52 UINT16 CurrentIndex;\r
53\r
54 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
55 Status = gRT->GetVariable(\r
56 L"CapsuleLast",\r
57 &gEfiCapsuleReportGuid,\r
58 NULL,\r
59 &Size,\r
60 CapsuleLastStr\r
61 );\r
62 if (EFI_ERROR(Status)) {\r
63 return -1;\r
64 }\r
65 CurrentIndex = (UINT16)StrHexToUintn(&CapsuleLastStr[sizeof("Capsule") - 1]);\r
66 return CurrentIndex;\r
67}\r
68\r
d2a16030
JY
69/**\r
70 Get a new capsule status variable index.\r
71\r
72 @return A new capsule status variable index.\r
777034ce 73 @retval 0 No new capsule status variable index. Rolling over.\r
d2a16030
JY
74**/\r
75INTN\r
76GetNewCapsuleResultIndex (\r
77 VOID\r
78 )\r
79{\r
80 INTN CurrentIndex;\r
81\r
82 CurrentIndex = GetCurrentCapsuleLastIndex();\r
83 if (CurrentIndex >= PcdGet16(PcdCapsuleMax)) {\r
777034ce
JY
84 DEBUG((DEBUG_INFO, " CapsuleResult variable Rolling Over!\n"));\r
85 return 0;\r
d2a16030
JY
86 }\r
87\r
88 return CurrentIndex + 1;\r
89}\r
90\r
91/**\r
92 Write a new capsule status variable.\r
93\r
94 @param[in] CapsuleResult The capsule status variable\r
95 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes\r
96\r
97 @retval EFI_SUCCESS The capsule status variable is recorded.\r
98 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
99**/\r
100EFI_STATUS\r
101WriteNewCapsuleResultVariable (\r
102 IN VOID *CapsuleResult,\r
103 IN UINTN CapsuleResultSize\r
104 )\r
105{\r
106 INTN CapsuleResultIndex;\r
107 CHAR16 CapsuleResultStr[sizeof("Capsule####")];\r
108 UINTN Size;\r
109 EFI_STATUS Status;\r
110\r
111 CapsuleResultIndex = GetNewCapsuleResultIndex();\r
112 DEBUG((DEBUG_INFO, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex));\r
777034ce 113\r
d2a16030
JY
114 UnicodeSPrint(\r
115 CapsuleResultStr,\r
116 sizeof(CapsuleResultStr),\r
117 L"Capsule%04x",\r
118 CapsuleResultIndex\r
119 );\r
120\r
121 Status = gRT->SetVariable(\r
122 CapsuleResultStr,\r
123 &gEfiCapsuleReportGuid,\r
124 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
125 CapsuleResultSize,\r
126 CapsuleResult\r
127 );\r
128 if (!EFI_ERROR(Status)) {\r
129 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
130 DEBUG((DEBUG_INFO, "Set CapsuleLast - %s\n", CapsuleResultStr));\r
131 Status = gRT->SetVariable(\r
132 L"CapsuleLast",\r
133 &gEfiCapsuleReportGuid,\r
134 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
135 Size,\r
136 CapsuleResultStr\r
137 );\r
138 }\r
139\r
140 return Status;\r
141}\r
142\r
143/**\r
144 Record capsule status variable and to local cache.\r
145\r
146 @param[in] CapsuleHeader The capsule image header\r
147 @param[in] CapsuleStatus The capsule process stauts\r
148\r
149 @retval EFI_SUCCESS The capsule status variable is recorded.\r
150 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
151**/\r
152EFI_STATUS\r
153RecordCapsuleStatusVariable (\r
154 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
155 IN EFI_STATUS CapsuleStatus\r
156 )\r
157{\r
158 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable;\r
159 EFI_STATUS Status;\r
160\r
161 CapsuleResultVariable.VariableTotalSize = sizeof(CapsuleResultVariable);\r
d8487a34 162 CapsuleResultVariable.Reserved = 0;\r
d2a16030
JY
163 CopyGuid (&CapsuleResultVariable.CapsuleGuid, &CapsuleHeader->CapsuleGuid);\r
164 ZeroMem(&CapsuleResultVariable.CapsuleProcessed, sizeof(CapsuleResultVariable.CapsuleProcessed));\r
165 gRT->GetTime(&CapsuleResultVariable.CapsuleProcessed, NULL);\r
166 CapsuleResultVariable.CapsuleStatus = CapsuleStatus;\r
167\r
3f31ea1b 168 Status = EFI_SUCCESS;\r
d2a16030
JY
169 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
170 Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable));\r
171 }\r
172 return Status;\r
173}\r
174\r
175/**\r
176 Record FMP capsule status variable and to local cache.\r
177\r
178 @param[in] CapsuleHeader The capsule image header\r
179 @param[in] CapsuleStatus The capsule process stauts\r
180 @param[in] PayloadIndex FMP payload index\r
181 @param[in] ImageHeader FMP image header\r
8f6db161 182 @param[in] FmpDevicePath DevicePath associated with the FMP producer\r
d2a16030
JY
183\r
184 @retval EFI_SUCCESS The capsule status variable is recorded.\r
185 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
186**/\r
187EFI_STATUS\r
188RecordFmpCapsuleStatusVariable (\r
189 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
190 IN EFI_STATUS CapsuleStatus,\r
191 IN UINTN PayloadIndex,\r
8f6db161
JY
192 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,\r
193 IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL\r
d2a16030
JY
194 )\r
195{\r
d2a16030
JY
196 EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResultVariableHeader;\r
197 EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultVariableFmp;\r
198 EFI_STATUS Status;\r
b857bf48 199 UINT8 *CapsuleResultVariable;\r
8f6db161
JY
200 UINTN CapsuleResultVariableSize;\r
201 CHAR16 *DevicePathStr;\r
202 UINTN DevicePathStrSize;\r
d2a16030 203\r
8f6db161
JY
204 DevicePathStr = NULL;\r
205 if (FmpDevicePath != NULL) {\r
206 DevicePathStr = ConvertDevicePathToText (FmpDevicePath, FALSE, FALSE);\r
207 }\r
208 if (DevicePathStr != NULL) {\r
209 DevicePathStrSize = StrSize(DevicePathStr);\r
210 } else {\r
211 DevicePathStrSize = sizeof(CHAR16);\r
212 }\r
d8487a34 213 //\r
8f6db161 214 // Allocate zero CHAR16 for CapsuleFileName.\r
d8487a34 215 //\r
8f6db161 216 CapsuleResultVariableSize = sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + sizeof(CHAR16) + DevicePathStrSize;\r
d8487a34 217 CapsuleResultVariable = AllocateZeroPool (CapsuleResultVariableSize);\r
b857bf48
DB
218 if (CapsuleResultVariable == NULL) {\r
219 return EFI_OUT_OF_RESOURCES;\r
220 }\r
221 CapsuleResultVariableHeader = (VOID *)CapsuleResultVariable;\r
8f6db161 222 CapsuleResultVariableHeader->VariableTotalSize = (UINT32)CapsuleResultVariableSize;\r
d8487a34 223 CapsuleResultVariableHeader->Reserved = 0;\r
d2a16030
JY
224 CopyGuid(&CapsuleResultVariableHeader->CapsuleGuid, &CapsuleHeader->CapsuleGuid);\r
225 ZeroMem(&CapsuleResultVariableHeader->CapsuleProcessed, sizeof(CapsuleResultVariableHeader->CapsuleProcessed));\r
226 gRT->GetTime(&CapsuleResultVariableHeader->CapsuleProcessed, NULL);\r
227 CapsuleResultVariableHeader->CapsuleStatus = CapsuleStatus;\r
228\r
b857bf48 229 CapsuleResultVariableFmp = (VOID *)(CapsuleResultVariable + sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER));\r
d2a16030
JY
230 CapsuleResultVariableFmp->Version = 0x1;\r
231 CapsuleResultVariableFmp->PayloadIndex = (UINT8)PayloadIndex;\r
232 CapsuleResultVariableFmp->UpdateImageIndex = ImageHeader->UpdateImageIndex;\r
233 CopyGuid (&CapsuleResultVariableFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId);\r
8f6db161
JY
234 if (DevicePathStr != NULL) {\r
235 CopyMem ((UINT8 *)CapsuleResultVariableFmp + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + sizeof(CHAR16), DevicePathStr, DevicePathStrSize);\r
236 FreePool (DevicePathStr);\r
237 DevicePathStr = NULL;\r
238 }\r
d2a16030 239\r
3f31ea1b 240 Status = EFI_SUCCESS;\r
d2a16030 241 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
b857bf48 242 Status = WriteNewCapsuleResultVariable(CapsuleResultVariable, CapsuleResultVariableSize);\r
d2a16030 243 }\r
b857bf48 244 FreePool (CapsuleResultVariable);\r
d2a16030
JY
245 return Status;\r
246}\r
247\r
248/**\r
249 Initialize CapsuleMax variables.\r
250**/\r
251VOID\r
252InitCapsuleMaxVariable (\r
253 VOID\r
254 )\r
255{\r
256 EFI_STATUS Status;\r
257 UINTN Size;\r
258 CHAR16 CapsuleMaxStr[sizeof("Capsule####")];\r
259 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
260\r
261 UnicodeSPrint(\r
262 CapsuleMaxStr,\r
263 sizeof(CapsuleMaxStr),\r
264 L"Capsule%04x",\r
265 PcdGet16(PcdCapsuleMax)\r
266 );\r
267\r
268 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
269 Status = gRT->SetVariable(\r
270 L"CapsuleMax",\r
271 &gEfiCapsuleReportGuid,\r
272 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
273 Size,\r
274 CapsuleMaxStr\r
275 );\r
276 if (!EFI_ERROR(Status)) {\r
277 // Lock it per UEFI spec.\r
278 Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);\r
279 if (!EFI_ERROR(Status)) {\r
280 Status = VariableLock->RequestToLock(VariableLock, L"CapsuleMax", &gEfiCapsuleReportGuid);\r
281 ASSERT_EFI_ERROR(Status);\r
282 }\r
283 }\r
284}\r
285\r
286/**\r
287 Initialize CapsuleLast variables.\r
288**/\r
289VOID\r
290InitCapsuleLastVariable (\r
291 VOID\r
292 )\r
293{\r
294 EFI_STATUS Status;\r
295 EFI_BOOT_MODE BootMode;\r
296 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
297 VOID *CapsuleResult;\r
298 UINTN Size;\r
299 CHAR16 CapsuleLastStr[sizeof("Capsule####")];\r
300\r
301 BootMode = GetBootModeHob();\r
302 if (BootMode == BOOT_ON_FLASH_UPDATE) {\r
303 Status = gRT->SetVariable(\r
304 L"CapsuleLast",\r
305 &gEfiCapsuleReportGuid,\r
306 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
307 0,\r
308 NULL\r
309 );\r
310 // Do not lock it because it will be updated later.\r
311 } else {\r
312 //\r
313 // Check if OS/APP cleared L"Capsule####"\r
314 //\r
315 ZeroMem(CapsuleLastStr, sizeof(CapsuleLastStr));\r
316 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
317 Status = gRT->GetVariable(\r
318 L"CapsuleLast",\r
319 &gEfiCapsuleReportGuid,\r
320 NULL,\r
321 &Size,\r
322 CapsuleLastStr\r
323 );\r
324 if (!EFI_ERROR(Status)) {\r
325 //\r
326 // L"CapsuleLast" is got, check if data is there.\r
327 //\r
328 Status = GetVariable2 (\r
329 CapsuleLastStr,\r
330 &gEfiCapsuleReportGuid,\r
331 (VOID **) &CapsuleResult,\r
332 NULL\r
333 );\r
334 if (EFI_ERROR(Status)) {\r
335 //\r
336 // If no data, delete L"CapsuleLast"\r
337 //\r
338 Status = gRT->SetVariable(\r
339 L"CapsuleLast",\r
340 &gEfiCapsuleReportGuid,\r
341 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
342 0,\r
343 NULL\r
344 );\r
dd4eaf15
HW
345 } else {\r
346 if (CapsuleResult != NULL) {\r
347 FreePool (CapsuleResult);\r
348 }\r
d2a16030
JY
349 }\r
350 }\r
351\r
352 // Lock it in normal boot path per UEFI spec.\r
353 Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);\r
354 if (!EFI_ERROR(Status)) {\r
355 Status = VariableLock->RequestToLock(VariableLock, L"CapsuleLast", &gEfiCapsuleReportGuid);\r
356 ASSERT_EFI_ERROR(Status);\r
357 }\r
358 }\r
359}\r
360\r
361/**\r
362 Initialize capsule update variables.\r
363**/\r
364VOID\r
365InitCapsuleUpdateVariable (\r
366 VOID\r
367 )\r
368{\r
369 EFI_STATUS Status;\r
370 UINTN Index;\r
371 CHAR16 CapsuleVarName[30];\r
372 CHAR16 *TempVarName;\r
373\r
374 //\r
375 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...\r
376 // as early as possible which will avoid the next time boot after the capsule update\r
377 // will still into the capsule loop\r
378 //\r
379 StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), EFI_CAPSULE_VARIABLE_NAME);\r
380 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
381 Index = 0;\r
382 while (TRUE) {\r
383 if (Index > 0) {\r
9f4048f7
HW
384 UnicodeValueToStringS (\r
385 TempVarName,\r
386 sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),\r
387 0,\r
388 Index,\r
389 0\r
390 );\r
d2a16030
JY
391 }\r
392 Status = gRT->SetVariable (\r
393 CapsuleVarName,\r
394 &gEfiCapsuleVendorGuid,\r
395 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
396 0,\r
397 (VOID *)NULL\r
398 );\r
399 if (EFI_ERROR (Status)) {\r
400 //\r
401 // There is no capsule variables, quit\r
402 //\r
403 break;\r
404 }\r
405 Index++;\r
406 }\r
407}\r
408\r
409/**\r
410 Initialize capsule related variables.\r
411**/\r
412VOID\r
413InitCapsuleVariable (\r
414 VOID\r
415 )\r
416{\r
417 InitCapsuleUpdateVariable();\r
418 InitCapsuleMaxVariable();\r
419 InitCapsuleLastVariable();\r
420 //\r
421 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"\r
422 // to check status and delete them.\r
423 //\r
424}\r