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