TianoCore EDK2 master
Loading...
Searching...
No Matches
MmCommunicationPei.c
1
9#include <PiPei.h>
11
13#include <Ppi/MmCommunication.h>
14
15#include <Library/BaseLib.h>
17#include <Library/ArmSmcLib.h>
18#include <Library/DebugLib.h>
19#include <Library/PcdLib.h>
22
48EFIAPI
49MmCommunicationPeim (
51 IN OUT VOID *CommBuffer,
52 IN OUT UINTN *CommSize
53 )
54{
55 EFI_MM_COMMUNICATE_HEADER *CommunicateHeader;
56 EFI_MM_COMMUNICATE_HEADER *TempCommHeader;
57 ARM_SMC_ARGS CommunicateSmcArgs;
58 EFI_STATUS Status;
59 UINTN BufferSize;
60
61 ZeroMem (&CommunicateSmcArgs, sizeof (ARM_SMC_ARGS));
62
63 // Check that our static buffer is looking good.
64 // We are using PcdMmBufferBase to transfer variable data.
65 // We are not using the full size of the buffer since there is a cost
66 // of copying data between Normal and Secure World.
67 if ((PcdGet64 (PcdMmBufferBase) == 0) || (PcdGet64 (PcdMmBufferSize) == 0)) {
68 ASSERT (PcdGet64 (PcdMmBufferSize) > 0);
69 ASSERT (PcdGet64 (PcdMmBufferBase) != 0);
70 return EFI_UNSUPPORTED;
71 }
72
73 //
74 // Check parameters
75 //
76 if ((CommBuffer == NULL) || (CommSize == NULL)) {
77 ASSERT (CommBuffer != NULL);
78 ASSERT (CommSize != NULL);
79 return EFI_INVALID_PARAMETER;
80 }
81
82 // If the length of the CommBuffer is 0 then return the expected length.
83 // This case can be used by the consumer of this driver to find out the
84 // max size that can be used for allocating CommBuffer.
85 if ((*CommSize == 0) || (*CommSize > (UINTN)PcdGet64 (PcdMmBufferSize))) {
86 DEBUG ((
87 DEBUG_ERROR,
88 "%a Invalid CommSize value 0x%llx!\n",
89 __func__,
90 *CommSize
91 ));
92 *CommSize = (UINTN)PcdGet64 (PcdMmBufferSize);
93 return EFI_BAD_BUFFER_SIZE;
94 }
95
96 // Given CommBuffer is not NULL here, we use it to test the legitimacy of CommSize.
97 TempCommHeader = (EFI_MM_COMMUNICATE_HEADER *)(UINTN)CommBuffer;
98
99 // CommBuffer is a mandatory parameter. Hence, Rely on
100 // MessageLength + Header to ascertain the
101 // total size of the communication payload rather than
102 // rely on optional CommSize parameter
103 BufferSize = TempCommHeader->MessageLength +
104 sizeof (TempCommHeader->HeaderGuid) +
105 sizeof (TempCommHeader->MessageLength);
106
107 //
108 // If CommSize is supplied it must match MessageLength + sizeof (EFI_MM_COMMUNICATE_HEADER);
109 //
110 if (*CommSize != BufferSize) {
111 DEBUG ((
112 DEBUG_ERROR,
113 "%a Unexpected CommSize value, has: 0x%llx vs. expected: 0x%llx!\n",
114 __func__,
115 *CommSize,
116 BufferSize
117 ));
118 return EFI_INVALID_PARAMETER;
119 }
120
121 // Now we know that the size is something we can handle, copy it over to the designated comm buffer.
122 CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)(UINTN)(PcdGet64 (PcdMmBufferBase));
123
124 CopyMem (CommunicateHeader, CommBuffer, *CommSize);
125
126 // SMC Function ID
127 CommunicateSmcArgs.Arg0 = ARM_SMC_ID_MM_COMMUNICATE_AARCH64;
128
129 // Cookie
130 CommunicateSmcArgs.Arg1 = 0;
131
132 // comm_buffer_address (64-bit physical address)
133 CommunicateSmcArgs.Arg2 = (UINTN)CommunicateHeader;
134
135 // comm_size_address (not used, indicated by setting to zero)
136 CommunicateSmcArgs.Arg3 = 0;
137
138 // Call the Standalone MM environment.
139 ArmCallSmc (&CommunicateSmcArgs);
140
141 switch (CommunicateSmcArgs.Arg0) {
142 case ARM_SMC_MM_RET_SUCCESS:
143 // On successful return, the size of data being returned is inferred from
144 // MessageLength + Header.
145 BufferSize = CommunicateHeader->MessageLength +
146 sizeof (CommunicateHeader->HeaderGuid) +
147 sizeof (CommunicateHeader->MessageLength);
148 if (BufferSize > (UINTN)PcdGet64 (PcdMmBufferSize)) {
149 // Something bad has happened, we should have landed in ARM_SMC_MM_RET_NO_MEMORY
150 DEBUG ((
151 DEBUG_ERROR,
152 "%a Returned buffer exceeds communication buffer limit. Has: 0x%llx vs. max: 0x%llx!\n",
153 __func__,
154 BufferSize,
155 (UINTN)PcdGet64 (PcdMmBufferSize)
156 ));
157 Status = EFI_BAD_BUFFER_SIZE;
158 break;
159 }
160
161 CopyMem (CommBuffer, CommunicateHeader, BufferSize);
162 *CommSize = BufferSize;
163 Status = EFI_SUCCESS;
164 break;
165
166 case ARM_SMC_MM_RET_INVALID_PARAMS:
167 Status = EFI_INVALID_PARAMETER;
168 break;
169
170 case ARM_SMC_MM_RET_DENIED:
171 Status = EFI_ACCESS_DENIED;
172 break;
173
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;
178 ASSERT (0);
179 break;
180
181 default:
182 Status = EFI_ACCESS_DENIED;
183 ASSERT (0);
184 break;
185 }
186
187 return Status;
188}
189
190//
191// Module globals for the MM Communication PPI
192//
193STATIC CONST EFI_PEI_MM_COMMUNICATION_PPI mPeiMmCommunication = {
194 MmCommunicationPeim
195};
196
197STATIC CONST EFI_PEI_PPI_DESCRIPTOR mPeiMmCommunicationPpi = {
198 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
199 &gEfiPeiMmCommunicationPpiGuid,
200 (VOID *)&mPeiMmCommunication
201};
202
214EFIAPI
215MmCommunicationPeiInitialize (
216 IN EFI_PEI_FILE_HANDLE FileHandle,
217 IN CONST EFI_PEI_SERVICES **PeiServices
218 )
219{
220 return PeiServicesInstallPpi (&mPeiMmCommunicationPpi);
221}
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)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_STATUS EFIAPI PeiServicesInstallPpi(IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define PcdGet64(TokenName)
Definition: PcdLib.h:375
VOID * EFI_PEI_FILE_HANDLE
Definition: PiPeiCis.h:26
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112