VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdeModulePkg/Universal/EsrtDxe/EsrtDxe.c@ 99404

Last change on this file since 99404 was 99404, checked in by vboxsync, 23 months ago

Devices/EFI/FirmwareNew: Update to edk2-stable202302 and make it build, bugref:4643

  • Property svn:eol-style set to native
File size: 17.8 KB
Line 
1/** @file
2 Esrt management module.
3
4Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5SPDX-License-Identifier: BSD-2-Clause-Patent
6
7**/
8#include "EsrtImpl.h"
9
10//
11// Module globals.
12//
13
14ESRT_PRIVATE_DATA mPrivate;
15
16ESRT_MANAGEMENT_PROTOCOL mEsrtManagementProtocolTemplate = {
17 EsrtDxeGetEsrtEntry,
18 EsrtDxeUpdateEsrtEntry,
19 EsrtDxeRegisterEsrtEntry,
20 EsrtDxeUnRegisterEsrtEntry,
21 EsrtDxeSyncFmp,
22 EsrtDxeLockEsrtRepository
23};
24
25/**
26 Get ESRT entry from ESRT Cache by FwClass Guid
27
28 @param[in] FwClass FwClass of Esrt entry to get
29 @param[in, out] Entry Esrt entry returned
30
31 @retval EFI_SUCCESS The variable saving this Esrt Entry exists.
32 @retval EF_NOT_FOUND No correct variable found.
33 @retval EFI_WRITE_PROTECTED ESRT Cache repository is locked
34
35**/
36EFI_STATUS
37EFIAPI
38EsrtDxeGetEsrtEntry (
39 IN EFI_GUID *FwClass,
40 IN OUT EFI_SYSTEM_RESOURCE_ENTRY *Entry
41 )
42{
43 EFI_STATUS Status;
44
45 if ((FwClass == NULL) || (Entry == NULL)) {
46 return EFI_INVALID_PARAMETER;
47 }
48
49 Status = EfiAcquireLockOrFail (&mPrivate.NonFmpLock);
50 if (EFI_ERROR (Status)) {
51 return Status;
52 }
53
54 //
55 // Find in Non-FMP Cached Esrt Repository
56 //
57 Status = GetEsrtEntry (
58 FwClass,
59 ESRT_FROM_NONFMP,
60 Entry
61 );
62
63 EfiReleaseLock (&mPrivate.NonFmpLock);
64
65 if (EFI_ERROR (Status)) {
66 Status = EfiAcquireLockOrFail (&mPrivate.FmpLock);
67 if (EFI_ERROR (Status)) {
68 return Status;
69 }
70
71 //
72 // Find in FMP Cached Esrt NV Variable
73 //
74 Status = GetEsrtEntry (
75 FwClass,
76 ESRT_FROM_FMP,
77 Entry
78 );
79
80 EfiReleaseLock (&mPrivate.FmpLock);
81 }
82
83 return Status;
84}
85
86/**
87 Update one ESRT entry in ESRT Cache.
88
89 @param[in] Entry Esrt entry to be updated
90
91 @retval EFI_SUCCESS Successfully update an ESRT entry in cache.
92 @retval EFI_INVALID_PARAMETER Entry does't exist in ESRT Cache
93 @retval EFI_WRITE_PROTECTED ESRT Cache repositoy is locked
94
95**/
96EFI_STATUS
97EFIAPI
98EsrtDxeUpdateEsrtEntry (
99 IN EFI_SYSTEM_RESOURCE_ENTRY *Entry
100 )
101{
102 EFI_STATUS Status;
103
104 if (Entry == NULL) {
105 return EFI_INVALID_PARAMETER;
106 }
107
108 Status = EfiAcquireLockOrFail (&mPrivate.FmpLock);
109 if (EFI_ERROR (Status)) {
110 return Status;
111 }
112
113 Status = UpdateEsrtEntry (Entry, ESRT_FROM_FMP);
114
115 if (!EFI_ERROR (Status)) {
116 EfiReleaseLock (&mPrivate.FmpLock);
117 return Status;
118 }
119
120 EfiReleaseLock (&mPrivate.FmpLock);
121
122 Status = EfiAcquireLockOrFail (&mPrivate.NonFmpLock);
123 if (EFI_ERROR (Status)) {
124 return Status;
125 }
126
127 Status = UpdateEsrtEntry (Entry, ESRT_FROM_NONFMP);
128
129 EfiReleaseLock (&mPrivate.NonFmpLock);
130
131 return Status;
132}
133
134/**
135 Non-FMP instance to unregister Esrt Entry from ESRT Cache.
136
137 @param[in] FwClass FwClass of Esrt entry to Unregister
138
139 @retval EFI_SUCCESS Insert all entries Successfully
140 @retval EFI_NOT_FOUND Entry of FwClass does not exsit
141
142**/
143EFI_STATUS
144EFIAPI
145EsrtDxeUnRegisterEsrtEntry (
146 IN EFI_GUID *FwClass
147 )
148{
149 EFI_STATUS Status;
150
151 if (FwClass == NULL) {
152 return EFI_INVALID_PARAMETER;
153 }
154
155 Status = EfiAcquireLockOrFail (&mPrivate.NonFmpLock);
156 if (EFI_ERROR (Status)) {
157 return Status;
158 }
159
160 Status = DeleteEsrtEntry (FwClass, ESRT_FROM_NONFMP);
161
162 EfiReleaseLock (&mPrivate.NonFmpLock);
163
164 return Status;
165}
166
167/**
168 Non-FMP instance to register one ESRT entry into ESRT Cache.
169
170 @param[in] Entry Esrt entry to be set
171
172 @retval EFI_SUCCESS Successfully set a variable.
173 @retval EFI_INVALID_PARAMETER ESRT Entry is already exist
174 @retval EFI_OUT_OF_RESOURCES Non-FMP ESRT repository is full
175
176**/
177EFI_STATUS
178EFIAPI
179EsrtDxeRegisterEsrtEntry (
180 IN EFI_SYSTEM_RESOURCE_ENTRY *Entry
181 )
182{
183 EFI_STATUS Status;
184 EFI_SYSTEM_RESOURCE_ENTRY EsrtEntryTmp;
185
186 if (Entry == NULL) {
187 return EFI_INVALID_PARAMETER;
188 }
189
190 Status = EfiAcquireLockOrFail (&mPrivate.NonFmpLock);
191 if (EFI_ERROR (Status)) {
192 return Status;
193 }
194
195 Status = GetEsrtEntry (
196 &Entry->FwClass,
197 ESRT_FROM_NONFMP,
198 &EsrtEntryTmp
199 );
200
201 if (Status == EFI_NOT_FOUND) {
202 Status = InsertEsrtEntry (Entry, ESRT_FROM_NONFMP);
203 }
204
205 EfiReleaseLock (&mPrivate.NonFmpLock);
206
207 return Status;
208}
209
210/**
211 This function syn up Cached ESRT with data from FMP instances
212 Function should be called after Connect All in order to locate all FMP protocols
213 installed.
214
215 @retval EFI_SUCCESS Successfully sync cache repository from FMP instances
216 @retval EFI_NOT_FOUND No FMP Instance are found
217 @retval EFI_OUT_OF_RESOURCES Resource allocaton fail
218
219**/
220EFI_STATUS
221EFIAPI
222EsrtDxeSyncFmp (
223 VOID
224 )
225{
226 EFI_STATUS Status;
227 UINTN Index1;
228 UINTN Index2;
229 UINTN Index3;
230 EFI_HANDLE *HandleBuffer;
231 EFI_FIRMWARE_MANAGEMENT_PROTOCOL **FmpBuf;
232 UINTN NumberOfHandles;
233 UINTN *DescriptorSizeBuf;
234 EFI_FIRMWARE_IMAGE_DESCRIPTOR **FmpImageInfoBuf;
235 EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;
236 UINT8 *FmpImageInfoCountBuf;
237 UINT32 *FmpImageInfoDescriptorVerBuf;
238 UINTN ImageInfoSize;
239 UINT32 PackageVersion;
240 CHAR16 *PackageVersionName;
241 EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepositoryNew;
242 UINTN EntryNumNew;
243
244 NumberOfHandles = 0;
245 EntryNumNew = 0;
246 FmpBuf = NULL;
247 HandleBuffer = NULL;
248 FmpImageInfoBuf = NULL;
249 FmpImageInfoCountBuf = NULL;
250 PackageVersionName = NULL;
251 DescriptorSizeBuf = NULL;
252 FmpImageInfoDescriptorVerBuf = NULL;
253 EsrtRepositoryNew = NULL;
254
255 //
256 // Get image information from all FMP protocol
257 //
258 Status = gBS->LocateHandleBuffer (
259 ByProtocol,
260 &gEfiFirmwareManagementProtocolGuid,
261 NULL,
262 &NumberOfHandles,
263 &HandleBuffer
264 );
265
266 if (Status == EFI_NOT_FOUND) {
267 EntryNumNew = 0;
268 goto UPDATE_REPOSITORY;
269 } else if (EFI_ERROR (Status)) {
270 goto END;
271 }
272
273 //
274 // Allocate buffer to hold new FMP ESRT Cache repository
275 //
276 EsrtRepositoryNew = AllocateZeroPool (PcdGet32 (PcdMaxFmpEsrtCacheNum) * sizeof (EFI_SYSTEM_RESOURCE_ENTRY));
277 if (EsrtRepositoryNew == NULL) {
278 Status = EFI_OUT_OF_RESOURCES;
279 goto END;
280 }
281
282 FmpBuf = AllocatePool (sizeof (EFI_FIRMWARE_MANAGEMENT_PROTOCOL *) * NumberOfHandles);
283 if (FmpBuf == NULL) {
284 Status = EFI_OUT_OF_RESOURCES;
285 goto END;
286 }
287
288 FmpImageInfoBuf = AllocateZeroPool (sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR *) * NumberOfHandles);
289 if (FmpImageInfoBuf == NULL) {
290 Status = EFI_OUT_OF_RESOURCES;
291 goto END;
292 }
293
294 FmpImageInfoCountBuf = AllocateZeroPool (sizeof (UINT8) * NumberOfHandles);
295 if (FmpImageInfoCountBuf == NULL) {
296 Status = EFI_OUT_OF_RESOURCES;
297 goto END;
298 }
299
300 DescriptorSizeBuf = AllocateZeroPool (sizeof (UINTN) * NumberOfHandles);
301 if (DescriptorSizeBuf == NULL) {
302 Status = EFI_OUT_OF_RESOURCES;
303 goto END;
304 }
305
306 FmpImageInfoDescriptorVerBuf = AllocateZeroPool (sizeof (UINT32) * NumberOfHandles);
307 if (FmpImageInfoDescriptorVerBuf == NULL) {
308 Status = EFI_OUT_OF_RESOURCES;
309 goto END;
310 }
311
312 //
313 // Get all FmpImageInfo Descriptor into FmpImageInfoBuf
314 //
315 for (Index1 = 0; Index1 < NumberOfHandles; Index1++) {
316 Status = gBS->HandleProtocol (
317 HandleBuffer[Index1],
318 &gEfiFirmwareManagementProtocolGuid,
319 (VOID **)&FmpBuf[Index1]
320 );
321
322 if (EFI_ERROR (Status)) {
323 continue;
324 }
325
326 ImageInfoSize = 0;
327 Status = FmpBuf[Index1]->GetImageInfo (
328 FmpBuf[Index1],
329 &ImageInfoSize,
330 NULL,
331 NULL,
332 NULL,
333 NULL,
334 NULL,
335 NULL
336 );
337
338 if (Status == EFI_BUFFER_TOO_SMALL) {
339 FmpImageInfoBuf[Index1] = AllocateZeroPool (ImageInfoSize);
340 if (FmpImageInfoBuf[Index1] == NULL) {
341 Status = EFI_OUT_OF_RESOURCES;
342 goto END;
343 }
344 } else {
345 continue;
346 }
347
348 PackageVersionName = NULL;
349 Status = FmpBuf[Index1]->GetImageInfo (
350 FmpBuf[Index1],
351 &ImageInfoSize,
352 FmpImageInfoBuf[Index1],
353 &FmpImageInfoDescriptorVerBuf[Index1],
354 &FmpImageInfoCountBuf[Index1],
355 &DescriptorSizeBuf[Index1],
356 &PackageVersion,
357 &PackageVersionName
358 );
359
360 //
361 // If FMP GetInformation interface failed, skip this resource
362 //
363 if (EFI_ERROR (Status)) {
364 FmpImageInfoCountBuf[Index1] = 0;
365 continue;
366 }
367
368 if (PackageVersionName != NULL) {
369 FreePool (PackageVersionName);
370 }
371 }
372
373 //
374 // Create new FMP cache repository based on FmpImageInfoBuf
375 //
376 for (Index2 = 0; Index2 < NumberOfHandles; Index2++) {
377 TempFmpImageInfo = FmpImageInfoBuf[Index2];
378 for (Index3 = 0; Index3 < FmpImageInfoCountBuf[Index2]; Index3++) {
379 if ( ((TempFmpImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_IN_USE) != 0)
380 && ((TempFmpImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_IN_USE) != 0))
381 {
382 //
383 // Always put the first smallest version of Image info into ESRT cache
384 //
385 for (Index1 = 0; Index1 < EntryNumNew; Index1++) {
386 if (CompareGuid (&EsrtRepositoryNew[Index1].FwClass, &TempFmpImageInfo->ImageTypeId)) {
387 if (EsrtRepositoryNew[Index1].FwVersion > TempFmpImageInfo->Version) {
388 SetEsrtEntryFromFmpInfo (&EsrtRepositoryNew[Index1], TempFmpImageInfo, FmpImageInfoDescriptorVerBuf[Index2]);
389 }
390
391 break;
392 }
393 }
394
395 //
396 // New ImageTypeId can't be found in EsrtRepositoryNew. Create a new one
397 //
398 if (Index1 == EntryNumNew) {
399 SetEsrtEntryFromFmpInfo (&EsrtRepositoryNew[EntryNumNew], TempFmpImageInfo, FmpImageInfoDescriptorVerBuf[Index2]);
400 EntryNumNew++;
401 if (EntryNumNew >= PcdGet32 (PcdMaxFmpEsrtCacheNum)) {
402 break;
403 }
404 }
405 }
406
407 //
408 // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
409 //
410 TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSizeBuf[Index2]);
411 }
412 }
413
414UPDATE_REPOSITORY:
415
416 Status = EfiAcquireLockOrFail (&mPrivate.FmpLock);
417 if (EFI_ERROR (Status)) {
418 return Status;
419 }
420
421 Status = gRT->SetVariable (
422 EFI_ESRT_FMP_VARIABLE_NAME,
423 &gEfiCallerIdGuid,
424 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
425 EntryNumNew * sizeof (EFI_SYSTEM_RESOURCE_ENTRY),
426 EsrtRepositoryNew
427 );
428
429 EfiReleaseLock (&mPrivate.FmpLock);
430
431END:
432 if (EsrtRepositoryNew != NULL) {
433 FreePool (EsrtRepositoryNew);
434 }
435
436 if (HandleBuffer != NULL) {
437 FreePool (HandleBuffer);
438 }
439
440 if (FmpBuf != NULL) {
441 FreePool (FmpBuf);
442 }
443
444 if (FmpImageInfoCountBuf != NULL) {
445 FreePool (FmpImageInfoCountBuf);
446 }
447
448 if (DescriptorSizeBuf != NULL) {
449 FreePool (DescriptorSizeBuf);
450 }
451
452 if (FmpImageInfoDescriptorVerBuf != NULL) {
453 FreePool (FmpImageInfoDescriptorVerBuf);
454 }
455
456 if (FmpImageInfoBuf != NULL) {
457 for (Index1 = 0; Index1 < NumberOfHandles; Index1++) {
458 if (FmpImageInfoBuf[Index1] != NULL) {
459 FreePool (FmpImageInfoBuf[Index1]);
460 }
461 }
462
463 FreePool (FmpImageInfoBuf);
464 }
465
466 return Status;
467}
468
469/**
470 This function locks up Esrt repository to be readonly. It should be called
471 before gEfiEndOfDxeEventGroupGuid event signaled
472
473 @retval EFI_SUCCESS Locks up FMP Non-FMP repository successfully
474
475**/
476EFI_STATUS
477EFIAPI
478EsrtDxeLockEsrtRepository (
479 VOID
480 )
481{
482 EFI_STATUS Status;
483 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
484
485 //
486 // Mark ACPI_GLOBAL_VARIABLE variable to read-only if the Variable Lock protocol exists
487 //
488 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);
489 if (!EFI_ERROR (Status)) {
490 Status = VariableLock->RequestToLock (VariableLock, EFI_ESRT_FMP_VARIABLE_NAME, &gEfiCallerIdGuid);
491 DEBUG ((DEBUG_INFO, "EsrtDxe Lock EsrtFmp Variable Status 0x%x", Status));
492
493 Status = VariableLock->RequestToLock (VariableLock, EFI_ESRT_NONFMP_VARIABLE_NAME, &gEfiCallerIdGuid);
494 DEBUG ((DEBUG_INFO, "EsrtDxe Lock EsrtNonFmp Variable Status 0x%x", Status));
495 }
496
497 return Status;
498}
499
500/**
501 Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
502 install the Esrt Table into system configuration table
503
504 @param[in] Event The Event that is being processed.
505 @param[in] Context The Event Context.
506
507**/
508VOID
509EFIAPI
510EsrtReadyToBootEventNotify (
511 IN EFI_EVENT Event,
512 IN VOID *Context
513 )
514{
515 EFI_STATUS Status;
516 EFI_SYSTEM_RESOURCE_TABLE *EsrtTable;
517 EFI_SYSTEM_RESOURCE_ENTRY *FmpEsrtRepository;
518 EFI_SYSTEM_RESOURCE_ENTRY *NonFmpEsrtRepository;
519 UINTN FmpRepositorySize;
520 UINTN NonFmpRepositorySize;
521
522 FmpEsrtRepository = NULL;
523 NonFmpEsrtRepository = NULL;
524 FmpRepositorySize = 0;
525 NonFmpRepositorySize = 0;
526
527 Status = EfiAcquireLockOrFail (&mPrivate.NonFmpLock);
528 if (EFI_ERROR (Status)) {
529 return;
530 }
531
532 Status = GetVariable2 (
533 EFI_ESRT_NONFMP_VARIABLE_NAME,
534 &gEfiCallerIdGuid,
535 (VOID **)&NonFmpEsrtRepository,
536 &NonFmpRepositorySize
537 );
538
539 if (EFI_ERROR (Status)) {
540 NonFmpRepositorySize = 0;
541 }
542
543 if (NonFmpRepositorySize % sizeof (EFI_SYSTEM_RESOURCE_ENTRY) != 0) {
544 DEBUG ((DEBUG_ERROR, "NonFmp Repository Corrupt. Need to rebuild NonFmp Repository.\n"));
545 NonFmpRepositorySize = 0;
546 }
547
548 EfiReleaseLock (&mPrivate.NonFmpLock);
549
550 Status = EfiAcquireLockOrFail (&mPrivate.FmpLock);
551 Status = GetVariable2 (
552 EFI_ESRT_FMP_VARIABLE_NAME,
553 &gEfiCallerIdGuid,
554 (VOID **)&FmpEsrtRepository,
555 &FmpRepositorySize
556 );
557
558 if (EFI_ERROR (Status)) {
559 FmpRepositorySize = 0;
560 }
561
562 if (FmpRepositorySize % sizeof (EFI_SYSTEM_RESOURCE_ENTRY) != 0) {
563 DEBUG ((DEBUG_ERROR, "Fmp Repository Corrupt. Need to rebuild Fmp Repository.\n"));
564 FmpRepositorySize = 0;
565 }
566
567 EfiReleaseLock (&mPrivate.FmpLock);
568
569 //
570 // Skip ESRT table publish if no ESRT entry exists
571 //
572 if (NonFmpRepositorySize + FmpRepositorySize == 0) {
573 goto EXIT;
574 }
575
576 EsrtTable = AllocatePool (sizeof (EFI_SYSTEM_RESOURCE_TABLE) + NonFmpRepositorySize + FmpRepositorySize);
577 if (EsrtTable == NULL) {
578 DEBUG ((DEBUG_ERROR, "Esrt table memory allocation failure\n"));
579 goto EXIT;
580 }
581
582 EsrtTable->FwResourceVersion = EFI_SYSTEM_RESOURCE_TABLE_FIRMWARE_RESOURCE_VERSION;
583 EsrtTable->FwResourceCount = (UINT32)((NonFmpRepositorySize + FmpRepositorySize) / sizeof (EFI_SYSTEM_RESOURCE_ENTRY));
584 EsrtTable->FwResourceCountMax = PcdGet32 (PcdMaxNonFmpEsrtCacheNum) + PcdGet32 (PcdMaxFmpEsrtCacheNum);
585
586 if ((NonFmpRepositorySize != 0) && (NonFmpEsrtRepository != NULL)) {
587 CopyMem (EsrtTable + 1, NonFmpEsrtRepository, NonFmpRepositorySize);
588 }
589
590 if ((FmpRepositorySize != 0) && (FmpEsrtRepository != NULL)) {
591 CopyMem ((UINT8 *)(EsrtTable + 1) + NonFmpRepositorySize, FmpEsrtRepository, FmpRepositorySize);
592 }
593
594 //
595 // Publish Esrt to system config table
596 //
597 Status = gBS->InstallConfigurationTable (&gEfiSystemResourceTableGuid, EsrtTable);
598
599 //
600 // Only one successful install
601 //
602 gBS->CloseEvent (Event);
603
604EXIT:
605
606 if (FmpEsrtRepository != NULL) {
607 FreePool (FmpEsrtRepository);
608 }
609
610 if (NonFmpEsrtRepository != NULL) {
611 FreePool (NonFmpEsrtRepository);
612 }
613}
614
615/**
616 The module Entry Point of the Esrt DXE driver that manages cached ESRT repository
617 & publishes ESRT table
618
619 @param[in] ImageHandle The firmware allocated handle for the EFI image.
620 @param[in] SystemTable A pointer to the EFI System Table.
621
622 @retval EFI_SUCCESS The entry point is executed successfully.
623 @retval Other Some error occurs when executing this entry point.
624
625**/
626EFI_STATUS
627EFIAPI
628EsrtDxeEntryPoint (
629 IN EFI_HANDLE ImageHandle,
630 IN EFI_SYSTEM_TABLE *SystemTable
631 )
632{
633 EFI_STATUS Status;
634
635 EfiInitializeLock (&mPrivate.FmpLock, TPL_CALLBACK);
636 EfiInitializeLock (&mPrivate.NonFmpLock, TPL_CALLBACK);
637
638 //
639 // Install Esrt management Protocol
640 //
641 Status = gBS->InstallMultipleProtocolInterfaces (
642 &mPrivate.Handle,
643 &gEsrtManagementProtocolGuid,
644 &mEsrtManagementProtocolTemplate,
645 NULL
646 );
647 ASSERT_EFI_ERROR (Status);
648
649 //
650 // Register notify function to install Esrt Table on ReadyToBoot Event.
651 //
652 Status = gBS->CreateEventEx (
653 EVT_NOTIFY_SIGNAL,
654 TPL_CALLBACK,
655 EsrtReadyToBootEventNotify,
656 NULL,
657 &gEfiEventReadyToBootGuid,
658 &mPrivate.Event
659 );
660 ASSERT_EFI_ERROR (Status);
661
662 return EFI_SUCCESS;
663}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette