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