microsoft/mu_feature_ffa

Public

mirrored fromhttps://github.com/microsoft/mu_feature_ffaAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
ef8c8ffe3e9cd9f6fd3732ade9463d4841c3472e

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

FfaFeaturePkg/Library/SecurePartitionEntryPoint/StandaloneMmCoreEntryPoint.c

433lines · modecode

1/** @file
2 Entry point to the Secure Partition when initialized during the SEC
3 phase on ARM platforms
4
5Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR>
6Copyright (c), Microsoft Corporation.
7SPDX-License-Identifier: BSD-2-Clause-Patent
8
9**/
10
11#include <PiMm.h>
12
13#include <Library/ArmStandaloneMmCoreEntryPoint.h>
14
15#include <PiPei.h>
16#include <Guid/MmramMemoryReserve.h>
17#include <Guid/MpInformation.h>
18
19#include <libfdt.h>
20#include <Library/ArmMmuLib.h>
21#include <Library/ArmSvcLib.h>
22#include <Library/DebugLib.h>
23#include <Library/BaseLib.h>
24#include <Library/BaseMemoryLib.h>
25#include <Library/SerialPortLib.h>
26#include <Library/ArmStandaloneMmMmuLib.h>
27#include <Library/SecurePartitionServicesTableLib.h>
28#include <Library/PcdLib.h>
29
30#include <IndustryStandard/ArmStdSmc.h>
31#include <IndustryStandard/ArmMmSvc.h>
32#include <IndustryStandard/ArmFfaSvc.h>
33#include <IndustryStandard/ArmFfaBootInfo.h>
34
35#define FFA_PAGE_4K 0
36#define FFA_PAGE_16K 1
37#define FFA_PAGE_64K 2
38
39// Materialize the Secure Partition Services Table
40SECURE_PARTITION_SERVICES_TABLE mSpst = {
41 .FDTAddress = NULL
42};
43
44/**
45 This structure is used to stage boot information required to initialize the
46 standalone MM environment when FF-A is used as the interface between this
47 secure partition and the SPMC. This structure supersedes
48 EFI_SECURE_PARTITION_BOOT_INFO and reduces the amount of information that must
49 be passed by the SPMC for SP initialization.
50**/
51typedef struct {
52 UINT64 SpMemBase;
53 UINT64 SpMemSize;
54 UINT64 SpHeapBase;
55 UINT64 SpHeapSize;
56} SP_BOOT_INFO;
57
58/**
59 An StMM SP implements partial support for FF-A v1.0. The FF-A ABIs are used to
60 get and set permissions of memory pages in collaboration with the SPMC and
61 signalling completion of initialisation. The original Arm MM communication
62 interface is used for communication with the Normal world. A TF-A specific
63 interface is used for initialising the SP.
64
65 With FF-A v1.1, the StMM SP uses only FF-A ABIs for initialisation and
66 communication. This is subject to support for FF-A v1.1 in the SPMC. If this
67 is not the case, the StMM implementation reverts to the FF-A v1.0
68 behaviour. Any of this is applicable only if the feature flag PcdFfaEnable is
69 TRUE.
70
71 This function helps the caller determine whether FF-A v1.1 or v1.0 are
72 available and if only FF-A ABIs can be used at runtime.
73**/
74STATIC
75EFI_STATUS
76CheckFfaCompatibility (
77 BOOLEAN *UseOnlyFfaAbis
78 )
79{
80 UINT16 SpmcMajorVer;
81 UINT16 SpmcMinorVer;
82 EFI_STATUS Status;
83
84 Status = ArmFfaLibGetVersion (
85 ARM_FFA_MAJOR_VERSION,
86 ARM_FFA_MINOR_VERSION,
87 &SpmcMajorVer,
88 &SpmcMinorVer
89 );
90 if (EFI_ERROR (Status)) {
91 return Status;
92 }
93
94 // If the major versions differ then all bets are off.
95 if (SpmcMajorVer != ARM_FFA_MAJOR_VERSION) {
96 return EFI_UNSUPPORTED;
97 }
98
99 // We advertised v1.1 as our version. If the SPMC supports it, it must return
100 // the same or a compatible version. If it does not then FF-A ABIs cannot be
101 // used for all communication.
102 if (SpmcMinorVer >= ARM_FFA_MINOR_VERSION) {
103 *UseOnlyFfaAbis = TRUE;
104 } else {
105 *UseOnlyFfaAbis = FALSE;
106 }
107
108 // We have validated that there is a compatible FF-A
109 // implementation. So. return success.
110 return EFI_SUCCESS;
111}
112
113STATIC
114EFI_STATUS
115ReadProperty32 (
116 IN VOID *DtbAddress,
117 IN INT32 Offset,
118 IN CHAR8 *Property,
119 OUT UINT32 *Value
120 )
121{
122 CONST UINT32 *Property32;
123
124 Property32 = fdt_getprop (DtbAddress, Offset, Property, NULL);
125 if (Property32 == NULL) {
126 DEBUG ((
127 DEBUG_ERROR,
128 "%s: Missing in FF-A boot information manifest\n",
129 Property
130 ));
131 return EFI_INVALID_PARAMETER;
132 }
133
134 *Value = fdt32_to_cpu (*Property32);
135
136 return EFI_SUCCESS;
137}
138
139STATIC
140EFI_STATUS
141ReadProperty64 (
142 IN VOID *DtbAddress,
143 IN INT32 Offset,
144 IN CHAR8 *Property,
145 OUT UINT64 *Value
146 )
147{
148 CONST UINT64 *Property64;
149
150 Property64 = fdt_getprop (DtbAddress, Offset, Property, NULL);
151 if (Property64 == NULL) {
152 DEBUG ((
153 DEBUG_ERROR,
154 "%s: Missing in FF-A boot information manifest\n",
155 Property
156 ));
157 return EFI_INVALID_PARAMETER;
158 }
159
160 *Value = fdt64_to_cpu (*Property64);
161
162 return EFI_SUCCESS;
163}
164
165/**
166
167 Populates FF-A boot information structure.
168
169 This function receives the address of a DTB from which boot information defind
170 by FF-A and required to initialize the standalone environment is extracted.
171
172 @param [in, out] SpBootInfo Pointer to a pre-allocated boot info structure to be
173 populated.
174 @param [in] DtbAddress Address of the Device tree from where boot
175 information will be fetched.
176**/
177STATIC
178EFI_STATUS
179PopulateBootinformation (
180 IN OUT SP_BOOT_INFO *SpBootInfo,
181 IN VOID *DtbAddress
182 )
183{
184 INTN Status;
185 INT32 Offset;
186 UINT64 MemBase;
187 UINT32 EntryPointOffset;
188 UINT32 PageSize;
189
190 Offset = fdt_node_offset_by_compatible (DtbAddress, -1, "arm,ffa-manifest-1.0");
191
192 DEBUG ((DEBUG_INFO, "Offset = %d \n", Offset));
193 if (Offset < 0) {
194 DEBUG ((DEBUG_ERROR, "Missing FF-A boot information in manifest\n"));
195 return EFI_NOT_FOUND;
196 }
197
198 Status = ReadProperty64 (
199 DtbAddress,
200 Offset,
201 "load-address",
202 &MemBase
203 );
204 if (Status != EFI_SUCCESS) {
205 return Status;
206 }
207
208 Status = ReadProperty32 (
209 DtbAddress,
210 Offset,
211 "entrypoint-offset",
212 &EntryPointOffset
213 );
214
215 SpBootInfo->SpMemBase = MemBase + EntryPointOffset;
216 DEBUG ((DEBUG_INFO, "sp mem base = 0x%llx\n", SpBootInfo->SpMemBase));
217
218 Status = ReadProperty64 (
219 DtbAddress,
220 Offset,
221 "image-size",
222 &SpBootInfo->SpMemSize
223 );
224 if (Status != EFI_SUCCESS) {
225 return Status;
226 }
227
228 DEBUG ((DEBUG_INFO, "sp mem size = 0x%llx\n", SpBootInfo->SpMemSize));
229
230 Status = ReadProperty32 (DtbAddress, Offset, "xlat-granule", &PageSize);
231 if (Status != EFI_SUCCESS) {
232 return Status;
233 }
234
235 /* EFI_PAGE_SIZE is 4KB */
236 switch (PageSize) {
237 case FFA_PAGE_4K:
238 PageSize = EFI_PAGE_SIZE;
239 break;
240
241 case FFA_PAGE_16K:
242 PageSize = 4 * EFI_PAGE_SIZE;
243 break;
244
245 case FFA_PAGE_64K:
246 PageSize = 16 * EFI_PAGE_SIZE;
247 break;
248
249 default:
250 DEBUG ((DEBUG_ERROR, "Invalid page type = %lu\n", PageSize));
251 return EFI_INVALID_PARAMETER;
252 break;
253 }
254
255 DEBUG ((DEBUG_INFO, "Page Size = 0x%lx\n", PageSize));
256
257 DEBUG ((DEBUG_WARN, "Skip heap buffer info for non stmm secure partitions\n"));
258
259 return EFI_SUCCESS;
260}
261
262STATIC
263EFI_STATUS
264GetSpManifest (
265 IN OUT UINT64 **SpManifestAddr,
266 IN VOID *BootInfoAddr
267 )
268{
269 EFI_FFA_BOOT_INFO_HEADER *FfaBootInfo;
270 EFI_FFA_BOOT_INFO_DESC *FfaBootInfoDesc;
271
272 // Paranoid check to avoid an inadvertent NULL pointer dereference.
273 if (BootInfoAddr == NULL) {
274 DEBUG ((DEBUG_ERROR, "FF-A Boot information is NULL\n"));
275 return EFI_INVALID_PARAMETER;
276 }
277
278 // Check boot information magic number.
279 FfaBootInfo = (EFI_FFA_BOOT_INFO_HEADER *)BootInfoAddr;
280 if (FfaBootInfo->Magic != FFA_BOOT_INFO_SIGNATURE) {
281 DEBUG ((
282 DEBUG_ERROR,
283 "FfaBootInfo Magic no. is invalid 0x%ux\n",
284 FfaBootInfo->Magic
285 ));
286 return EFI_INVALID_PARAMETER;
287 }
288
289 FfaBootInfoDesc =
290 (EFI_FFA_BOOT_INFO_DESC *)((UINT8 *)BootInfoAddr +
291 FfaBootInfo->OffsetBootInfoDesc);
292
293 if (FfaBootInfoDesc->Type ==
294 (FFA_BOOT_INFO_TYPE (FFA_BOOT_INFO_TYPE_STD) |
295 FFA_BOOT_INFO_TYPE_ID (FFA_BOOT_INFO_TYPE_ID_FDT)))
296 {
297 *SpManifestAddr = (UINT64 *)FfaBootInfoDesc->Content;
298 return EFI_SUCCESS;
299 }
300
301 DEBUG ((DEBUG_ERROR, "SP manifest not found \n"));
302 return EFI_NOT_FOUND;
303}
304
305/**
306 The entry point of Standalone MM Foundation.
307
308 @param [in] SharedBufAddress Pointer to the Buffer between SPM and SP.
309 @param [in] SharedBufSize Size of the shared buffer.
310 @param [in] cookie1 Cookie 1
311 @param [in] cookie2 Cookie 2
312
313**/
314VOID
315EFIAPI
316ModuleEntryPoint (
317 IN VOID *SharedBufAddress,
318 IN UINT64 SharedBufSize,
319 IN UINT64 cookie1,
320 IN UINT64 cookie2
321 )
322{
323 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
324 SP_BOOT_INFO SpBootInfo = { 0 };
325 EFI_STATUS Status;
326 INT32 Ret;
327 UINT32 SectionHeaderOffset;
328 UINT16 NumberOfSections;
329 VOID *TeData;
330 UINTN TeDataSize;
331 EFI_PHYSICAL_ADDRESS ImageBase;
332 UINT64 *DtbAddress;
333 EFI_FIRMWARE_VOLUME_HEADER *BfvAddress;
334 BOOLEAN UseOnlyFfaAbis = FALSE;
335
336 Status = CheckFfaCompatibility (&UseOnlyFfaAbis);
337 if (EFI_ERROR (Status) || !UseOnlyFfaAbis) {
338 goto finish;
339 }
340
341 // If only FF-A is used, the DTB address is passed in the Boot information
342 // structure. Else, the Boot info is copied from Sharedbuffer.
343 Status = GetSpManifest (&DtbAddress, SharedBufAddress);
344 if (Status != EFI_SUCCESS) {
345 goto finish;
346 }
347
348 // Extract boot information from the DTB
349 Status = PopulateBootinformation (&SpBootInfo, (VOID *)DtbAddress);
350 if (Status != EFI_SUCCESS) {
351 goto finish;
352 }
353
354 // Stash the base address of the boot firmware volume
355 BfvAddress = (EFI_FIRMWARE_VOLUME_HEADER *)SpBootInfo.SpMemBase;
356
357 // Locate PE/COFF File information for the Standalone MM core module
358 Status = LocateStandaloneMmCorePeCoffData (BfvAddress, &TeData, &TeDataSize);
359
360 if (EFI_ERROR (Status)) {
361 goto finish;
362 }
363
364 // Obtain the PE/COFF Section information for the Standalone MM core module
365 Status = GetStandaloneMmCorePeCoffSections (
366 TeData,
367 &ImageContext,
368 &ImageBase,
369 &SectionHeaderOffset,
370 &NumberOfSections
371 );
372
373 if (EFI_ERROR (Status)) {
374 goto finish;
375 }
376
377 //
378 // ImageBase may deviate from ImageContext.ImageAddress if we are dealing
379 // with a TE image, in which case the latter points to the actual offset
380 // of the image, whereas ImageBase refers to the address where the image
381 // would start if the stripped PE headers were still in place. In either
382 // case, we need to fix up ImageBase so it refers to the actual current
383 // load address.
384 //
385 ImageBase += (UINTN)TeData - ImageContext.ImageAddress;
386
387 // Update the memory access permissions of individual sections in the
388 // Standalone MM core module
389 Status = UpdateMmFoundationPeCoffPermissions (
390 &ImageContext,
391 ImageBase,
392 SectionHeaderOffset,
393 NumberOfSections,
394 ArmSetMemoryRegionNoExec,
395 ArmSetMemoryRegionReadOnly,
396 ArmClearMemoryRegionReadOnly
397 );
398
399 if (EFI_ERROR (Status)) {
400 goto finish;
401 }
402
403 // Now that we can update globals, initialize the SPST for other libraries
404 mSpst.FDTAddress = DtbAddress;
405 gSpst = &mSpst;
406
407 if (ImageContext.ImageAddress != (UINTN)TeData) {
408 ImageContext.ImageAddress = (UINTN)TeData;
409 ArmSetMemoryRegionNoExec (ImageBase, SIZE_4KB);
410 ArmClearMemoryRegionReadOnly (ImageBase, SIZE_4KB);
411
412 Status = PeCoffLoaderRelocateImage (&ImageContext);
413 ASSERT_EFI_ERROR (Status);
414 }
415
416 ProcessLibraryConstructorList (NULL, NULL);
417
418 //
419 // Call the MM Core entry point
420 //
421 ProcessModuleEntryPointList (NULL);
422
423finish:
424 if (Status == RETURN_UNSUPPORTED) {
425 Ret = -1;
426 } else if (Status == RETURN_INVALID_PARAMETER) {
427 Ret = -2;
428 } else if (Status == EFI_NOT_FOUND) {
429 Ret = -7;
430 } else {
431 Ret = 0;
432 }
433}
434