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