mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 01:16:21 +00:00 
			
		
		
		
	 4059386c70
			
		
	
	
		4059386c70
		
	
	
	
	
		
			
			https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
		
			
				
	
	
		
			367 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			367 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| 
 | |
|   Copyright (c) 2016-2018, ARM Limited. All rights reserved.
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include <Library/ArmLib.h>
 | |
| #include <Library/ArmSmcLib.h>
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Library/DebugLib.h>
 | |
| #include <Library/DxeServicesTableLib.h>
 | |
| #include <Library/HobLib.h>
 | |
| #include <Library/PcdLib.h>
 | |
| #include <Library/UefiBootServicesTableLib.h>
 | |
| #include <Library/UefiRuntimeServicesTableLib.h>
 | |
| 
 | |
| #include <Protocol/MmCommunication.h>
 | |
| 
 | |
| #include <IndustryStandard/ArmStdSmc.h>
 | |
| 
 | |
| #include "MmCommunicate.h"
 | |
| 
 | |
| //
 | |
| // Address, Length of the pre-allocated buffer for communication with the secure
 | |
| // world.
 | |
| //
 | |
| STATIC ARM_MEMORY_REGION_DESCRIPTOR  mNsCommBuffMemRegion;
 | |
| 
 | |
| // Notification event when virtual address map is set.
 | |
| STATIC EFI_EVENT  mSetVirtualAddressMapEvent;
 | |
| 
 | |
| //
 | |
| // Handle to install the MM Communication Protocol
 | |
| //
 | |
| STATIC EFI_HANDLE  mMmCommunicateHandle;
 | |
| 
 | |
| /**
 | |
|   Communicates with a registered handler.
 | |
| 
 | |
|   This function provides an interface to send and receive messages to the
 | |
|   Standalone MM environment on behalf of UEFI services.  This function is part
 | |
|   of the MM Communication Protocol that may be called in physical mode prior to
 | |
|   SetVirtualAddressMap() and in virtual mode after SetVirtualAddressMap().
 | |
| 
 | |
|   @param[in]      This                The EFI_MM_COMMUNICATION_PROTOCOL
 | |
|                                       instance.
 | |
|   @param[in, out] CommBuffer          A pointer to the buffer to convey
 | |
|                                       into MMRAM.
 | |
|   @param[in, out] CommSize            The size of the data buffer being
 | |
|                                       passed in. This is optional.
 | |
| 
 | |
|   @retval EFI_SUCCESS                 The message was successfully posted.
 | |
|   @retval EFI_INVALID_PARAMETER       The CommBuffer was NULL.
 | |
|   @retval EFI_BAD_BUFFER_SIZE         The buffer size is incorrect for the MM
 | |
|                                       implementation. If this error is
 | |
|                                       returned, the MessageLength field in
 | |
|                                       the CommBuffer header or the integer
 | |
|                                       pointed by CommSize are updated to reflect
 | |
|                                       the maximum payload size the
 | |
|                                       implementation can accommodate.
 | |
|   @retval EFI_ACCESS_DENIED           The CommunicateBuffer parameter
 | |
|                                       or CommSize parameter, if not omitted,
 | |
|                                       are in address range that cannot be
 | |
|                                       accessed by the MM environment
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MmCommunicationCommunicate (
 | |
|   IN CONST EFI_MM_COMMUNICATION_PROTOCOL  *This,
 | |
|   IN OUT VOID                             *CommBuffer,
 | |
|   IN OUT UINTN                            *CommSize OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_MM_COMMUNICATE_HEADER   *CommunicateHeader;
 | |
|   ARM_SMC_ARGS                CommunicateSmcArgs;
 | |
|   EFI_STATUS                  Status;
 | |
|   UINTN                       BufferSize;
 | |
| 
 | |
|   Status = EFI_ACCESS_DENIED;
 | |
|   BufferSize = 0;
 | |
| 
 | |
|   ZeroMem (&CommunicateSmcArgs, sizeof (ARM_SMC_ARGS));
 | |
| 
 | |
|   //
 | |
|   // Check parameters
 | |
|   //
 | |
|   if (CommBuffer == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   CommunicateHeader = CommBuffer;
 | |
|   // CommBuffer is a mandatory parameter. Hence, Rely on
 | |
|   // MessageLength + Header to ascertain the
 | |
|   // total size of the communication payload rather than
 | |
|   // rely on optional CommSize parameter
 | |
|   BufferSize = CommunicateHeader->MessageLength +
 | |
|                sizeof (CommunicateHeader->HeaderGuid) +
 | |
|                sizeof (CommunicateHeader->MessageLength);
 | |
| 
 | |
|   // If the length of the CommBuffer is 0 then return the expected length.
 | |
|   if (CommSize) {
 | |
|     // This case can be used by the consumer of this driver to find out the
 | |
|     // max size that can be used for allocating CommBuffer.
 | |
|     if ((*CommSize == 0) ||
 | |
|         (*CommSize > mNsCommBuffMemRegion.Length)) {
 | |
|       *CommSize = mNsCommBuffMemRegion.Length;
 | |
|       return EFI_BAD_BUFFER_SIZE;
 | |
|     }
 | |
|     //
 | |
|     // CommSize must match MessageLength + sizeof (EFI_MM_COMMUNICATE_HEADER);
 | |
|     //
 | |
|     if (*CommSize != BufferSize) {
 | |
|         return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If the buffer size is 0 or greater than what can be tolerated by the MM
 | |
|   // environment then return the expected size.
 | |
|   //
 | |
|   if ((BufferSize == 0) ||
 | |
|       (BufferSize > mNsCommBuffMemRegion.Length)) {
 | |
|     CommunicateHeader->MessageLength = mNsCommBuffMemRegion.Length -
 | |
|                                        sizeof (CommunicateHeader->HeaderGuid) -
 | |
|                                        sizeof (CommunicateHeader->MessageLength);
 | |
|     return EFI_BAD_BUFFER_SIZE;
 | |
|   }
 | |
| 
 | |
|   // SMC Function ID
 | |
|   CommunicateSmcArgs.Arg0 = ARM_SMC_ID_MM_COMMUNICATE_AARCH64;
 | |
| 
 | |
|   // Cookie
 | |
|   CommunicateSmcArgs.Arg1 = 0;
 | |
| 
 | |
|   // Copy Communication Payload
 | |
|   CopyMem ((VOID *)mNsCommBuffMemRegion.VirtualBase, CommBuffer, BufferSize);
 | |
| 
 | |
|   // comm_buffer_address (64-bit physical address)
 | |
|   CommunicateSmcArgs.Arg2 = (UINTN)mNsCommBuffMemRegion.PhysicalBase;
 | |
| 
 | |
|   // comm_size_address (not used, indicated by setting to zero)
 | |
|   CommunicateSmcArgs.Arg3 = 0;
 | |
| 
 | |
|   // Call the Standalone MM environment.
 | |
|   ArmCallSmc (&CommunicateSmcArgs);
 | |
| 
 | |
|   switch (CommunicateSmcArgs.Arg0) {
 | |
|   case ARM_SMC_MM_RET_SUCCESS:
 | |
|     ZeroMem (CommBuffer, BufferSize);
 | |
|     // On successful return, the size of data being returned is inferred from
 | |
|     // MessageLength + Header.
 | |
|     CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)mNsCommBuffMemRegion.VirtualBase;
 | |
|     BufferSize = CommunicateHeader->MessageLength +
 | |
|                  sizeof (CommunicateHeader->HeaderGuid) +
 | |
|                  sizeof (CommunicateHeader->MessageLength);
 | |
| 
 | |
|     CopyMem (
 | |
|       CommBuffer,
 | |
|       (VOID *)mNsCommBuffMemRegion.VirtualBase,
 | |
|       BufferSize
 | |
|       );
 | |
|     Status = EFI_SUCCESS;
 | |
|     break;
 | |
| 
 | |
|   case ARM_SMC_MM_RET_INVALID_PARAMS:
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     break;
 | |
| 
 | |
|   case ARM_SMC_MM_RET_DENIED:
 | |
|     Status = EFI_ACCESS_DENIED;
 | |
|     break;
 | |
| 
 | |
|   case ARM_SMC_MM_RET_NO_MEMORY:
 | |
|     // Unexpected error since the CommSize was checked for zero length
 | |
|     // prior to issuing the SMC
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     ASSERT (0);
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     Status = EFI_ACCESS_DENIED;
 | |
|     ASSERT (0);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| //
 | |
| // MM Communication Protocol instance
 | |
| //
 | |
| EFI_MM_COMMUNICATION_PROTOCOL  mMmCommunication = {
 | |
|   MmCommunicationCommunicate
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Notification callback on SetVirtualAddressMap event.
 | |
| 
 | |
|   This function notifies the MM communication protocol interface on
 | |
|   SetVirtualAddressMap event and converts pointers used in this driver
 | |
|   from physical to virtual address.
 | |
| 
 | |
|   @param  Event          SetVirtualAddressMap event.
 | |
|   @param  Context        A context when the SetVirtualAddressMap triggered.
 | |
| 
 | |
|   @retval EFI_SUCCESS    The function executed successfully.
 | |
|   @retval Other          Some error occurred when executing this function.
 | |
| 
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| EFIAPI
 | |
| NotifySetVirtualAddressMap (
 | |
|   IN EFI_EVENT  Event,
 | |
|   IN VOID      *Context
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   Status = gRT->ConvertPointer (
 | |
|                   EFI_OPTIONAL_PTR,
 | |
|                   (VOID **)&mNsCommBuffMemRegion.VirtualBase
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "NotifySetVirtualAddressMap():"
 | |
|             " Unable to convert MM runtime pointer. Status:0x%r\n", Status));
 | |
|   }
 | |
| 
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| GetMmCompatibility ()
 | |
| {
 | |
|   EFI_STATUS   Status;
 | |
|   UINT32       MmVersion;
 | |
|   ARM_SMC_ARGS MmVersionArgs;
 | |
| 
 | |
|   // MM_VERSION uses SMC32 calling conventions
 | |
|   MmVersionArgs.Arg0 = ARM_SMC_ID_MM_VERSION_AARCH32;
 | |
| 
 | |
|   ArmCallSmc (&MmVersionArgs);
 | |
| 
 | |
|   MmVersion = MmVersionArgs.Arg0;
 | |
| 
 | |
|   if ((MM_MAJOR_VER(MmVersion) == MM_CALLER_MAJOR_VER) &&
 | |
|       (MM_MINOR_VER(MmVersion) >= MM_CALLER_MINOR_VER)) {
 | |
|     DEBUG ((DEBUG_INFO, "MM Version: Major=0x%x, Minor=0x%x\n",
 | |
|             MM_MAJOR_VER(MmVersion), MM_MINOR_VER(MmVersion)));
 | |
|     Status = EFI_SUCCESS;
 | |
|   } else {
 | |
|     DEBUG ((DEBUG_ERROR, "Incompatible MM Versions.\n Current Version: Major=0x%x, Minor=0x%x.\n Expected: Major=0x%x, Minor>=0x%x.\n",
 | |
|             MM_MAJOR_VER(MmVersion), MM_MINOR_VER(MmVersion), MM_CALLER_MAJOR_VER, MM_CALLER_MINOR_VER));
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The Entry Point for MM Communication
 | |
| 
 | |
|   This function installs the MM communication protocol interface and finds out
 | |
|   what type of buffer management will be required prior to invoking the
 | |
|   communication SMC.
 | |
| 
 | |
|   @param  ImageHandle    The firmware allocated handle for the EFI image.
 | |
|   @param  SystemTable    A pointer to the EFI System Table.
 | |
| 
 | |
|   @retval EFI_SUCCESS    The entry point is executed successfully.
 | |
|   @retval Other          Some error occurred when executing this entry point.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MmCommunicationInitialize (
 | |
|   IN EFI_HANDLE         ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE  *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                 Status;
 | |
| 
 | |
|   // Check if we can make the MM call
 | |
|   Status = GetMmCompatibility ();
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     goto ReturnErrorStatus;
 | |
|   }
 | |
| 
 | |
|   mNsCommBuffMemRegion.PhysicalBase = PcdGet64 (PcdMmBufferBase);
 | |
|   // During boot , Virtual and Physical are same
 | |
|   mNsCommBuffMemRegion.VirtualBase = mNsCommBuffMemRegion.PhysicalBase;
 | |
|   mNsCommBuffMemRegion.Length = PcdGet64 (PcdMmBufferSize);
 | |
| 
 | |
|   ASSERT (mNsCommBuffMemRegion.PhysicalBase != 0);
 | |
| 
 | |
|   ASSERT (mNsCommBuffMemRegion.Length != 0);
 | |
| 
 | |
|   Status = gDS->AddMemorySpace (
 | |
|                   EfiGcdMemoryTypeReserved,
 | |
|                   mNsCommBuffMemRegion.PhysicalBase,
 | |
|                   mNsCommBuffMemRegion.Length,
 | |
|                   EFI_MEMORY_WB |
 | |
|                   EFI_MEMORY_XP |
 | |
|                   EFI_MEMORY_RUNTIME
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "MmCommunicateInitialize: "
 | |
|             "Failed to add MM-NS Buffer Memory Space\n"));
 | |
|     goto ReturnErrorStatus;
 | |
|   }
 | |
| 
 | |
|   Status = gDS->SetMemorySpaceAttributes (
 | |
|                   mNsCommBuffMemRegion.PhysicalBase,
 | |
|                   mNsCommBuffMemRegion.Length,
 | |
|                   EFI_MEMORY_WB | EFI_MEMORY_XP | EFI_MEMORY_RUNTIME
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "MmCommunicateInitialize: "
 | |
|             "Failed to set MM-NS Buffer Memory attributes\n"));
 | |
|     goto CleanAddedMemorySpace;
 | |
|   }
 | |
| 
 | |
|   // Install the communication protocol
 | |
|   Status = gBS->InstallProtocolInterface (
 | |
|                   &mMmCommunicateHandle,
 | |
|                   &gEfiMmCommunicationProtocolGuid,
 | |
|                   EFI_NATIVE_INTERFACE,
 | |
|                   &mMmCommunication
 | |
|                   );
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "MmCommunicationInitialize: "
 | |
|             "Failed to install MM communication protocol\n"));
 | |
|     goto CleanAddedMemorySpace;
 | |
|   }
 | |
| 
 | |
|   // Register notification callback when virtual address is associated
 | |
|   // with the physical address.
 | |
|   // Create a Set Virtual Address Map event.
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
 | |
|                   TPL_NOTIFY,
 | |
|                   NotifySetVirtualAddressMap,
 | |
|                   NULL,
 | |
|                   &mSetVirtualAddressMapEvent
 | |
|                   );
 | |
|   if (Status == EFI_SUCCESS) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   gBS->UninstallProtocolInterface (
 | |
|          mMmCommunicateHandle,
 | |
|          &gEfiMmCommunicationProtocolGuid,
 | |
|          &mMmCommunication
 | |
|          );
 | |
| 
 | |
| CleanAddedMemorySpace:
 | |
|   gDS->RemoveMemorySpace (
 | |
|          mNsCommBuffMemRegion.PhysicalBase,
 | |
|          mNsCommBuffMemRegion.Length
 | |
|          );
 | |
| 
 | |
| ReturnErrorStatus:
 | |
|   return EFI_INVALID_PARAMETER;
 | |
| }
 |