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