VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/ArmPkg/Drivers/MmCommunicationPei/MmCommunicationPei.c@ 108794

Last change on this file since 108794 was 108794, checked in by vboxsync, 2 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 13.2 KB
Line 
1/** @file -- MmCommunicationPei.c
2 Provides an interface to send MM request in PEI
3
4 Copyright (c) 2016-2021, Arm Limited. All rights reserved.<BR>
5 Copyright (c) Microsoft Corporation.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7**/
8
9#include <PiPei.h>
10#include <IndustryStandard/ArmStdSmc.h>
11#include <IndustryStandard/MmCommunicate.h>
12
13#include <Protocol/MmCommunication.h>
14#include <Ppi/MmCommunication.h>
15
16#include <Library/BaseLib.h>
17#include <Library/BaseMemoryLib.h>
18#include <Library/ArmFfaLib.h>
19#include <Library/ArmSmcLib.h>
20#include <Library/DebugLib.h>
21#include <Library/PcdLib.h>
22#include <Library/PeimEntryPoint.h>
23#include <Library/PeiServicesLib.h>
24
25//
26// Partition ID if FF-A support is enabled
27//
28STATIC UINT16 mPartId;
29STATIC UINT16 mStMmPartId;
30
31/**
32 Check mm communication compatibility when use SPM_MM.
33
34**/
35STATIC
36EFI_STATUS
37EFIAPI
38GetMmCompatibility (
39 VOID
40 )
41{
42 EFI_STATUS Status;
43 UINT32 MmVersion;
44 ARM_SMC_ARGS MmVersionArgs;
45
46 // MM_VERSION uses SMC32 calling conventions
47 MmVersionArgs.Arg0 = ARM_SMC_ID_MM_VERSION_AARCH32;
48
49 ArmCallSmc (&MmVersionArgs);
50 if (MmVersionArgs.Arg0 == ARM_SMC_MM_RET_NOT_SUPPORTED) {
51 return EFI_UNSUPPORTED;
52 }
53
54 MmVersion = MmVersionArgs.Arg0;
55
56 if ((MM_MAJOR_VER (MmVersion) == MM_CALLER_MAJOR_VER) &&
57 (MM_MINOR_VER (MmVersion) >= MM_CALLER_MINOR_VER))
58 {
59 DEBUG ((
60 DEBUG_INFO,
61 "MM Version: Major=0x%x, Minor=0x%x\n",
62 MM_MAJOR_VER (MmVersion),
63 MM_MINOR_VER (MmVersion)
64 ));
65 Status = EFI_SUCCESS;
66 } else {
67 DEBUG ((
68 DEBUG_ERROR,
69 "Incompatible MM Versions.\n Current Version: Major=0x%x, Minor=0x%x.\n Expected: Major=0x%x, Minor>=0x%x.\n",
70 MM_MAJOR_VER (MmVersion),
71 MM_MINOR_VER (MmVersion),
72 MM_CALLER_MAJOR_VER,
73 MM_CALLER_MINOR_VER
74 ));
75 Status = EFI_UNSUPPORTED;
76 }
77
78 return Status;
79}
80
81/**
82 Check mm communication compatibility when use FF-A.
83
84**/
85STATIC
86EFI_STATUS
87EFIAPI
88GetFfaCompatibility (
89 VOID
90 )
91{
92 EFI_STATUS Status;
93 UINT16 CurrentMajorVersion;
94 UINT16 CurrentMinorVersion;
95
96 Status = ArmFfaLibGetVersion (
97 ARM_FFA_MAJOR_VERSION,
98 ARM_FFA_MINOR_VERSION,
99 &CurrentMajorVersion,
100 &CurrentMinorVersion
101 );
102 if (EFI_ERROR (Status)) {
103 return EFI_UNSUPPORTED;
104 }
105
106 if ((ARM_FFA_MAJOR_VERSION != CurrentMajorVersion) ||
107 (ARM_FFA_MINOR_VERSION > CurrentMinorVersion))
108 {
109 DEBUG ((
110 DEBUG_INFO,
111 "Incompatible FF-A Versions for MM_COMM.\n" \
112 "Request Version: Major=0x%x, Minor=0x%x.\n" \
113 "Current Version: Major=0x%x, Minor>=0x%x.\n",
114 ARM_FFA_MAJOR_VERSION,
115 ARM_FFA_MINOR_VERSION,
116 CurrentMajorVersion,
117 CurrentMinorVersion
118 ));
119 return EFI_UNSUPPORTED;
120 }
121
122 DEBUG ((
123 DEBUG_INFO,
124 "FF-A Version for MM_COMM: Major=0x%x, Minor=0x%x\n",
125 CurrentMajorVersion,
126 CurrentMinorVersion
127 ));
128
129 return EFI_SUCCESS;
130}
131
132/**
133 Initialize communication via FF-A.
134
135**/
136STATIC
137EFI_STATUS
138EFIAPI
139InitializeFfaCommunication (
140 VOID
141 )
142{
143 EFI_STATUS Status;
144 VOID *TxBuffer;
145 UINT64 TxBufferSize;
146 VOID *RxBuffer;
147 UINT64 RxBufferSize;
148 EFI_FFA_PART_INFO_DESC *StmmPartInfo;
149 UINT32 Count;
150 UINT32 Size;
151
152 Status = ArmFfaLibPartitionIdGet (&mPartId);
153 if (EFI_ERROR (Status)) {
154 DEBUG ((
155 DEBUG_ERROR,
156 "Failed to get partition id. Status: %r\n",
157 Status
158 ));
159 return Status;
160 }
161
162 Status = ArmFfaLibGetRxTxBuffers (
163 &TxBuffer,
164 &TxBufferSize,
165 &RxBuffer,
166 &RxBufferSize
167 );
168 if (EFI_ERROR (Status)) {
169 DEBUG ((
170 DEBUG_ERROR,
171 "Failed to get Rx/Tx Buffer. Status: %r\n",
172 Status
173 ));
174 return Status;
175 }
176
177 Status = ArmFfaLibPartitionInfoGet (
178 &gEfiMmCommunication2ProtocolGuid,
179 FFA_PART_INFO_FLAG_TYPE_DESC,
180 &Count,
181 &Size
182 );
183 if (EFI_ERROR (Status)) {
184 DEBUG ((
185 DEBUG_ERROR,
186 "Failed to get Stmm(%g) partition Info. Status: %r\n",
187 &gEfiMmCommunication2ProtocolGuid,
188 Status
189 ));
190 return Status;
191 }
192
193 if ((Count != 1) || (Size < sizeof (EFI_FFA_PART_INFO_DESC))) {
194 Status = EFI_INVALID_PARAMETER;
195 DEBUG ((
196 DEBUG_ERROR,
197 "Invalid partition Info(%g). Count: %d, Size: %d\n",
198 &gEfiMmCommunication2ProtocolGuid,
199 Count,
200 Size
201 ));
202 goto ErrorHandler;
203 }
204
205 StmmPartInfo = (EFI_FFA_PART_INFO_DESC *)RxBuffer;
206
207 if ((StmmPartInfo->PartitionProps & FFA_PART_PROP_RECV_DIRECT_REQ) == 0x00) {
208 Status = EFI_UNSUPPORTED;
209 DEBUG ((DEBUG_ERROR, "StandaloneMm doesn't receive DIRECT_MSG_REQ...\n"));
210 goto ErrorHandler;
211 }
212
213 mStMmPartId = StmmPartInfo->PartitionId;
214
215ErrorHandler:
216 ArmFfaLibRxRelease (mPartId);
217 return Status;
218}
219
220/**
221 Initialize mm communication.
222
223**/
224STATIC
225EFI_STATUS
226EFIAPI
227InitializeCommunication (
228 VOID
229 )
230{
231 EFI_STATUS Status;
232
233 Status = EFI_UNSUPPORTED;
234
235 if (IsFfaSupported ()) {
236 Status = GetFfaCompatibility ();
237 if (!EFI_ERROR (Status)) {
238 Status = InitializeFfaCommunication ();
239 }
240 } else {
241 Status = GetMmCompatibility ();
242 // No further initialisation required for SpmMM
243 }
244
245 return Status;
246}
247
248/**
249 Send mm communicate request via FF-A.
250
251 @retval EFI_SUCCESS
252 @retval Others Error.
253
254**/
255STATIC
256EFI_STATUS
257EFIAPI
258SendFfaMmCommunicate (
259 VOID
260 )
261{
262 EFI_STATUS Status;
263 DIRECT_MSG_ARGS CommunicateArgs;
264
265 ZeroMem (&CommunicateArgs, sizeof (DIRECT_MSG_ARGS));
266
267 CommunicateArgs.Arg0 = (UINTN)PcdGet64 (PcdMmBufferBase);
268
269 Status = ArmFfaLibMsgSendDirectReq (
270 mStMmPartId,
271 0,
272 &CommunicateArgs
273 );
274
275 while (Status == EFI_INTERRUPT_PENDING) {
276 // We are assuming vCPU0 of the StMM SP since it is UP.
277 Status = ArmFfaLibRun (mStMmPartId, 0x00);
278 }
279
280 return Status;
281}
282
283/**
284 Convert SmcMmRet value to EFI_STATUS.
285
286 @param[in] SmcMmRet Mm return code
287
288 @retval EFI_SUCCESS
289 @retval Others Error status correspond to SmcMmRet
290
291**/
292STATIC
293EFI_STATUS
294SmcMmRetToEfiStatus (
295 IN UINTN SmcMmRet
296 )
297{
298 switch ((UINT32)SmcMmRet) {
299 case ARM_SMC_MM_RET_SUCCESS:
300 return EFI_SUCCESS;
301 case ARM_SMC_MM_RET_INVALID_PARAMS:
302 return EFI_INVALID_PARAMETER;
303 case ARM_SMC_MM_RET_DENIED:
304 return EFI_ACCESS_DENIED;
305 case ARM_SMC_MM_RET_NO_MEMORY:
306 return EFI_OUT_OF_RESOURCES;
307 default:
308 return EFI_ACCESS_DENIED;
309 }
310}
311
312/**
313 Send mm communicate request via SPM_MM.
314
315 @retval EFI_SUCCESS
316 @retval Others Error.
317
318**/
319STATIC
320EFI_STATUS
321EFIAPI
322SendSpmMmCommunicate (
323 VOID
324 )
325{
326 ARM_SMC_ARGS CommunicateSmcArgs;
327
328 ZeroMem (&CommunicateSmcArgs, sizeof (ARM_SMC_ARGS));
329
330 // SMC Function ID
331 CommunicateSmcArgs.Arg0 = ARM_SMC_ID_MM_COMMUNICATE_AARCH64;
332
333 // Cookie
334 CommunicateSmcArgs.Arg1 = 0;
335
336 // comm_buffer_address (64-bit physical address)
337 CommunicateSmcArgs.Arg2 = (UINTN)PcdGet64 (PcdMmBufferBase);
338
339 // comm_size_address (not used, indicated by setting to zero)
340 CommunicateSmcArgs.Arg3 = 0;
341
342 // Call the Standalone MM environment.
343 ArmCallSmc (&CommunicateSmcArgs);
344
345 return SmcMmRetToEfiStatus (CommunicateSmcArgs.Arg0);
346}
347
348/**
349 MmCommunicationPeim
350 Communicates with a registered handler.
351 This function provides a service to send and receive messages from a registered UEFI service during PEI.
352
353 @param[in] This The EFI_PEI_MM_COMMUNICATION_PPI instance.
354 @param[in, out] CommBuffer Pointer to the data buffer
355 @param[in, out] CommSize The size of the data buffer being passed in. On exit, the
356 size of data being returned. Zero if the handler does not
357 wish to reply with any data.
358
359 @retval EFI_SUCCESS The message was successfully posted.
360 @retval EFI_INVALID_PARAMETER CommBuffer or CommSize was NULL, or *CommSize does not
361 match MessageLength + sizeof (EFI_MM_COMMUNICATE_HEADER).
362 @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.
363 If this error is returned, the MessageLength field
364 in the CommBuffer header or the integer pointed by
365 CommSize, are updated to reflect the maximum payload
366 size the implementation can accommodate.
367 @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,
368 if not omitted, are in address range that cannot be
369 accessed by the MM environment.
370**/
371STATIC
372EFI_STATUS
373EFIAPI
374MmCommunicationPeim (
375 IN CONST EFI_PEI_MM_COMMUNICATION_PPI *This,
376 IN OUT VOID *CommBuffer,
377 IN OUT UINTN *CommSize
378 )
379{
380 EFI_MM_COMMUNICATE_HEADER *CommunicateHeader;
381 EFI_MM_COMMUNICATE_HEADER *TempCommHeader;
382 EFI_STATUS Status;
383 UINTN BufferSize;
384
385 //
386 // Check parameters
387 //
388 if ((CommBuffer == NULL) || (CommSize == NULL)) {
389 ASSERT (CommBuffer != NULL);
390 ASSERT (CommSize != NULL);
391 return EFI_INVALID_PARAMETER;
392 }
393
394 // If the length of the CommBuffer is 0 then return the expected length.
395 // This case can be used by the consumer of this driver to find out the
396 // max size that can be used for allocating CommBuffer.
397 if ((*CommSize == 0) || (*CommSize > (UINTN)PcdGet64 (PcdMmBufferSize))) {
398 DEBUG ((
399 DEBUG_ERROR,
400 "%a Invalid CommSize value 0x%llx!\n",
401 __func__,
402 *CommSize
403 ));
404 *CommSize = (UINTN)PcdGet64 (PcdMmBufferSize);
405 return EFI_BAD_BUFFER_SIZE;
406 }
407
408 // Given CommBuffer is not NULL here, we use it to test the legitimacy of CommSize.
409 TempCommHeader = (EFI_MM_COMMUNICATE_HEADER *)(UINTN)CommBuffer;
410
411 // CommBuffer is a mandatory parameter. Hence, Rely on
412 // MessageLength + Header to ascertain the
413 // total size of the communication payload rather than
414 // rely on optional CommSize parameter
415 BufferSize = TempCommHeader->MessageLength +
416 sizeof (TempCommHeader->HeaderGuid) +
417 sizeof (TempCommHeader->MessageLength);
418
419 //
420 // If CommSize is supplied it must match MessageLength + sizeof (EFI_MM_COMMUNICATE_HEADER);
421 //
422 if (*CommSize != BufferSize) {
423 DEBUG ((
424 DEBUG_ERROR,
425 "%a Unexpected CommSize value, has: 0x%llx vs. expected: 0x%llx!\n",
426 __func__,
427 *CommSize,
428 BufferSize
429 ));
430 return EFI_INVALID_PARAMETER;
431 }
432
433 // Now we know that the size is something we can handle, copy it over to the designated comm buffer.
434 CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)(UINTN)(PcdGet64 (PcdMmBufferBase));
435
436 CopyMem (CommunicateHeader, CommBuffer, *CommSize);
437
438 if (IsFfaSupported ()) {
439 Status = SendFfaMmCommunicate ();
440 } else {
441 Status = SendSpmMmCommunicate ();
442 }
443
444 if (!EFI_ERROR (Status)) {
445 // On successful return, the size of data being returned is inferred from
446 // MessageLength + Header.
447 BufferSize = CommunicateHeader->MessageLength +
448 sizeof (CommunicateHeader->HeaderGuid) +
449 sizeof (CommunicateHeader->MessageLength);
450 if (BufferSize > (UINTN)PcdGet64 (PcdMmBufferSize)) {
451 // Something bad has happened, we should have landed in ARM_SMC_MM_RET_NO_MEMORY
452 Status = EFI_BAD_BUFFER_SIZE;
453 DEBUG ((
454 DEBUG_ERROR,
455 "%a Returned buffer exceeds communication buffer limit. Has: 0x%llx vs. max: 0x%llx!\n",
456 __func__,
457 BufferSize,
458 (UINTN)PcdGet64 (PcdMmBufferSize)
459 ));
460 } else {
461 CopyMem (CommBuffer, CommunicateHeader, BufferSize);
462 *CommSize = BufferSize;
463 }
464 }
465
466 return Status;
467}
468
469//
470// Module globals for the MM Communication PPI
471//
472STATIC CONST EFI_PEI_MM_COMMUNICATION_PPI mPeiMmCommunication = {
473 MmCommunicationPeim
474};
475
476STATIC CONST EFI_PEI_PPI_DESCRIPTOR mPeiMmCommunicationPpi = {
477 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
478 &gEfiPeiMmCommunicationPpiGuid,
479 (VOID *)&mPeiMmCommunication
480};
481
482/**
483 Entry point of PEI MM Communication driver
484
485 @param FileHandle Handle of the file being invoked.
486 Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
487 @param PeiServices General purpose services available to every PEIM.
488
489 @retval EFI_SUCCESS If the interface could be successfully installed
490 @retval Others Returned from PeiServicesInstallPpi()
491**/
492EFI_STATUS
493EFIAPI
494MmCommunicationPeiInitialize (
495 IN EFI_PEI_FILE_HANDLE FileHandle,
496 IN CONST EFI_PEI_SERVICES **PeiServices
497 )
498{
499 EFI_STATUS Status;
500
501 // Check that our static buffer is looking good.
502 // We are using PcdMmBufferBase to transfer variable data.
503 // We are not using the full size of the buffer since there is a cost
504 // of copying data between Normal and Secure World.
505 if ((PcdGet64 (PcdMmBufferBase) == 0) || (PcdGet64 (PcdMmBufferSize) == 0)) {
506 ASSERT (PcdGet64 (PcdMmBufferSize) > 0);
507 ASSERT (PcdGet64 (PcdMmBufferBase) != 0);
508 return EFI_UNSUPPORTED;
509 }
510
511 // Check if we can make the MM call
512 Status = InitializeCommunication ();
513 if (EFI_ERROR (Status)) {
514 return Status;
515 }
516
517 return PeiServicesInstallPpi (&mPeiMmCommunicationPpi);
518}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette