]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmp.c
MdeModulePkg: Remove trailing white space
[mirror_edk2.git] / MdeModulePkg / Universal / EsrtFmpDxe / EsrtFmp.c
1 /** @file
2 Publishes ESRT table from Firmware Management Protocol instances
3
4 Copyright (c) 2016, Microsoft Corporation
5 Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
6
7 All rights reserved.
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10 1. Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
20 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
24 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 **/
28
29 #include <Uefi.h>
30 #include <Library/BaseLib.h>
31 #include <Library/BaseMemoryLib.h>
32 #include <Library/MemoryAllocationLib.h>
33 #include <Library/UefiBootServicesTableLib.h>
34 #include <Library/DebugLib.h>
35 #include <Library/PcdLib.h>
36 #include <Library/UefiLib.h>
37 #include <Protocol/FirmwareManagement.h>
38 #include <Guid/EventGroup.h>
39 #include <Guid/SystemResourceTable.h>
40
41 /**
42 Print ESRT to debug console.
43
44 @param[in] Table Pointer to the ESRT table.
45
46 **/
47 VOID
48 EFIAPI
49 PrintTable (
50 IN EFI_SYSTEM_RESOURCE_TABLE *Table
51 );
52
53 //
54 // Number of ESRT entries to grow by each time we run out of room
55 //
56 #define GROWTH_STEP 10
57
58 /**
59 Install EFI System Resource Table into the UEFI Configuration Table
60
61 @param[in] Table Pointer to the ESRT.
62
63 @return Status code.
64
65 **/
66 EFI_STATUS
67 InstallEfiSystemResourceTableInUefiConfigurationTable (
68 IN EFI_SYSTEM_RESOURCE_TABLE *Table
69 )
70 {
71 EFI_STATUS Status;
72
73 Status = EFI_SUCCESS;
74 if (Table->FwResourceCount == 0) {
75 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Can't install ESRT table because it has zero Entries. \n"));
76 Status = EFI_UNSUPPORTED;
77 } else {
78 //
79 // Install the pointer into config table
80 //
81 Status = gBS->InstallConfigurationTable (&gEfiSystemResourceTableGuid, Table);
82 if (EFI_ERROR (Status)) {
83 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Can't install ESRT table. Status: %r. \n", Status));
84 } else {
85 DEBUG ((DEBUG_INFO, "EsrtFmpDxe: Installed ESRT table. \n"));
86 }
87 }
88 return Status;
89 }
90
91 /**
92 Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.
93
94 @param[in] FmpImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR
95
96 @return TRUE It is a system FMP.
97 @return FALSE It is a device FMP.
98 **/
99 BOOLEAN
100 IsSystemFmp (
101 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfo
102 )
103 {
104 GUID *Guid;
105 UINTN Count;
106 UINTN Index;
107
108 Guid = PcdGetPtr (PcdSystemFmpCapsuleImageTypeIdGuid);
109 Count = PcdGetSize (PcdSystemFmpCapsuleImageTypeIdGuid) / sizeof(GUID);
110
111 for (Index = 0; Index < Count; Index++, Guid++) {
112 if (CompareGuid (&FmpImageInfo->ImageTypeId, Guid)) {
113 return TRUE;
114 }
115 }
116
117 return FALSE;
118 }
119
120 /**
121 Function to create a single ESRT Entry and add it to the ESRT
122 given a FMP descriptor. If the guid is already in the ESRT it
123 will be ignored. The ESRT will grow if it does not have enough room.
124
125 @param[in, out] Table On input, pointer to the pointer to the ESRT.
126 On output, same as input or pointer to the pointer
127 to new enlarged ESRT.
128 @param[in] FmpImageInfoBuf Pointer to the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
129 @param[in] FmpVersion FMP Version.
130
131 @return Status code.
132
133 **/
134 EFI_STATUS
135 CreateEsrtEntry (
136 IN OUT EFI_SYSTEM_RESOURCE_TABLE **Table,
137 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf,
138 IN UINT32 FmpVersion
139 )
140 {
141 UINTN Index;
142 EFI_SYSTEM_RESOURCE_ENTRY *Entry;
143 UINTN NewSize;
144 EFI_SYSTEM_RESOURCE_TABLE *NewTable;
145
146 Index = 0;
147 Entry = NULL;
148
149 Entry = (EFI_SYSTEM_RESOURCE_ENTRY *)((*Table) + 1);
150 //
151 // Make sure Guid isn't already in the list
152 //
153 for (Index = 0; Index < (*Table)->FwResourceCount; Index++) {
154 if (CompareGuid (&Entry->FwClass, &FmpImageInfoBuf->ImageTypeId)) {
155 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: ESRT Entry already exists for FMP Instance with GUID %g\n", &Entry->FwClass));
156 return EFI_INVALID_PARAMETER;
157 }
158 Entry++;
159 }
160
161 //
162 // Grow table if needed
163 //
164 if ((*Table)->FwResourceCount >= (*Table)->FwResourceCountMax) {
165 NewSize = (((*Table)->FwResourceCountMax + GROWTH_STEP) * sizeof (EFI_SYSTEM_RESOURCE_ENTRY)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE);
166 NewTable = AllocateZeroPool (NewSize);
167 if (NewTable == NULL) {
168 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to allocate memory larger table for ESRT. \n"));
169 return EFI_OUT_OF_RESOURCES;
170 }
171 //
172 // Copy the whole old table into new table buffer
173 //
174 CopyMem (
175 NewTable,
176 (*Table),
177 (((*Table)->FwResourceCountMax) * sizeof (EFI_SYSTEM_RESOURCE_ENTRY)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE)
178 );
179 //
180 // Update max
181 //
182 NewTable->FwResourceCountMax = NewTable->FwResourceCountMax + GROWTH_STEP;
183 //
184 // Free old table
185 //
186 FreePool ((*Table));
187 //
188 // Reassign pointer to new table.
189 //
190 (*Table) = NewTable;
191 }
192
193 //
194 // ESRT table has enough room for the new entry so add new entry
195 //
196 Entry = (EFI_SYSTEM_RESOURCE_ENTRY *)(((UINT8 *)(*Table)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE));
197 //
198 // Move to the location of new entry
199 //
200 Entry = Entry + (*Table)->FwResourceCount;
201 //
202 // Increment resource count
203 //
204 (*Table)->FwResourceCount++;
205
206 CopyGuid (&Entry->FwClass, &FmpImageInfoBuf->ImageTypeId);
207
208 if (IsSystemFmp (FmpImageInfoBuf)) {
209 DEBUG ((DEBUG_INFO, "EsrtFmpDxe: Found an ESRT entry for a System Device.\n"));
210 Entry->FwType = (UINT32)(ESRT_FW_TYPE_SYSTEMFIRMWARE);
211 } else {
212 Entry->FwType = (UINT32)(ESRT_FW_TYPE_DEVICEFIRMWARE);
213 }
214
215 Entry->FwVersion = FmpImageInfoBuf->Version;
216 Entry->LowestSupportedFwVersion = 0;
217 Entry->CapsuleFlags = 0;
218 Entry->LastAttemptVersion = 0;
219 Entry->LastAttemptStatus = 0;
220
221 //
222 // VERSION 2 has Lowest Supported
223 //
224 if (FmpVersion >= 2) {
225 Entry->LowestSupportedFwVersion = FmpImageInfoBuf->LowestSupportedImageVersion;
226 }
227
228 //
229 // VERSION 3 supports last attempt values
230 //
231 if (FmpVersion >= 3) {
232 Entry->LastAttemptVersion = FmpImageInfoBuf->LastAttemptVersion;
233 Entry->LastAttemptStatus = FmpImageInfoBuf->LastAttemptStatus;
234 }
235
236 return EFI_SUCCESS;
237 }
238
239 /**
240 Function to create ESRT based on FMP Instances.
241 Create ESRT table, get the descriptors from FMP Instance and
242 create ESRT entries (ESRE).
243
244 @return Pointer to the ESRT created.
245
246 **/
247 EFI_SYSTEM_RESOURCE_TABLE *
248 CreateFmpBasedEsrt (
249 VOID
250 )
251 {
252 EFI_STATUS Status;
253 EFI_SYSTEM_RESOURCE_TABLE *Table;
254 UINTN NoProtocols;
255 VOID **Buffer;
256 UINTN Index;
257 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
258 UINTN DescriptorSize;
259 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
260 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBufOrg;
261 UINT8 FmpImageInfoCount;
262 UINT32 FmpImageInfoDescriptorVer;
263 UINTN ImageInfoSize;
264 UINT32 PackageVersion;
265 CHAR16 *PackageVersionName;
266
267 Status = EFI_SUCCESS;
268 Table = NULL;
269 NoProtocols = 0;
270 Buffer = NULL;
271 PackageVersionName = NULL;
272 FmpImageInfoBuf = NULL;
273 FmpImageInfoBufOrg = NULL;
274 Fmp = NULL;
275
276 Status = EfiLocateProtocolBuffer (
277 &gEfiFirmwareManagementProtocolGuid,
278 &NoProtocols,
279 &Buffer
280 );
281 if (EFI_ERROR(Status) || (Buffer == NULL)) {
282 return NULL;
283 }
284
285 //
286 // Allocate Memory for table
287 //
288 Table = AllocateZeroPool (
289 (GROWTH_STEP * sizeof (EFI_SYSTEM_RESOURCE_ENTRY)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE)
290 );
291 if (Table == NULL) {
292 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to allocate memory for ESRT.\n"));
293 gBS->FreePool (Buffer);
294 return NULL;
295 }
296
297 Table->FwResourceCount = 0;
298 Table->FwResourceCountMax = GROWTH_STEP;
299 Table->FwResourceVersion = EFI_SYSTEM_RESOURCE_TABLE_FIRMWARE_RESOURCE_VERSION;
300
301 for (Index = 0; Index < NoProtocols; Index++) {
302 Fmp = (EFI_FIRMWARE_MANAGEMENT_PROTOCOL *) Buffer[Index];
303
304 ImageInfoSize = 0;
305 Status = Fmp->GetImageInfo (
306 Fmp, // FMP Pointer
307 &ImageInfoSize, // Buffer Size (in this case 0)
308 NULL, // NULL so we can get size
309 &FmpImageInfoDescriptorVer, // DescriptorVersion
310 &FmpImageInfoCount, // DescriptorCount
311 &DescriptorSize, // DescriptorSize
312 &PackageVersion, // PackageVersion
313 &PackageVersionName // PackageVersionName
314 );
315
316 if (Status != EFI_BUFFER_TOO_SMALL) {
317 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Unexpected Failure in GetImageInfo. Status = %r\n", Status));
318 continue;
319 }
320
321 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
322 if (FmpImageInfoBuf == NULL) {
323 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to get memory for descriptors.\n"));
324 continue;
325 }
326
327 FmpImageInfoBufOrg = FmpImageInfoBuf;
328 PackageVersionName = NULL;
329 Status = Fmp->GetImageInfo (
330 Fmp,
331 &ImageInfoSize, // ImageInfoSize
332 FmpImageInfoBuf, // ImageInfo
333 &FmpImageInfoDescriptorVer, // DescriptorVersion
334 &FmpImageInfoCount, // DescriptorCount
335 &DescriptorSize, // DescriptorSize
336 &PackageVersion, // PackageVersion
337 &PackageVersionName // PackageVersionName
338 );
339 if (EFI_ERROR (Status)) {
340 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failure in GetImageInfo. Status = %r\n", Status));
341 FreePool (FmpImageInfoBufOrg);
342 FmpImageInfoBufOrg = NULL;
343 continue;
344 }
345
346 //
347 // Check each descriptor and read from the one specified
348 //
349 while (FmpImageInfoCount > 0) {
350 //
351 // If the descriptor has the IN USE bit set, create ESRT entry otherwise ignore.
352 //
353 if ((FmpImageInfoBuf->AttributesSetting & FmpImageInfoBuf->AttributesSupported & IMAGE_ATTRIBUTE_IN_USE) == IMAGE_ATTRIBUTE_IN_USE) {
354 //
355 // Create ESRT entry
356 //
357 CreateEsrtEntry (&Table, FmpImageInfoBuf, FmpImageInfoDescriptorVer);
358 }
359 FmpImageInfoCount--;
360 //
361 // Increment the buffer pointer ahead by the size of the descriptor
362 //
363 FmpImageInfoBuf = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)(((UINT8 *)FmpImageInfoBuf) + DescriptorSize);
364 }
365
366 if (PackageVersionName != NULL) {
367 FreePool (PackageVersionName);
368 PackageVersionName = NULL;
369 }
370 FreePool (FmpImageInfoBufOrg);
371 FmpImageInfoBufOrg = NULL;
372 }
373
374 gBS->FreePool (Buffer);
375 return Table;
376 }
377
378 /**
379 Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
380 install the Efi System Resource Table.
381
382 @param[in] Event The Event that is being processed.
383 @param[in] Context The Event Context.
384
385 **/
386 VOID
387 EFIAPI
388 EsrtReadyToBootEventNotify (
389 IN EFI_EVENT Event,
390 IN VOID *Context
391 )
392 {
393 EFI_STATUS Status;
394 EFI_SYSTEM_RESOURCE_TABLE *Table;
395
396 Table = CreateFmpBasedEsrt ();
397 if (Table != NULL) {
398 //
399 // Print table on debug builds
400 //
401 DEBUG_CODE_BEGIN ();
402 PrintTable (Table);
403 DEBUG_CODE_END ();
404
405 Status = InstallEfiSystemResourceTableInUefiConfigurationTable (Table);
406 if (EFI_ERROR (Status)) {
407 FreePool (Table);
408 }
409 } else {
410 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Can't install ESRT table because it is NULL. \n"));
411 }
412
413 //
414 // Close the event to prevent it be signalled again.
415 //
416 gBS->CloseEvent (Event);
417 }
418
419 /**
420 The module Entry Point of the Efi System Resource Table DXE driver.
421
422 @param[in] ImageHandle The firmware allocated handle for the EFI image.
423 @param[in] SystemTable A pointer to the EFI System Table.
424
425 @retval EFI_SUCCESS The entry point is executed successfully.
426 @retval Other Some error occurs when executing this entry point.
427
428 **/
429 EFI_STATUS
430 EFIAPI
431 EsrtFmpEntryPoint (
432 IN EFI_HANDLE ImageHandle,
433 IN EFI_SYSTEM_TABLE *SystemTable
434 )
435 {
436 EFI_STATUS Status;
437 EFI_EVENT EsrtReadyToBootEvent;
438
439 //
440 // Register notify function to install ESRT on ReadyToBoot Event.
441 //
442 Status = EfiCreateEventReadyToBootEx (
443 TPL_CALLBACK,
444 EsrtReadyToBootEventNotify,
445 NULL,
446 &EsrtReadyToBootEvent
447 );
448
449 ASSERT_EFI_ERROR (Status);
450 if (EFI_ERROR (Status)) {
451 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to register for ready to boot\n"));
452 }
453
454 return Status;
455 }