Declare module wide variables for SPM major and minor versions to be used in checking the SPM version compatibility. Use the SPM major and minor version macros declared in the previous patch for the version check. Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org> Reviewed-by: Sami Mujawar <sami.mujawar@arm.com> Acked-by: Ard Biesheuvel <ardb@kernel.org>
334 lines
11 KiB
C
334 lines
11 KiB
C
/** @file
|
|
Entry point to the Standalone MM Foundation when initialized during the SEC
|
|
phase on ARM platforms
|
|
|
|
Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
|
|
#include <PiMm.h>
|
|
|
|
#include <Library/AArch64/StandaloneMmCoreEntryPoint.h>
|
|
|
|
#include <PiPei.h>
|
|
#include <Guid/MmramMemoryReserve.h>
|
|
#include <Guid/MpInformation.h>
|
|
|
|
#include <Library/ArmMmuLib.h>
|
|
#include <Library/ArmSvcLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/HobLib.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/SerialPortLib.h>
|
|
|
|
#include <IndustryStandard/ArmStdSmc.h>
|
|
#include <IndustryStandard/ArmMmSvc.h>
|
|
#include <IndustryStandard/ArmFfaSvc.h>
|
|
|
|
#define SPM_MAJOR_VER_MASK 0xFFFF0000
|
|
#define SPM_MINOR_VER_MASK 0x0000FFFF
|
|
#define SPM_MAJOR_VER_SHIFT 16
|
|
|
|
STATIC CONST UINT32 mSpmMajorVer = SPM_MAJOR_VERSION;
|
|
STATIC CONST UINT32 mSpmMinorVer = SPM_MINOR_VERSION;
|
|
|
|
#define BOOT_PAYLOAD_VERSION 1
|
|
|
|
PI_MM_ARM_TF_CPU_DRIVER_ENTRYPOINT CpuDriverEntryPoint = NULL;
|
|
|
|
/**
|
|
Retrieve a pointer to and print the boot information passed by privileged
|
|
secure firmware.
|
|
|
|
@param [in] SharedBufAddress The pointer memory shared with privileged
|
|
firmware.
|
|
|
|
**/
|
|
EFI_SECURE_PARTITION_BOOT_INFO *
|
|
GetAndPrintBootinformation (
|
|
IN VOID *SharedBufAddress
|
|
)
|
|
{
|
|
EFI_SECURE_PARTITION_BOOT_INFO *PayloadBootInfo;
|
|
EFI_SECURE_PARTITION_CPU_INFO *PayloadCpuInfo;
|
|
UINTN Index;
|
|
|
|
PayloadBootInfo = (EFI_SECURE_PARTITION_BOOT_INFO *) SharedBufAddress;
|
|
|
|
if (PayloadBootInfo == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "PayloadBootInfo NULL\n"));
|
|
return NULL;
|
|
}
|
|
|
|
if (PayloadBootInfo->Header.Version != BOOT_PAYLOAD_VERSION) {
|
|
DEBUG ((DEBUG_ERROR, "Boot Information Version Mismatch. Current=0x%x, Expected=0x%x.\n",
|
|
PayloadBootInfo->Header.Version, BOOT_PAYLOAD_VERSION));
|
|
return NULL;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "NumSpMemRegions - 0x%x\n", PayloadBootInfo->NumSpMemRegions));
|
|
DEBUG ((DEBUG_INFO, "SpMemBase - 0x%lx\n", PayloadBootInfo->SpMemBase));
|
|
DEBUG ((DEBUG_INFO, "SpMemLimit - 0x%lx\n", PayloadBootInfo->SpMemLimit));
|
|
DEBUG ((DEBUG_INFO, "SpImageBase - 0x%lx\n", PayloadBootInfo->SpImageBase));
|
|
DEBUG ((DEBUG_INFO, "SpStackBase - 0x%lx\n", PayloadBootInfo->SpStackBase));
|
|
DEBUG ((DEBUG_INFO, "SpHeapBase - 0x%lx\n", PayloadBootInfo->SpHeapBase));
|
|
DEBUG ((DEBUG_INFO, "SpNsCommBufBase - 0x%lx\n", PayloadBootInfo->SpNsCommBufBase));
|
|
DEBUG ((DEBUG_INFO, "SpSharedBufBase - 0x%lx\n", PayloadBootInfo->SpSharedBufBase));
|
|
|
|
DEBUG ((DEBUG_INFO, "SpImageSize - 0x%x\n", PayloadBootInfo->SpImageSize));
|
|
DEBUG ((DEBUG_INFO, "SpPcpuStackSize - 0x%x\n", PayloadBootInfo->SpPcpuStackSize));
|
|
DEBUG ((DEBUG_INFO, "SpHeapSize - 0x%x\n", PayloadBootInfo->SpHeapSize));
|
|
DEBUG ((DEBUG_INFO, "SpNsCommBufSize - 0x%x\n", PayloadBootInfo->SpNsCommBufSize));
|
|
DEBUG ((DEBUG_INFO, "SpPcpuSharedBufSize - 0x%x\n", PayloadBootInfo->SpPcpuSharedBufSize));
|
|
|
|
DEBUG ((DEBUG_INFO, "NumCpus - 0x%x\n", PayloadBootInfo->NumCpus));
|
|
DEBUG ((DEBUG_INFO, "CpuInfo - 0x%p\n", PayloadBootInfo->CpuInfo));
|
|
|
|
PayloadCpuInfo = (EFI_SECURE_PARTITION_CPU_INFO *) PayloadBootInfo->CpuInfo;
|
|
|
|
if (PayloadCpuInfo == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "PayloadCpuInfo NULL\n"));
|
|
return NULL;
|
|
}
|
|
|
|
for (Index = 0; Index < PayloadBootInfo->NumCpus; Index++) {
|
|
DEBUG ((DEBUG_INFO, "Mpidr - 0x%lx\n", PayloadCpuInfo[Index].Mpidr));
|
|
DEBUG ((DEBUG_INFO, "LinearId - 0x%x\n", PayloadCpuInfo[Index].LinearId));
|
|
DEBUG ((DEBUG_INFO, "Flags - 0x%x\n", PayloadCpuInfo[Index].Flags));
|
|
}
|
|
|
|
return PayloadBootInfo;
|
|
}
|
|
|
|
/**
|
|
A loop to delegated events.
|
|
|
|
@param [in] EventCompleteSvcArgs Pointer to the event completion arguments.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
DelegatedEventLoop (
|
|
IN ARM_SVC_ARGS *EventCompleteSvcArgs
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN SvcStatus;
|
|
|
|
while (TRUE) {
|
|
ArmCallSvc (EventCompleteSvcArgs);
|
|
|
|
DEBUG ((DEBUG_INFO, "Received delegated event\n"));
|
|
DEBUG ((DEBUG_INFO, "X0 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg0));
|
|
DEBUG ((DEBUG_INFO, "X1 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg1));
|
|
DEBUG ((DEBUG_INFO, "X2 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg2));
|
|
DEBUG ((DEBUG_INFO, "X3 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg3));
|
|
|
|
Status = CpuDriverEntryPoint (
|
|
EventCompleteSvcArgs->Arg0,
|
|
EventCompleteSvcArgs->Arg3,
|
|
EventCompleteSvcArgs->Arg1
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Failed delegated event 0x%x, Status 0x%x\n",
|
|
EventCompleteSvcArgs->Arg0, Status));
|
|
}
|
|
|
|
switch (Status) {
|
|
case EFI_SUCCESS:
|
|
SvcStatus = ARM_SVC_SPM_RET_SUCCESS;
|
|
break;
|
|
case EFI_INVALID_PARAMETER:
|
|
SvcStatus = ARM_SVC_SPM_RET_INVALID_PARAMS;
|
|
break;
|
|
case EFI_ACCESS_DENIED:
|
|
SvcStatus = ARM_SVC_SPM_RET_DENIED;
|
|
break;
|
|
case EFI_OUT_OF_RESOURCES:
|
|
SvcStatus = ARM_SVC_SPM_RET_NO_MEMORY;
|
|
break;
|
|
case EFI_UNSUPPORTED:
|
|
SvcStatus = ARM_SVC_SPM_RET_NOT_SUPPORTED;
|
|
break;
|
|
default:
|
|
SvcStatus = ARM_SVC_SPM_RET_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
EventCompleteSvcArgs->Arg0 = ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64;
|
|
EventCompleteSvcArgs->Arg1 = SvcStatus;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Query the SPM version, check compatibility and return success if compatible.
|
|
|
|
@retval EFI_SUCCESS SPM versions compatible.
|
|
@retval EFI_UNSUPPORTED SPM versions not compatible.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetSpmVersion (VOID)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT16 SpmMajorVersion;
|
|
UINT16 SpmMinorVersion;
|
|
UINT32 SpmVersion;
|
|
ARM_SVC_ARGS SpmVersionArgs;
|
|
|
|
SpmVersionArgs.Arg0 = ARM_SVC_ID_SPM_VERSION_AARCH32;
|
|
|
|
ArmCallSvc (&SpmVersionArgs);
|
|
|
|
SpmVersion = SpmVersionArgs.Arg0;
|
|
|
|
SpmMajorVersion = ((SpmVersion & SPM_MAJOR_VER_MASK) >> SPM_MAJOR_VER_SHIFT);
|
|
SpmMinorVersion = ((SpmVersion & SPM_MINOR_VER_MASK) >> 0);
|
|
|
|
// Different major revision values indicate possibly incompatible functions.
|
|
// For two revisions, A and B, for which the major revision values are
|
|
// identical, if the minor revision value of revision B is greater than
|
|
// the minor revision value of revision A, then every function in
|
|
// revision A must work in a compatible way with revision B.
|
|
// However, it is possible for revision B to have a higher
|
|
// function count than revision A.
|
|
if ((SpmMajorVersion == mSpmMajorVer) &&
|
|
(SpmMinorVersion >= mSpmMinorVer))
|
|
{
|
|
DEBUG ((DEBUG_INFO, "SPM Version: Major=0x%x, Minor=0x%x\n",
|
|
SpmMajorVersion, SpmMinorVersion));
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
DEBUG ((DEBUG_INFO, "Incompatible SPM Versions.\n Current Version: Major=0x%x, Minor=0x%x.\n Expected: Major=0x%x, Minor>=0x%x.\n",
|
|
SpmMajorVersion, SpmMinorVersion, mSpmMajorVer, mSpmMinorVer));
|
|
Status = EFI_UNSUPPORTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
The entry point of Standalone MM Foundation.
|
|
|
|
@param [in] SharedBufAddress Pointer to the Buffer between SPM and SP.
|
|
@param [in] SharedBufSize Size of the shared buffer.
|
|
@param [in] cookie1 Cookie 1
|
|
@param [in] cookie2 Cookie 2
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
_ModuleEntryPoint (
|
|
IN VOID *SharedBufAddress,
|
|
IN UINT64 SharedBufSize,
|
|
IN UINT64 cookie1,
|
|
IN UINT64 cookie2
|
|
)
|
|
{
|
|
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
|
|
EFI_SECURE_PARTITION_BOOT_INFO *PayloadBootInfo;
|
|
ARM_SVC_ARGS InitMmFoundationSvcArgs;
|
|
EFI_STATUS Status;
|
|
UINT32 SectionHeaderOffset;
|
|
UINT16 NumberOfSections;
|
|
VOID *HobStart;
|
|
VOID *TeData;
|
|
UINTN TeDataSize;
|
|
EFI_PHYSICAL_ADDRESS ImageBase;
|
|
|
|
// Get Secure Partition Manager Version Information
|
|
Status = GetSpmVersion ();
|
|
if (EFI_ERROR (Status)) {
|
|
goto finish;
|
|
}
|
|
|
|
PayloadBootInfo = GetAndPrintBootinformation (SharedBufAddress);
|
|
if (PayloadBootInfo == NULL) {
|
|
Status = EFI_UNSUPPORTED;
|
|
goto finish;
|
|
}
|
|
|
|
// Locate PE/COFF File information for the Standalone MM core module
|
|
Status = LocateStandaloneMmCorePeCoffData (
|
|
(EFI_FIRMWARE_VOLUME_HEADER *) PayloadBootInfo->SpImageBase,
|
|
&TeData,
|
|
&TeDataSize
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto finish;
|
|
}
|
|
|
|
// Obtain the PE/COFF Section information for the Standalone MM core module
|
|
Status = GetStandaloneMmCorePeCoffSections (
|
|
TeData,
|
|
&ImageContext,
|
|
&ImageBase,
|
|
&SectionHeaderOffset,
|
|
&NumberOfSections
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto finish;
|
|
}
|
|
|
|
//
|
|
// ImageBase may deviate from ImageContext.ImageAddress if we are dealing
|
|
// with a TE image, in which case the latter points to the actual offset
|
|
// of the image, whereas ImageBase refers to the address where the image
|
|
// would start if the stripped PE headers were still in place. In either
|
|
// case, we need to fix up ImageBase so it refers to the actual current
|
|
// load address.
|
|
//
|
|
ImageBase += (UINTN)TeData - ImageContext.ImageAddress;
|
|
|
|
// Update the memory access permissions of individual sections in the
|
|
// Standalone MM core module
|
|
Status = UpdateMmFoundationPeCoffPermissions (
|
|
&ImageContext,
|
|
ImageBase,
|
|
SectionHeaderOffset,
|
|
NumberOfSections,
|
|
ArmSetMemoryRegionNoExec,
|
|
ArmSetMemoryRegionReadOnly,
|
|
ArmClearMemoryRegionReadOnly
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto finish;
|
|
}
|
|
|
|
if (ImageContext.ImageAddress != (UINTN)TeData) {
|
|
ImageContext.ImageAddress = (UINTN)TeData;
|
|
ArmSetMemoryRegionNoExec (ImageBase, SIZE_4KB);
|
|
ArmClearMemoryRegionReadOnly (ImageBase, SIZE_4KB);
|
|
|
|
Status = PeCoffLoaderRelocateImage (&ImageContext);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
|
|
//
|
|
// Create Hoblist based upon boot information passed by privileged software
|
|
//
|
|
HobStart = CreateHobListFromBootInfo (&CpuDriverEntryPoint, PayloadBootInfo);
|
|
|
|
//
|
|
// Call the MM Core entry point
|
|
//
|
|
ProcessModuleEntryPointList (HobStart);
|
|
|
|
DEBUG ((DEBUG_INFO, "Shared Cpu Driver EP 0x%lx\n", (UINT64) CpuDriverEntryPoint));
|
|
|
|
finish:
|
|
ZeroMem (&InitMmFoundationSvcArgs, sizeof(InitMmFoundationSvcArgs));
|
|
InitMmFoundationSvcArgs.Arg0 = ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64;
|
|
InitMmFoundationSvcArgs.Arg1 = Status;
|
|
DelegatedEventLoop (&InitMmFoundationSvcArgs);
|
|
}
|