microsoft/mu_feature_ffa

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
fix_upload

Branches

Tags

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

Clone

HTTPS

Download ZIP

FfaFeaturePkg/Library/SecurePartitionEntryPoint/StandaloneMmCoreEntryPoint.c

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