3 Copyright (c) 2016-2021, Arm Limited. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <Library/ArmLib.h>
10 #include <Library/ArmSmcLib.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/DxeServicesTableLib.h>
14 #include <Library/HobLib.h>
15 #include <Library/PcdLib.h>
16 #include <Library/UefiBootServicesTableLib.h>
17 #include <Library/UefiRuntimeServicesTableLib.h>
19 #include <Protocol/MmCommunication2.h>
21 #include <IndustryStandard/ArmStdSmc.h>
23 #include "MmCommunicate.h"
26 // Address, Length of the pre-allocated buffer for communication with the secure
29 STATIC ARM_MEMORY_REGION_DESCRIPTOR mNsCommBuffMemRegion
;
31 // Notification event when virtual address map is set.
32 STATIC EFI_EVENT mSetVirtualAddressMapEvent
;
35 // Handle to install the MM Communication Protocol
37 STATIC EFI_HANDLE mMmCommunicateHandle
;
40 Communicates with a registered handler.
42 This function provides a service to send and receive messages from a registered UEFI service.
44 @param[in] This The EFI_MM_COMMUNICATION_PROTOCOL instance.
45 @param[in] CommBufferPhysical Physical address of the MM communication buffer
46 @param[in] CommBufferVirtual Virtual address of the MM communication buffer
47 @param[in] CommSize The size of the data buffer being passed in. On exit, the size of data
48 being returned. Zero if the handler does not wish to reply with any data.
49 This parameter is optional and may be NULL.
51 @retval EFI_SUCCESS The message was successfully posted.
52 @retval EFI_INVALID_PARAMETER CommBufferPhysical was NULL or CommBufferVirtual was NULL.
53 @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.
54 If this error is returned, the MessageLength field
55 in the CommBuffer header or the integer pointed by
56 CommSize, are updated to reflect the maximum payload
57 size the implementation can accommodate.
58 @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,
59 if not omitted, are in address range that cannot be
60 accessed by the MM environment.
65 MmCommunication2Communicate (
66 IN CONST EFI_MM_COMMUNICATION2_PROTOCOL
*This
,
67 IN OUT VOID
*CommBufferPhysical
,
68 IN OUT VOID
*CommBufferVirtual
,
69 IN OUT UINTN
*CommSize OPTIONAL
72 EFI_MM_COMMUNICATE_HEADER
*CommunicateHeader
;
73 ARM_SMC_ARGS CommunicateSmcArgs
;
77 Status
= EFI_ACCESS_DENIED
;
80 ZeroMem (&CommunicateSmcArgs
, sizeof (ARM_SMC_ARGS
));
85 if (CommBufferVirtual
== NULL
) {
86 return EFI_INVALID_PARAMETER
;
89 CommunicateHeader
= CommBufferVirtual
;
90 // CommBuffer is a mandatory parameter. Hence, Rely on
91 // MessageLength + Header to ascertain the
92 // total size of the communication payload rather than
93 // rely on optional CommSize parameter
94 BufferSize
= CommunicateHeader
->MessageLength
+
95 sizeof (CommunicateHeader
->HeaderGuid
) +
96 sizeof (CommunicateHeader
->MessageLength
);
98 // If the length of the CommBuffer is 0 then return the expected length.
100 // This case can be used by the consumer of this driver to find out the
101 // max size that can be used for allocating CommBuffer.
102 if ((*CommSize
== 0) ||
103 (*CommSize
> mNsCommBuffMemRegion
.Length
))
105 *CommSize
= mNsCommBuffMemRegion
.Length
;
106 return EFI_BAD_BUFFER_SIZE
;
110 // CommSize must match MessageLength + sizeof (EFI_MM_COMMUNICATE_HEADER);
112 if (*CommSize
!= BufferSize
) {
113 return EFI_INVALID_PARAMETER
;
118 // If the buffer size is 0 or greater than what can be tolerated by the MM
119 // environment then return the expected size.
121 if ((BufferSize
== 0) ||
122 (BufferSize
> mNsCommBuffMemRegion
.Length
))
124 CommunicateHeader
->MessageLength
= mNsCommBuffMemRegion
.Length
-
125 sizeof (CommunicateHeader
->HeaderGuid
) -
126 sizeof (CommunicateHeader
->MessageLength
);
127 return EFI_BAD_BUFFER_SIZE
;
131 CommunicateSmcArgs
.Arg0
= ARM_SMC_ID_MM_COMMUNICATE_AARCH64
;
134 CommunicateSmcArgs
.Arg1
= 0;
136 // Copy Communication Payload
137 CopyMem ((VOID
*)mNsCommBuffMemRegion
.VirtualBase
, CommBufferVirtual
, BufferSize
);
139 // comm_buffer_address (64-bit physical address)
140 CommunicateSmcArgs
.Arg2
= (UINTN
)mNsCommBuffMemRegion
.PhysicalBase
;
142 // comm_size_address (not used, indicated by setting to zero)
143 CommunicateSmcArgs
.Arg3
= 0;
145 // Call the Standalone MM environment.
146 ArmCallSmc (&CommunicateSmcArgs
);
148 switch (CommunicateSmcArgs
.Arg0
) {
149 case ARM_SMC_MM_RET_SUCCESS
:
150 ZeroMem (CommBufferVirtual
, BufferSize
);
151 // On successful return, the size of data being returned is inferred from
152 // MessageLength + Header.
153 CommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*)mNsCommBuffMemRegion
.VirtualBase
;
154 BufferSize
= CommunicateHeader
->MessageLength
+
155 sizeof (CommunicateHeader
->HeaderGuid
) +
156 sizeof (CommunicateHeader
->MessageLength
);
160 (VOID
*)mNsCommBuffMemRegion
.VirtualBase
,
163 Status
= EFI_SUCCESS
;
166 case ARM_SMC_MM_RET_INVALID_PARAMS
:
167 Status
= EFI_INVALID_PARAMETER
;
170 case ARM_SMC_MM_RET_DENIED
:
171 Status
= EFI_ACCESS_DENIED
;
174 case ARM_SMC_MM_RET_NO_MEMORY
:
175 // Unexpected error since the CommSize was checked for zero length
176 // prior to issuing the SMC
177 Status
= EFI_OUT_OF_RESOURCES
;
182 Status
= EFI_ACCESS_DENIED
;
190 // MM Communication Protocol instance
192 STATIC EFI_MM_COMMUNICATION2_PROTOCOL mMmCommunication2
= {
193 MmCommunication2Communicate
197 Notification callback on SetVirtualAddressMap event.
199 This function notifies the MM communication protocol interface on
200 SetVirtualAddressMap event and converts pointers used in this driver
201 from physical to virtual address.
203 @param Event SetVirtualAddressMap event.
204 @param Context A context when the SetVirtualAddressMap triggered.
206 @retval EFI_SUCCESS The function executed successfully.
207 @retval Other Some error occurred when executing this function.
213 NotifySetVirtualAddressMap (
220 Status
= gRT
->ConvertPointer (
222 (VOID
**)&mNsCommBuffMemRegion
.VirtualBase
224 if (EFI_ERROR (Status
)) {
227 "NotifySetVirtualAddressMap():"
228 " Unable to convert MM runtime pointer. Status:0x%r\n",
241 ARM_SMC_ARGS MmVersionArgs
;
243 // MM_VERSION uses SMC32 calling conventions
244 MmVersionArgs
.Arg0
= ARM_SMC_ID_MM_VERSION_AARCH32
;
246 ArmCallSmc (&MmVersionArgs
);
248 MmVersion
= MmVersionArgs
.Arg0
;
250 if ((MM_MAJOR_VER (MmVersion
) == MM_CALLER_MAJOR_VER
) &&
251 (MM_MINOR_VER (MmVersion
) >= MM_CALLER_MINOR_VER
))
255 "MM Version: Major=0x%x, Minor=0x%x\n",
256 MM_MAJOR_VER (MmVersion
),
257 MM_MINOR_VER (MmVersion
)
259 Status
= EFI_SUCCESS
;
263 "Incompatible MM Versions.\n Current Version: Major=0x%x, Minor=0x%x.\n Expected: Major=0x%x, Minor>=0x%x.\n",
264 MM_MAJOR_VER (MmVersion
),
265 MM_MINOR_VER (MmVersion
),
269 Status
= EFI_UNSUPPORTED
;
275 STATIC EFI_GUID
*CONST mGuidedEventGuid
[] = {
276 &gEfiEndOfDxeEventGroupGuid
,
277 &gEfiEventExitBootServicesGuid
,
278 &gEfiEventReadyToBootGuid
,
281 STATIC EFI_EVENT mGuidedEvent
[ARRAY_SIZE (mGuidedEventGuid
)];
284 Event notification that is fired when GUIDed Event Group is signaled.
286 @param Event The Event that is being processed, not used.
287 @param Context Event Context, not used.
293 MmGuidedEventNotify (
298 EFI_MM_COMMUNICATE_HEADER Header
;
302 // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure
304 CopyGuid (&Header
.HeaderGuid
, Context
);
305 Header
.MessageLength
= 1;
308 Size
= sizeof (Header
);
309 MmCommunication2Communicate (&mMmCommunication2
, &Header
, &Header
, &Size
);
313 The Entry Point for MM Communication
315 This function installs the MM communication protocol interface and finds out
316 what type of buffer management will be required prior to invoking the
319 @param ImageHandle The firmware allocated handle for the EFI image.
320 @param SystemTable A pointer to the EFI System Table.
322 @retval EFI_SUCCESS The entry point is executed successfully.
323 @retval Other Some error occurred when executing this entry point.
328 MmCommunication2Initialize (
329 IN EFI_HANDLE ImageHandle
,
330 IN EFI_SYSTEM_TABLE
*SystemTable
336 // Check if we can make the MM call
337 Status
= GetMmCompatibility ();
338 if (EFI_ERROR (Status
)) {
339 goto ReturnErrorStatus
;
342 mNsCommBuffMemRegion
.PhysicalBase
= PcdGet64 (PcdMmBufferBase
);
343 // During boot , Virtual and Physical are same
344 mNsCommBuffMemRegion
.VirtualBase
= mNsCommBuffMemRegion
.PhysicalBase
;
345 mNsCommBuffMemRegion
.Length
= PcdGet64 (PcdMmBufferSize
);
347 ASSERT (mNsCommBuffMemRegion
.PhysicalBase
!= 0);
349 ASSERT (mNsCommBuffMemRegion
.Length
!= 0);
351 Status
= gDS
->AddMemorySpace (
352 EfiGcdMemoryTypeReserved
,
353 mNsCommBuffMemRegion
.PhysicalBase
,
354 mNsCommBuffMemRegion
.Length
,
359 if (EFI_ERROR (Status
)) {
362 "MmCommunicateInitialize: "
363 "Failed to add MM-NS Buffer Memory Space\n"
365 goto ReturnErrorStatus
;
368 Status
= gDS
->SetMemorySpaceAttributes (
369 mNsCommBuffMemRegion
.PhysicalBase
,
370 mNsCommBuffMemRegion
.Length
,
371 EFI_MEMORY_WB
| EFI_MEMORY_XP
| EFI_MEMORY_RUNTIME
373 if (EFI_ERROR (Status
)) {
376 "MmCommunicateInitialize: "
377 "Failed to set MM-NS Buffer Memory attributes\n"
379 goto CleanAddedMemorySpace
;
382 // Install the communication protocol
383 Status
= gBS
->InstallProtocolInterface (
384 &mMmCommunicateHandle
,
385 &gEfiMmCommunication2ProtocolGuid
,
386 EFI_NATIVE_INTERFACE
,
389 if (EFI_ERROR (Status
)) {
392 "MmCommunicationInitialize: "
393 "Failed to install MM communication protocol\n"
395 goto CleanAddedMemorySpace
;
398 // Register notification callback when virtual address is associated
399 // with the physical address.
400 // Create a Set Virtual Address Map event.
401 Status
= gBS
->CreateEvent (
402 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
,
404 NotifySetVirtualAddressMap
,
406 &mSetVirtualAddressMapEvent
408 ASSERT_EFI_ERROR (Status
);
410 for (Index
= 0; Index
< ARRAY_SIZE (mGuidedEventGuid
); Index
++) {
411 Status
= gBS
->CreateEventEx (
415 mGuidedEventGuid
[Index
],
416 mGuidedEventGuid
[Index
],
419 ASSERT_EFI_ERROR (Status
);
420 if (EFI_ERROR (Status
)) {
421 while (Index
-- > 0) {
422 gBS
->CloseEvent (mGuidedEvent
[Index
]);
425 goto UninstallProtocol
;
432 gBS
->UninstallProtocolInterface (
433 mMmCommunicateHandle
,
434 &gEfiMmCommunication2ProtocolGuid
,
438 CleanAddedMemorySpace
:
439 gDS
->RemoveMemorySpace (
440 mNsCommBuffMemRegion
.PhysicalBase
,
441 mNsCommBuffMemRegion
.Length
445 return EFI_INVALID_PARAMETER
;