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, out] CommBufferPhysical Physical address of the MM communication buffer
46 @param[in, out] CommBufferVirtual Virtual address of the MM communication buffer
47 @param[in, out] CommSize The size of the data buffer being passed in. On input,
48 when not omitted, the buffer should cover EFI_MM_COMMUNICATE_HEADER
49 and the value of MessageLength field. On exit, the size
50 of data being returned. Zero if the handler does not
51 wish to reply with any data. This parameter is optional
54 @retval EFI_SUCCESS The message was successfully posted.
55 @retval EFI_INVALID_PARAMETER CommBufferPhysical or CommBufferVirtual was NULL, or
56 integer value pointed by CommSize does not cover
57 EFI_MM_COMMUNICATE_HEADER and the value of MessageLength
59 @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.
60 If this error is returned, the MessageLength field
61 in the CommBuffer header or the integer pointed by
62 CommSize, are updated to reflect the maximum payload
63 size the implementation can accommodate.
64 @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,
65 if not omitted, are in address range that cannot be
66 accessed by the MM environment.
71 MmCommunication2Communicate (
72 IN CONST EFI_MM_COMMUNICATION2_PROTOCOL
*This
,
73 IN OUT VOID
*CommBufferPhysical
,
74 IN OUT VOID
*CommBufferVirtual
,
75 IN OUT UINTN
*CommSize OPTIONAL
78 EFI_MM_COMMUNICATE_HEADER
*CommunicateHeader
;
79 ARM_SMC_ARGS CommunicateSmcArgs
;
83 Status
= EFI_ACCESS_DENIED
;
86 ZeroMem (&CommunicateSmcArgs
, sizeof (ARM_SMC_ARGS
));
91 if ((CommBufferVirtual
== NULL
) || (CommBufferPhysical
== NULL
)) {
92 return EFI_INVALID_PARAMETER
;
96 CommunicateHeader
= CommBufferVirtual
;
97 // CommBuffer is a mandatory parameter. Hence, Rely on
98 // MessageLength + Header to ascertain the
99 // total size of the communication payload rather than
100 // rely on optional CommSize parameter
101 BufferSize
= CommunicateHeader
->MessageLength
+
102 sizeof (CommunicateHeader
->HeaderGuid
) +
103 sizeof (CommunicateHeader
->MessageLength
);
105 // If CommSize is not omitted, perform size inspection before proceeding.
106 if (CommSize
!= NULL
) {
107 // This case can be used by the consumer of this driver to find out the
108 // max size that can be used for allocating CommBuffer.
109 if ((*CommSize
== 0) ||
110 (*CommSize
> mNsCommBuffMemRegion
.Length
))
112 *CommSize
= mNsCommBuffMemRegion
.Length
;
113 Status
= EFI_BAD_BUFFER_SIZE
;
117 // CommSize should cover at least MessageLength + sizeof (EFI_MM_COMMUNICATE_HEADER);
119 if (*CommSize
< BufferSize
) {
120 Status
= EFI_INVALID_PARAMETER
;
125 // If the message length is 0 or greater than what can be tolerated by the MM
126 // environment then return the expected size.
128 if ((CommunicateHeader
->MessageLength
== 0) ||
129 (BufferSize
> mNsCommBuffMemRegion
.Length
))
131 CommunicateHeader
->MessageLength
= mNsCommBuffMemRegion
.Length
-
132 sizeof (CommunicateHeader
->HeaderGuid
) -
133 sizeof (CommunicateHeader
->MessageLength
);
134 Status
= EFI_BAD_BUFFER_SIZE
;
137 // MessageLength or CommSize check has failed, return here.
138 if (EFI_ERROR (Status
)) {
143 CommunicateSmcArgs
.Arg0
= ARM_SMC_ID_MM_COMMUNICATE_AARCH64
;
146 CommunicateSmcArgs
.Arg1
= 0;
148 // Copy Communication Payload
149 CopyMem ((VOID
*)mNsCommBuffMemRegion
.VirtualBase
, CommBufferVirtual
, BufferSize
);
151 // comm_buffer_address (64-bit physical address)
152 CommunicateSmcArgs
.Arg2
= (UINTN
)mNsCommBuffMemRegion
.PhysicalBase
;
154 // comm_size_address (not used, indicated by setting to zero)
155 CommunicateSmcArgs
.Arg3
= 0;
157 // Call the Standalone MM environment.
158 ArmCallSmc (&CommunicateSmcArgs
);
160 switch (CommunicateSmcArgs
.Arg0
) {
161 case ARM_SMC_MM_RET_SUCCESS
:
162 ZeroMem (CommBufferVirtual
, BufferSize
);
163 // On successful return, the size of data being returned is inferred from
164 // MessageLength + Header.
165 CommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*)mNsCommBuffMemRegion
.VirtualBase
;
166 BufferSize
= CommunicateHeader
->MessageLength
+
167 sizeof (CommunicateHeader
->HeaderGuid
) +
168 sizeof (CommunicateHeader
->MessageLength
);
172 (VOID
*)mNsCommBuffMemRegion
.VirtualBase
,
175 Status
= EFI_SUCCESS
;
178 case ARM_SMC_MM_RET_INVALID_PARAMS
:
179 Status
= EFI_INVALID_PARAMETER
;
182 case ARM_SMC_MM_RET_DENIED
:
183 Status
= EFI_ACCESS_DENIED
;
186 case ARM_SMC_MM_RET_NO_MEMORY
:
187 // Unexpected error since the CommSize was checked for zero length
188 // prior to issuing the SMC
189 Status
= EFI_OUT_OF_RESOURCES
;
194 Status
= EFI_ACCESS_DENIED
;
202 // MM Communication Protocol instance
204 STATIC EFI_MM_COMMUNICATION2_PROTOCOL mMmCommunication2
= {
205 MmCommunication2Communicate
209 Notification callback on SetVirtualAddressMap event.
211 This function notifies the MM communication protocol interface on
212 SetVirtualAddressMap event and converts pointers used in this driver
213 from physical to virtual address.
215 @param Event SetVirtualAddressMap event.
216 @param Context A context when the SetVirtualAddressMap triggered.
218 @retval EFI_SUCCESS The function executed successfully.
219 @retval Other Some error occurred when executing this function.
225 NotifySetVirtualAddressMap (
232 Status
= gRT
->ConvertPointer (
234 (VOID
**)&mNsCommBuffMemRegion
.VirtualBase
236 if (EFI_ERROR (Status
)) {
239 "NotifySetVirtualAddressMap():"
240 " Unable to convert MM runtime pointer. Status:0x%r\n",
253 ARM_SMC_ARGS MmVersionArgs
;
255 // MM_VERSION uses SMC32 calling conventions
256 MmVersionArgs
.Arg0
= ARM_SMC_ID_MM_VERSION_AARCH32
;
258 ArmCallSmc (&MmVersionArgs
);
260 MmVersion
= MmVersionArgs
.Arg0
;
262 if ((MM_MAJOR_VER (MmVersion
) == MM_CALLER_MAJOR_VER
) &&
263 (MM_MINOR_VER (MmVersion
) >= MM_CALLER_MINOR_VER
))
267 "MM Version: Major=0x%x, Minor=0x%x\n",
268 MM_MAJOR_VER (MmVersion
),
269 MM_MINOR_VER (MmVersion
)
271 Status
= EFI_SUCCESS
;
275 "Incompatible MM Versions.\n Current Version: Major=0x%x, Minor=0x%x.\n Expected: Major=0x%x, Minor>=0x%x.\n",
276 MM_MAJOR_VER (MmVersion
),
277 MM_MINOR_VER (MmVersion
),
281 Status
= EFI_UNSUPPORTED
;
287 STATIC EFI_GUID
*CONST mGuidedEventGuid
[] = {
288 &gEfiEndOfDxeEventGroupGuid
,
289 &gEfiEventExitBootServicesGuid
,
290 &gEfiEventReadyToBootGuid
,
293 STATIC EFI_EVENT mGuidedEvent
[ARRAY_SIZE (mGuidedEventGuid
)];
296 Event notification that is fired when GUIDed Event Group is signaled.
298 @param Event The Event that is being processed, not used.
299 @param Context Event Context, not used.
305 MmGuidedEventNotify (
310 EFI_MM_COMMUNICATE_HEADER Header
;
314 // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure
316 CopyGuid (&Header
.HeaderGuid
, Context
);
317 Header
.MessageLength
= 1;
320 Size
= sizeof (Header
);
321 MmCommunication2Communicate (&mMmCommunication2
, &Header
, &Header
, &Size
);
325 The Entry Point for MM Communication
327 This function installs the MM communication protocol interface and finds out
328 what type of buffer management will be required prior to invoking the
331 @param ImageHandle The firmware allocated handle for the EFI image.
332 @param SystemTable A pointer to the EFI System Table.
334 @retval EFI_SUCCESS The entry point is executed successfully.
335 @retval Other Some error occurred when executing this entry point.
340 MmCommunication2Initialize (
341 IN EFI_HANDLE ImageHandle
,
342 IN EFI_SYSTEM_TABLE
*SystemTable
348 // Check if we can make the MM call
349 Status
= GetMmCompatibility ();
350 if (EFI_ERROR (Status
)) {
351 goto ReturnErrorStatus
;
354 mNsCommBuffMemRegion
.PhysicalBase
= PcdGet64 (PcdMmBufferBase
);
355 // During boot , Virtual and Physical are same
356 mNsCommBuffMemRegion
.VirtualBase
= mNsCommBuffMemRegion
.PhysicalBase
;
357 mNsCommBuffMemRegion
.Length
= PcdGet64 (PcdMmBufferSize
);
359 ASSERT (mNsCommBuffMemRegion
.PhysicalBase
!= 0);
361 ASSERT (mNsCommBuffMemRegion
.Length
!= 0);
363 Status
= gDS
->AddMemorySpace (
364 EfiGcdMemoryTypeReserved
,
365 mNsCommBuffMemRegion
.PhysicalBase
,
366 mNsCommBuffMemRegion
.Length
,
371 if (EFI_ERROR (Status
)) {
374 "MmCommunicateInitialize: "
375 "Failed to add MM-NS Buffer Memory Space\n"
377 goto ReturnErrorStatus
;
380 Status
= gDS
->SetMemorySpaceAttributes (
381 mNsCommBuffMemRegion
.PhysicalBase
,
382 mNsCommBuffMemRegion
.Length
,
383 EFI_MEMORY_WB
| EFI_MEMORY_XP
| EFI_MEMORY_RUNTIME
385 if (EFI_ERROR (Status
)) {
388 "MmCommunicateInitialize: "
389 "Failed to set MM-NS Buffer Memory attributes\n"
391 goto CleanAddedMemorySpace
;
394 // Install the communication protocol
395 Status
= gBS
->InstallProtocolInterface (
396 &mMmCommunicateHandle
,
397 &gEfiMmCommunication2ProtocolGuid
,
398 EFI_NATIVE_INTERFACE
,
401 if (EFI_ERROR (Status
)) {
404 "MmCommunicationInitialize: "
405 "Failed to install MM communication protocol\n"
407 goto CleanAddedMemorySpace
;
410 // Register notification callback when virtual address is associated
411 // with the physical address.
412 // Create a Set Virtual Address Map event.
413 Status
= gBS
->CreateEvent (
414 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
,
416 NotifySetVirtualAddressMap
,
418 &mSetVirtualAddressMapEvent
420 ASSERT_EFI_ERROR (Status
);
422 for (Index
= 0; Index
< ARRAY_SIZE (mGuidedEventGuid
); Index
++) {
423 Status
= gBS
->CreateEventEx (
427 mGuidedEventGuid
[Index
],
428 mGuidedEventGuid
[Index
],
431 ASSERT_EFI_ERROR (Status
);
432 if (EFI_ERROR (Status
)) {
433 while (Index
-- > 0) {
434 gBS
->CloseEvent (mGuidedEvent
[Index
]);
437 goto UninstallProtocol
;
444 gBS
->UninstallProtocolInterface (
445 mMmCommunicateHandle
,
446 &gEfiMmCommunication2ProtocolGuid
,
450 CleanAddedMemorySpace
:
451 gDS
->RemoveMemorySpace (
452 mNsCommBuffMemRegion
.PhysicalBase
,
453 mNsCommBuffMemRegion
.Length
457 return EFI_INVALID_PARAMETER
;