audk/PrmPkg/PrmConfigDxe/PrmConfigDxe.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

513 lines
16 KiB
C
Raw Normal View History

/** @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;
PrmPkg: Add ALLOCATE_CONTEXT_BUFFER_IN_FW build option There's currently two approaches being considered for how to allocate the context buffer passed to PRM handlers: 1. The context buffer is allocated and populated in firmware. As such, the FW converts all pointers internal to the buffer to virtual memory addresses at the virtual address change event. A single context buffer pointer is given to the OS via the PRM ACPI table and the OS converts this single physical address to a virtual address when it passes the context buffer as a pointer to PRM handlers. 2. The context buffer is allocated and populated in the OS. The OS gets all the information needed to populate the context buffer from other pre-existing resources (mainly physical addresses in the PRM ACPI table). The OS converts all the physical addresses to virtual addresses, allocates the context buffer instances, and fills in the information. The OS passes the context buffer virtual address to PRM handlers. The prior behavior was (1). The current POR behavior has moved to (2). Until (2) is used more widely, it can be kept around with fairly minimal overhead via a build flag in a few places. So the default behavior is now (2) (the expected permanent behavior) with (1) easily enabled by defining "ALLOCATE_CONTEXT_BUFFER_IN_FW" in the compiler defined macros. A DSC define was added in PrmPkg.dsc to set this compiler macro in the package build. At some point in the future, all code (and some peripheral code) surrounded with this build flag can be removed if (2) is fully decided upon. Cc: Andrew Fish <afish@apple.com> Cc: Kang Gao <kang.gao@intel.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Michael Kubacki <michael.kubacki@microsoft.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Benjamin You <benjamin.you@intel.com> Cc: Liu Yun <yun.y.liu@intel.com> Cc: Ankit Sinha <ankit.sinha@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Acked-by: Michael D Kinney <michael.d.kinney@intel.com> Acked-by: Liming Gao <gaoliming@byosoft.com.cn> Acked-by: Leif Lindholm <quic_llindhol@quicinc.com> Reviewed-by: Ankit Sinha <ankit.sinha@intel.com>
2020-04-14 01:38:19 +02:00
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_, __func__));
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_,
__func__,
Index
));
DEBUG ((
DEBUG_INFO,
" %a %a: Physical address = 0x%016x. Length = 0x%x.\n",
_DBGMSGID_,
__func__,
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_,
__func__,
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_,
__func__,
Status,
RuntimeMmioRanges->Range[Index].PhysicalBaseAddress
));
} else {
DEBUG ((DEBUG_INFO, " %a %a: Successfully set runtime attribute for the MMIO range.\n", _DBGMSGID_, __func__));
}
}
}
/**
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_, __func__));
RangeIndex = 0;
PrmPkg: Add ALLOCATE_CONTEXT_BUFFER_IN_FW build option There's currently two approaches being considered for how to allocate the context buffer passed to PRM handlers: 1. The context buffer is allocated and populated in firmware. As such, the FW converts all pointers internal to the buffer to virtual memory addresses at the virtual address change event. A single context buffer pointer is given to the OS via the PRM ACPI table and the OS converts this single physical address to a virtual address when it passes the context buffer as a pointer to PRM handlers. 2. The context buffer is allocated and populated in the OS. The OS gets all the information needed to populate the context buffer from other pre-existing resources (mainly physical addresses in the PRM ACPI table). The OS converts all the physical addresses to virtual addresses, allocates the context buffer instances, and fills in the information. The OS passes the context buffer virtual address to PRM handlers. The prior behavior was (1). The current POR behavior has moved to (2). Until (2) is used more widely, it can be kept around with fairly minimal overhead via a build flag in a few places. So the default behavior is now (2) (the expected permanent behavior) with (1) easily enabled by defining "ALLOCATE_CONTEXT_BUFFER_IN_FW" in the compiler defined macros. A DSC define was added in PrmPkg.dsc to set this compiler macro in the package build. At some point in the future, all code (and some peripheral code) surrounded with this build flag can be removed if (2) is fully decided upon. Cc: Andrew Fish <afish@apple.com> Cc: Kang Gao <kang.gao@intel.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Michael Kubacki <michael.kubacki@microsoft.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Benjamin You <benjamin.you@intel.com> Cc: Liu Yun <yun.y.liu@intel.com> Cc: Ankit Sinha <ankit.sinha@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Acked-by: Michael D Kinney <michael.d.kinney@intel.com> Acked-by: Liming Gao <gaoliming@byosoft.com.cn> Acked-by: Leif Lindholm <quic_llindhol@quicinc.com> Reviewed-by: Ankit Sinha <ankit.sinha@intel.com>
2020-04-14 01:38:19 +02:00
mRuntimeMmioRanges = AllocateRuntimeZeroPool (sizeof (*mRuntimeMmioRanges) * mMaxRuntimeMmioRangeCount);
if ((mRuntimeMmioRanges == NULL) && (mMaxRuntimeMmioRangeCount > 0)) {
DEBUG ((
DEBUG_ERROR,
PrmPkg: Add ALLOCATE_CONTEXT_BUFFER_IN_FW build option There's currently two approaches being considered for how to allocate the context buffer passed to PRM handlers: 1. The context buffer is allocated and populated in firmware. As such, the FW converts all pointers internal to the buffer to virtual memory addresses at the virtual address change event. A single context buffer pointer is given to the OS via the PRM ACPI table and the OS converts this single physical address to a virtual address when it passes the context buffer as a pointer to PRM handlers. 2. The context buffer is allocated and populated in the OS. The OS gets all the information needed to populate the context buffer from other pre-existing resources (mainly physical addresses in the PRM ACPI table). The OS converts all the physical addresses to virtual addresses, allocates the context buffer instances, and fills in the information. The OS passes the context buffer virtual address to PRM handlers. The prior behavior was (1). The current POR behavior has moved to (2). Until (2) is used more widely, it can be kept around with fairly minimal overhead via a build flag in a few places. So the default behavior is now (2) (the expected permanent behavior) with (1) easily enabled by defining "ALLOCATE_CONTEXT_BUFFER_IN_FW" in the compiler defined macros. A DSC define was added in PrmPkg.dsc to set this compiler macro in the package build. At some point in the future, all code (and some peripheral code) surrounded with this build flag can be removed if (2) is fully decided upon. Cc: Andrew Fish <afish@apple.com> Cc: Kang Gao <kang.gao@intel.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Michael Kubacki <michael.kubacki@microsoft.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Benjamin You <benjamin.you@intel.com> Cc: Liu Yun <yun.y.liu@intel.com> Cc: Ankit Sinha <ankit.sinha@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Acked-by: Michael D Kinney <michael.d.kinney@intel.com> Acked-by: Liming Gao <gaoliming@byosoft.com.cn> Acked-by: Leif Lindholm <quic_llindhol@quicinc.com> Reviewed-by: Ankit Sinha <ankit.sinha@intel.com>
2020-04-14 01:38:19 +02:00
" %a %a: Memory allocation for runtime MMIO pointer array failed.\n",
_DBGMSGID_,
__func__
));
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_,
__func__,
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_,
__func__,
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_, __func__));
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_, __func__));
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_, __func__));
return EFI_NOT_FOUND;
}
if (IsZeroGuid (&PrmContextBuffer->HandlerGuid)) {
DEBUG ((DEBUG_ERROR, " %a %a: The PRM context buffer GUID is zero.\n", _DBGMSGID_, __func__));
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_,
__func__,
&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.
**/
PrmPkg: Enforce stricter types Makes the following changes to enforce stricter types: 1. PrmPkg/PrmConfigDxe The function PrmConfigEndOfDxeNotification () is used as a notify function (of type EFI_EVENT_NOTIFY), however it has a return type of EFI_STATUS whereas the return type should actually be VOID. 2. PrmPkg/PrmLoaderDxe Updates the following types to be more accurate than were allowed in the VS compiler: * 3rd actual argument given to GetModuleContextBuffers () is explicitly marked as CONST PRM_MODULE_CONTEXT_BUFFERS ** * 3rd actual argument given to GetContextBuffer () is explicitly marked as CONST PRM_CONTEXT_BUFFER ** * PrmLoaderEndOfDxeNotification () return type is changed to VOID to align with the EFI_EVENT_NOTIFY type 3. PrmPkg/Application/PrmInfo Updates the following types to be more accurate than were allowed in the VS compiler: * SHELL_STATUS in ParseParameterList () is now EFI_STATUS * 3rd actual argument given to GetModuleContextBuffers () is explicitly marked as CONST PRM_MODULE_CONTEXT_BUFFERS ** * 3rd actual argument given to GetContextBuffer () is explicitly marked as CONST PRM_CONTEXT_BUFFER ** Cc: Andrew Fish <afish@apple.com> Cc: Kang Gao <kang.gao@intel.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Michael Kubacki <michael.kubacki@microsoft.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Benjamin You <benjamin.you@intel.com> Cc: Liu Yun <yun.y.liu@intel.com> Cc: Ankit Sinha <ankit.sinha@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Acked-by: Michael D Kinney <michael.d.kinney@intel.com> Acked-by: Liming Gao <gaoliming@byosoft.com.cn> Acked-by: Leif Lindholm <quic_llindhol@quicinc.com> Reviewed-by: Ankit Sinha <ankit.sinha@intel.com>
2020-06-16 18:32:38 +02:00
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_, __func__));
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_,
__func__,
&PrmConfigProtocol->ModuleContextBuffers.ModuleGuid
));
DEBUG ((DEBUG_INFO, " %a %a: Validating module context buffers...\n", _DBGMSGID_, __func__));
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_,
__func__,
CurrentContextBuffer->HandlerGuid
));
}
}
DEBUG ((DEBUG_INFO, " %a %a: Module context buffer validation complete.\n", _DBGMSGID_, __func__));
if (PrmConfigProtocol->ModuleContextBuffers.RuntimeMmioRanges != NULL) {
DEBUG ((
DEBUG_INFO,
PrmPkg: Add ALLOCATE_CONTEXT_BUFFER_IN_FW build option There's currently two approaches being considered for how to allocate the context buffer passed to PRM handlers: 1. The context buffer is allocated and populated in firmware. As such, the FW converts all pointers internal to the buffer to virtual memory addresses at the virtual address change event. A single context buffer pointer is given to the OS via the PRM ACPI table and the OS converts this single physical address to a virtual address when it passes the context buffer as a pointer to PRM handlers. 2. The context buffer is allocated and populated in the OS. The OS gets all the information needed to populate the context buffer from other pre-existing resources (mainly physical addresses in the PRM ACPI table). The OS converts all the physical addresses to virtual addresses, allocates the context buffer instances, and fills in the information. The OS passes the context buffer virtual address to PRM handlers. The prior behavior was (1). The current POR behavior has moved to (2). Until (2) is used more widely, it can be kept around with fairly minimal overhead via a build flag in a few places. So the default behavior is now (2) (the expected permanent behavior) with (1) easily enabled by defining "ALLOCATE_CONTEXT_BUFFER_IN_FW" in the compiler defined macros. A DSC define was added in PrmPkg.dsc to set this compiler macro in the package build. At some point in the future, all code (and some peripheral code) surrounded with this build flag can be removed if (2) is fully decided upon. Cc: Andrew Fish <afish@apple.com> Cc: Kang Gao <kang.gao@intel.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Michael Kubacki <michael.kubacki@microsoft.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Benjamin You <benjamin.you@intel.com> Cc: Liu Yun <yun.y.liu@intel.com> Cc: Ankit Sinha <ankit.sinha@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Acked-by: Michael D Kinney <michael.d.kinney@intel.com> Acked-by: Liming Gao <gaoliming@byosoft.com.cn> Acked-by: Leif Lindholm <quic_llindhol@quicinc.com> Reviewed-by: Ankit Sinha <ankit.sinha@intel.com>
2020-04-14 01:38:19 +02:00
" %a %a: Found %d PRM runtime MMIO ranges.\n",
_DBGMSGID_,
__func__,
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_, __func__));
//
// Register a notification function to change memory attributes at end of DXE
//
Event = NULL;
PrmPkg: Enforce stricter types Makes the following changes to enforce stricter types: 1. PrmPkg/PrmConfigDxe The function PrmConfigEndOfDxeNotification () is used as a notify function (of type EFI_EVENT_NOTIFY), however it has a return type of EFI_STATUS whereas the return type should actually be VOID. 2. PrmPkg/PrmLoaderDxe Updates the following types to be more accurate than were allowed in the VS compiler: * 3rd actual argument given to GetModuleContextBuffers () is explicitly marked as CONST PRM_MODULE_CONTEXT_BUFFERS ** * 3rd actual argument given to GetContextBuffer () is explicitly marked as CONST PRM_CONTEXT_BUFFER ** * PrmLoaderEndOfDxeNotification () return type is changed to VOID to align with the EFI_EVENT_NOTIFY type 3. PrmPkg/Application/PrmInfo Updates the following types to be more accurate than were allowed in the VS compiler: * SHELL_STATUS in ParseParameterList () is now EFI_STATUS * 3rd actual argument given to GetModuleContextBuffers () is explicitly marked as CONST PRM_MODULE_CONTEXT_BUFFERS ** * 3rd actual argument given to GetContextBuffer () is explicitly marked as CONST PRM_CONTEXT_BUFFER ** Cc: Andrew Fish <afish@apple.com> Cc: Kang Gao <kang.gao@intel.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Michael Kubacki <michael.kubacki@microsoft.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Benjamin You <benjamin.you@intel.com> Cc: Liu Yun <yun.y.liu@intel.com> Cc: Ankit Sinha <ankit.sinha@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Acked-by: Michael D Kinney <michael.d.kinney@intel.com> Acked-by: Liming Gao <gaoliming@byosoft.com.cn> Acked-by: Leif Lindholm <quic_llindhol@quicinc.com> Reviewed-by: Ankit Sinha <ankit.sinha@intel.com>
2020-06-16 18:32:38 +02:00
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;
}