From: Yao, Jiewen Date: Mon, 2 Feb 2015 14:40:44 +0000 (+0000) Subject: Add SmmMemLib, which can be used by SMM driver or SMM core to check communication... X-Git-Tag: edk2-stable201903~10378 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=d425764e3f55f949e17daa42aaf0b8c2c2ad4046 Add SmmMemLib, which can be used by SMM driver or SMM core to check communication buffer. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Gao, Liming" Reviewed-by: "Fan, Jeff" git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16693 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/MdePkg/Include/Library/SmmMemLib.h b/MdePkg/Include/Library/SmmMemLib.h new file mode 100644 index 0000000000..5186fd5d44 --- /dev/null +++ b/MdePkg/Include/Library/SmmMemLib.h @@ -0,0 +1,138 @@ +/** @file + Provides services for SMM Memory Operation. + + The SMM Mem Library provides function for checking if buffer is outside SMRAM and valid. + It also provides functions for copy data from SMRAM to non-SMRAM, from non-SMRAM to SMRAM, + from non-SMRAM to non-SMRAM, or set data in non-SMRAM. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _SMM_MEM_LIB_H_ +#define _SMM_MEM_LIB_H_ + +/** + This function check if the buffer is valid per processor architecture and not overlap with SMRAM. + + @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 SMRAM. + @retval FALSE This buffer is not valid per processor architecture or overlap with SMRAM. +**/ +BOOLEAN +EFIAPI +SmmIsBufferOutsideSmmValid ( + IN EFI_PHYSICAL_ADDRESS Buffer, + IN UINT64 Length + ); + +/** + Copies a source buffer (non-SMRAM) to a destination buffer (SMRAM). + + This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM). + It checks if source buffer is valid per processor architecture and not overlap with SMRAM. + 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 SMRAM. + @retval EFI_SUCCESS Memory is copied. + +**/ +EFI_STATUS +EFIAPI +SmmCopyMemToSmram ( + OUT VOID *DestinationBuffer, + IN CONST VOID *SourceBuffer, + IN UINTN Length + ); + +/** + Copies a source buffer (SMRAM) to a destination buffer (NON-SMRAM). + + This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM). + It checks if destination buffer is valid per processor architecture and not overlap with SMRAM. + 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 DesinationBuffer is invalid per processor architecture or overlap with SMRAM. + @retval EFI_SUCCESS Memory is copied. + +**/ +EFI_STATUS +EFIAPI +SmmCopyMemFromSmram ( + OUT VOID *DestinationBuffer, + IN CONST VOID *SourceBuffer, + IN UINTN Length + ); + +/** + Copies a source buffer (NON-SMRAM) to a destination buffer (NON-SMRAM). + + This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM). + It checks if source buffer and destination buffer are valid per processor architecture and not overlap with SMRAM. + 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 DesinationBuffer is invalid per processor architecture or overlap with SMRAM. + @retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with SMRAM. + @retval EFI_SUCCESS Memory is copied. + +**/ +EFI_STATUS +EFIAPI +SmmCopyMem ( + OUT VOID *DestinationBuffer, + IN CONST VOID *SourceBuffer, + IN UINTN Length + ); + +/** + Fills a target buffer (NON-SMRAM) with a byte value. + + This function fills a target buffer (non-SMRAM) with a byte value. + It checks if target buffer is valid per processor architecture and not overlap with SMRAM. + 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 SMRAM. + @retval EFI_SUCCESS Memory is set. + +**/ +EFI_STATUS +EFIAPI +SmmSetMem ( + OUT VOID *Buffer, + IN UINTN Length, + IN UINT8 Value + ); + +#endif \ No newline at end of file diff --git a/MdePkg/Library/SmmMemLib/SmmMemLib.c b/MdePkg/Library/SmmMemLib/SmmMemLib.c new file mode 100644 index 0000000000..21f67d219d --- /dev/null +++ b/MdePkg/Library/SmmMemLib/SmmMemLib.c @@ -0,0 +1,343 @@ +/** @file + Instance of SMM memory check library. + + SMM memory check library library implementation. This library consumes SMM_ACCESS2_PROTOCOL + to get SMRAM information. In order to use this library instance, the platform should produce + all SMRAM range via SMM_ACCESS2_PROTOCOL, including the range for firmware (like SMM Core + and SMM driver) and/or specific dedicated hardware. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +EFI_SMRAM_DESCRIPTOR *mSmmMemLibInternalSmramRanges; +UINTN mSmmMemLibInternalSmramCount; + +// +// Maximum support address used to check input buffer +// +EFI_PHYSICAL_ADDRESS mSmmMemLibInternalMaximumSupportAddress = 0; + +/** + Caculate and save the maximum support address. + +**/ +VOID +SmmMemLibInternalCaculateMaximumSupportAddress ( + VOID + ) +{ + VOID *Hob; + UINT32 RegEax; + UINT8 PhysicalAddressBits; + + // + // Get physical address bits supported. + // + Hob = GetFirstHob (EFI_HOB_TYPE_CPU); + if (Hob != NULL) { + PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace; + } else { + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000008) { + AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); + PhysicalAddressBits = (UINT8) RegEax; + } else { + PhysicalAddressBits = 36; + } + } + // + // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses. + // + ASSERT (PhysicalAddressBits <= 52); + if (PhysicalAddressBits > 48) { + PhysicalAddressBits = 48; + } + + // + // Save the maximum support address in one global variable + // + mSmmMemLibInternalMaximumSupportAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, PhysicalAddressBits) - 1); + DEBUG ((EFI_D_INFO, "mSmmMemLibInternalMaximumSupportAddress = 0x%lx\n", mSmmMemLibInternalMaximumSupportAddress)); +} + +/** + This function check if the buffer is valid per processor architecture and not overlap with SMRAM. + + @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 SMRAM. + @retval FALSE This buffer is not valid per processor architecture or overlap with SMRAM. +**/ +BOOLEAN +EFIAPI +SmmIsBufferOutsideSmmValid ( + 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 > mSmmMemLibInternalMaximumSupportAddress) || + (Buffer > mSmmMemLibInternalMaximumSupportAddress) || + ((Length != 0) && (Buffer > (mSmmMemLibInternalMaximumSupportAddress - (Length - 1)))) ) { + // + // Overflow happen + // + DEBUG (( + EFI_D_ERROR, + "SmmIsBufferOutsideSmmValid: Overflow: Buffer (0x%lx) - Length (0x%lx), MaximumSupportAddress (0x%lx)\n", + Buffer, + Length, + mSmmMemLibInternalMaximumSupportAddress + )); + return FALSE; + } + + for (Index = 0; Index < mSmmMemLibInternalSmramCount; Index ++) { + if (((Buffer >= mSmmMemLibInternalSmramRanges[Index].CpuStart) && (Buffer < mSmmMemLibInternalSmramRanges[Index].CpuStart + mSmmMemLibInternalSmramRanges[Index].PhysicalSize)) || + ((mSmmMemLibInternalSmramRanges[Index].CpuStart >= Buffer) && (mSmmMemLibInternalSmramRanges[Index].CpuStart < Buffer + Length))) { + DEBUG (( + EFI_D_ERROR, + "SmmIsBufferOutsideSmmValid: Overlap: Buffer (0x%lx) - Length (0x%lx), ", + Buffer, + Length + )); + DEBUG (( + EFI_D_ERROR, + "CpuStart (0x%lx) - PhysicalSize (0x%lx)\n", + mSmmMemLibInternalSmramRanges[Index].CpuStart, + mSmmMemLibInternalSmramRanges[Index].PhysicalSize + )); + return FALSE; + } + } + + return TRUE; +} + +/** + Copies a source buffer (non-SMRAM) to a destination buffer (SMRAM). + + This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM). + It checks if source buffer is valid per processor architecture and not overlap with SMRAM. + 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 SMRAM. + @retval EFI_SUCCESS Memory is copied. + +**/ +EFI_STATUS +EFIAPI +SmmCopyMemToSmram ( + OUT VOID *DestinationBuffer, + IN CONST VOID *SourceBuffer, + IN UINTN Length + ) +{ + if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) { + DEBUG ((EFI_D_ERROR, "SmmCopyMemToSmram: 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 (SMRAM) to a destination buffer (NON-SMRAM). + + This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM). + It checks if destination buffer is valid per processor architecture and not overlap with SMRAM. + 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 DesinationBuffer is invalid per processor architecture or overlap with SMRAM. + @retval EFI_SUCCESS Memory is copied. + +**/ +EFI_STATUS +EFIAPI +SmmCopyMemFromSmram ( + OUT VOID *DestinationBuffer, + IN CONST VOID *SourceBuffer, + IN UINTN Length + ) +{ + if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) { + DEBUG ((EFI_D_ERROR, "SmmCopyMemFromSmram: 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-SMRAM) to a destination buffer (NON-SMRAM). + + This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM). + It checks if source buffer and destination buffer are valid per processor architecture and not overlap with SMRAM. + 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 DesinationBuffer is invalid per processor architecture or overlap with SMRAM. + @retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with SMRAM. + @retval EFI_SUCCESS Memory is copied. + +**/ +EFI_STATUS +EFIAPI +SmmCopyMem ( + OUT VOID *DestinationBuffer, + IN CONST VOID *SourceBuffer, + IN UINTN Length + ) +{ + if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) { + DEBUG ((EFI_D_ERROR, "SmmCopyMem: Security Violation: Destination (0x%x), Length (0x%x)\n", DestinationBuffer, Length)); + return EFI_SECURITY_VIOLATION; + } + if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) { + DEBUG ((EFI_D_ERROR, "SmmCopyMem: 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-SMRAM) with a byte value. + + This function fills a target buffer (non-SMRAM) with a byte value. + It checks if target buffer is valid per processor architecture and not overlap with SMRAM. + 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 SMRAM. + @retval EFI_SUCCESS Memory is set. + +**/ +EFI_STATUS +EFIAPI +SmmSetMem ( + OUT VOID *Buffer, + IN UINTN Length, + IN UINT8 Value + ) +{ + if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, Length)) { + DEBUG ((EFI_D_ERROR, "SmmSetMem: 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 Smm Mem library + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +SmmMemLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_SMM_ACCESS2_PROTOCOL *SmmAccess; + UINTN Size; + + // + // Get SMRAM information + // + Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess); + ASSERT_EFI_ERROR (Status); + + Size = 0; + Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + + mSmmMemLibInternalSmramRanges = AllocatePool (Size); + ASSERT (mSmmMemLibInternalSmramRanges != NULL); + + Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmmMemLibInternalSmramRanges); + ASSERT_EFI_ERROR (Status); + + mSmmMemLibInternalSmramCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR); + + // + // Caculate and save maximum support address + // + SmmMemLibInternalCaculateMaximumSupportAddress (); + + return EFI_SUCCESS; +} + +/** + The destructor function frees resource used in the Smm Mem library + + @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 deconstructor always returns EFI_SUCCESS. +**/ +EFI_STATUS +EFIAPI +SmmMemLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + FreePool (mSmmMemLibInternalSmramRanges); + + return EFI_SUCCESS; +} diff --git a/MdePkg/Library/SmmMemLib/SmmMemLib.inf b/MdePkg/Library/SmmMemLib/SmmMemLib.inf new file mode 100644 index 0000000000..778923bfe4 --- /dev/null +++ b/MdePkg/Library/SmmMemLib/SmmMemLib.inf @@ -0,0 +1,53 @@ +## @file +# Instance of SMM memory check library. +# +# SMM memory check library library implementation. This library consumes SMM_ACCESS2_PROTOCOL +# to get SMRAM information. In order to use this library instance, the platform should produce +# all SMRAM range via SMM_ACCESS2_PROTOCOL, including the range for firmware (like SMM Core +# and SMM driver) and/or specific dedicated hardware. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SmmMemLib + MODULE_UNI_FILE = SmmMemLib.uni + FILE_GUID = 7F23F839-C81C-4B89-8132-69746FCBCE52 + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = SmmMemLib|DXE_SMM_DRIVER SMM_CORE + CONSTRUCTOR = SmmMemLibConstructor + DESTRUCTOR = SmmMemLibDestructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + SmmMemLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + SmmServicesTableLib + UefiBootServicesTableLib + DebugLib + BaseMemoryLib + HobLib + MemoryAllocationLib + +[Protocols] + gEfiSmmAccess2ProtocolGuid diff --git a/MdePkg/Library/SmmMemLib/SmmMemLib.uni b/MdePkg/Library/SmmMemLib/SmmMemLib.uni new file mode 100644 index 0000000000..7fd7869e01 Binary files /dev/null and b/MdePkg/Library/SmmMemLib/SmmMemLib.uni differ diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec index 573277d51f..e0a28d7997 100644 --- a/MdePkg/MdePkg.dec +++ b/MdePkg/MdePkg.dec @@ -238,6 +238,10 @@ # Only available to SMM/DXE Combined and SMM module types. SmmServicesTableLib|Include/Library/SmmServicesTableLib.h + ## @libraryclass Provides services for Smm Memory Operation. + # + SmmMemLib|Include/Library/SmmMemLib.h + ## @libraryclass Provides services to enable/disable periodic SMI handlers. # SmmPeriodicSmiLib|Include/Library/SmmPeriodicSmiLib.h diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc index 6e527f4e0d..a9301fb415 100644 --- a/MdePkg/MdePkg.dsc +++ b/MdePkg/MdePkg.dsc @@ -150,6 +150,7 @@ MdePkg/Library/BaseS3PciLib/BaseS3PciLib.inf MdePkg/Library/BaseS3SmbusLib/BaseS3SmbusLib.inf MdePkg/Library/BaseS3StallLib/BaseS3StallLib.inf + MdePkg/Library/SmmMemLib/SmmMemLib.inf [Components.IPF] MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf