TianoCore EDK2 master
Loading...
Searching...
No Matches
MmCommunication.c
Go to the documentation of this file.
1
9#include <Library/ArmLib.h>
10#include <Library/ArmSmcLib.h>
12#include <Library/DebugLib.h>
14#include <Library/HobLib.h>
15#include <Library/PcdLib.h>
18
20
22
23#include "MmCommunicate.h"
24
25//
26// Address, Length of the pre-allocated buffer for communication with the secure
27// world.
28//
29STATIC ARM_MEMORY_REGION_DESCRIPTOR mNsCommBuffMemRegion;
30
31// Notification event when virtual address map is set.
32STATIC EFI_EVENT mSetVirtualAddressMapEvent;
33
34//
35// Handle to install the MM Communication Protocol
36//
37STATIC EFI_HANDLE mMmCommunicateHandle;
38
70EFIAPI
73 IN OUT VOID *CommBufferPhysical,
74 IN OUT VOID *CommBufferVirtual,
75 IN OUT UINTN *CommSize OPTIONAL
76 )
77{
78 EFI_MM_COMMUNICATE_HEADER *CommunicateHeader;
79 ARM_SMC_ARGS CommunicateSmcArgs;
80 EFI_STATUS Status;
81 UINTN BufferSize;
82
83 Status = EFI_ACCESS_DENIED;
84 BufferSize = 0;
85
86 ZeroMem (&CommunicateSmcArgs, sizeof (ARM_SMC_ARGS));
87
88 //
89 // Check parameters
90 //
91 if ((CommBufferVirtual == NULL) || (CommBufferPhysical == NULL)) {
92 return EFI_INVALID_PARAMETER;
93 }
94
95 Status = EFI_SUCCESS;
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);
104
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))
111 {
112 *CommSize = mNsCommBuffMemRegion.Length;
113 Status = EFI_BAD_BUFFER_SIZE;
114 }
115
116 //
117 // CommSize should cover at least MessageLength + sizeof (EFI_MM_COMMUNICATE_HEADER);
118 //
119 if (*CommSize < BufferSize) {
120 Status = EFI_INVALID_PARAMETER;
121 }
122 }
123
124 //
125 // If the message length is 0 or greater than what can be tolerated by the MM
126 // environment then return the expected size.
127 //
128 if ((CommunicateHeader->MessageLength == 0) ||
129 (BufferSize > mNsCommBuffMemRegion.Length))
130 {
131 CommunicateHeader->MessageLength = mNsCommBuffMemRegion.Length -
132 sizeof (CommunicateHeader->HeaderGuid) -
133 sizeof (CommunicateHeader->MessageLength);
134 Status = EFI_BAD_BUFFER_SIZE;
135 }
136
137 // MessageLength or CommSize check has failed, return here.
138 if (EFI_ERROR (Status)) {
139 return Status;
140 }
141
142 // SMC Function ID
143 CommunicateSmcArgs.Arg0 = ARM_SMC_ID_MM_COMMUNICATE_AARCH64;
144
145 // Cookie
146 CommunicateSmcArgs.Arg1 = 0;
147
148 // Copy Communication Payload
149 CopyMem ((VOID *)mNsCommBuffMemRegion.VirtualBase, CommBufferVirtual, BufferSize);
150
151 // comm_buffer_address (64-bit physical address)
152 CommunicateSmcArgs.Arg2 = (UINTN)mNsCommBuffMemRegion.PhysicalBase;
153
154 // comm_size_address (not used, indicated by setting to zero)
155 CommunicateSmcArgs.Arg3 = 0;
156
157 // Call the Standalone MM environment.
158 ArmCallSmc (&CommunicateSmcArgs);
159
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);
169
170 CopyMem (
171 CommBufferVirtual,
172 (VOID *)mNsCommBuffMemRegion.VirtualBase,
173 BufferSize
174 );
175 Status = EFI_SUCCESS;
176 break;
177
178 case ARM_SMC_MM_RET_INVALID_PARAMS:
179 Status = EFI_INVALID_PARAMETER;
180 break;
181
182 case ARM_SMC_MM_RET_DENIED:
183 Status = EFI_ACCESS_DENIED;
184 break;
185
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;
190 ASSERT (0);
191 break;
192
193 default:
194 Status = EFI_ACCESS_DENIED;
195 ASSERT (0);
196 }
197
198 return Status;
199}
200
201//
202// MM Communication Protocol instance
203//
204STATIC EFI_MM_COMMUNICATION2_PROTOCOL mMmCommunication2 = {
206};
207
222STATIC
223VOID
224EFIAPI
226 IN EFI_EVENT Event,
227 IN VOID *Context
228 )
229{
230 EFI_STATUS Status;
231
232 Status = gRT->ConvertPointer (
233 EFI_OPTIONAL_PTR,
234 (VOID **)&mNsCommBuffMemRegion.VirtualBase
235 );
236 if (EFI_ERROR (Status)) {
237 DEBUG ((
238 DEBUG_ERROR,
239 "NotifySetVirtualAddressMap():"
240 " Unable to convert MM runtime pointer. Status:0x%r\n",
241 Status
242 ));
243 }
244}
245
246STATIC
248GetMmCompatibility (
249 )
250{
251 EFI_STATUS Status;
252 UINT32 MmVersion;
253 ARM_SMC_ARGS MmVersionArgs;
254
255 // MM_VERSION uses SMC32 calling conventions
256 MmVersionArgs.Arg0 = ARM_SMC_ID_MM_VERSION_AARCH32;
257
258 ArmCallSmc (&MmVersionArgs);
259
260 MmVersion = MmVersionArgs.Arg0;
261
262 if ((MM_MAJOR_VER (MmVersion) == MM_CALLER_MAJOR_VER) &&
263 (MM_MINOR_VER (MmVersion) >= MM_CALLER_MINOR_VER))
264 {
265 DEBUG ((
266 DEBUG_INFO,
267 "MM Version: Major=0x%x, Minor=0x%x\n",
268 MM_MAJOR_VER (MmVersion),
269 MM_MINOR_VER (MmVersion)
270 ));
271 Status = EFI_SUCCESS;
272 } else {
273 DEBUG ((
274 DEBUG_ERROR,
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),
278 MM_CALLER_MAJOR_VER,
279 MM_CALLER_MINOR_VER
280 ));
281 Status = EFI_UNSUPPORTED;
282 }
283
284 return Status;
285}
286
287STATIC EFI_GUID *CONST mGuidedEventGuid[] = {
288 &gEfiEndOfDxeEventGroupGuid,
289 &gEfiEventExitBootServicesGuid,
290 &gEfiEventReadyToBootGuid,
291};
292
293STATIC EFI_EVENT mGuidedEvent[ARRAY_SIZE (mGuidedEventGuid)];
294
302STATIC
303VOID
304EFIAPI
306 IN EFI_EVENT Event,
307 IN VOID *Context
308 )
309{
311 UINTN Size;
312
313 //
314 // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure
315 //
316 CopyGuid (&Header.HeaderGuid, Context);
317 Header.MessageLength = 1;
318 Header.Data[0] = 0;
319
320 Size = sizeof (Header);
321 MmCommunication2Communicate (&mMmCommunication2, &Header, &Header, &Size);
322}
323
339EFIAPI
341 IN EFI_HANDLE ImageHandle,
342 IN EFI_SYSTEM_TABLE *SystemTable
343 )
344{
345 EFI_STATUS Status;
346 UINTN Index;
347
348 // Check if we can make the MM call
349 Status = GetMmCompatibility ();
350 if (EFI_ERROR (Status)) {
351 goto ReturnErrorStatus;
352 }
353
354 mNsCommBuffMemRegion.PhysicalBase = PcdGet64 (PcdMmBufferBase);
355 // During boot , Virtual and Physical are same
356 mNsCommBuffMemRegion.VirtualBase = mNsCommBuffMemRegion.PhysicalBase;
357 mNsCommBuffMemRegion.Length = PcdGet64 (PcdMmBufferSize);
358
359 ASSERT (mNsCommBuffMemRegion.PhysicalBase != 0);
360
361 ASSERT (mNsCommBuffMemRegion.Length != 0);
362
363 Status = gDS->AddMemorySpace (
365 mNsCommBuffMemRegion.PhysicalBase,
366 mNsCommBuffMemRegion.Length,
367 EFI_MEMORY_WB |
368 EFI_MEMORY_XP |
369 EFI_MEMORY_RUNTIME
370 );
371 if (EFI_ERROR (Status)) {
372 DEBUG ((
373 DEBUG_ERROR,
374 "MmCommunicateInitialize: "
375 "Failed to add MM-NS Buffer Memory Space\n"
376 ));
377 goto ReturnErrorStatus;
378 }
379
380 Status = gDS->SetMemorySpaceAttributes (
381 mNsCommBuffMemRegion.PhysicalBase,
382 mNsCommBuffMemRegion.Length,
383 EFI_MEMORY_WB | EFI_MEMORY_XP | EFI_MEMORY_RUNTIME
384 );
385 if (EFI_ERROR (Status)) {
386 DEBUG ((
387 DEBUG_ERROR,
388 "MmCommunicateInitialize: "
389 "Failed to set MM-NS Buffer Memory attributes\n"
390 ));
391 goto CleanAddedMemorySpace;
392 }
393
394 // Install the communication protocol
395 Status = gBS->InstallProtocolInterface (
396 &mMmCommunicateHandle,
397 &gEfiMmCommunication2ProtocolGuid,
399 &mMmCommunication2
400 );
401 if (EFI_ERROR (Status)) {
402 DEBUG ((
403 DEBUG_ERROR,
404 "MmCommunicationInitialize: "
405 "Failed to install MM communication protocol\n"
406 ));
407 goto CleanAddedMemorySpace;
408 }
409
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,
415 TPL_NOTIFY,
417 NULL,
418 &mSetVirtualAddressMapEvent
419 );
420 ASSERT_EFI_ERROR (Status);
421
422 for (Index = 0; Index < ARRAY_SIZE (mGuidedEventGuid); Index++) {
423 Status = gBS->CreateEventEx (
424 EVT_NOTIFY_SIGNAL,
425 TPL_CALLBACK,
427 mGuidedEventGuid[Index],
428 mGuidedEventGuid[Index],
429 &mGuidedEvent[Index]
430 );
431 ASSERT_EFI_ERROR (Status);
432 if (EFI_ERROR (Status)) {
433 while (Index-- > 0) {
434 gBS->CloseEvent (mGuidedEvent[Index]);
435 }
436
437 goto UninstallProtocol;
438 }
439 }
440
441 return EFI_SUCCESS;
442
443UninstallProtocol:
444 gBS->UninstallProtocolInterface (
445 mMmCommunicateHandle,
446 &gEfiMmCommunication2ProtocolGuid,
447 &mMmCommunication2
448 );
449
450CleanAddedMemorySpace:
451 gDS->RemoveMemorySpace (
452 mNsCommBuffMemRegion.PhysicalBase,
453 mNsCommBuffMemRegion.Length
454 );
455
456ReturnErrorStatus:
457 return EFI_INVALID_PARAMETER;
458}
UINT64 UINTN
VOID ArmCallSmc(IN OUT ARM_SMC_ARGS *Args)
Definition: ArmSmcLibNull.c:14
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
GUID *EFIAPI CopyGuid(OUT GUID *DestinationGuid, IN CONST GUID *SourceGuid)
Definition: MemLibGuid.c:39
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_DXE_SERVICES * gDS
EFI_RUNTIME_SERVICES * gRT
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define ARRAY_SIZE(Array)
Definition: Base.h:1393
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
EFI_STATUS EFIAPI MmCommunication2Initialize(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
STATIC VOID EFIAPI NotifySetVirtualAddressMap(IN EFI_EVENT Event, IN VOID *Context)
EFI_STATUS EFIAPI MmCommunication2Communicate(IN CONST EFI_MM_COMMUNICATION2_PROTOCOL *This, IN OUT VOID *CommBufferPhysical, IN OUT VOID *CommBufferVirtual, IN OUT UINTN *CommSize OPTIONAL)
STATIC VOID EFIAPI MmGuidedEventNotify(IN EFI_EVENT Event, IN VOID *Context)
#define PcdGet64(TokenName)
Definition: PcdLib.h:375
@ EfiGcdMemoryTypeReserved
Definition: PiDxeCis.h:32
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
@ EFI_NATIVE_INTERFACE
Definition: UefiSpec.h:1193
Definition: Base.h:213