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