]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
MdeModulePkg: Add Capsule On Disk APIs into CapsuleLib.
[mirror_edk2.git] / MdeModulePkg / Library / DxeCapsuleLibFmp / DxeCapsuleReportLib.c
1 /** @file
2 DXE capsule report related function.
3
4 Copyright (c) 2016 - 2019, 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 <Protocol/VariableLock.h>
12 #include <Guid/CapsuleReport.h>
13 #include <Guid/FmpCapsule.h>
14 #include <Guid/CapsuleVendor.h>
15
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Library/UefiRuntimeServicesTableLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/UefiLib.h>
23 #include <Library/PcdLib.h>
24 #include <Library/HobLib.h>
25 #include <Library/PrintLib.h>
26 #include <Library/ReportStatusCodeLib.h>
27 #include <Library/DevicePathLib.h>
28 #include <Library/CapsuleLib.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 Write a new capsule status variable.
99
100 @param[in] CapsuleResult The capsule status variable
101 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
102
103 @retval EFI_SUCCESS The capsule status variable is recorded.
104 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
105 **/
106 EFI_STATUS
107 WriteNewCapsuleResultVariable (
108 IN VOID *CapsuleResult,
109 IN UINTN CapsuleResultSize
110 )
111 {
112 INTN CapsuleResultIndex;
113 CHAR16 CapsuleResultStr[sizeof("Capsule####")];
114 UINTN Size;
115 EFI_STATUS Status;
116
117 CapsuleResultIndex = GetNewCapsuleResultIndex();
118 DEBUG((DEBUG_INFO, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex));
119
120 UnicodeSPrint(
121 CapsuleResultStr,
122 sizeof(CapsuleResultStr),
123 L"Capsule%04x",
124 CapsuleResultIndex
125 );
126
127 Status = gRT->SetVariable(
128 CapsuleResultStr,
129 &gEfiCapsuleReportGuid,
130 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
131 CapsuleResultSize,
132 CapsuleResult
133 );
134 if (!EFI_ERROR(Status)) {
135 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator
136 DEBUG((DEBUG_INFO, "Set CapsuleLast - %s\n", CapsuleResultStr));
137 Status = gRT->SetVariable(
138 L"CapsuleLast",
139 &gEfiCapsuleReportGuid,
140 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
141 Size,
142 CapsuleResultStr
143 );
144 }
145
146 return Status;
147 }
148
149 /**
150 Record capsule status variable and to local cache.
151
152 @param[in] CapsuleHeader The capsule image header
153 @param[in] CapsuleStatus The capsule process stauts
154
155 @retval EFI_SUCCESS The capsule status variable is recorded.
156 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
157 **/
158 EFI_STATUS
159 RecordCapsuleStatusVariable (
160 IN EFI_CAPSULE_HEADER *CapsuleHeader,
161 IN EFI_STATUS CapsuleStatus
162 )
163 {
164 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable;
165 EFI_STATUS Status;
166
167 CapsuleResultVariable.VariableTotalSize = sizeof(CapsuleResultVariable);
168 CapsuleResultVariable.Reserved = 0;
169 CopyGuid (&CapsuleResultVariable.CapsuleGuid, &CapsuleHeader->CapsuleGuid);
170 ZeroMem(&CapsuleResultVariable.CapsuleProcessed, sizeof(CapsuleResultVariable.CapsuleProcessed));
171 gRT->GetTime(&CapsuleResultVariable.CapsuleProcessed, NULL);
172 CapsuleResultVariable.CapsuleStatus = CapsuleStatus;
173
174 Status = EFI_SUCCESS;
175 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
176 Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable));
177 }
178 return Status;
179 }
180
181 /**
182 Record FMP capsule status variable and to local cache.
183
184 @param[in] CapsuleHeader The capsule image header
185 @param[in] CapsuleStatus The capsule process stauts
186 @param[in] PayloadIndex FMP payload index
187 @param[in] ImageHeader FMP image header
188 @param[in] FmpDevicePath DevicePath associated with the FMP producer
189 @param[in] CapFileName Capsule file name
190
191 @retval EFI_SUCCESS The capsule status variable is recorded.
192 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
193 **/
194 EFI_STATUS
195 RecordFmpCapsuleStatusVariable (
196 IN EFI_CAPSULE_HEADER *CapsuleHeader,
197 IN EFI_STATUS CapsuleStatus,
198 IN UINTN PayloadIndex,
199 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
200 IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath, OPTIONAL
201 IN CHAR16 *CapFileName OPTIONAL
202 )
203 {
204 EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResultVariableHeader;
205 EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultVariableFmp;
206 EFI_STATUS Status;
207 UINT8 *CapsuleResultVariable;
208 UINTN CapsuleResultVariableSize;
209 CHAR16 *DevicePathStr;
210 UINTN DevicePathStrSize;
211 UINTN CapFileNameSize;
212
213 DevicePathStr = NULL;
214 CapFileNameSize = sizeof(CHAR16);
215
216 if (FmpDevicePath != NULL) {
217 DevicePathStr = ConvertDevicePathToText (FmpDevicePath, FALSE, FALSE);
218 }
219 if (DevicePathStr != NULL) {
220 DevicePathStrSize = StrSize(DevicePathStr);
221 } else {
222 DevicePathStrSize = sizeof(CHAR16);
223 }
224
225 if (CapFileName != NULL) {
226 CapFileNameSize = StrSize(CapFileName);
227 }
228
229 //
230 // Allocate room for CapsuleFileName.
231 //
232 CapsuleResultVariableSize = sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize + DevicePathStrSize;
233
234 CapsuleResultVariable = AllocateZeroPool (CapsuleResultVariableSize);
235 if (CapsuleResultVariable == NULL) {
236 return EFI_OUT_OF_RESOURCES;
237 }
238 CapsuleResultVariableHeader = (VOID *)CapsuleResultVariable;
239 CapsuleResultVariableHeader->VariableTotalSize = (UINT32)CapsuleResultVariableSize;
240 CapsuleResultVariableHeader->Reserved = 0;
241 CopyGuid(&CapsuleResultVariableHeader->CapsuleGuid, &CapsuleHeader->CapsuleGuid);
242 ZeroMem(&CapsuleResultVariableHeader->CapsuleProcessed, sizeof(CapsuleResultVariableHeader->CapsuleProcessed));
243 gRT->GetTime(&CapsuleResultVariableHeader->CapsuleProcessed, NULL);
244 CapsuleResultVariableHeader->CapsuleStatus = CapsuleStatus;
245
246 CapsuleResultVariableFmp = (VOID *)(CapsuleResultVariable + sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER));
247 CapsuleResultVariableFmp->Version = 0x1;
248 CapsuleResultVariableFmp->PayloadIndex = (UINT8)PayloadIndex;
249 CapsuleResultVariableFmp->UpdateImageIndex = ImageHeader->UpdateImageIndex;
250 CopyGuid (&CapsuleResultVariableFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId);
251
252 if (CapFileName != NULL) {
253 CopyMem((UINT8 *)CapsuleResultVariableFmp + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP), CapFileName, CapFileNameSize);
254 }
255
256 if (DevicePathStr != NULL) {
257 CopyMem ((UINT8 *)CapsuleResultVariableFmp + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize, DevicePathStr, DevicePathStrSize);
258 FreePool (DevicePathStr);
259 DevicePathStr = NULL;
260 }
261
262 Status = EFI_SUCCESS;
263 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
264 Status = WriteNewCapsuleResultVariable(CapsuleResultVariable, CapsuleResultVariableSize);
265 }
266 FreePool (CapsuleResultVariable);
267 return Status;
268 }
269
270 /**
271 Initialize CapsuleMax variables.
272 **/
273 VOID
274 InitCapsuleMaxVariable (
275 VOID
276 )
277 {
278 EFI_STATUS Status;
279 UINTN Size;
280 CHAR16 CapsuleMaxStr[sizeof("Capsule####")];
281 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
282
283 UnicodeSPrint(
284 CapsuleMaxStr,
285 sizeof(CapsuleMaxStr),
286 L"Capsule%04x",
287 PcdGet16(PcdCapsuleMax)
288 );
289
290 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator
291 Status = gRT->SetVariable(
292 L"CapsuleMax",
293 &gEfiCapsuleReportGuid,
294 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
295 Size,
296 CapsuleMaxStr
297 );
298 if (!EFI_ERROR(Status)) {
299 // Lock it per UEFI spec.
300 Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);
301 if (!EFI_ERROR(Status)) {
302 Status = VariableLock->RequestToLock(VariableLock, L"CapsuleMax", &gEfiCapsuleReportGuid);
303 ASSERT_EFI_ERROR(Status);
304 }
305 }
306 }
307
308 /**
309 Initialize CapsuleLast variables.
310 **/
311 VOID
312 InitCapsuleLastVariable (
313 VOID
314 )
315 {
316 EFI_STATUS Status;
317 EFI_BOOT_MODE BootMode;
318 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
319 VOID *CapsuleResult;
320 UINTN Size;
321 CHAR16 CapsuleLastStr[sizeof("Capsule####")];
322
323 BootMode = GetBootModeHob();
324 if (BootMode == BOOT_ON_FLASH_UPDATE) {
325 Status = gRT->SetVariable(
326 L"CapsuleLast",
327 &gEfiCapsuleReportGuid,
328 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
329 0,
330 NULL
331 );
332 // Do not lock it because it will be updated later.
333 } else {
334 //
335 // Check if OS/APP cleared L"Capsule####"
336 //
337 ZeroMem(CapsuleLastStr, sizeof(CapsuleLastStr));
338 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator
339 Status = gRT->GetVariable(
340 L"CapsuleLast",
341 &gEfiCapsuleReportGuid,
342 NULL,
343 &Size,
344 CapsuleLastStr
345 );
346 if (!EFI_ERROR(Status)) {
347 //
348 // L"CapsuleLast" is got, check if data is there.
349 //
350 Status = GetVariable2 (
351 CapsuleLastStr,
352 &gEfiCapsuleReportGuid,
353 (VOID **) &CapsuleResult,
354 NULL
355 );
356 if (EFI_ERROR(Status)) {
357 //
358 // If no data, delete L"CapsuleLast"
359 //
360 Status = gRT->SetVariable(
361 L"CapsuleLast",
362 &gEfiCapsuleReportGuid,
363 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
364 0,
365 NULL
366 );
367 } else {
368 if (CapsuleResult != NULL) {
369 FreePool (CapsuleResult);
370 }
371 }
372 }
373
374 // Lock it in normal boot path per UEFI spec.
375 Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);
376 if (!EFI_ERROR(Status)) {
377 Status = VariableLock->RequestToLock(VariableLock, L"CapsuleLast", &gEfiCapsuleReportGuid);
378 ASSERT_EFI_ERROR(Status);
379 }
380 }
381 }
382
383 /**
384 Initialize capsule update variables.
385 **/
386 VOID
387 InitCapsuleUpdateVariable (
388 VOID
389 )
390 {
391 EFI_STATUS Status;
392 UINTN Index;
393 CHAR16 CapsuleVarName[30];
394 CHAR16 *TempVarName;
395
396 //
397 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
398 // as early as possible which will avoid the next time boot after the capsule update
399 // will still into the capsule loop
400 //
401 StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), EFI_CAPSULE_VARIABLE_NAME);
402 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
403 Index = 0;
404 while (TRUE) {
405 if (Index > 0) {
406 UnicodeValueToStringS (
407 TempVarName,
408 sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),
409 0,
410 Index,
411 0
412 );
413 }
414 Status = gRT->SetVariable (
415 CapsuleVarName,
416 &gEfiCapsuleVendorGuid,
417 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
418 0,
419 (VOID *)NULL
420 );
421 if (EFI_ERROR (Status)) {
422 //
423 // There is no capsule variables, quit
424 //
425 break;
426 }
427 Index++;
428 }
429 }
430
431 /**
432 Initialize capsule relocation info variable.
433 **/
434 VOID
435 InitCapsuleRelocationInfo (
436 VOID
437 )
438 {
439 EFI_STATUS Status;
440 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
441
442 CoDClearCapsuleRelocationInfo();
443
444 //
445 // Unlock Capsule On Disk relocation Info variable only when Capsule On Disk flag is enabled
446 //
447 if (!CoDCheckCapsuleOnDiskFlag()) {
448 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
449 if (!EFI_ERROR (Status)) {
450 Status = VariableLock->RequestToLock (VariableLock, COD_RELOCATION_INFO_VAR_NAME, &gEfiCapsuleVendorGuid);
451 ASSERT_EFI_ERROR (Status);
452 }
453 }
454 }
455
456 /**
457 Initialize capsule related variables.
458 **/
459 VOID
460 InitCapsuleVariable (
461 VOID
462 )
463 {
464 InitCapsuleUpdateVariable();
465 InitCapsuleMaxVariable();
466 InitCapsuleLastVariable();
467 InitCapsuleRelocationInfo();
468
469 //
470 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
471 // to check status and delete them.
472 //
473 }