/** @file | |
Instance of MM memory check library. | |
MM memory check library implementation. This library consumes MM_ACCESS_PROTOCOL | |
to get MMRAM information. In order to use this library instance, the platform should produce | |
all MMRAM range via MM_ACCESS_PROTOCOL, including the range for firmware (like MM Core | |
and MM driver) and/or specific dedicated hardware. | |
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> | |
Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <PiMm.h> | |
#include <Library/BaseLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/DebugLib.h> | |
EFI_MMRAM_DESCRIPTOR *mMmMemLibInternalMmramRanges; | |
UINTN mMmMemLibInternalMmramCount; | |
// | |
// Maximum support address used to check input buffer | |
// | |
EFI_PHYSICAL_ADDRESS mMmMemLibInternalMaximumSupportAddress = 0; | |
/** | |
Calculate and save the maximum support address. | |
**/ | |
VOID | |
MmMemLibInternalCalculateMaximumSupportAddress ( | |
VOID | |
); | |
/** | |
Initialize cached Mmram Ranges from HOB. | |
@retval EFI_UNSUPPORTED The routine is unable to extract MMRAM information. | |
@retval EFI_SUCCESS MmRanges are populated successfully. | |
**/ | |
EFI_STATUS | |
MmMemLibInternalPopulateMmramRanges ( | |
VOID | |
); | |
/** | |
Deinitialize cached Mmram Ranges. | |
**/ | |
VOID | |
MmMemLibInternalFreeMmramRanges ( | |
VOID | |
); | |
/** | |
This function check if the buffer is valid per processor architecture and not overlap with MMRAM. | |
@param Buffer The buffer start address to be checked. | |
@param Length The buffer length to be checked. | |
@retval TRUE This buffer is valid per processor architecture and not overlap with MMRAM. | |
@retval FALSE This buffer is not valid per processor architecture or overlap with MMRAM. | |
**/ | |
BOOLEAN | |
EFIAPI | |
MmIsBufferOutsideMmValid ( | |
IN EFI_PHYSICAL_ADDRESS Buffer, | |
IN UINT64 Length | |
) | |
{ | |
UINTN Index; | |
// | |
// Check override. | |
// NOTE: (B:0->L:4G) is invalid for IA32, but (B:1->L:4G-1)/(B:4G-1->L:1) is valid. | |
// | |
if ((Length > mMmMemLibInternalMaximumSupportAddress) || | |
(Buffer > mMmMemLibInternalMaximumSupportAddress) || | |
((Length != 0) && (Buffer > (mMmMemLibInternalMaximumSupportAddress - (Length - 1))))) | |
{ | |
// | |
// Overflow happen | |
// | |
DEBUG (( | |
DEBUG_ERROR, | |
"MmIsBufferOutsideMmValid: Overflow: Buffer (0x%lx) - Length (0x%lx), MaximumSupportAddress (0x%lx)\n", | |
Buffer, | |
Length, | |
mMmMemLibInternalMaximumSupportAddress | |
)); | |
return FALSE; | |
} | |
for (Index = 0; Index < mMmMemLibInternalMmramCount; Index++) { | |
if (((Buffer >= mMmMemLibInternalMmramRanges[Index].CpuStart) && | |
(Buffer < mMmMemLibInternalMmramRanges[Index].CpuStart + mMmMemLibInternalMmramRanges[Index].PhysicalSize)) || | |
((mMmMemLibInternalMmramRanges[Index].CpuStart >= Buffer) && | |
(mMmMemLibInternalMmramRanges[Index].CpuStart < Buffer + Length))) | |
{ | |
DEBUG (( | |
DEBUG_ERROR, | |
"MmIsBufferOutsideMmValid: Overlap: Buffer (0x%lx) - Length (0x%lx), ", | |
Buffer, | |
Length | |
)); | |
DEBUG (( | |
DEBUG_ERROR, | |
"CpuStart (0x%lx) - PhysicalSize (0x%lx)\n", | |
mMmMemLibInternalMmramRanges[Index].CpuStart, | |
mMmMemLibInternalMmramRanges[Index].PhysicalSize | |
)); | |
return FALSE; | |
} | |
} | |
return TRUE; | |
} | |
/** | |
Copies a source buffer (non-MMRAM) to a destination buffer (MMRAM). | |
This function copies a source buffer (non-MMRAM) to a destination buffer (MMRAM). | |
It checks if source buffer is valid per processor architecture and not overlap with MMRAM. | |
If the check passes, it copies memory and returns EFI_SUCCESS. | |
If the check fails, it return EFI_SECURITY_VIOLATION. | |
The implementation must be reentrant. | |
@param DestinationBuffer The pointer to the destination buffer of the memory copy. | |
@param SourceBuffer The pointer to the source buffer of the memory copy. | |
@param Length The number of bytes to copy from SourceBuffer to DestinationBuffer. | |
@retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with MMRAM. | |
@retval EFI_SUCCESS Memory is copied. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
MmCopyMemToMmram ( | |
OUT VOID *DestinationBuffer, | |
IN CONST VOID *SourceBuffer, | |
IN UINTN Length | |
) | |
{ | |
if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) { | |
DEBUG ((DEBUG_ERROR, "MmCopyMemToMmram: Security Violation: Source (0x%x), Length (0x%x)\n", SourceBuffer, Length)); | |
return EFI_SECURITY_VIOLATION; | |
} | |
CopyMem (DestinationBuffer, SourceBuffer, Length); | |
return EFI_SUCCESS; | |
} | |
/** | |
Copies a source buffer (MMRAM) to a destination buffer (NON-MMRAM). | |
This function copies a source buffer (non-MMRAM) to a destination buffer (MMRAM). | |
It checks if destination buffer is valid per processor architecture and not overlap with MMRAM. | |
If the check passes, it copies memory and returns EFI_SUCCESS. | |
If the check fails, it returns EFI_SECURITY_VIOLATION. | |
The implementation must be reentrant. | |
@param DestinationBuffer The pointer to the destination buffer of the memory copy. | |
@param SourceBuffer The pointer to the source buffer of the memory copy. | |
@param Length The number of bytes to copy from SourceBuffer to DestinationBuffer. | |
@retval EFI_SECURITY_VIOLATION The DestinationBuffer is invalid per processor architecture or overlap with MMRAM. | |
@retval EFI_SUCCESS Memory is copied. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
MmCopyMemFromMmram ( | |
OUT VOID *DestinationBuffer, | |
IN CONST VOID *SourceBuffer, | |
IN UINTN Length | |
) | |
{ | |
if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"MmCopyMemFromMmram: Security Violation: Destination (0x%x), Length (0x%x)\n", | |
DestinationBuffer, | |
Length | |
)); | |
return EFI_SECURITY_VIOLATION; | |
} | |
CopyMem (DestinationBuffer, SourceBuffer, Length); | |
return EFI_SUCCESS; | |
} | |
/** | |
Copies a source buffer (NON-MMRAM) to a destination buffer (NON-MMRAM). | |
This function copies a source buffer (non-MMRAM) to a destination buffer (MMRAM). | |
It checks if source buffer and destination buffer are valid per processor architecture and not overlap with MMRAM. | |
If the check passes, it copies memory and returns EFI_SUCCESS. | |
If the check fails, it returns EFI_SECURITY_VIOLATION. | |
The implementation must be reentrant, and it must handle the case where source buffer overlaps destination buffer. | |
@param DestinationBuffer The pointer to the destination buffer of the memory copy. | |
@param SourceBuffer The pointer to the source buffer of the memory copy. | |
@param Length The number of bytes to copy from SourceBuffer to DestinationBuffer. | |
@retval EFI_SECURITY_VIOLATION The DestinationBuffer is invalid per processor architecture or overlap with MMRAM. | |
@retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with MMRAM. | |
@retval EFI_SUCCESS Memory is copied. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
MmCopyMem ( | |
OUT VOID *DestinationBuffer, | |
IN CONST VOID *SourceBuffer, | |
IN UINTN Length | |
) | |
{ | |
if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"MmCopyMem: Security Violation: Destination (0x%x), Length (0x%x)\n", | |
DestinationBuffer, | |
Length | |
)); | |
return EFI_SECURITY_VIOLATION; | |
} | |
if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) { | |
DEBUG ((DEBUG_ERROR, "MmCopyMem: Security Violation: Source (0x%x), Length (0x%x)\n", SourceBuffer, Length)); | |
return EFI_SECURITY_VIOLATION; | |
} | |
CopyMem (DestinationBuffer, SourceBuffer, Length); | |
return EFI_SUCCESS; | |
} | |
/** | |
Fills a target buffer (NON-MMRAM) with a byte value. | |
This function fills a target buffer (non-MMRAM) with a byte value. | |
It checks if target buffer is valid per processor architecture and not overlap with MMRAM. | |
If the check passes, it fills memory and returns EFI_SUCCESS. | |
If the check fails, it returns EFI_SECURITY_VIOLATION. | |
@param Buffer The memory to set. | |
@param Length The number of bytes to set. | |
@param Value The value with which to fill Length bytes of Buffer. | |
@retval EFI_SECURITY_VIOLATION The Buffer is invalid per processor architecture or overlap with MMRAM. | |
@retval EFI_SUCCESS Memory is set. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
MmSetMem ( | |
OUT VOID *Buffer, | |
IN UINTN Length, | |
IN UINT8 Value | |
) | |
{ | |
if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, Length)) { | |
DEBUG ((DEBUG_ERROR, "MmSetMem: Security Violation: Source (0x%x), Length (0x%x)\n", Buffer, Length)); | |
return EFI_SECURITY_VIOLATION; | |
} | |
SetMem (Buffer, Length, Value); | |
return EFI_SUCCESS; | |
} | |
/** | |
The constructor function initializes the Mm Mem library | |
@param [in] ImageHandle The firmware allocated handle for the EFI image. | |
@param [in] MmSystemTable A pointer to the EFI System Table. | |
@retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
MemLibConstructor ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_MM_SYSTEM_TABLE *MmSystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Calculate and save maximum support address | |
// | |
MmMemLibInternalCalculateMaximumSupportAddress (); | |
// | |
// Initialize cached Mmram Ranges from HOB. | |
// | |
Status = MmMemLibInternalPopulateMmramRanges (); | |
return Status; | |
} | |
/** | |
Destructor for Mm Mem library. | |
@param ImageHandle The image handle of the process. | |
@param MmSystemTable The EFI System Table pointer. | |
@retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
MemLibDestructor ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_MM_SYSTEM_TABLE *MmSystemTable | |
) | |
{ | |
// | |
// Deinitialize cached Mmram Ranges. | |
// | |
MmMemLibInternalFreeMmramRanges (); | |
return EFI_SUCCESS; | |
} |