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