]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/EsrtDxe/EsrtImpl.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / EsrtDxe / EsrtImpl.c
1 /** @file
2 Esrt management implementation.
3
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "EsrtImpl.h"
10
11 /**
12 Find Esrt Entry stored in ESRT repository.
13
14 @param[in] FwClass Firmware class guid in Esrt entry
15 @param[in] Attribute Esrt from Non FMP or FMP instance
16 @param[out] Entry Esrt entry returned
17
18 @retval EFI_SUCCESS Successfully find an Esrt entry
19 @retval EF_NOT_FOUND No Esrt entry found
20
21 **/
22 EFI_STATUS
23 GetEsrtEntry (
24 IN EFI_GUID *FwClass,
25 IN UINTN Attribute,
26 OUT EFI_SYSTEM_RESOURCE_ENTRY *Entry
27 )
28 {
29 EFI_STATUS Status;
30 CHAR16 *VariableName;
31 EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepository;
32 UINTN RepositorySize;
33 UINTN Index;
34 UINTN EsrtNum;
35
36 EsrtRepository = NULL;
37
38 //
39 // Get Esrt index buffer
40 //
41 if (Attribute == ESRT_FROM_FMP) {
42 VariableName = EFI_ESRT_FMP_VARIABLE_NAME;
43 } else {
44 VariableName = EFI_ESRT_NONFMP_VARIABLE_NAME;
45 }
46
47 Status = GetVariable2 (
48 VariableName,
49 &gEfiCallerIdGuid,
50 (VOID **) &EsrtRepository,
51 &RepositorySize
52 );
53
54 if (EFI_ERROR(Status)) {
55 goto EXIT;
56 }
57
58 if (RepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY) != 0) {
59 DEBUG((EFI_D_ERROR, "Repository Corrupt. Need to rebuild Repository.\n"));
60 Status = EFI_ABORTED;
61 goto EXIT;
62 }
63
64 Status = EFI_NOT_FOUND;
65 EsrtNum = RepositorySize/sizeof(EFI_SYSTEM_RESOURCE_ENTRY);
66 for (Index = 0; Index < EsrtNum; Index++) {
67 if (CompareGuid(FwClass, &EsrtRepository[Index].FwClass)) {
68 CopyMem(Entry, &EsrtRepository[Index], sizeof(EFI_SYSTEM_RESOURCE_ENTRY));
69 Status = EFI_SUCCESS;
70 break;
71 }
72 }
73
74 EXIT:
75 if (EsrtRepository != NULL) {
76 FreePool(EsrtRepository);
77 }
78
79 return Status;
80 }
81
82 /**
83 Insert a new ESRT entry into ESRT Cache repository.
84
85 @param[in] Entry Esrt entry to be set
86 @param[in] Attribute Esrt from Esrt private protocol or FMP instance
87
88 @retval EFI_SUCCESS Successfully set a variable.
89
90 **/
91 EFI_STATUS
92 InsertEsrtEntry(
93 IN EFI_SYSTEM_RESOURCE_ENTRY *Entry,
94 UINTN Attribute
95 )
96 {
97 EFI_STATUS Status;
98 CHAR16 *VariableName;
99 EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepository;
100 UINTN RepositorySize;
101 EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepositoryNew;
102
103 EsrtRepository = NULL;
104 EsrtRepositoryNew = NULL;
105
106 //
107 // Get Esrt index buffer
108 //
109 if (Attribute == ESRT_FROM_FMP) {
110 VariableName = EFI_ESRT_FMP_VARIABLE_NAME;
111 } else {
112 VariableName = EFI_ESRT_NONFMP_VARIABLE_NAME;
113 }
114
115 Status = GetVariable2 (
116 VariableName,
117 &gEfiCallerIdGuid,
118 (VOID **) &EsrtRepository,
119 &RepositorySize
120 );
121
122 if (Status == EFI_NOT_FOUND) {
123 //
124 // If not exist, create new Esrt cache repository
125 //
126 Status = gRT->SetVariable(
127 VariableName,
128 &gEfiCallerIdGuid,
129 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
130 sizeof(EFI_SYSTEM_RESOURCE_ENTRY),
131 Entry
132 );
133 return Status;
134
135 } else if (Status == EFI_SUCCESS) {
136 //
137 // if exist, update Esrt cache repository
138 //
139 if (RepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY) != 0) {
140 DEBUG((EFI_D_ERROR, "Repository Corrupt. Need to rebuild Repository.\n"));
141 //
142 // Repository is corrupt. Clear Repository before insert new entry
143 //
144 Status = gRT->SetVariable(
145 VariableName,
146 &gEfiCallerIdGuid,
147 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
148 0,
149 EsrtRepository
150 );
151 FreePool(EsrtRepository);
152 RepositorySize = 0;
153 EsrtRepository = NULL;
154 }
155
156 //
157 // Check Repository size constraint
158 //
159 if ((Attribute == ESRT_FROM_FMP && RepositorySize >= PcdGet32(PcdMaxFmpEsrtCacheNum) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY))
160 ||(Attribute == ESRT_FROM_NONFMP && RepositorySize >= PcdGet32(PcdMaxNonFmpEsrtCacheNum) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY)) ) {
161 Status = EFI_OUT_OF_RESOURCES;
162 goto EXIT;
163 }
164
165 EsrtRepositoryNew = AllocatePool(RepositorySize + sizeof(EFI_SYSTEM_RESOURCE_ENTRY));
166 if (EsrtRepositoryNew == NULL) {
167 Status = EFI_OUT_OF_RESOURCES;
168 goto EXIT;
169 }
170
171 if (RepositorySize != 0 && EsrtRepository != NULL) {
172 CopyMem(EsrtRepositoryNew, EsrtRepository, RepositorySize);
173 }
174 CopyMem((UINT8 *)EsrtRepositoryNew + RepositorySize, Entry, sizeof(EFI_SYSTEM_RESOURCE_ENTRY));
175
176 Status = gRT->SetVariable(
177 VariableName,
178 &gEfiCallerIdGuid,
179 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
180 RepositorySize + sizeof(EFI_SYSTEM_RESOURCE_ENTRY),
181 EsrtRepositoryNew
182 );
183 }
184
185 EXIT:
186 if (EsrtRepository != NULL) {
187 FreePool(EsrtRepository);
188 }
189
190 if (EsrtRepositoryNew != NULL) {
191 FreePool(EsrtRepositoryNew);
192 }
193
194 return Status;
195 }
196
197 /**
198 Delete ESRT Entry from ESRT repository.
199
200 @param[in] FwClass FwClass of Esrt entry to delete
201 @param[in] Attribute Esrt from Esrt private protocol or FMP instance
202
203 @retval EFI_SUCCESS Insert all entries Successfully
204 @retval EFI_NOT_FOUND ESRT entry with FwClass doesn't exsit
205
206 **/
207 EFI_STATUS
208 DeleteEsrtEntry(
209 IN EFI_GUID *FwClass,
210 IN UINTN Attribute
211 )
212 {
213 EFI_STATUS Status;
214 CHAR16 *VariableName;
215 EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepository;
216 UINTN RepositorySize;
217 UINTN Index;
218 UINTN EsrtNum;
219
220 EsrtRepository = NULL;
221
222 //
223 // Get Esrt index buffer
224 //
225 if (Attribute == ESRT_FROM_FMP) {
226 VariableName = EFI_ESRT_FMP_VARIABLE_NAME;
227 } else {
228 VariableName = EFI_ESRT_NONFMP_VARIABLE_NAME;
229 }
230
231 Status = GetVariable2 (
232 VariableName,
233 &gEfiCallerIdGuid,
234 (VOID **) &EsrtRepository,
235 &RepositorySize
236 );
237
238 if (EFI_ERROR(Status)) {
239 goto EXIT;
240 }
241
242 if ((RepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY)) != 0) {
243 DEBUG((EFI_D_ERROR, "Repository Corrupt. Need to rebuild Repository.\n"));
244 //
245 // Repository is corrupt. Clear Repository before insert new entry
246 //
247 Status = gRT->SetVariable(
248 VariableName,
249 &gEfiCallerIdGuid,
250 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
251 0,
252 EsrtRepository
253 );
254 goto EXIT;
255 }
256
257 Status = EFI_NOT_FOUND;
258 EsrtNum = RepositorySize/sizeof(EFI_SYSTEM_RESOURCE_ENTRY);
259 for (Index = 0; Index < EsrtNum; Index++) {
260 //
261 // Delete Esrt entry if it is found in repository
262 //
263 if (CompareGuid(FwClass, &EsrtRepository[Index].FwClass)) {
264 //
265 // If delete Esrt entry is not at the rail
266 //
267 if (Index < EsrtNum - 1) {
268 CopyMem(&EsrtRepository[Index], &EsrtRepository[Index + 1], (EsrtNum - Index - 1) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY));
269 }
270
271 //
272 // Update New Repository
273 //
274 Status = gRT->SetVariable(
275 VariableName,
276 &gEfiCallerIdGuid,
277 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
278 (EsrtNum - 1) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY),
279 EsrtRepository
280 );
281 break;
282 }
283 }
284
285 EXIT:
286 if (EsrtRepository != NULL) {
287 FreePool(EsrtRepository);
288 }
289
290 return Status;
291
292 }
293
294 /**
295 Update one ESRT entry in ESRT repository
296
297 @param[in] Entry Esrt entry to be set
298 @param[in] Attribute Esrt from Non Esrt or FMP instance
299
300 @retval EFI_SUCCESS Successfully Update a variable.
301 @retval EFI_NOT_FOUND The Esrt enry doesn't exist
302
303 **/
304 EFI_STATUS
305 UpdateEsrtEntry(
306 IN EFI_SYSTEM_RESOURCE_ENTRY *Entry,
307 UINTN Attribute
308 )
309 {
310 EFI_STATUS Status;
311 CHAR16 *VariableName;
312 EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepository;
313 UINTN RepositorySize;
314 UINTN Index;
315 UINTN EsrtNum;
316
317 EsrtRepository = NULL;
318
319 //
320 // Get Esrt index buffer
321 //
322 if (Attribute == ESRT_FROM_FMP) {
323 VariableName = EFI_ESRT_FMP_VARIABLE_NAME;
324 } else {
325 VariableName = EFI_ESRT_NONFMP_VARIABLE_NAME;
326 }
327
328 Status = GetVariable2 (
329 VariableName,
330 &gEfiCallerIdGuid,
331 (VOID **) &EsrtRepository,
332 &RepositorySize
333 );
334
335 if (!EFI_ERROR(Status)) {
336 //
337 // if exist, update Esrt cache repository
338 //
339 if (RepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY) != 0) {
340 DEBUG((EFI_D_ERROR, "Repository Corrupt. Need to rebuild Repository.\n"));
341 //
342 // Repository is corrupt. Clear Repository before insert new entry
343 //
344 Status = gRT->SetVariable(
345 VariableName,
346 &gEfiCallerIdGuid,
347 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
348 0,
349 EsrtRepository
350 );
351 Status = EFI_NOT_FOUND;
352 goto EXIT;
353 }
354
355 Status = EFI_NOT_FOUND;
356 EsrtNum = RepositorySize/sizeof(EFI_SYSTEM_RESOURCE_ENTRY);
357 for (Index = 0; Index < EsrtNum; Index++) {
358 //
359 // Update Esrt entry if it is found in repository
360 //
361 if (CompareGuid(&Entry->FwClass, &EsrtRepository[Index].FwClass)) {
362
363 CopyMem(&EsrtRepository[Index], Entry, sizeof(EFI_SYSTEM_RESOURCE_ENTRY));
364 //
365 // Update New Repository
366 //
367 Status = gRT->SetVariable(
368 VariableName,
369 &gEfiCallerIdGuid,
370 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
371 RepositorySize,
372 EsrtRepository
373 );
374 break;
375 }
376 }
377 }
378
379 EXIT:
380 if (EsrtRepository != NULL) {
381 FreePool(EsrtRepository);
382 }
383
384 return Status;
385 }
386
387 /**
388 Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.
389
390 @param[in] FmpImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR
391
392 @return TRUE It is a system FMP.
393 @return FALSE It is a device FMP.
394 **/
395 BOOLEAN
396 IsSystemFmp (
397 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfo
398 )
399 {
400 GUID *Guid;
401 UINTN Count;
402 UINTN Index;
403
404 Guid = PcdGetPtr(PcdSystemFmpCapsuleImageTypeIdGuid);
405 Count = PcdGetSize(PcdSystemFmpCapsuleImageTypeIdGuid)/sizeof(GUID);
406
407 for (Index = 0; Index < Count; Index++, Guid++) {
408 if (CompareGuid(&FmpImageInfo->ImageTypeId, Guid)) {
409 return TRUE;
410 }
411 }
412
413 return FALSE;
414 }
415
416 /**
417 Init one ESRT entry according to input FmpImageInfo (V1, V2, V3) .
418
419 @param[in, out] EsrtEntry Esrt entry to be Init
420 @param[in] FmpImageInfo FMP image info descriptor
421 @param[in] DescriptorVersion FMP Image info descriptor version
422
423 **/
424 VOID
425 SetEsrtEntryFromFmpInfo (
426 IN OUT EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry,
427 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfo,
428 IN UINT32 DescriptorVersion
429 )
430 {
431 EsrtEntry->FwVersion = FmpImageInfo->Version;
432 EsrtEntry->FwClass = FmpImageInfo->ImageTypeId;
433 if (IsSystemFmp(FmpImageInfo)) {
434 EsrtEntry->FwType = ESRT_FW_TYPE_SYSTEMFIRMWARE;
435 } else {
436 EsrtEntry->FwType = ESRT_FW_TYPE_DEVICEFIRMWARE;
437 }
438 EsrtEntry->LowestSupportedFwVersion = 0;
439 EsrtEntry->CapsuleFlags = 0;
440 EsrtEntry->LastAttemptVersion = 0;
441 EsrtEntry->LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
442
443 if (DescriptorVersion >= 2) {
444 //
445 // LowestSupportedImageVersion only available in FMP V2 or higher
446 //
447 EsrtEntry->LowestSupportedFwVersion = FmpImageInfo->LowestSupportedImageVersion;
448 }
449
450 if (DescriptorVersion >= 3) {
451 //
452 // LastAttemptVersion & LastAttemptStatus only available in FMP V3 or higher
453 //
454 EsrtEntry->LastAttemptVersion = FmpImageInfo->LastAttemptVersion;
455 EsrtEntry->LastAttemptStatus = FmpImageInfo->LastAttemptStatus;
456 }
457
458 //
459 // Set capsule customized flag
460 //
461 if ((FmpImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0
462 && (FmpImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0) {
463 EsrtEntry->CapsuleFlags = PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag);
464 }
465 }