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