]>
Commit | Line | Data |
---|---|---|
3f7af17c MK |
1 | /** @file\r |
2 | \r | |
3 | This file contains the implementation for a Platform Runtime Mechanism (PRM)\r | |
4 | loader driver.\r | |
5 | \r | |
6 | Copyright (c) Microsoft Corporation\r | |
7 | SPDX-License-Identifier: BSD-2-Clause-Patent\r | |
8 | \r | |
9 | **/\r | |
10 | \r | |
11 | #include "PrmAcpiTable.h"\r | |
12 | #include "PrmLoader.h"\r | |
13 | \r | |
14 | #include <IndustryStandard/Acpi.h>\r | |
15 | #include <Library/BaseLib.h>\r | |
16 | #include <Library/BaseMemoryLib.h>\r | |
17 | #include <Library/DebugLib.h>\r | |
18 | #include <Library/MemoryAllocationLib.h>\r | |
19 | #include <Library/PrmContextBufferLib.h>\r | |
20 | #include <Library/UefiBootServicesTableLib.h>\r | |
21 | #include <Library/UefiLib.h>\r | |
22 | #include <Protocol/AcpiTable.h>\r | |
23 | #include <Protocol/LoadedImage.h>\r | |
24 | #include <Protocol/PrmConfig.h>\r | |
25 | \r | |
26 | #include <PrmContextBuffer.h>\r | |
27 | #include <PrmMmio.h>\r | |
28 | #include <PrmModuleUpdate.h>\r | |
29 | \r | |
30 | LIST_ENTRY mPrmModuleList;\r | |
31 | \r | |
32 | // Todo: Potentially refactor mPrmHandlerCount and mPrmModuleCount into localized structures\r | |
33 | // in the future.\r | |
34 | UINT32 mPrmHandlerCount;\r | |
35 | UINT32 mPrmModuleCount;\r | |
36 | \r | |
37 | /**\r | |
38 | Gets a pointer to the export directory in a given PE/COFF image.\r | |
39 | \r | |
40 | @param[in] ImageExportDirectory A pointer to an export directory table in a PE/COFF image.\r | |
41 | @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r | |
42 | PE/COFF image context for the Image containing the PRM Module Export\r | |
43 | Descriptor table.\r | |
44 | @param[out] ExportDescriptor A pointer to a pointer to the PRM Module Export Descriptor table found\r | |
45 | in the ImageExportDirectory given.\r | |
46 | \r | |
47 | @retval EFI_SUCCESS The PRM Module Export Descriptor table was found successfully.\r | |
48 | @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r | |
49 | @retval EFI_NOT_FOUND The PRM Module Export Descriptor table was not found in the given\r | |
50 | ImageExportDirectory.\r | |
51 | \r | |
52 | **/\r | |
53 | EFI_STATUS\r | |
54 | GetPrmModuleExportDescriptorTable (\r | |
55 | IN EFI_IMAGE_EXPORT_DIRECTORY *ImageExportDirectory,\r | |
56 | IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r | |
57 | OUT PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT **ExportDescriptor\r | |
58 | )\r | |
59 | {\r | |
60 | UINTN Index;\r | |
61 | EFI_PHYSICAL_ADDRESS CurrentImageAddress;\r | |
62 | UINT16 PrmModuleExportDescriptorOrdinal;\r | |
63 | CONST CHAR8 *CurrentExportName;\r | |
64 | UINT16 *OrdinalTable;\r | |
65 | UINT32 *ExportNamePointerTable;\r | |
66 | UINT32 *ExportAddressTable;\r | |
67 | PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *TempExportDescriptor;\r | |
68 | \r | |
69 | DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r | |
70 | \r | |
71 | *ExportDescriptor = NULL;\r | |
72 | \r | |
73 | if (ImageExportDirectory == NULL ||\r | |
74 | PeCoffLoaderImageContext == NULL ||\r | |
75 | PeCoffLoaderImageContext->ImageAddress == 0 ||\r | |
76 | ExportDescriptor == NULL) {\r | |
77 | return EFI_INVALID_PARAMETER;\r | |
78 | }\r | |
79 | \r | |
80 | DEBUG ((\r | |
81 | DEBUG_INFO,\r | |
82 | " %a %a: %d exported names found in this image.\n",\r | |
83 | _DBGMSGID_,\r | |
84 | __FUNCTION__,\r | |
85 | ImageExportDirectory->NumberOfNames\r | |
86 | ));\r | |
87 | \r | |
88 | //\r | |
89 | // The export name pointer table and export ordinal table form two parallel arrays associated by index.\r | |
90 | //\r | |
91 | CurrentImageAddress = PeCoffLoaderImageContext->ImageAddress;\r | |
92 | ExportAddressTable = (UINT32 *) ((UINTN) CurrentImageAddress + ImageExportDirectory->AddressOfFunctions);\r | |
93 | ExportNamePointerTable = (UINT32 *) ((UINTN) CurrentImageAddress + ImageExportDirectory->AddressOfNames);\r | |
94 | OrdinalTable = (UINT16 *) ((UINTN) CurrentImageAddress + ImageExportDirectory->AddressOfNameOrdinals);\r | |
95 | \r | |
96 | for (Index = 0; Index < ImageExportDirectory->NumberOfNames; Index++) {\r | |
97 | CurrentExportName = (CONST CHAR8 *) ((UINTN) CurrentImageAddress + ExportNamePointerTable[Index]);\r | |
98 | DEBUG ((\r | |
99 | DEBUG_INFO,\r | |
100 | " %a %a: Export Name[0x%x] - %a.\n",\r | |
101 | _DBGMSGID_,\r | |
102 | __FUNCTION__,\r | |
103 | Index,\r | |
104 | CurrentExportName\r | |
105 | ));\r | |
106 | if (\r | |
107 | AsciiStrnCmp (\r | |
108 | PRM_STRING(PRM_MODULE_EXPORT_DESCRIPTOR_NAME),\r | |
109 | CurrentExportName,\r | |
110 | AsciiStrLen (PRM_STRING(PRM_MODULE_EXPORT_DESCRIPTOR_NAME))\r | |
111 | ) == 0) {\r | |
112 | PrmModuleExportDescriptorOrdinal = OrdinalTable[Index];\r | |
113 | DEBUG ((\r | |
114 | DEBUG_INFO,\r | |
115 | " %a %a: PRM Module Export Descriptor found. Ordinal = %d.\n",\r | |
116 | _DBGMSGID_,\r | |
117 | __FUNCTION__,\r | |
118 | PrmModuleExportDescriptorOrdinal\r | |
119 | ));\r | |
120 | if (PrmModuleExportDescriptorOrdinal >= ImageExportDirectory->NumberOfFunctions) {\r | |
121 | DEBUG ((DEBUG_ERROR, "%a %a: The PRM Module Export Descriptor ordinal value is invalid.\n", _DBGMSGID_, __FUNCTION__));\r | |
122 | return EFI_NOT_FOUND;\r | |
123 | }\r | |
124 | TempExportDescriptor = (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *) ((UINTN) CurrentImageAddress + ExportAddressTable[PrmModuleExportDescriptorOrdinal]);\r | |
125 | if (TempExportDescriptor->Signature == PRM_MODULE_EXPORT_DESCRIPTOR_SIGNATURE) {\r | |
126 | *ExportDescriptor = TempExportDescriptor;\r | |
127 | DEBUG ((DEBUG_INFO, " %a %a: PRM Module Export Descriptor found at 0x%x.\n", _DBGMSGID_, __FUNCTION__, (UINTN) ExportDescriptor));\r | |
128 | } else {\r | |
129 | DEBUG ((\r | |
130 | DEBUG_INFO,\r | |
131 | " %a %a: PRM Module Export Descriptor found at 0x%x but signature check failed.\n",\r | |
132 | _DBGMSGID_,\r | |
133 | __FUNCTION__,\r | |
134 | (UINTN) TempExportDescriptor\r | |
135 | ));\r | |
136 | }\r | |
137 | DEBUG ((DEBUG_INFO, " %a %a: Exiting export iteration since export descriptor found.\n", _DBGMSGID_, __FUNCTION__));\r | |
138 | return EFI_SUCCESS;\r | |
139 | }\r | |
140 | }\r | |
141 | \r | |
142 | return EFI_NOT_FOUND;\r | |
143 | }\r | |
144 | \r | |
145 | /**\r | |
146 | Gets a pointer to the export directory in a given PE/COFF image.\r | |
147 | \r | |
148 | @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory\r | |
149 | and already relocated to the memory base address. RVAs in the image given\r | |
150 | should be valid.\r | |
151 | @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r | |
152 | PE/COFF image context for the Image given.\r | |
153 | @param[out] ImageExportDirectory A pointer to a pointer to the export directory found in the Image given.\r | |
154 | \r | |
155 | @retval EFI_SUCCESS The export directory was found successfully.\r | |
156 | @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r | |
157 | @retval EFI_UNSUPPORTED The PE/COFF image given is not supported as a PRM Module.\r | |
158 | @retval EFI_NOT_FOUND The image export directory could not be found for this image.\r | |
159 | \r | |
160 | **/\r | |
161 | EFI_STATUS\r | |
162 | GetExportDirectoryInPeCoffImage (\r | |
163 | IN VOID *Image,\r | |
164 | IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r | |
165 | OUT EFI_IMAGE_EXPORT_DIRECTORY **ImageExportDirectory\r | |
166 | )\r | |
167 | {\r | |
168 | UINT16 Magic;\r | |
169 | UINT32 NumberOfRvaAndSizes;\r | |
170 | EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion;\r | |
171 | EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r | |
172 | EFI_IMAGE_EXPORT_DIRECTORY *ExportDirectory;\r | |
173 | EFI_IMAGE_SECTION_HEADER *SectionHeader;\r | |
174 | \r | |
175 | if (Image == NULL || PeCoffLoaderImageContext == NULL || ImageExportDirectory == NULL) {\r | |
176 | return EFI_INVALID_PARAMETER;\r | |
177 | }\r | |
178 | \r | |
179 | DirectoryEntry = NULL;\r | |
180 | ExportDirectory = NULL;\r | |
181 | \r | |
182 | //\r | |
183 | // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+\r | |
184 | // image instead of using the Magic field. Some systems might generate a PE32+\r | |
185 | // image with PE32 magic.\r | |
186 | //\r | |
187 | switch (PeCoffLoaderImageContext->Machine) {\r | |
188 | case EFI_IMAGE_MACHINE_IA32:\r | |
189 | // Todo: Add EFI_IMAGE_MACHINE_ARMT\r | |
190 | //\r | |
191 | // Assume PE32 image with IA32 Machine field.\r | |
192 | //\r | |
193 | Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r | |
194 | break;\r | |
195 | case EFI_IMAGE_MACHINE_X64:\r | |
196 | //\r | |
197 | // Assume PE32+ image with X64 Machine field\r | |
198 | //\r | |
199 | Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r | |
200 | break;\r | |
201 | default:\r | |
202 | //\r | |
203 | // For unknown Machine field, use Magic in optional header\r | |
204 | //\r | |
205 | DEBUG ((\r | |
206 | DEBUG_WARN,\r | |
207 | "%a %a: The machine type for this image is not valid for a PRM module.\n",\r | |
208 | _DBGMSGID_,\r | |
209 | __FUNCTION__\r | |
210 | ));\r | |
211 | return EFI_UNSUPPORTED;\r | |
212 | }\r | |
213 | \r | |
214 | OptionalHeaderPtrUnion.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (\r | |
215 | (UINTN) Image +\r | |
216 | PeCoffLoaderImageContext->PeCoffHeaderOffset\r | |
217 | );\r | |
218 | \r | |
219 | //\r | |
220 | // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.\r | |
221 | //\r | |
222 | if (OptionalHeaderPtrUnion.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r | |
223 | DEBUG ((DEBUG_ERROR, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_, __FUNCTION__));\r | |
224 | return EFI_UNSUPPORTED;\r | |
225 | }\r | |
226 | \r | |
227 | SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r | |
228 | (UINTN) Image +\r | |
229 | PeCoffLoaderImageContext->PeCoffHeaderOffset +\r | |
230 | sizeof (UINT32) +\r | |
231 | sizeof (EFI_IMAGE_FILE_HEADER) +\r | |
232 | PeCoffLoaderImageContext->SizeOfHeaders\r | |
233 | );\r | |
234 | if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r | |
235 | //\r | |
236 | // Use the PE32 offset to get the Export Directory Entry\r | |
237 | //\r | |
238 | NumberOfRvaAndSizes = OptionalHeaderPtrUnion.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r | |
239 | DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHeaderPtrUnion.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT]);\r | |
240 | } else if (OptionalHeaderPtrUnion.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r | |
241 | //\r | |
242 | // Use the PE32+ offset get the Export Directory Entry\r | |
243 | //\r | |
244 | NumberOfRvaAndSizes = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r | |
245 | DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT]);\r | |
246 | } else {\r | |
247 | return EFI_UNSUPPORTED;\r | |
248 | }\r | |
249 | \r | |
250 | if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_EXPORT || DirectoryEntry->VirtualAddress == 0) {\r | |
251 | //\r | |
252 | // The export directory is not present\r | |
253 | //\r | |
254 | return EFI_NOT_FOUND;\r | |
255 | } else if (((UINT32) (~0) - DirectoryEntry->VirtualAddress) < DirectoryEntry->Size) {\r | |
256 | //\r | |
257 | // The directory address overflows\r | |
258 | //\r | |
259 | DEBUG ((DEBUG_ERROR, "%a %a: The export directory entry in this image results in overflow.\n", _DBGMSGID_, __FUNCTION__));\r | |
260 | return EFI_UNSUPPORTED;\r | |
261 | } else {\r | |
262 | DEBUG ((DEBUG_INFO, "%a %a: Export Directory Entry found in the image at 0x%x.\n", _DBGMSGID_, __FUNCTION__, (UINTN) OptionalHeaderPtrUnion.Pe32));\r | |
263 | DEBUG ((DEBUG_INFO, " %a %a: Directory Entry Virtual Address = 0x%x.\n", _DBGMSGID_, __FUNCTION__, DirectoryEntry->VirtualAddress));\r | |
264 | \r | |
265 | ExportDirectory = (EFI_IMAGE_EXPORT_DIRECTORY *) ((UINTN) Image + DirectoryEntry->VirtualAddress);\r | |
266 | DEBUG ((\r | |
267 | DEBUG_INFO,\r | |
268 | " %a %a: Export Directory Table found successfully at 0x%x. Name address = 0x%x. Name = %a.\n",\r | |
269 | _DBGMSGID_,\r | |
270 | __FUNCTION__,\r | |
271 | (UINTN) ExportDirectory,\r | |
272 | ((UINTN) Image + ExportDirectory->Name),\r | |
273 | (CHAR8 *) ((UINTN) Image + ExportDirectory->Name)\r | |
274 | ));\r | |
275 | }\r | |
276 | *ImageExportDirectory = ExportDirectory;\r | |
277 | \r | |
278 | return EFI_SUCCESS;\r | |
279 | }\r | |
280 | \r | |
281 | /**\r | |
282 | Returns the image major and image minor version in a given PE/COFF image.\r | |
283 | \r | |
284 | @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory\r | |
285 | and already relocated to the memory base address. RVAs in the image given\r | |
286 | should be valid.\r | |
287 | @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r | |
288 | PE/COFF image context for the Image given.\r | |
289 | @param[out] ImageMajorVersion A pointer to a UINT16 buffer to hold the image major version.\r | |
290 | @param[out] ImageMinorVersion A pointer to a UINT16 buffer to hold the image minor version.\r | |
291 | \r | |
292 | @retval EFI_SUCCESS The image version was read successfully.\r | |
293 | @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r | |
294 | @retval EFI_UNSUPPORTED The PE/COFF image given is not supported.\r | |
295 | \r | |
296 | **/\r | |
297 | EFI_STATUS\r | |
298 | GetImageVersionInPeCoffImage (\r | |
299 | IN VOID *Image,\r | |
300 | IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r | |
301 | OUT UINT16 *ImageMajorVersion,\r | |
302 | OUT UINT16 *ImageMinorVersion\r | |
303 | )\r | |
304 | {\r | |
305 | EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion;\r | |
306 | UINT16 Magic;\r | |
307 | \r | |
308 | DEBUG ((DEBUG_INFO, " %a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r | |
309 | \r | |
310 | if (Image == NULL || PeCoffLoaderImageContext == NULL || ImageMajorVersion == NULL || ImageMinorVersion == NULL) {\r | |
311 | return EFI_INVALID_PARAMETER;\r | |
312 | }\r | |
313 | \r | |
314 | //\r | |
315 | // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+\r | |
316 | // image instead of using the Magic field. Some systems might generate a PE32+\r | |
317 | // image with PE32 magic.\r | |
318 | //\r | |
319 | switch (PeCoffLoaderImageContext->Machine) {\r | |
320 | case EFI_IMAGE_MACHINE_IA32:\r | |
321 | // Todo: Add EFI_IMAGE_MACHINE_ARMT\r | |
322 | //\r | |
323 | // Assume PE32 image with IA32 Machine field.\r | |
324 | //\r | |
325 | Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r | |
326 | break;\r | |
327 | case EFI_IMAGE_MACHINE_X64:\r | |
328 | //\r | |
329 | // Assume PE32+ image with X64 Machine field\r | |
330 | //\r | |
331 | Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r | |
332 | break;\r | |
333 | default:\r | |
334 | //\r | |
335 | // For unknown Machine field, use Magic in optional header\r | |
336 | //\r | |
337 | DEBUG ((\r | |
338 | DEBUG_WARN,\r | |
339 | "%a %a: The machine type for this image is not valid for a PRM module.\n",\r | |
340 | _DBGMSGID_,\r | |
341 | __FUNCTION__\r | |
342 | ));\r | |
343 | return EFI_UNSUPPORTED;\r | |
344 | }\r | |
345 | \r | |
346 | OptionalHeaderPtrUnion.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (\r | |
347 | (UINTN) Image +\r | |
348 | PeCoffLoaderImageContext->PeCoffHeaderOffset\r | |
349 | );\r | |
350 | //\r | |
351 | // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.\r | |
352 | //\r | |
353 | if (OptionalHeaderPtrUnion.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r | |
354 | DEBUG ((DEBUG_ERROR, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_, __FUNCTION__));\r | |
355 | return EFI_UNSUPPORTED;\r | |
356 | }\r | |
357 | \r | |
358 | if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r | |
359 | //\r | |
360 | // Use the PE32 offset to get the Export Directory Entry\r | |
361 | //\r | |
362 | *ImageMajorVersion = OptionalHeaderPtrUnion.Pe32->OptionalHeader.MajorImageVersion;\r | |
363 | *ImageMinorVersion = OptionalHeaderPtrUnion.Pe32->OptionalHeader.MinorImageVersion;\r | |
364 | } else {\r | |
365 | //\r | |
366 | // Use the PE32+ offset to get the Export Directory Entry\r | |
367 | //\r | |
368 | *ImageMajorVersion = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.MajorImageVersion;\r | |
369 | *ImageMinorVersion = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.MinorImageVersion;\r | |
370 | }\r | |
371 | \r | |
372 | DEBUG ((DEBUG_INFO, " %a %a - Image Major Version: 0x%02x.\n", _DBGMSGID_, __FUNCTION__, *ImageMajorVersion));\r | |
373 | DEBUG ((DEBUG_INFO, " %a %a - Image Minor Version: 0x%02x.\n", _DBGMSGID_, __FUNCTION__, *ImageMinorVersion));\r | |
374 | \r | |
375 | return EFI_SUCCESS;\r | |
376 | }\r | |
377 | \r | |
378 | /**\r | |
379 | Creates a new PRM Module Image Context linked list entry.\r | |
380 | \r | |
381 | @retval PrmModuleImageContextListEntry If successful, a pointer a PRM Module Image Context linked list entry\r | |
382 | otherwise, NULL is returned.\r | |
383 | \r | |
384 | **/\r | |
385 | STATIC\r | |
386 | PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *\r | |
387 | CreateNewPrmModuleImageContextListEntry (\r | |
388 | VOID\r | |
389 | )\r | |
390 | {\r | |
391 | PRM_MODULE_IMAGE_CONTEXT *PrmModuleImageContext;\r | |
392 | PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *PrmModuleImageContextListEntry;\r | |
393 | \r | |
394 | DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r | |
395 | \r | |
396 | PrmModuleImageContext = AllocateZeroPool (sizeof (*PrmModuleImageContext));\r | |
397 | if (PrmModuleImageContext == NULL) {\r | |
398 | return NULL;\r | |
399 | }\r | |
400 | DEBUG ((\r | |
401 | DEBUG_INFO,\r | |
402 | " %a %a: Allocated PrmModuleImageContext at 0x%x of size 0x%x bytes.\n",\r | |
403 | _DBGMSGID_,\r | |
404 | __FUNCTION__,\r | |
405 | (UINTN) PrmModuleImageContext,\r | |
406 | sizeof (*PrmModuleImageContext)\r | |
407 | ));\r | |
408 | \r | |
409 | PrmModuleImageContextListEntry = AllocateZeroPool (sizeof (*PrmModuleImageContextListEntry));\r | |
410 | if (PrmModuleImageContextListEntry == NULL) {\r | |
411 | FreePool (PrmModuleImageContext);\r | |
412 | return NULL;\r | |
413 | }\r | |
414 | DEBUG ((\r | |
415 | DEBUG_INFO,\r | |
416 | " %a %a: Allocated PrmModuleImageContextListEntry at 0x%x of size 0x%x bytes.\n",\r | |
417 | _DBGMSGID_,\r | |
418 | __FUNCTION__,\r | |
419 | (UINTN) PrmModuleImageContextListEntry,\r | |
420 | sizeof (*PrmModuleImageContextListEntry)\r | |
421 | ));\r | |
422 | \r | |
423 | PrmModuleImageContextListEntry->Signature = PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE;\r | |
424 | PrmModuleImageContextListEntry->Context = PrmModuleImageContext;\r | |
425 | \r | |
426 | return PrmModuleImageContextListEntry;\r | |
427 | }\r | |
428 | \r | |
429 | /**\r | |
430 | Discovers all PRM Modules loaded during the DXE boot phase.\r | |
431 | \r | |
432 | Each PRM Module discovered is placed into a linked list so the list can br processsed in the future.\r | |
433 | \r | |
434 | @retval EFI_SUCCESS All PRM Modules were discovered successfully.\r | |
435 | @retval EFI_NOT_FOUND The gEfiLoadedImageProtocolGuid protocol could not be found.\r | |
436 | @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the new PRM Context\r | |
437 | linked list nodes.\r | |
438 | \r | |
439 | **/\r | |
440 | EFI_STATUS\r | |
441 | DiscoverPrmModules (\r | |
442 | VOID\r | |
443 | )\r | |
444 | {\r | |
445 | EFI_STATUS Status;\r | |
446 | PRM_MODULE_IMAGE_CONTEXT TempPrmModuleImageContext;\r | |
447 | PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *PrmModuleImageContextListEntry;\r | |
448 | EFI_LOADED_IMAGE_PROTOCOL *LoadedImageProtocol;\r | |
449 | EFI_HANDLE *HandleBuffer;\r | |
450 | UINTN HandleCount;\r | |
451 | UINTN Index;\r | |
452 | \r | |
453 | DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r | |
454 | \r | |
455 | Status = gBS->LocateHandleBuffer (\r | |
456 | ByProtocol,\r | |
457 | &gEfiLoadedImageProtocolGuid,\r | |
458 | NULL,\r | |
459 | &HandleCount,\r | |
460 | &HandleBuffer\r | |
461 | );\r | |
462 | if (EFI_ERROR (Status) && (HandleCount == 0)) {\r | |
463 | DEBUG ((DEBUG_ERROR, "%a %a: No LoadedImageProtocol instances found!\n", _DBGMSGID_, __FUNCTION__));\r | |
464 | return EFI_NOT_FOUND;\r | |
465 | }\r | |
466 | \r | |
467 | for (Index = 0; Index < HandleCount; Index++) {\r | |
468 | Status = gBS->HandleProtocol (\r | |
469 | HandleBuffer[Index],\r | |
470 | &gEfiLoadedImageProtocolGuid,\r | |
471 | (VOID **) &LoadedImageProtocol\r | |
472 | );\r | |
473 | if (EFI_ERROR (Status)) {\r | |
474 | continue;\r | |
475 | }\r | |
476 | \r | |
477 | ZeroMem (&TempPrmModuleImageContext, sizeof (TempPrmModuleImageContext));\r | |
478 | TempPrmModuleImageContext.PeCoffImageContext.Handle = LoadedImageProtocol->ImageBase;\r | |
479 | TempPrmModuleImageContext.PeCoffImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r | |
480 | \r | |
481 | Status = PeCoffLoaderGetImageInfo (&TempPrmModuleImageContext.PeCoffImageContext);\r | |
482 | if (EFI_ERROR (Status) || TempPrmModuleImageContext.PeCoffImageContext.ImageError != IMAGE_ERROR_SUCCESS) {\r | |
483 | DEBUG ((\r | |
484 | DEBUG_WARN,\r | |
485 | "%a %a: ImageHandle 0x%016lx is not a valid PE/COFF image. It cannot be considered a PRM module.\n",\r | |
486 | _DBGMSGID_,\r | |
487 | __FUNCTION__,\r | |
488 | (EFI_PHYSICAL_ADDRESS) (UINTN) LoadedImageProtocol->ImageBase\r | |
489 | ));\r | |
490 | continue;\r | |
491 | }\r | |
492 | if (TempPrmModuleImageContext.PeCoffImageContext.IsTeImage) {\r | |
493 | // A PRM Module is not allowed to be a TE image\r | |
494 | continue;\r | |
495 | }\r | |
496 | \r | |
497 | // Attempt to find an export table in this image\r | |
498 | Status = GetExportDirectoryInPeCoffImage (\r | |
499 | LoadedImageProtocol->ImageBase,\r | |
500 | &TempPrmModuleImageContext.PeCoffImageContext,\r | |
501 | &TempPrmModuleImageContext.ExportDirectory\r | |
502 | );\r | |
503 | if (EFI_ERROR (Status)) {\r | |
504 | continue;\r | |
505 | }\r | |
506 | \r | |
507 | // Attempt to find the PRM Module Export Descriptor in the export table\r | |
508 | Status = GetPrmModuleExportDescriptorTable (\r | |
509 | TempPrmModuleImageContext.ExportDirectory,\r | |
510 | &TempPrmModuleImageContext.PeCoffImageContext,\r | |
511 | &TempPrmModuleImageContext.ExportDescriptor\r | |
512 | );\r | |
513 | if (EFI_ERROR (Status)) {\r | |
514 | continue;\r | |
515 | }\r | |
516 | // A PRM Module Export Descriptor was successfully found, this is considered a PRM Module.\r | |
517 | \r | |
518 | //\r | |
519 | // Create a new PRM Module image context node\r | |
520 | //\r | |
521 | PrmModuleImageContextListEntry = CreateNewPrmModuleImageContextListEntry ();\r | |
522 | if (PrmModuleImageContextListEntry == NULL) {\r | |
523 | return EFI_OUT_OF_RESOURCES;\r | |
524 | }\r | |
525 | CopyMem (\r | |
526 | PrmModuleImageContextListEntry->Context,\r | |
527 | &TempPrmModuleImageContext,\r | |
528 | sizeof (*(PrmModuleImageContextListEntry->Context))\r | |
529 | );\r | |
530 | InsertTailList (&mPrmModuleList, &PrmModuleImageContextListEntry->Link);\r | |
531 | mPrmHandlerCount += TempPrmModuleImageContext.ExportDescriptor->NumberPrmHandlers;\r | |
532 | mPrmModuleCount++; // Todo: Match with global variable refactor change in the future\r | |
533 | DEBUG ((DEBUG_INFO, "%a %a: New PRM Module inserted into list to be processed.\n", _DBGMSGID_, __FUNCTION__));\r | |
534 | }\r | |
535 | \r | |
536 | return EFI_SUCCESS;\r | |
537 | }\r | |
538 | \r | |
539 | /**\r | |
540 | Gets the address of an entry in an image export table by ASCII name.\r | |
541 | \r | |
542 | @param[in] ExportName A pointer to an ASCII name string of the entry name.\r | |
543 | @param[in] ImageBaseAddress The base address of the PE/COFF image.\r | |
544 | @param[in] ImageExportDirectory A pointer to the export directory in the image.\r | |
545 | @param[out] ExportPhysicalAddress A pointer that will be updated with the address of the address of the\r | |
546 | export entry if found.\r | |
547 | \r | |
548 | @retval EFI_SUCCESS The export entry was found successfully.\r | |
549 | @retval EFI_INVALID_PARAMETER A required pointer argument is NULL.\r | |
550 | @retval EFI_NOT_FOUND An entry with the given ExportName was not found.\r | |
551 | \r | |
552 | **/\r | |
553 | EFI_STATUS\r | |
554 | GetExportEntryAddress (\r | |
555 | IN CONST CHAR8 *ExportName,\r | |
556 | IN EFI_PHYSICAL_ADDRESS ImageBaseAddress,\r | |
557 | IN EFI_IMAGE_EXPORT_DIRECTORY *ImageExportDirectory,\r | |
558 | OUT EFI_PHYSICAL_ADDRESS *ExportPhysicalAddress\r | |
559 | )\r | |
560 | {\r | |
561 | UINTN ExportNameIndex;\r | |
562 | UINT16 CurrentExportOrdinal;\r | |
563 | UINT32 *ExportAddressTable;\r | |
564 | UINT32 *ExportNamePointerTable;\r | |
565 | UINT16 *OrdinalTable;\r | |
566 | CONST CHAR8 *ExportNameTablePointerName;\r | |
567 | \r | |
568 | if (ExportName == NULL || ImageBaseAddress == 0 || ImageExportDirectory == NULL || ExportPhysicalAddress == NULL) {\r | |
569 | return EFI_INVALID_PARAMETER;\r | |
570 | }\r | |
571 | *ExportPhysicalAddress = 0;\r | |
572 | \r | |
573 | ExportAddressTable = (UINT32 *) ((UINTN) ImageBaseAddress + ImageExportDirectory->AddressOfFunctions);\r | |
574 | ExportNamePointerTable = (UINT32 *) ((UINTN) ImageBaseAddress + ImageExportDirectory->AddressOfNames);\r | |
575 | OrdinalTable = (UINT16 *) ((UINTN) ImageBaseAddress + ImageExportDirectory->AddressOfNameOrdinals);\r | |
576 | \r | |
577 | for (ExportNameIndex = 0; ExportNameIndex < ImageExportDirectory->NumberOfNames; ExportNameIndex++) {\r | |
578 | ExportNameTablePointerName = (CONST CHAR8 *) ((UINTN) ImageBaseAddress + ExportNamePointerTable[ExportNameIndex]);\r | |
579 | \r | |
580 | if (AsciiStrnCmp (ExportName, ExportNameTablePointerName, PRM_HANDLER_NAME_MAXIMUM_LENGTH) == 0) {\r | |
581 | CurrentExportOrdinal = OrdinalTable[ExportNameIndex];\r | |
582 | \r | |
583 | ASSERT (CurrentExportOrdinal < ImageExportDirectory->NumberOfFunctions);\r | |
584 | if (CurrentExportOrdinal >= ImageExportDirectory->NumberOfFunctions) {\r | |
585 | DEBUG ((DEBUG_ERROR, " %a %a: The export ordinal value is invalid.\n", _DBGMSGID_, __FUNCTION__));\r | |
586 | break;\r | |
587 | }\r | |
588 | \r | |
589 | *ExportPhysicalAddress = (EFI_PHYSICAL_ADDRESS) ((UINTN) ImageBaseAddress + ExportAddressTable[CurrentExportOrdinal]);\r | |
590 | return EFI_SUCCESS;\r | |
591 | }\r | |
592 | }\r | |
593 | \r | |
594 | return EFI_NOT_FOUND;\r | |
595 | }\r | |
596 | \r | |
597 | /**\r | |
598 | Processes a list of PRM context entries to build a PRM ACPI table.\r | |
599 | \r | |
600 | The ACPI table buffer is allocated and the table structure is built inside this function.\r | |
601 | \r | |
602 | @param[out] PrmAcpiDescriptionTable A pointer to a pointer to a buffer that is allocated within this function\r | |
603 | and will contain the PRM ACPI table. In case of an error in this function,\r | |
604 | *PrmAcpiDescriptorTable will be NULL.\r | |
605 | \r | |
606 | @retval EFI_SUCCESS All PRM Modules were processed to construct the PRM ACPI table successfully.\r | |
607 | @retval EFI_INVALID_PARAMETER THe parameter PrmAcpiDescriptionTable is NULL.\r | |
608 | @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the PRM ACPI table boot services\r | |
609 | memory data buffer.\r | |
610 | \r | |
611 | **/\r | |
612 | EFI_STATUS\r | |
613 | ProcessPrmModules (\r | |
614 | OUT PRM_ACPI_DESCRIPTION_TABLE **PrmAcpiDescriptionTable\r | |
615 | )\r | |
616 | {\r | |
617 | EFI_IMAGE_EXPORT_DIRECTORY *CurrentImageExportDirectory;\r | |
618 | PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *CurrentExportDescriptorStruct;\r | |
619 | LIST_ENTRY *Link;\r | |
620 | PRM_ACPI_DESCRIPTION_TABLE *PrmAcpiTable;\r | |
621 | PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *TempListEntry;\r | |
622 | CONST CHAR8 *CurrentExportDescriptorHandlerName;\r | |
623 | \r | |
624 | PRM_CONTEXT_BUFFER *CurrentContextBuffer;\r | |
625 | PRM_MODULE_CONTEXT_BUFFERS *CurrentModuleContextBuffers;\r | |
626 | PRM_MODULE_INFORMATION_STRUCT *CurrentModuleInfoStruct;\r | |
627 | PRM_HANDLER_INFORMATION_STRUCT *CurrentHandlerInfoStruct;\r | |
628 | \r | |
629 | EFI_STATUS Status;\r | |
630 | EFI_PHYSICAL_ADDRESS CurrentImageAddress;\r | |
631 | UINTN HandlerIndex;\r | |
632 | UINT32 PrmAcpiDescriptionTableBufferSize;\r | |
633 | \r | |
634 | UINT64 HandlerPhysicalAddress;\r | |
635 | \r | |
636 | DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r | |
637 | \r | |
638 | if (PrmAcpiDescriptionTable == NULL) {\r | |
639 | return EFI_INVALID_PARAMETER;\r | |
640 | }\r | |
641 | Link = NULL;\r | |
642 | *PrmAcpiDescriptionTable = NULL;\r | |
643 | \r | |
644 | DEBUG ((DEBUG_INFO, " %a %a: %d total PRM modules to process.\n", _DBGMSGID_, __FUNCTION__, mPrmModuleCount));\r | |
645 | DEBUG ((DEBUG_INFO, " %a %a: %d total PRM handlers to process.\n", _DBGMSGID_, __FUNCTION__, mPrmHandlerCount));\r | |
646 | \r | |
647 | PrmAcpiDescriptionTableBufferSize = (OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE, PrmModuleInfoStructure) +\r | |
648 | (OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT, HandlerInfoStructure) * mPrmModuleCount) +\r | |
649 | (sizeof (PRM_HANDLER_INFORMATION_STRUCT) * mPrmHandlerCount)\r | |
650 | );\r | |
651 | DEBUG ((DEBUG_INFO, " %a %a: Total PRM ACPI table size: 0x%x.\n", _DBGMSGID_, __FUNCTION__, PrmAcpiDescriptionTableBufferSize));\r | |
652 | \r | |
653 | PrmAcpiTable = AllocateZeroPool ((UINTN) PrmAcpiDescriptionTableBufferSize);\r | |
654 | if (PrmAcpiTable == NULL) {\r | |
655 | return EFI_OUT_OF_RESOURCES;\r | |
656 | }\r | |
657 | \r | |
658 | PrmAcpiTable->Header.Signature = PRM_TABLE_SIGNATURE;\r | |
659 | PrmAcpiTable->Header.Length = PrmAcpiDescriptionTableBufferSize;\r | |
660 | PrmAcpiTable->Header.Revision = PRM_TABLE_REVISION;\r | |
661 | PrmAcpiTable->Header.Checksum = 0x0;\r | |
662 | CopyMem (&PrmAcpiTable->Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (PrmAcpiTable->Header.OemId));\r | |
663 | PrmAcpiTable->Header.OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);\r | |
664 | PrmAcpiTable->Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);\r | |
665 | PrmAcpiTable->Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);\r | |
666 | PrmAcpiTable->Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);\r | |
667 | PrmAcpiTable->PrmModuleInfoOffset = OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE, PrmModuleInfoStructure);\r | |
668 | PrmAcpiTable->PrmModuleInfoCount = mPrmModuleCount;\r | |
669 | \r | |
670 | //\r | |
671 | // Iterate across all PRM Modules on the list\r | |
672 | //\r | |
673 | CurrentModuleInfoStruct = &PrmAcpiTable->PrmModuleInfoStructure[0];\r | |
674 | EFI_LIST_FOR_EACH(Link, &mPrmModuleList)\r | |
675 | {\r | |
676 | TempListEntry = CR(Link, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY, Link, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE);\r | |
677 | CurrentImageAddress = TempListEntry->Context->PeCoffImageContext.ImageAddress;\r | |
678 | CurrentImageExportDirectory = TempListEntry->Context->ExportDirectory;\r | |
679 | CurrentExportDescriptorStruct = TempListEntry->Context->ExportDescriptor;\r | |
680 | \r | |
681 | DEBUG ((\r | |
682 | DEBUG_INFO,\r | |
683 | " %a %a: PRM Module - %a with %d handlers.\n",\r | |
684 | _DBGMSGID_,\r | |
685 | __FUNCTION__,\r | |
686 | (CHAR8 *) ((UINTN) CurrentImageAddress + CurrentImageExportDirectory->Name),\r | |
687 | CurrentExportDescriptorStruct->NumberPrmHandlers\r | |
688 | ));\r | |
689 | \r | |
690 | CurrentModuleInfoStruct->StructureRevision = PRM_MODULE_INFORMATION_STRUCT_REVISION;\r | |
691 | CurrentModuleInfoStruct->StructureLength = (\r | |
692 | OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT, HandlerInfoStructure) +\r | |
693 | (CurrentExportDescriptorStruct->NumberPrmHandlers * sizeof (PRM_HANDLER_INFORMATION_STRUCT))\r | |
694 | );\r | |
695 | CopyGuid (&CurrentModuleInfoStruct->Identifier, &CurrentExportDescriptorStruct->ModuleGuid);\r | |
696 | CurrentModuleInfoStruct->HandlerCount = (UINT32) CurrentExportDescriptorStruct->NumberPrmHandlers;\r | |
697 | CurrentModuleInfoStruct->HandlerInfoOffset = OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT, HandlerInfoStructure);\r | |
698 | \r | |
699 | CurrentModuleInfoStruct->MajorRevision = 0;\r | |
700 | CurrentModuleInfoStruct->MinorRevision = 0;\r | |
701 | Status = GetImageVersionInPeCoffImage (\r | |
702 | (VOID *) (UINTN) CurrentImageAddress,\r | |
703 | &TempListEntry->Context->PeCoffImageContext,\r | |
704 | &CurrentModuleInfoStruct->MajorRevision,\r | |
705 | &CurrentModuleInfoStruct->MinorRevision\r | |
706 | );\r | |
707 | ASSERT_EFI_ERROR (Status);\r | |
708 | \r | |
709 | Status = GetExportEntryAddress (\r | |
710 | PRM_STRING (PRM_MODULE_UPDATE_LOCK_DESCRIPTOR_NAME),\r | |
711 | CurrentImageAddress,\r | |
712 | CurrentImageExportDirectory,\r | |
713 | (EFI_PHYSICAL_ADDRESS *) &(CurrentModuleInfoStruct->ModuleUpdateLock)\r | |
714 | );\r | |
715 | ASSERT_EFI_ERROR (Status);\r | |
716 | if (!EFI_ERROR (Status)) {\r | |
717 | DEBUG ((\r | |
718 | DEBUG_INFO,\r | |
719 | " %a %a: Found PRM module update lock physical address at 0x%016x.\n",\r | |
720 | _DBGMSGID_,\r | |
721 | __FUNCTION__,\r | |
722 | CurrentModuleInfoStruct->ModuleUpdateLock\r | |
723 | ));\r | |
724 | }\r | |
725 | \r | |
726 | // It is currently valid for a PRM module not to use a context buffer\r | |
727 | Status = GetModuleContextBuffers (\r | |
728 | ByModuleGuid,\r | |
729 | &CurrentModuleInfoStruct->Identifier,\r | |
730 | &CurrentModuleContextBuffers\r | |
731 | );\r | |
732 | ASSERT (!EFI_ERROR (Status) || Status == EFI_NOT_FOUND);\r | |
733 | if (!EFI_ERROR (Status) && CurrentModuleContextBuffers != NULL) {\r | |
734 | CurrentModuleInfoStruct->RuntimeMmioRanges = (UINT64) (UINTN) CurrentModuleContextBuffers->RuntimeMmioRanges;\r | |
735 | }\r | |
736 | \r | |
737 | //\r | |
738 | // Iterate across all PRM handlers in the PRM Module\r | |
739 | //\r | |
740 | for (HandlerIndex = 0; HandlerIndex < CurrentExportDescriptorStruct->NumberPrmHandlers; HandlerIndex++) {\r | |
741 | CurrentHandlerInfoStruct = &(CurrentModuleInfoStruct->HandlerInfoStructure[HandlerIndex]);\r | |
742 | \r | |
743 | CurrentHandlerInfoStruct->StructureRevision = PRM_HANDLER_INFORMATION_STRUCT_REVISION;\r | |
744 | CurrentHandlerInfoStruct->StructureLength = sizeof (PRM_HANDLER_INFORMATION_STRUCT);\r | |
745 | CopyGuid (\r | |
746 | &CurrentHandlerInfoStruct->Identifier,\r | |
747 | &CurrentExportDescriptorStruct->PrmHandlerExportDescriptors[HandlerIndex].PrmHandlerGuid\r | |
748 | );\r | |
749 | \r | |
750 | CurrentExportDescriptorHandlerName = (CONST CHAR8 *) CurrentExportDescriptorStruct->PrmHandlerExportDescriptors[HandlerIndex].PrmHandlerName;\r | |
751 | \r | |
752 | Status = GetContextBuffer (\r | |
753 | &CurrentHandlerInfoStruct->Identifier,\r | |
754 | CurrentModuleContextBuffers,\r | |
755 | &CurrentContextBuffer\r | |
756 | );\r | |
757 | if (!EFI_ERROR (Status)) {\r | |
758 | CurrentHandlerInfoStruct->PrmContextBuffer = (UINT64) CurrentContextBuffer;\r | |
759 | }\r | |
760 | \r | |
761 | Status = GetExportEntryAddress (\r | |
762 | CurrentExportDescriptorHandlerName,\r | |
763 | CurrentImageAddress,\r | |
764 | CurrentImageExportDirectory,\r | |
765 | &HandlerPhysicalAddress\r | |
766 | );\r | |
767 | ASSERT_EFI_ERROR (Status);\r | |
768 | if (!EFI_ERROR (Status)) {\r | |
769 | CurrentHandlerInfoStruct->PhysicalAddress = HandlerPhysicalAddress;\r | |
770 | DEBUG ((\r | |
771 | DEBUG_INFO,\r | |
772 | " %a %a: Found %a handler physical address at 0x%016x.\n",\r | |
773 | _DBGMSGID_,\r | |
774 | __FUNCTION__,\r | |
775 | CurrentExportDescriptorHandlerName,\r | |
776 | CurrentHandlerInfoStruct->PhysicalAddress\r | |
777 | ));\r | |
778 | }\r | |
779 | }\r | |
780 | CurrentModuleInfoStruct = (PRM_MODULE_INFORMATION_STRUCT *) ((UINTN) CurrentModuleInfoStruct + CurrentModuleInfoStruct->StructureLength);\r | |
781 | }\r | |
782 | *PrmAcpiDescriptionTable = PrmAcpiTable;\r | |
783 | \r | |
784 | return EFI_SUCCESS;\r | |
785 | }\r | |
786 | \r | |
787 | /**\r | |
788 | Publishes the PRM ACPI table (PRMT).\r | |
789 | \r | |
790 | @param[in] PrmAcpiDescriptionTable A pointer to a buffer with a completely populated and valid PRM\r | |
791 | ACPI description table.\r | |
792 | \r | |
793 | @retval EFI_SUCCESS The PRM ACPI was installed successfully.\r | |
794 | @retval EFI_INVALID_PARAMETER THe parameter PrmAcpiDescriptionTable is NULL or the table signature\r | |
795 | in the table provided is invalid.\r | |
796 | @retval EFI_NOT_FOUND The protocol gEfiAcpiTableProtocolGuid could not be found.\r | |
797 | @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the PRM ACPI table buffer.\r | |
798 | \r | |
799 | **/\r | |
800 | EFI_STATUS\r | |
801 | PublishPrmAcpiTable (\r | |
802 | IN PRM_ACPI_DESCRIPTION_TABLE *PrmAcpiDescriptionTable\r | |
803 | )\r | |
804 | {\r | |
805 | EFI_STATUS Status;\r | |
806 | EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;\r | |
807 | UINTN TableKey;\r | |
808 | \r | |
809 | if (PrmAcpiDescriptionTable == NULL || PrmAcpiDescriptionTable->Header.Signature != PRM_TABLE_SIGNATURE) {\r | |
810 | return EFI_INVALID_PARAMETER;\r | |
811 | }\r | |
812 | \r | |
813 | Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);\r | |
814 | if (!EFI_ERROR (Status)) {\r | |
815 | TableKey = 0;\r | |
816 | //\r | |
817 | // Publish the PRM ACPI table. The table checksum will be computed during installation.\r | |
818 | //\r | |
819 | Status = AcpiTableProtocol->InstallAcpiTable (\r | |
820 | AcpiTableProtocol,\r | |
821 | PrmAcpiDescriptionTable,\r | |
822 | PrmAcpiDescriptionTable->Header.Length,\r | |
823 | &TableKey\r | |
824 | );\r | |
825 | if (!EFI_ERROR (Status)) {\r | |
826 | DEBUG ((DEBUG_INFO, "%a %a: The PRMT ACPI table was installed successfully.\n", _DBGMSGID_, __FUNCTION__));\r | |
827 | }\r | |
828 | }\r | |
829 | ASSERT_EFI_ERROR (Status);\r | |
830 | \r | |
831 | return Status;\r | |
832 | }\r | |
833 | \r | |
834 | /**\r | |
835 | The PRM Loader END_OF_DXE protocol notification event handler.\r | |
836 | \r | |
837 | All PRM Modules that are eligible for dispatch should have been loaded the DXE Dispatcher at the\r | |
838 | time of this function invocation.\r | |
839 | \r | |
840 | The main responsibilities of the PRM Loader are executed from this function which include 3 phases:\r | |
841 | 1.) Disover PRM Modules - Find all PRM modules loaded during DXE dispatch and insert a PRM Module\r | |
842 | Context entry into a linked list to be handed off to phase 2.\r | |
843 | 2.) Process PRM Modules - Build a GUID to PRM handler mapping for each module that is described in the\r | |
844 | PRM ACPI table so the OS can resolve a PRM Handler GUID to the corresponding PRM Handler physical address.\r | |
845 | 3.) Publish PRM ACPI Table - Publish the PRM ACPI table with the information gathered in the phase 2.\r | |
846 | \r | |
847 | @param[in] Event Event whose notification function is being invoked.\r | |
848 | @param[in] Context The pointer to the notification function's context,\r | |
849 | which is implementation-dependent.\r | |
850 | \r | |
851 | @retval EFI_SUCCESS The function executed successfully\r | |
852 | \r | |
853 | **/\r | |
854 | EFI_STATUS\r | |
855 | EFIAPI\r | |
856 | PrmLoaderEndOfDxeNotification (\r | |
857 | IN EFI_EVENT Event,\r | |
858 | IN VOID *Context\r | |
859 | )\r | |
860 | {\r | |
861 | EFI_STATUS Status;\r | |
862 | PRM_ACPI_DESCRIPTION_TABLE *PrmAcpiDescriptionTable;\r | |
863 | \r | |
864 | DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r | |
865 | \r | |
866 | InitializeListHead (&mPrmModuleList);\r | |
867 | \r | |
868 | Status = DiscoverPrmModules ();\r | |
869 | ASSERT_EFI_ERROR (Status);\r | |
870 | \r | |
871 | Status = ProcessPrmModules (&PrmAcpiDescriptionTable);\r | |
872 | ASSERT_EFI_ERROR (Status);\r | |
873 | \r | |
874 | Status = PublishPrmAcpiTable (PrmAcpiDescriptionTable);\r | |
875 | ASSERT_EFI_ERROR (Status);\r | |
876 | \r | |
877 | if (PrmAcpiDescriptionTable != NULL) {\r | |
878 | FreePool (PrmAcpiDescriptionTable);\r | |
879 | }\r | |
880 | gBS->CloseEvent (Event);\r | |
881 | \r | |
882 | return EFI_SUCCESS;\r | |
883 | }\r | |
884 | \r | |
885 | /**\r | |
886 | The entry point for this module.\r | |
887 | \r | |
888 | @param ImageHandle The firmware allocated handle for the EFI image.\r | |
889 | @param SystemTable A pointer to the EFI System Table.\r | |
890 | \r | |
891 | @retval EFI_SUCCESS The entry point is executed successfully.\r | |
892 | @retval Others An error occurred when executing this entry point.\r | |
893 | \r | |
894 | **/\r | |
895 | EFI_STATUS\r | |
896 | EFIAPI\r | |
897 | PrmLoaderEntryPoint (\r | |
898 | IN EFI_HANDLE ImageHandle,\r | |
899 | IN EFI_SYSTEM_TABLE *SystemTable\r | |
900 | )\r | |
901 | {\r | |
902 | EFI_STATUS Status;\r | |
903 | EFI_EVENT EndOfDxeEvent;\r | |
904 | \r | |
905 | DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r | |
906 | \r | |
907 | //\r | |
908 | // Discover and process installed PRM modules at the End of DXE\r | |
909 | // The PRM ACPI table is published if one or PRM modules are discovered\r | |
910 | //\r | |
911 | Status = gBS->CreateEventEx(\r | |
912 | EVT_NOTIFY_SIGNAL,\r | |
913 | TPL_CALLBACK,\r | |
914 | PrmLoaderEndOfDxeNotification,\r | |
915 | NULL,\r | |
916 | &gEfiEndOfDxeEventGroupGuid,\r | |
917 | &EndOfDxeEvent\r | |
918 | );\r | |
919 | if (EFI_ERROR (Status)) {\r | |
920 | DEBUG ((DEBUG_ERROR, "%a %a: EndOfDxe callback registration failed! %r.\n", _DBGMSGID_, __FUNCTION__, Status));\r | |
921 | ASSERT_EFI_ERROR (Status);\r | |
922 | }\r | |
923 | \r | |
924 | return EFI_SUCCESS;\r | |
925 | }\r |