]> git.proxmox.com Git - mirror_edk2.git/blame - PrmPkg/PrmConfigDxe/PrmConfigDxe.c
PrmPkg: Enforce stricter types
[mirror_edk2.git] / PrmPkg / PrmConfigDxe / PrmConfigDxe.c
CommitLineData
3f7af17c
MK
1/** @file\r
2\r
3 This file contains the implementation for a Platform Runtime Mechanism (PRM) configuration driver.\r
4\r
5 Copyright (c) Microsoft Corporation\r
6 Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
8\r
9**/\r
10\r
11#include <Library/BaseLib.h>\r
12#include <Library/BaseMemoryLib.h>\r
13#include <Library/DebugLib.h>\r
14#include <Library/DxeServicesTableLib.h>\r
15#include <Library/MemoryAllocationLib.h>\r
16#include <Library/UefiBootServicesTableLib.h>\r
17#include <Library/UefiRuntimeServicesTableLib.h>\r
18#include <Library/UefiLib.h>\r
19\r
20#include <PiDxe.h>\r
21#include <PrmContextBuffer.h>\r
22#include <PrmDataBuffer.h>\r
23#include <PrmMmio.h>\r
24#include <Protocol/PrmConfig.h>\r
25\r
26#define _DBGMSGID_ "[PRMCONFIG]"\r
27\r
28STATIC UINTN mMaxRuntimeMmioRangeCount;\r
3f7af17c 29\r
e8467976 30GLOBAL_REMOVE_IF_UNREFERENCED STATIC PRM_RUNTIME_MMIO_RANGES **mRuntimeMmioRanges;\r
3f7af17c
MK
31\r
32/**\r
33 Converts the runtime memory range physical addresses to virtual addresses.\r
34\r
35 @param[in] RuntimeMmioRanges A pointer to a PRM_RUNTIME_MMIO_RANGES buffer.\r
36\r
37**/\r
38VOID\r
39ConvertRuntimeMemoryRangeAddresses (\r
40 IN PRM_RUNTIME_MMIO_RANGES *RuntimeMmioRanges\r
41 )\r
42{\r
43 UINTN Index;\r
44\r
45 if (RuntimeMmioRanges == NULL || RuntimeMmioRanges->Count == 0) {\r
46 return;\r
47 }\r
48\r
49 for (Index = 0; Index < (UINTN) RuntimeMmioRanges->Count; Index++) {\r
50 RuntimeMmioRanges->Range[Index].VirtualBaseAddress = RuntimeMmioRanges->Range[Index].PhysicalBaseAddress;\r
51 gRT->ConvertPointer (0x0, (VOID **) &(RuntimeMmioRanges->Range[Index].VirtualBaseAddress));\r
52 }\r
53}\r
54\r
55/**\r
56 Sets the runtime memory range attributes.\r
57\r
58 The EFI_MEMORY_RUNTIME attribute is set for each PRM_RUNTIME_MMIO_RANGE present\r
59 in the buffer provided.\r
60\r
61 @param[in] RuntimeMmioRanges A pointer to a PRM_RUNTIME_MMIO_RANGES buffer.\r
62\r
63**/\r
64VOID\r
65SetRuntimeMemoryRangeAttributes (\r
66 IN PRM_RUNTIME_MMIO_RANGES *RuntimeMmioRanges\r
67 )\r
68{\r
69 EFI_STATUS Status;\r
70 EFI_STATUS Status2;\r
71 UINTN Index;\r
72 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
73\r
74 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
75\r
76 if (RuntimeMmioRanges == NULL || RuntimeMmioRanges->Count == 0) {\r
77 return;\r
78 }\r
79\r
80 for (Index = 0; Index < (UINTN) RuntimeMmioRanges->Count; Index++) {\r
81 DEBUG ((\r
82 DEBUG_INFO, " %a %a: Runtime MMIO Range [%d].\n", _DBGMSGID_, __FUNCTION__, Index));\r
83 DEBUG ((\r
84 DEBUG_INFO,\r
85 " %a %a: Physical address = 0x%016x. Length = 0x%x.\n",\r
86 _DBGMSGID_,\r
87 __FUNCTION__,\r
88 RuntimeMmioRanges->Range[Index].PhysicalBaseAddress,\r
89 RuntimeMmioRanges->Range[Index].Length\r
90 ));\r
91\r
92 // Runtime memory ranges should cover ranges on a page boundary\r
93 ASSERT ((RuntimeMmioRanges->Range[Index].PhysicalBaseAddress & EFI_PAGE_MASK) == 0);\r
94 ASSERT ((RuntimeMmioRanges->Range[Index].Length & EFI_PAGE_MASK) == 0);\r
95\r
96 Status2 = EFI_NOT_FOUND;\r
97 Status = gDS->GetMemorySpaceDescriptor (RuntimeMmioRanges->Range[Index].PhysicalBaseAddress, &Descriptor);\r
98 if (!EFI_ERROR (Status) &&\r
99 (\r
100 (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo && Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) ||\r
101 ((Descriptor.Length & EFI_PAGE_MASK) != 0)\r
102 )\r
103 ) {\r
104 Status2 = gDS->RemoveMemorySpace (\r
105 RuntimeMmioRanges->Range[Index].PhysicalBaseAddress,\r
106 Descriptor.Length\r
107 );\r
108 }\r
109\r
110 if (Status == EFI_NOT_FOUND || !EFI_ERROR (Status2)) {\r
111 Status = gDS->AddMemorySpace (\r
112 EfiGcdMemoryTypeMemoryMappedIo,\r
113 RuntimeMmioRanges->Range[Index].PhysicalBaseAddress,\r
114 (UINT64) RuntimeMmioRanges->Range[Index].Length,\r
115 EFI_MEMORY_UC | EFI_MEMORY_RUNTIME\r
116 );\r
117 ASSERT_EFI_ERROR (Status);\r
118\r
119 Status = gDS->AllocateMemorySpace (\r
120 EfiGcdAllocateAddress,\r
121 EfiGcdMemoryTypeMemoryMappedIo,\r
122 0,\r
123 (UINT64) RuntimeMmioRanges->Range[Index].Length,\r
124 &RuntimeMmioRanges->Range[Index].PhysicalBaseAddress,\r
125 gImageHandle,\r
126 NULL\r
127 );\r
128 ASSERT_EFI_ERROR (Status);\r
129 }\r
130\r
131 Status = gDS->GetMemorySpaceDescriptor (RuntimeMmioRanges->Range[Index].PhysicalBaseAddress, &Descriptor);\r
132 ASSERT_EFI_ERROR (Status);\r
133 if (EFI_ERROR (Status)) {\r
134 DEBUG ((\r
135 DEBUG_ERROR,\r
136 " %a %a: Error [%r] finding descriptor for runtime memory range 0x%016x.\n",\r
137 _DBGMSGID_,\r
138 __FUNCTION__,\r
139 Status,\r
140 RuntimeMmioRanges->Range[Index].PhysicalBaseAddress\r
141 ));\r
142 continue;\r
143 }\r
144 if ((Descriptor.Attributes & EFI_MEMORY_RUNTIME) != 0) {\r
145 continue;\r
146 }\r
147\r
148 Status = gDS->SetMemorySpaceAttributes (\r
149 RuntimeMmioRanges->Range[Index].PhysicalBaseAddress,\r
150 (UINT64) RuntimeMmioRanges->Range[Index].Length,\r
151 Descriptor.Attributes | EFI_MEMORY_RUNTIME\r
152 );\r
153 ASSERT_EFI_ERROR (Status);\r
154 if (EFI_ERROR (Status)) {\r
155 DEBUG ((\r
156 DEBUG_ERROR,\r
157 " %a %a: Error [%r] setting descriptor for runtime memory range 0x%016x.\n",\r
158 _DBGMSGID_,\r
159 __FUNCTION__,\r
160 Status,\r
161 RuntimeMmioRanges->Range[Index].PhysicalBaseAddress\r
162 ));\r
163 } else {\r
164 DEBUG ((DEBUG_INFO, " %a %a: Successfully set runtime attribute for the MMIO range.\n", _DBGMSGID_, __FUNCTION__));\r
165 }\r
166 }\r
167}\r
168\r
169/**\r
170 Stores pointers or pointer to resources that should be converted in the virtual address change event.\r
171\r
172**/\r
173VOID\r
174StoreVirtualMemoryAddressChangePointers (\r
175 VOID\r
176 )\r
177{\r
178 EFI_STATUS Status;\r
3f7af17c
MK
179 UINTN HandleCount;\r
180 UINTN HandleIndex;\r
181 UINTN RangeIndex;\r
3f7af17c
MK
182 EFI_HANDLE *HandleBuffer;\r
183 PRM_CONFIG_PROTOCOL *PrmConfigProtocol;\r
3f7af17c
MK
184\r
185 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
186\r
187 RangeIndex = 0;\r
3f7af17c 188\r
e8467976
MK
189 mRuntimeMmioRanges = AllocateRuntimeZeroPool (sizeof (*mRuntimeMmioRanges) * mMaxRuntimeMmioRangeCount);\r
190 if (mRuntimeMmioRanges == NULL && mMaxRuntimeMmioRangeCount > 0) {\r
3f7af17c
MK
191 DEBUG ((\r
192 DEBUG_ERROR,\r
e8467976 193 " %a %a: Memory allocation for runtime MMIO pointer array failed.\n",\r
3f7af17c
MK
194 _DBGMSGID_,\r
195 __FUNCTION__\r
196 ));\r
197 ASSERT (FALSE);\r
198 return;\r
199 }\r
200\r
201 HandleBuffer = NULL;\r
202 Status = gBS->LocateHandleBuffer (\r
203 ByProtocol,\r
204 &gPrmConfigProtocolGuid,\r
205 NULL,\r
206 &HandleCount,\r
207 &HandleBuffer\r
208 );\r
209 if (!EFI_ERROR (Status)) {\r
210 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {\r
211 Status = gBS->HandleProtocol (\r
212 HandleBuffer[HandleIndex],\r
213 &gPrmConfigProtocolGuid,\r
214 (VOID **) &PrmConfigProtocol\r
215 );\r
216 ASSERT_EFI_ERROR (Status);\r
217 if (EFI_ERROR (Status) || PrmConfigProtocol == NULL) {\r
218 continue;\r
219 }\r
220\r
3f7af17c
MK
221 if (PrmConfigProtocol->ModuleContextBuffers.RuntimeMmioRanges != NULL) {\r
222 if (RangeIndex >= mMaxRuntimeMmioRangeCount) {\r
223 Status = EFI_BUFFER_TOO_SMALL;\r
224 DEBUG ((\r
225 DEBUG_ERROR,\r
226 " %a %a: Index out of bounds - Actual count (%d) of runtime MMIO ranges exceeds maximum count (%d).\n",\r
227 _DBGMSGID_,\r
228 __FUNCTION__,\r
229 RangeIndex + 1,\r
230 mMaxRuntimeMmioRangeCount\r
231 ));\r
232 ASSERT_EFI_ERROR (Status);\r
233 return;\r
234 }\r
235 mRuntimeMmioRanges[RangeIndex++] = PrmConfigProtocol->ModuleContextBuffers.RuntimeMmioRanges;\r
236 }\r
237 }\r
238 DEBUG ((\r
239 DEBUG_INFO,\r
240 " %a %a: %d MMIO ranges buffers saved for future virtual memory conversion.\n",\r
241 _DBGMSGID_,\r
242 __FUNCTION__,\r
243 RangeIndex\r
244 ));\r
3f7af17c
MK
245 }\r
246}\r
247\r
248/**\r
249 Validates a data buffer for a PRM module.\r
250\r
251 Verifies the buffer header signature is valid and the length meets the minimum size.\r
252\r
253 @param[in] PrmDataBuffer A pointer to the data buffer for this PRM module.\r
254\r
255 @retval EFI_SUCCESS The data buffer was validated successfully.\r
256 @retval EFI_INVALID_PARAMETER The pointer given for PrmDataBuffer is NULL.\r
257 @retval EFI_NOT_FOUND The data buffer signature is not valid.\r
258 @retval EFI_BUFFER_TOO_SMALL The buffer size is too small.\r
259\r
260**/\r
261EFI_STATUS\r
262ValidatePrmDataBuffer (\r
263 IN CONST PRM_DATA_BUFFER *PrmDataBuffer\r
264 )\r
265{\r
266 if (PrmDataBuffer == NULL) {\r
267 return EFI_INVALID_PARAMETER;\r
268 }\r
269\r
270 if (PrmDataBuffer->Header.Signature != PRM_DATA_BUFFER_HEADER_SIGNATURE) {\r
271 DEBUG ((DEBUG_ERROR, " %a %a: The PRM data buffer signature is invalid. PRM module.\n", _DBGMSGID_, __FUNCTION__));\r
272 return EFI_NOT_FOUND;\r
273 }\r
274 if (PrmDataBuffer->Header.Length < sizeof (PRM_DATA_BUFFER_HEADER)) {\r
275 DEBUG ((DEBUG_ERROR, " %a %a: The PRM data buffer length is invalid.\n", _DBGMSGID_, __FUNCTION__));\r
276 return EFI_BUFFER_TOO_SMALL;\r
277 }\r
278\r
279 return EFI_SUCCESS;\r
280}\r
281\r
282/**\r
283 Validates a PRM context buffer.\r
284\r
285 Verifies the buffer header signature is valid and the GUID is set to a non-zero value.\r
286\r
287 @param[in] PrmContextBuffer A pointer to the context buffer for this PRM handler.\r
288\r
289 @retval EFI_SUCCESS The context buffer was validated successfully.\r
290 @retval EFI_INVALID_PARAMETER The pointer given for ContextBuffer is NULL.\r
291 @retval EFI_NOT_FOUND The proper value for a field was not found.\r
292\r
293**/\r
294EFI_STATUS\r
295ValidatePrmContextBuffer (\r
296 IN CONST PRM_CONTEXT_BUFFER *PrmContextBuffer\r
297 )\r
298{\r
299 if (PrmContextBuffer == NULL) {\r
300 return EFI_INVALID_PARAMETER;\r
301 }\r
302\r
303 if (PrmContextBuffer->Signature != PRM_CONTEXT_BUFFER_SIGNATURE) {\r
304 DEBUG ((DEBUG_ERROR, " %a %a: The PRM context buffer signature is invalid.\n", _DBGMSGID_, __FUNCTION__));\r
305 return EFI_NOT_FOUND;\r
306 }\r
307\r
308 if (IsZeroGuid (&PrmContextBuffer->HandlerGuid)) {\r
309 DEBUG ((DEBUG_ERROR, " %a %a: The PRM context buffer GUID is zero.\n", _DBGMSGID_, __FUNCTION__));\r
310 return EFI_NOT_FOUND;\r
311 }\r
312\r
313 if (PrmContextBuffer->StaticDataBuffer != NULL && EFI_ERROR (ValidatePrmDataBuffer (PrmContextBuffer->StaticDataBuffer))) {\r
314 DEBUG ((\r
315 DEBUG_ERROR,\r
316 " %a %a: Error in static buffer for PRM handler %g.\n",\r
317 _DBGMSGID_,\r
318 __FUNCTION__,\r
319 &PrmContextBuffer->HandlerGuid\r
320 ));\r
321 return EFI_NOT_FOUND;\r
322 }\r
323\r
324 return EFI_SUCCESS;\r
325}\r
326\r
327/**\r
328 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
329\r
330 This is notification function converts any registered PRM_RUNTIME_MMIO_RANGE\r
331 addresses to a virtual address.\r
332\r
333 @param[in] Event Event whose notification function is being invoked.\r
334 @param[in] Context Pointer to the notification function's context.\r
335\r
336**/\r
337VOID\r
338EFIAPI\r
339PrmConfigVirtualAddressChangeEvent (\r
340 IN EFI_EVENT Event,\r
341 IN VOID *Context\r
342 )\r
343{\r
344 UINTN Index;\r
345\r
3f7af17c
MK
346 //\r
347 // Convert runtime MMIO ranges\r
348 //\r
349 for (Index = 0; Index < mMaxRuntimeMmioRangeCount; Index++) {\r
350 ConvertRuntimeMemoryRangeAddresses (mRuntimeMmioRanges[Index]);\r
351 }\r
352}\r
353\r
354/**\r
355 The PRM Config END_OF_DXE protocol notification event handler.\r
356\r
357 Finds all of the PRM_CONFIG_PROTOCOL instances installed at end of DXE and\r
358 marks all PRM_RUNTIME_MMIO_RANGE entries as EFI_MEMORY_RUNTIME.\r
359\r
360 @param[in] Event Event whose notification function is being invoked.\r
361 @param[in] Context The pointer to the notification function's context,\r
362 which is implementation-dependent.\r
363\r
3f7af17c 364**/\r
e10c7764 365VOID\r
3f7af17c
MK
366EFIAPI\r
367PrmConfigEndOfDxeNotification (\r
368 IN EFI_EVENT Event,\r
369 IN VOID *Context\r
370 )\r
371{\r
372 EFI_STATUS Status;\r
373 UINTN HandleCount;\r
374 UINTN BufferIndex;\r
375 UINTN HandleIndex;\r
376 EFI_HANDLE *HandleBuffer;\r
377 PRM_CONTEXT_BUFFER *CurrentContextBuffer;\r
378 PRM_CONFIG_PROTOCOL *PrmConfigProtocol;\r
379\r
380 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
381\r
382 HandleBuffer = NULL;\r
383 Status = gBS->LocateHandleBuffer (\r
384 ByProtocol,\r
385 &gPrmConfigProtocolGuid,\r
386 NULL,\r
387 &HandleCount,\r
388 &HandleBuffer\r
389 );\r
390 if (!EFI_ERROR (Status)) {\r
391 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {\r
392 Status = gBS->HandleProtocol (\r
393 HandleBuffer[HandleIndex],\r
394 &gPrmConfigProtocolGuid,\r
395 (VOID **) &PrmConfigProtocol\r
396 );\r
397 ASSERT_EFI_ERROR (Status);\r
398 if (EFI_ERROR (Status) || PrmConfigProtocol == NULL) {\r
399 continue;\r
400 }\r
401\r
402 DEBUG ((\r
403 DEBUG_INFO,\r
404 " %a %a: Found PRM configuration protocol for PRM module %g.\n",\r
405 _DBGMSGID_,\r
406 __FUNCTION__,\r
407 &PrmConfigProtocol->ModuleContextBuffers.ModuleGuid\r
408 ));\r
409\r
410 DEBUG ((DEBUG_INFO, " %a %a: Validating module context buffers...\n", _DBGMSGID_, __FUNCTION__));\r
411 for (BufferIndex = 0; BufferIndex < PrmConfigProtocol->ModuleContextBuffers.BufferCount; BufferIndex++) {\r
412 CurrentContextBuffer = &(PrmConfigProtocol->ModuleContextBuffers.Buffer[BufferIndex]);\r
413\r
414 Status = ValidatePrmContextBuffer (CurrentContextBuffer);\r
415 if (EFI_ERROR (Status)) {\r
416 DEBUG ((\r
417 DEBUG_ERROR,\r
418 " %a %a: Context buffer validation failed for PRM handler %g.\n",\r
419 _DBGMSGID_,\r
420 __FUNCTION__,\r
421 CurrentContextBuffer->HandlerGuid\r
422 ));\r
423 }\r
3f7af17c
MK
424 }\r
425 DEBUG ((DEBUG_INFO, " %a %a: Module context buffer validation complete.\n", _DBGMSGID_, __FUNCTION__));\r
426\r
427 if (PrmConfigProtocol->ModuleContextBuffers.RuntimeMmioRanges != NULL) {\r
428 DEBUG ((\r
429 DEBUG_INFO,\r
e8467976 430 " %a %a: Found %d PRM runtime MMIO ranges.\n",\r
3f7af17c
MK
431 _DBGMSGID_,\r
432 __FUNCTION__,\r
433 PrmConfigProtocol->ModuleContextBuffers.RuntimeMmioRanges->Count\r
434 ));\r
435 SetRuntimeMemoryRangeAttributes (PrmConfigProtocol->ModuleContextBuffers.RuntimeMmioRanges);\r
436 mMaxRuntimeMmioRangeCount++;\r
437 }\r
438 }\r
439\r
440 StoreVirtualMemoryAddressChangePointers ();\r
441 }\r
442\r
443 if (HandleBuffer != NULL) {\r
444 gBS->FreePool (HandleBuffer);\r
445 }\r
446 gBS->CloseEvent(Event);\r
3f7af17c
MK
447}\r
448\r
449/**\r
450 The entry point for this module.\r
451\r
452 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
453 @param[in] SystemTable A pointer to the EFI System Table.\r
454\r
455 @retval EFI_SUCCESS The entry point is executed successfully.\r
456 @retval Others An error occurred when executing this entry point.\r
457\r
458**/\r
459EFI_STATUS\r
460EFIAPI\r
461PrmConfigEntryPoint (\r
462 IN EFI_HANDLE ImageHandle,\r
463 IN EFI_SYSTEM_TABLE *SystemTable\r
464 )\r
465{\r
466 EFI_STATUS Status;\r
467 EFI_EVENT Event;\r
468\r
469 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
470\r
471 //\r
472 // Register a notification function to change memory attributes at end of DXE\r
473 //\r
474 Event = NULL;\r
e10c7764 475 Status = gBS->CreateEventEx (\r
3f7af17c
MK
476 EVT_NOTIFY_SIGNAL,\r
477 TPL_CALLBACK,\r
478 PrmConfigEndOfDxeNotification,\r
479 NULL,\r
480 &gEfiEndOfDxeEventGroupGuid,\r
481 &Event\r
482 );\r
483 ASSERT_EFI_ERROR (Status);\r
484\r
485 //\r
486 // Register a notification function for virtual address change\r
487 //\r
488 Event = NULL;\r
489 Status = gBS->CreateEventEx (\r
490 EVT_NOTIFY_SIGNAL,\r
491 TPL_NOTIFY,\r
492 PrmConfigVirtualAddressChangeEvent,\r
493 NULL,\r
494 &gEfiEventVirtualAddressChangeGuid,\r
495 &Event\r
496 );\r
497 ASSERT_EFI_ERROR (Status);\r
498\r
499 return EFI_SUCCESS;\r
500}\r