1 /** @file
2   Entry point to the Standalone MM Foundation when initialized during the SEC
3   phase on ARM platforms
4 
5 Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 
11 #include <PiMm.h>
12 
13 #include <Library/AArch64/StandaloneMmCoreEntryPoint.h>
14 
15 #include <PiPei.h>
16 #include <Guid/MmramMemoryReserve.h>
17 #include <Guid/MpInformation.h>
18 
19 #include <Library/ArmMmuLib.h>
20 #include <Library/ArmSvcLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/HobLib.h>
23 #include <Library/BaseLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/SerialPortLib.h>
26 #include <Library/PcdLib.h>
27 
28 #include <IndustryStandard/ArmStdSmc.h>
29 #include <IndustryStandard/ArmMmSvc.h>
30 #include <IndustryStandard/ArmFfaSvc.h>
31 
32 #define SPM_MAJOR_VER_MASK        0xFFFF0000
33 #define SPM_MINOR_VER_MASK        0x0000FFFF
34 #define SPM_MAJOR_VER_SHIFT       16
35 #define FFA_NOT_SUPPORTED         -1
36 
37 STATIC CONST UINT32 mSpmMajorVer = SPM_MAJOR_VERSION;
38 STATIC CONST UINT32 mSpmMinorVer = SPM_MINOR_VERSION;
39 
40 STATIC CONST UINT32 mSpmMajorVerFfa = SPM_MAJOR_VERSION_FFA;
41 STATIC CONST UINT32 mSpmMinorVerFfa = SPM_MINOR_VERSION_FFA;
42 
43 #define BOOT_PAYLOAD_VERSION      1
44 
45 PI_MM_ARM_TF_CPU_DRIVER_ENTRYPOINT      CpuDriverEntryPoint = NULL;
46 
47 /**
48   Retrieve a pointer to and print the boot information passed by privileged
49   secure firmware.
50 
51   @param  [in] SharedBufAddress   The pointer memory shared with privileged
52                                   firmware.
53 
54 **/
55 EFI_SECURE_PARTITION_BOOT_INFO *
GetAndPrintBootinformation(IN VOID * SharedBufAddress)56 GetAndPrintBootinformation (
57   IN VOID                      *SharedBufAddress
58 )
59 {
60   EFI_SECURE_PARTITION_BOOT_INFO *PayloadBootInfo;
61   EFI_SECURE_PARTITION_CPU_INFO  *PayloadCpuInfo;
62   UINTN                          Index;
63 
64   PayloadBootInfo = (EFI_SECURE_PARTITION_BOOT_INFO *) SharedBufAddress;
65 
66   if (PayloadBootInfo == NULL) {
67     DEBUG ((DEBUG_ERROR, "PayloadBootInfo NULL\n"));
68     return NULL;
69   }
70 
71   if (PayloadBootInfo->Header.Version != BOOT_PAYLOAD_VERSION) {
72     DEBUG ((DEBUG_ERROR, "Boot Information Version Mismatch. Current=0x%x, Expected=0x%x.\n",
73             PayloadBootInfo->Header.Version, BOOT_PAYLOAD_VERSION));
74     return NULL;
75   }
76 
77   DEBUG ((DEBUG_INFO, "NumSpMemRegions - 0x%x\n", PayloadBootInfo->NumSpMemRegions));
78   DEBUG ((DEBUG_INFO, "SpMemBase       - 0x%lx\n", PayloadBootInfo->SpMemBase));
79   DEBUG ((DEBUG_INFO, "SpMemLimit      - 0x%lx\n", PayloadBootInfo->SpMemLimit));
80   DEBUG ((DEBUG_INFO, "SpImageBase     - 0x%lx\n", PayloadBootInfo->SpImageBase));
81   DEBUG ((DEBUG_INFO, "SpStackBase     - 0x%lx\n", PayloadBootInfo->SpStackBase));
82   DEBUG ((DEBUG_INFO, "SpHeapBase      - 0x%lx\n", PayloadBootInfo->SpHeapBase));
83   DEBUG ((DEBUG_INFO, "SpNsCommBufBase - 0x%lx\n", PayloadBootInfo->SpNsCommBufBase));
84   DEBUG ((DEBUG_INFO, "SpSharedBufBase - 0x%lx\n", PayloadBootInfo->SpSharedBufBase));
85 
86   DEBUG ((DEBUG_INFO, "SpImageSize     - 0x%x\n", PayloadBootInfo->SpImageSize));
87   DEBUG ((DEBUG_INFO, "SpPcpuStackSize - 0x%x\n", PayloadBootInfo->SpPcpuStackSize));
88   DEBUG ((DEBUG_INFO, "SpHeapSize      - 0x%x\n", PayloadBootInfo->SpHeapSize));
89   DEBUG ((DEBUG_INFO, "SpNsCommBufSize - 0x%x\n", PayloadBootInfo->SpNsCommBufSize));
90   DEBUG ((DEBUG_INFO, "SpPcpuSharedBufSize - 0x%x\n", PayloadBootInfo->SpPcpuSharedBufSize));
91 
92   DEBUG ((DEBUG_INFO, "NumCpus         - 0x%x\n", PayloadBootInfo->NumCpus));
93   DEBUG ((DEBUG_INFO, "CpuInfo         - 0x%p\n", PayloadBootInfo->CpuInfo));
94 
95   PayloadCpuInfo = (EFI_SECURE_PARTITION_CPU_INFO *) PayloadBootInfo->CpuInfo;
96 
97   if (PayloadCpuInfo == NULL) {
98     DEBUG ((DEBUG_ERROR, "PayloadCpuInfo NULL\n"));
99     return NULL;
100   }
101 
102   for (Index = 0; Index < PayloadBootInfo->NumCpus; Index++) {
103     DEBUG ((DEBUG_INFO, "Mpidr           - 0x%lx\n", PayloadCpuInfo[Index].Mpidr));
104     DEBUG ((DEBUG_INFO, "LinearId        - 0x%x\n", PayloadCpuInfo[Index].LinearId));
105     DEBUG ((DEBUG_INFO, "Flags           - 0x%x\n", PayloadCpuInfo[Index].Flags));
106   }
107 
108   return PayloadBootInfo;
109 }
110 
111 /**
112   A loop to delegated events.
113 
114   @param  [in] EventCompleteSvcArgs   Pointer to the event completion arguments.
115 
116 **/
117 VOID
118 EFIAPI
DelegatedEventLoop(IN ARM_SVC_ARGS * EventCompleteSvcArgs)119 DelegatedEventLoop (
120   IN ARM_SVC_ARGS *EventCompleteSvcArgs
121   )
122 {
123   BOOLEAN FfaEnabled;
124   EFI_STATUS Status;
125   UINTN SvcStatus;
126 
127   while (TRUE) {
128     ArmCallSvc (EventCompleteSvcArgs);
129 
130     DEBUG ((DEBUG_INFO, "Received delegated event\n"));
131     DEBUG ((DEBUG_INFO, "X0 :  0x%x\n", (UINT32) EventCompleteSvcArgs->Arg0));
132     DEBUG ((DEBUG_INFO, "X1 :  0x%x\n", (UINT32) EventCompleteSvcArgs->Arg1));
133     DEBUG ((DEBUG_INFO, "X2 :  0x%x\n", (UINT32) EventCompleteSvcArgs->Arg2));
134     DEBUG ((DEBUG_INFO, "X3 :  0x%x\n", (UINT32) EventCompleteSvcArgs->Arg3));
135     DEBUG ((DEBUG_INFO, "X4 :  0x%x\n", (UINT32) EventCompleteSvcArgs->Arg4));
136     DEBUG ((DEBUG_INFO, "X5 :  0x%x\n", (UINT32) EventCompleteSvcArgs->Arg5));
137     DEBUG ((DEBUG_INFO, "X6 :  0x%x\n", (UINT32) EventCompleteSvcArgs->Arg6));
138     DEBUG ((DEBUG_INFO, "X7 :  0x%x\n", (UINT32) EventCompleteSvcArgs->Arg7));
139 
140     FfaEnabled = FeaturePcdGet (PcdFfaEnable);
141     if (FfaEnabled) {
142       Status = CpuDriverEntryPoint (
143                  EventCompleteSvcArgs->Arg0,
144                  EventCompleteSvcArgs->Arg6,
145                  EventCompleteSvcArgs->Arg3
146                  );
147       if (EFI_ERROR (Status)) {
148         DEBUG ((DEBUG_ERROR, "Failed delegated event 0x%x, Status 0x%x\n",
149           EventCompleteSvcArgs->Arg3, Status));
150       }
151     } else {
152       Status = CpuDriverEntryPoint (
153                  EventCompleteSvcArgs->Arg0,
154                  EventCompleteSvcArgs->Arg3,
155                  EventCompleteSvcArgs->Arg1
156                  );
157       if (EFI_ERROR (Status)) {
158         DEBUG ((DEBUG_ERROR, "Failed delegated event 0x%x, Status 0x%x\n",
159           EventCompleteSvcArgs->Arg0, Status));
160       }
161     }
162 
163     switch (Status) {
164     case EFI_SUCCESS:
165       SvcStatus = ARM_SVC_SPM_RET_SUCCESS;
166       break;
167     case EFI_INVALID_PARAMETER:
168       SvcStatus = ARM_SVC_SPM_RET_INVALID_PARAMS;
169       break;
170     case EFI_ACCESS_DENIED:
171       SvcStatus = ARM_SVC_SPM_RET_DENIED;
172       break;
173     case EFI_OUT_OF_RESOURCES:
174       SvcStatus = ARM_SVC_SPM_RET_NO_MEMORY;
175       break;
176     case EFI_UNSUPPORTED:
177       SvcStatus = ARM_SVC_SPM_RET_NOT_SUPPORTED;
178       break;
179     default:
180       SvcStatus = ARM_SVC_SPM_RET_NOT_SUPPORTED;
181       break;
182     }
183 
184     if (FfaEnabled) {
185       EventCompleteSvcArgs->Arg0 = ARM_SVC_ID_FFA_MSG_SEND_DIRECT_RESP_AARCH64;
186       EventCompleteSvcArgs->Arg1 = 0;
187       EventCompleteSvcArgs->Arg2 = 0;
188       EventCompleteSvcArgs->Arg3 = ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64;
189       EventCompleteSvcArgs->Arg4 = SvcStatus;
190     } else {
191       EventCompleteSvcArgs->Arg0 = ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64;
192       EventCompleteSvcArgs->Arg1 = SvcStatus;
193     }
194   }
195 }
196 
197 /**
198   Query the SPM version, check compatibility and return success if compatible.
199 
200   @retval EFI_SUCCESS       SPM versions compatible.
201   @retval EFI_UNSUPPORTED   SPM versions not compatible.
202 **/
203 STATIC
204 EFI_STATUS
GetSpmVersion(VOID)205 GetSpmVersion (VOID)
206 {
207   EFI_STATUS   Status;
208   UINT16       CalleeSpmMajorVer;
209   UINT16       CallerSpmMajorVer;
210   UINT16       CalleeSpmMinorVer;
211   UINT16       CallerSpmMinorVer;
212   UINT32       SpmVersion;
213   ARM_SVC_ARGS SpmVersionArgs;
214 
215   if (FeaturePcdGet (PcdFfaEnable)) {
216     SpmVersionArgs.Arg0 = ARM_SVC_ID_FFA_VERSION_AARCH32;
217     SpmVersionArgs.Arg1 = mSpmMajorVerFfa << SPM_MAJOR_VER_SHIFT;
218     SpmVersionArgs.Arg1 |= mSpmMinorVerFfa;
219     CallerSpmMajorVer = mSpmMajorVerFfa;
220     CallerSpmMinorVer = mSpmMinorVerFfa;
221   } else {
222     SpmVersionArgs.Arg0 = ARM_SVC_ID_SPM_VERSION_AARCH32;
223     CallerSpmMajorVer = mSpmMajorVer;
224     CallerSpmMinorVer = mSpmMinorVer;
225   }
226 
227   ArmCallSvc (&SpmVersionArgs);
228 
229   SpmVersion = SpmVersionArgs.Arg0;
230   if (SpmVersion == FFA_NOT_SUPPORTED) {
231     return EFI_UNSUPPORTED;
232   }
233 
234   CalleeSpmMajorVer = ((SpmVersion & SPM_MAJOR_VER_MASK) >> SPM_MAJOR_VER_SHIFT);
235   CalleeSpmMinorVer = ((SpmVersion & SPM_MINOR_VER_MASK) >> 0);
236 
237   // Different major revision values indicate possibly incompatible functions.
238   // For two revisions, A and B, for which the major revision values are
239   // identical, if the minor revision value of revision B is greater than
240   // the minor revision value of revision A, then every function in
241   // revision A must work in a compatible way with revision B.
242   // However, it is possible for revision B to have a higher
243   // function count than revision A.
244   if ((CalleeSpmMajorVer == CallerSpmMajorVer) &&
245       (CalleeSpmMinorVer >= CallerSpmMinorVer))
246   {
247     DEBUG ((DEBUG_INFO, "SPM Version: Major=0x%x, Minor=0x%x\n",
248            CalleeSpmMajorVer, CalleeSpmMinorVer));
249     Status = EFI_SUCCESS;
250   }
251   else
252   {
253     DEBUG ((DEBUG_INFO, "Incompatible SPM Versions.\n Callee Version: Major=0x%x, Minor=0x%x.\n Caller: Major=0x%x, Minor>=0x%x.\n",
254             CalleeSpmMajorVer, CalleeSpmMinorVer, CallerSpmMajorVer, CallerSpmMinorVer));
255     Status = EFI_UNSUPPORTED;
256   }
257 
258   return Status;
259 }
260 
261 /**
262   Initialize parameters to be sent via SVC call.
263 
264   @param[out]     InitMmFoundationSvcArgs  Args structure
265   @param[out]     Ret                      Return Code
266 
267 **/
268 STATIC
269 VOID
InitArmSvcArgs(OUT ARM_SVC_ARGS * InitMmFoundationSvcArgs,OUT INT32 * Ret)270 InitArmSvcArgs (
271   OUT ARM_SVC_ARGS *InitMmFoundationSvcArgs,
272   OUT INT32 *Ret
273   )
274 {
275   if (FeaturePcdGet (PcdFfaEnable)) {
276     InitMmFoundationSvcArgs->Arg0 = ARM_SVC_ID_FFA_MSG_SEND_DIRECT_RESP_AARCH64;
277     InitMmFoundationSvcArgs->Arg1 = 0;
278     InitMmFoundationSvcArgs->Arg2 = 0;
279     InitMmFoundationSvcArgs->Arg3 = ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64;
280     InitMmFoundationSvcArgs->Arg4 = *Ret;
281   } else {
282     InitMmFoundationSvcArgs->Arg0 = ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64;
283     InitMmFoundationSvcArgs->Arg1 = *Ret;
284   }
285 }
286 
287 /**
288   The entry point of Standalone MM Foundation.
289 
290   @param  [in]  SharedBufAddress  Pointer to the Buffer between SPM and SP.
291   @param  [in]  SharedBufSize     Size of the shared buffer.
292   @param  [in]  cookie1           Cookie 1
293   @param  [in]  cookie2           Cookie 2
294 
295 **/
296 VOID
297 EFIAPI
_ModuleEntryPoint(IN VOID * SharedBufAddress,IN UINT64 SharedBufSize,IN UINT64 cookie1,IN UINT64 cookie2)298 _ModuleEntryPoint (
299   IN VOID    *SharedBufAddress,
300   IN UINT64  SharedBufSize,
301   IN UINT64  cookie1,
302   IN UINT64  cookie2
303   )
304 {
305   PE_COFF_LOADER_IMAGE_CONTEXT            ImageContext;
306   EFI_SECURE_PARTITION_BOOT_INFO          *PayloadBootInfo;
307   ARM_SVC_ARGS                            InitMmFoundationSvcArgs;
308   EFI_STATUS                              Status;
309   INT32                                   Ret;
310   UINT32                                  SectionHeaderOffset;
311   UINT16                                  NumberOfSections;
312   VOID                                    *HobStart;
313   VOID                                    *TeData;
314   UINTN                                   TeDataSize;
315   EFI_PHYSICAL_ADDRESS                    ImageBase;
316 
317   // Get Secure Partition Manager Version Information
318   Status = GetSpmVersion ();
319   if (EFI_ERROR (Status)) {
320     goto finish;
321   }
322 
323   PayloadBootInfo = GetAndPrintBootinformation (SharedBufAddress);
324   if (PayloadBootInfo == NULL) {
325     Status = EFI_UNSUPPORTED;
326     goto finish;
327   }
328 
329   // Locate PE/COFF File information for the Standalone MM core module
330   Status = LocateStandaloneMmCorePeCoffData (
331              (EFI_FIRMWARE_VOLUME_HEADER *) PayloadBootInfo->SpImageBase,
332              &TeData,
333              &TeDataSize
334              );
335 
336   if (EFI_ERROR (Status)) {
337     goto finish;
338   }
339 
340   // Obtain the PE/COFF Section information for the Standalone MM core module
341   Status = GetStandaloneMmCorePeCoffSections (
342              TeData,
343              &ImageContext,
344              &ImageBase,
345              &SectionHeaderOffset,
346              &NumberOfSections
347              );
348 
349   if (EFI_ERROR (Status)) {
350     goto finish;
351   }
352 
353   //
354   // ImageBase may deviate from ImageContext.ImageAddress if we are dealing
355   // with a TE image, in which case the latter points to the actual offset
356   // of the image, whereas ImageBase refers to the address where the image
357   // would start if the stripped PE headers were still in place. In either
358   // case, we need to fix up ImageBase so it refers to the actual current
359   // load address.
360   //
361   ImageBase += (UINTN)TeData - ImageContext.ImageAddress;
362 
363   // Update the memory access permissions of individual sections in the
364   // Standalone MM core module
365   Status = UpdateMmFoundationPeCoffPermissions (
366              &ImageContext,
367              ImageBase,
368              SectionHeaderOffset,
369              NumberOfSections,
370              ArmSetMemoryRegionNoExec,
371              ArmSetMemoryRegionReadOnly,
372              ArmClearMemoryRegionReadOnly
373              );
374 
375   if (EFI_ERROR (Status)) {
376     goto finish;
377   }
378 
379   if (ImageContext.ImageAddress != (UINTN)TeData) {
380     ImageContext.ImageAddress = (UINTN)TeData;
381     ArmSetMemoryRegionNoExec (ImageBase, SIZE_4KB);
382     ArmClearMemoryRegionReadOnly (ImageBase, SIZE_4KB);
383 
384     Status = PeCoffLoaderRelocateImage (&ImageContext);
385     ASSERT_EFI_ERROR (Status);
386   }
387 
388   //
389   // Create Hoblist based upon boot information passed by privileged software
390   //
391   HobStart = CreateHobListFromBootInfo (&CpuDriverEntryPoint, PayloadBootInfo);
392 
393   //
394   // Call the MM Core entry point
395   //
396   ProcessModuleEntryPointList (HobStart);
397 
398   DEBUG ((DEBUG_INFO, "Shared Cpu Driver EP 0x%lx\n", (UINT64) CpuDriverEntryPoint));
399 
400 finish:
401   if (Status == RETURN_UNSUPPORTED) {
402     Ret = -1;
403   } else if (Status == RETURN_INVALID_PARAMETER) {
404     Ret = -2;
405   } else if (Status == EFI_NOT_FOUND) {
406     Ret = -7;
407   } else {
408     Ret = 0;
409   }
410   ZeroMem (&InitMmFoundationSvcArgs, sizeof(InitMmFoundationSvcArgs));
411   InitArmSvcArgs (&InitMmFoundationSvcArgs, &Ret);
412   DelegatedEventLoop (&InitMmFoundationSvcArgs);
413 }
414