123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 |
- /** @file
- This file contains the implementation for a Platform Runtime Mechanism (PRM) configuration driver.
- Copyright (c) Microsoft Corporation
- Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <Library/BaseLib.h>
- #include <Library/BaseMemoryLib.h>
- #include <Library/DebugLib.h>
- #include <Library/DxeServicesTableLib.h>
- #include <Library/MemoryAllocationLib.h>
- #include <Library/UefiBootServicesTableLib.h>
- #include <Library/UefiRuntimeServicesTableLib.h>
- #include <Library/UefiLib.h>
- #include <PiDxe.h>
- #include <PrmContextBuffer.h>
- #include <PrmDataBuffer.h>
- #include <PrmMmio.h>
- #include <Protocol/PrmConfig.h>
- #define _DBGMSGID_ "[PRMCONFIG]"
- STATIC UINTN mMaxRuntimeMmioRangeCount;
- GLOBAL_REMOVE_IF_UNREFERENCED STATIC PRM_RUNTIME_MMIO_RANGES **mRuntimeMmioRanges;
- /**
- Converts the runtime memory range physical addresses to virtual addresses.
- @param[in] RuntimeMmioRanges A pointer to a PRM_RUNTIME_MMIO_RANGES buffer.
- **/
- VOID
- ConvertRuntimeMemoryRangeAddresses (
- IN PRM_RUNTIME_MMIO_RANGES *RuntimeMmioRanges
- )
- {
- UINTN Index;
- if ((RuntimeMmioRanges == NULL) || (RuntimeMmioRanges->Count == 0)) {
- return;
- }
- for (Index = 0; Index < (UINTN)RuntimeMmioRanges->Count; Index++) {
- RuntimeMmioRanges->Range[Index].VirtualBaseAddress = RuntimeMmioRanges->Range[Index].PhysicalBaseAddress;
- gRT->ConvertPointer (0x0, (VOID **)&(RuntimeMmioRanges->Range[Index].VirtualBaseAddress));
- }
- }
- /**
- Sets the runtime memory range attributes.
- The EFI_MEMORY_RUNTIME attribute is set for each PRM_RUNTIME_MMIO_RANGE present
- in the buffer provided.
- @param[in] RuntimeMmioRanges A pointer to a PRM_RUNTIME_MMIO_RANGES buffer.
- **/
- VOID
- SetRuntimeMemoryRangeAttributes (
- IN PRM_RUNTIME_MMIO_RANGES *RuntimeMmioRanges
- )
- {
- EFI_STATUS Status;
- EFI_STATUS Status2;
- UINTN Index;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
- DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));
- if ((RuntimeMmioRanges == NULL) || (RuntimeMmioRanges->Count == 0)) {
- return;
- }
- for (Index = 0; Index < (UINTN)RuntimeMmioRanges->Count; Index++) {
- DEBUG ((
- DEBUG_INFO,
- " %a %a: Runtime MMIO Range [%d].\n",
- _DBGMSGID_,
- __FUNCTION__,
- Index
- ));
- DEBUG ((
- DEBUG_INFO,
- " %a %a: Physical address = 0x%016x. Length = 0x%x.\n",
- _DBGMSGID_,
- __FUNCTION__,
- RuntimeMmioRanges->Range[Index].PhysicalBaseAddress,
- RuntimeMmioRanges->Range[Index].Length
- ));
- // Runtime memory ranges should cover ranges on a page boundary
- ASSERT ((RuntimeMmioRanges->Range[Index].PhysicalBaseAddress & EFI_PAGE_MASK) == 0);
- ASSERT ((RuntimeMmioRanges->Range[Index].Length & EFI_PAGE_MASK) == 0);
- Status2 = EFI_NOT_FOUND;
- Status = gDS->GetMemorySpaceDescriptor (RuntimeMmioRanges->Range[Index].PhysicalBaseAddress, &Descriptor);
- if (!EFI_ERROR (Status) &&
- (
- ((Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) && (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved)) ||
- ((Descriptor.Length & EFI_PAGE_MASK) != 0)
- )
- )
- {
- Status2 = gDS->RemoveMemorySpace (
- RuntimeMmioRanges->Range[Index].PhysicalBaseAddress,
- Descriptor.Length
- );
- }
- if ((Status == EFI_NOT_FOUND) || !EFI_ERROR (Status2)) {
- Status = gDS->AddMemorySpace (
- EfiGcdMemoryTypeMemoryMappedIo,
- RuntimeMmioRanges->Range[Index].PhysicalBaseAddress,
- (UINT64)RuntimeMmioRanges->Range[Index].Length,
- EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
- );
- ASSERT_EFI_ERROR (Status);
- Status = gDS->AllocateMemorySpace (
- EfiGcdAllocateAddress,
- EfiGcdMemoryTypeMemoryMappedIo,
- 0,
- (UINT64)RuntimeMmioRanges->Range[Index].Length,
- &RuntimeMmioRanges->Range[Index].PhysicalBaseAddress,
- gImageHandle,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
- }
- Status = gDS->GetMemorySpaceDescriptor (RuntimeMmioRanges->Range[Index].PhysicalBaseAddress, &Descriptor);
- ASSERT_EFI_ERROR (Status);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- " %a %a: Error [%r] finding descriptor for runtime memory range 0x%016x.\n",
- _DBGMSGID_,
- __FUNCTION__,
- Status,
- RuntimeMmioRanges->Range[Index].PhysicalBaseAddress
- ));
- continue;
- }
- if ((Descriptor.Attributes & EFI_MEMORY_RUNTIME) != 0) {
- continue;
- }
- Status = gDS->SetMemorySpaceAttributes (
- RuntimeMmioRanges->Range[Index].PhysicalBaseAddress,
- (UINT64)RuntimeMmioRanges->Range[Index].Length,
- Descriptor.Attributes | EFI_MEMORY_RUNTIME
- );
- ASSERT_EFI_ERROR (Status);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- " %a %a: Error [%r] setting descriptor for runtime memory range 0x%016x.\n",
- _DBGMSGID_,
- __FUNCTION__,
- Status,
- RuntimeMmioRanges->Range[Index].PhysicalBaseAddress
- ));
- } else {
- DEBUG ((DEBUG_INFO, " %a %a: Successfully set runtime attribute for the MMIO range.\n", _DBGMSGID_, __FUNCTION__));
- }
- }
- }
- /**
- Stores pointers or pointer to resources that should be converted in the virtual address change event.
- **/
- VOID
- StoreVirtualMemoryAddressChangePointers (
- VOID
- )
- {
- EFI_STATUS Status;
- UINTN HandleCount;
- UINTN HandleIndex;
- UINTN RangeIndex;
- EFI_HANDLE *HandleBuffer;
- PRM_CONFIG_PROTOCOL *PrmConfigProtocol;
- DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));
- RangeIndex = 0;
- mRuntimeMmioRanges = AllocateRuntimeZeroPool (sizeof (*mRuntimeMmioRanges) * mMaxRuntimeMmioRangeCount);
- if ((mRuntimeMmioRanges == NULL) && (mMaxRuntimeMmioRangeCount > 0)) {
- DEBUG ((
- DEBUG_ERROR,
- " %a %a: Memory allocation for runtime MMIO pointer array failed.\n",
- _DBGMSGID_,
- __FUNCTION__
- ));
- ASSERT (FALSE);
- return;
- }
- HandleBuffer = NULL;
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gPrmConfigProtocolGuid,
- NULL,
- &HandleCount,
- &HandleBuffer
- );
- if (!EFI_ERROR (Status)) {
- for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
- Status = gBS->HandleProtocol (
- HandleBuffer[HandleIndex],
- &gPrmConfigProtocolGuid,
- (VOID **)&PrmConfigProtocol
- );
- ASSERT_EFI_ERROR (Status);
- if (EFI_ERROR (Status) || (PrmConfigProtocol == NULL)) {
- continue;
- }
- if (PrmConfigProtocol->ModuleContextBuffers.RuntimeMmioRanges != NULL) {
- if (RangeIndex >= mMaxRuntimeMmioRangeCount) {
- Status = EFI_BUFFER_TOO_SMALL;
- DEBUG ((
- DEBUG_ERROR,
- " %a %a: Index out of bounds - Actual count (%d) of runtime MMIO ranges exceeds maximum count (%d).\n",
- _DBGMSGID_,
- __FUNCTION__,
- RangeIndex + 1,
- mMaxRuntimeMmioRangeCount
- ));
- ASSERT_EFI_ERROR (Status);
- return;
- }
- mRuntimeMmioRanges[RangeIndex++] = PrmConfigProtocol->ModuleContextBuffers.RuntimeMmioRanges;
- }
- }
- DEBUG ((
- DEBUG_INFO,
- " %a %a: %d MMIO ranges buffers saved for future virtual memory conversion.\n",
- _DBGMSGID_,
- __FUNCTION__,
- RangeIndex
- ));
- }
- }
- /**
- Validates a data buffer for a PRM module.
- Verifies the buffer header signature is valid and the length meets the minimum size.
- @param[in] PrmDataBuffer A pointer to the data buffer for this PRM module.
- @retval EFI_SUCCESS The data buffer was validated successfully.
- @retval EFI_INVALID_PARAMETER The pointer given for PrmDataBuffer is NULL.
- @retval EFI_NOT_FOUND The data buffer signature is not valid.
- @retval EFI_BUFFER_TOO_SMALL The buffer size is too small.
- **/
- EFI_STATUS
- ValidatePrmDataBuffer (
- IN CONST PRM_DATA_BUFFER *PrmDataBuffer
- )
- {
- if (PrmDataBuffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- if (PrmDataBuffer->Header.Signature != PRM_DATA_BUFFER_HEADER_SIGNATURE) {
- DEBUG ((DEBUG_ERROR, " %a %a: The PRM data buffer signature is invalid. PRM module.\n", _DBGMSGID_, __FUNCTION__));
- return EFI_NOT_FOUND;
- }
- if (PrmDataBuffer->Header.Length < sizeof (PRM_DATA_BUFFER_HEADER)) {
- DEBUG ((DEBUG_ERROR, " %a %a: The PRM data buffer length is invalid.\n", _DBGMSGID_, __FUNCTION__));
- return EFI_BUFFER_TOO_SMALL;
- }
- return EFI_SUCCESS;
- }
- /**
- Validates a PRM context buffer.
- Verifies the buffer header signature is valid and the GUID is set to a non-zero value.
- @param[in] PrmContextBuffer A pointer to the context buffer for this PRM handler.
- @retval EFI_SUCCESS The context buffer was validated successfully.
- @retval EFI_INVALID_PARAMETER The pointer given for ContextBuffer is NULL.
- @retval EFI_NOT_FOUND The proper value for a field was not found.
- **/
- EFI_STATUS
- ValidatePrmContextBuffer (
- IN CONST PRM_CONTEXT_BUFFER *PrmContextBuffer
- )
- {
- if (PrmContextBuffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- if (PrmContextBuffer->Signature != PRM_CONTEXT_BUFFER_SIGNATURE) {
- DEBUG ((DEBUG_ERROR, " %a %a: The PRM context buffer signature is invalid.\n", _DBGMSGID_, __FUNCTION__));
- return EFI_NOT_FOUND;
- }
- if (IsZeroGuid (&PrmContextBuffer->HandlerGuid)) {
- DEBUG ((DEBUG_ERROR, " %a %a: The PRM context buffer GUID is zero.\n", _DBGMSGID_, __FUNCTION__));
- return EFI_NOT_FOUND;
- }
- if ((PrmContextBuffer->StaticDataBuffer != NULL) && EFI_ERROR (ValidatePrmDataBuffer (PrmContextBuffer->StaticDataBuffer))) {
- DEBUG ((
- DEBUG_ERROR,
- " %a %a: Error in static buffer for PRM handler %g.\n",
- _DBGMSGID_,
- __FUNCTION__,
- &PrmContextBuffer->HandlerGuid
- ));
- return EFI_NOT_FOUND;
- }
- return EFI_SUCCESS;
- }
- /**
- Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
- This is notification function converts any registered PRM_RUNTIME_MMIO_RANGE
- addresses to a virtual address.
- @param[in] Event Event whose notification function is being invoked.
- @param[in] Context Pointer to the notification function's context.
- **/
- VOID
- EFIAPI
- PrmConfigVirtualAddressChangeEvent (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- UINTN Index;
- //
- // Convert runtime MMIO ranges
- //
- for (Index = 0; Index < mMaxRuntimeMmioRangeCount; Index++) {
- ConvertRuntimeMemoryRangeAddresses (mRuntimeMmioRanges[Index]);
- }
- }
- /**
- The PRM Config END_OF_DXE protocol notification event handler.
- Finds all of the PRM_CONFIG_PROTOCOL instances installed at end of DXE and
- marks all PRM_RUNTIME_MMIO_RANGE entries as EFI_MEMORY_RUNTIME.
- @param[in] Event Event whose notification function is being invoked.
- @param[in] Context The pointer to the notification function's context,
- which is implementation-dependent.
- **/
- VOID
- EFIAPI
- PrmConfigEndOfDxeNotification (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- EFI_STATUS Status;
- UINTN HandleCount;
- UINTN BufferIndex;
- UINTN HandleIndex;
- EFI_HANDLE *HandleBuffer;
- PRM_CONTEXT_BUFFER *CurrentContextBuffer;
- PRM_CONFIG_PROTOCOL *PrmConfigProtocol;
- DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));
- HandleBuffer = NULL;
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gPrmConfigProtocolGuid,
- NULL,
- &HandleCount,
- &HandleBuffer
- );
- if (!EFI_ERROR (Status)) {
- for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
- Status = gBS->HandleProtocol (
- HandleBuffer[HandleIndex],
- &gPrmConfigProtocolGuid,
- (VOID **)&PrmConfigProtocol
- );
- ASSERT_EFI_ERROR (Status);
- if (EFI_ERROR (Status) || (PrmConfigProtocol == NULL)) {
- continue;
- }
- DEBUG ((
- DEBUG_INFO,
- " %a %a: Found PRM configuration protocol for PRM module %g.\n",
- _DBGMSGID_,
- __FUNCTION__,
- &PrmConfigProtocol->ModuleContextBuffers.ModuleGuid
- ));
- DEBUG ((DEBUG_INFO, " %a %a: Validating module context buffers...\n", _DBGMSGID_, __FUNCTION__));
- for (BufferIndex = 0; BufferIndex < PrmConfigProtocol->ModuleContextBuffers.BufferCount; BufferIndex++) {
- CurrentContextBuffer = &(PrmConfigProtocol->ModuleContextBuffers.Buffer[BufferIndex]);
- Status = ValidatePrmContextBuffer (CurrentContextBuffer);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- " %a %a: Context buffer validation failed for PRM handler %g.\n",
- _DBGMSGID_,
- __FUNCTION__,
- CurrentContextBuffer->HandlerGuid
- ));
- }
- }
- DEBUG ((DEBUG_INFO, " %a %a: Module context buffer validation complete.\n", _DBGMSGID_, __FUNCTION__));
- if (PrmConfigProtocol->ModuleContextBuffers.RuntimeMmioRanges != NULL) {
- DEBUG ((
- DEBUG_INFO,
- " %a %a: Found %d PRM runtime MMIO ranges.\n",
- _DBGMSGID_,
- __FUNCTION__,
- PrmConfigProtocol->ModuleContextBuffers.RuntimeMmioRanges->Count
- ));
- SetRuntimeMemoryRangeAttributes (PrmConfigProtocol->ModuleContextBuffers.RuntimeMmioRanges);
- mMaxRuntimeMmioRangeCount++;
- }
- }
- StoreVirtualMemoryAddressChangePointers ();
- }
- if (HandleBuffer != NULL) {
- gBS->FreePool (HandleBuffer);
- }
- gBS->CloseEvent (Event);
- }
- /**
- The entry point for this module.
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
- @retval EFI_SUCCESS The entry point is executed successfully.
- @retval Others An error occurred when executing this entry point.
- **/
- EFI_STATUS
- EFIAPI
- PrmConfigEntryPoint (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- EFI_STATUS Status;
- EFI_EVENT Event;
- DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));
- //
- // Register a notification function to change memory attributes at end of DXE
- //
- Event = NULL;
- Status = gBS->CreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- PrmConfigEndOfDxeNotification,
- NULL,
- &gEfiEndOfDxeEventGroupGuid,
- &Event
- );
- ASSERT_EFI_ERROR (Status);
- //
- // Register a notification function for virtual address change
- //
- Event = NULL;
- Status = gBS->CreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- PrmConfigVirtualAddressChangeEvent,
- NULL,
- &gEfiEventVirtualAddressChangeGuid,
- &Event
- );
- ASSERT_EFI_ERROR (Status);
- return EFI_SUCCESS;
- }
|