]> git.proxmox.com Git - mirror_edk2.git/blob - StandaloneMmPkg/Drivers/StandaloneMmCpu/EventHandle.c
StandaloneMmPkg: Change OPTIONAL keyword usage style
[mirror_edk2.git] / StandaloneMmPkg / Drivers / StandaloneMmCpu / EventHandle.c
1 /** @file
2
3 Copyright (c) 2016 HP Development Company, L.P.
4 Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.
5 Copyright (c) 2021, Linaro Limited
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include <Base.h>
12 #include <Pi/PiMmCis.h>
13
14
15 #include <Library/ArmSvcLib.h>
16 #include <Library/ArmLib.h>
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/HobLib.h>
20
21 #include <Protocol/DebugSupport.h> // for EFI_SYSTEM_CONTEXT
22
23 #include <Guid/ZeroGuid.h>
24 #include <Guid/MmramMemoryReserve.h>
25
26 #include <IndustryStandard/ArmFfaSvc.h>
27 #include <IndustryStandard/ArmStdSmc.h>
28
29 #include "StandaloneMmCpu.h"
30
31 EFI_STATUS
32 EFIAPI
33 MmFoundationEntryRegister (
34 IN CONST EFI_MM_CONFIGURATION_PROTOCOL *This,
35 IN EFI_MM_ENTRY_POINT MmEntryPoint
36 );
37
38 //
39 // On ARM platforms every event is expected to have a GUID associated with
40 // it. It will be used by the MM Entry point to find the handler for the
41 // event. It will either be populated in a EFI_MM_COMMUNICATE_HEADER by the
42 // caller of the event (e.g. MM_COMMUNICATE SMC) or by the CPU driver
43 // (e.g. during an asynchronous event). In either case, this context is
44 // maintained in an array which has an entry for each CPU. The pointer to this
45 // array is held in PerCpuGuidedEventContext. Memory is allocated once the
46 // number of CPUs in the system are made known through the
47 // MP_INFORMATION_HOB_DATA.
48 //
49 EFI_MM_COMMUNICATE_HEADER **PerCpuGuidedEventContext = NULL;
50
51 // Descriptor with whereabouts of memory used for communication with the normal world
52 EFI_MMRAM_DESCRIPTOR mNsCommBuffer;
53
54 MP_INFORMATION_HOB_DATA *mMpInformationHobData;
55
56 EFI_MM_CONFIGURATION_PROTOCOL mMmConfig = {
57 0,
58 MmFoundationEntryRegister
59 };
60
61 STATIC EFI_MM_ENTRY_POINT mMmEntryPoint = NULL;
62
63 /**
64 The PI Standalone MM entry point for the TF-A CPU driver.
65
66 @param [in] EventId The event Id.
67 @param [in] CpuNumber The CPU number.
68 @param [in] NsCommBufferAddr Address of the NS common buffer.
69
70 @retval EFI_SUCCESS Success.
71 @retval EFI_INVALID_PARAMETER A parameter was invalid.
72 @retval EFI_ACCESS_DENIED Access not permitted.
73 @retval EFI_OUT_OF_RESOURCES Out of resources.
74 @retval EFI_UNSUPPORTED Operation not supported.
75 **/
76 EFI_STATUS
77 PiMmStandaloneArmTfCpuDriverEntry (
78 IN UINTN EventId,
79 IN UINTN CpuNumber,
80 IN UINTN NsCommBufferAddr
81 )
82 {
83 EFI_MM_COMMUNICATE_HEADER *GuidedEventContext;
84 EFI_MM_ENTRY_CONTEXT MmEntryPointContext;
85 EFI_STATUS Status;
86 UINTN NsCommBufferSize;
87
88 DEBUG ((DEBUG_INFO, "Received event - 0x%x on cpu %d\n", EventId, CpuNumber));
89
90 Status = EFI_SUCCESS;
91 //
92 // ARM TF passes SMC FID of the MM_COMMUNICATE interface as the Event ID upon
93 // receipt of a synchronous MM request. Use the Event ID to distinguish
94 // between synchronous and asynchronous events.
95 //
96 if ((ARM_SMC_ID_MM_COMMUNICATE != EventId) &&
97 (ARM_SVC_ID_FFA_MSG_SEND_DIRECT_REQ != EventId)) {
98 DEBUG ((DEBUG_INFO, "UnRecognized Event - 0x%x\n", EventId));
99 return EFI_INVALID_PARAMETER;
100 }
101
102 // Perform parameter validation of NsCommBufferAddr
103 if (NsCommBufferAddr == (UINTN)NULL) {
104 return EFI_INVALID_PARAMETER;
105 }
106
107 if (NsCommBufferAddr < mNsCommBuffer.PhysicalStart) {
108 return EFI_ACCESS_DENIED;
109 }
110
111 if ((NsCommBufferAddr + sizeof (EFI_MM_COMMUNICATE_HEADER)) >=
112 (mNsCommBuffer.PhysicalStart + mNsCommBuffer.PhysicalSize)) {
113 return EFI_INVALID_PARAMETER;
114 }
115
116 // Find out the size of the buffer passed
117 NsCommBufferSize = ((EFI_MM_COMMUNICATE_HEADER *) NsCommBufferAddr)->MessageLength +
118 sizeof (EFI_MM_COMMUNICATE_HEADER);
119
120 // perform bounds check.
121 if (NsCommBufferAddr + NsCommBufferSize >=
122 mNsCommBuffer.PhysicalStart + mNsCommBuffer.PhysicalSize) {
123 return EFI_ACCESS_DENIED;
124 }
125
126 GuidedEventContext = NULL;
127 // Now that the secure world can see the normal world buffer, allocate
128 // memory to copy the communication buffer to the secure world.
129 Status = mMmst->MmAllocatePool (
130 EfiRuntimeServicesData,
131 NsCommBufferSize,
132 (VOID **) &GuidedEventContext
133 );
134
135 if (Status != EFI_SUCCESS) {
136 DEBUG ((DEBUG_INFO, "Mem alloc failed - 0x%x\n", EventId));
137 return EFI_OUT_OF_RESOURCES;
138 }
139
140 // X1 contains the VA of the normal world memory accessible from
141 // S-EL0
142 CopyMem (GuidedEventContext, (CONST VOID *) NsCommBufferAddr, NsCommBufferSize);
143
144 // Stash the pointer to the allocated Event Context for this CPU
145 PerCpuGuidedEventContext[CpuNumber] = GuidedEventContext;
146
147 ZeroMem (&MmEntryPointContext, sizeof (EFI_MM_ENTRY_CONTEXT));
148
149 MmEntryPointContext.CurrentlyExecutingCpu = CpuNumber;
150 MmEntryPointContext.NumberOfCpus = mMpInformationHobData->NumberOfProcessors;
151
152 // Populate the MM system table with MP and state information
153 mMmst->CurrentlyExecutingCpu = CpuNumber;
154 mMmst->NumberOfCpus = mMpInformationHobData->NumberOfProcessors;
155 mMmst->CpuSaveStateSize = 0;
156 mMmst->CpuSaveState = NULL;
157
158 if (mMmEntryPoint == NULL) {
159 DEBUG ((DEBUG_INFO, "Mm Entry point Not Found\n"));
160 return EFI_UNSUPPORTED;
161 }
162
163 mMmEntryPoint (&MmEntryPointContext);
164
165 // Free the memory allocation done earlier and reset the per-cpu context
166 ASSERT (GuidedEventContext);
167 CopyMem ((VOID *)NsCommBufferAddr, (CONST VOID *) GuidedEventContext, NsCommBufferSize);
168
169 Status = mMmst->MmFreePool ((VOID *) GuidedEventContext);
170 if (Status != EFI_SUCCESS) {
171 return EFI_OUT_OF_RESOURCES;
172 }
173 PerCpuGuidedEventContext[CpuNumber] = NULL;
174
175 return Status;
176 }
177
178 /**
179 Registers the MM foundation entry point.
180
181 @param [in] This Pointer to the MM Configuration protocol.
182 @param [in] MmEntryPoint Function pointer to the MM Entry point.
183
184 @retval EFI_SUCCESS Success.
185 **/
186 EFI_STATUS
187 EFIAPI
188 MmFoundationEntryRegister (
189 IN CONST EFI_MM_CONFIGURATION_PROTOCOL *This,
190 IN EFI_MM_ENTRY_POINT MmEntryPoint
191 )
192 {
193 // store the entry point in a global
194 mMmEntryPoint = MmEntryPoint;
195 return EFI_SUCCESS;
196 }
197
198 /**
199 This function is the main entry point for an MM handler dispatch
200 or communicate-based callback.
201
202 @param DispatchHandle The unique handle assigned to this handler by
203 MmiHandlerRegister().
204 @param Context Points to an optional handler context which was
205 specified when the handler was registered.
206 @param CommBuffer A pointer to a collection of data in memory that will
207 be conveyed from a non-MM environment into an
208 MM environment.
209 @param CommBufferSize The size of the CommBuffer.
210
211 @return Status Code
212
213 **/
214 EFI_STATUS
215 EFIAPI
216 PiMmCpuTpFwRootMmiHandler (
217 IN EFI_HANDLE DispatchHandle,
218 IN CONST VOID *Context OPTIONAL,
219 IN OUT VOID *CommBuffer OPTIONAL,
220 IN OUT UINTN *CommBufferSize OPTIONAL
221 )
222 {
223 EFI_STATUS Status;
224 UINTN CpuNumber;
225
226 ASSERT (Context == NULL);
227 ASSERT (CommBuffer == NULL);
228 ASSERT (CommBufferSize == NULL);
229
230 CpuNumber = mMmst->CurrentlyExecutingCpu;
231 if (PerCpuGuidedEventContext[CpuNumber] == NULL) {
232 return EFI_NOT_FOUND;
233 }
234
235 DEBUG ((DEBUG_INFO, "CommBuffer - 0x%x, CommBufferSize - 0x%x\n",
236 PerCpuGuidedEventContext[CpuNumber],
237 PerCpuGuidedEventContext[CpuNumber]->MessageLength));
238
239 Status = mMmst->MmiManage (
240 &PerCpuGuidedEventContext[CpuNumber]->HeaderGuid,
241 NULL,
242 PerCpuGuidedEventContext[CpuNumber]->Data,
243 &PerCpuGuidedEventContext[CpuNumber]->MessageLength
244 );
245
246 if (Status != EFI_SUCCESS) {
247 DEBUG ((DEBUG_WARN, "Unable to manage Guided Event - %d\n", Status));
248 }
249
250 return Status;
251 }