1232 lines
38 KiB
C
1232 lines
38 KiB
C
/** @file
|
|
Entry point to the Standalone MM Foundation when initialized during the SEC
|
|
phase on ARM platforms
|
|
|
|
Copyright (c) 2017 - 2024, Arm Ltd. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
@par Glossary:
|
|
- SpmMM - An implementation where the Secure Partition Manager resides at EL3
|
|
with management services running from an isolated Secure Partitions
|
|
at S-EL0, and the communication protocol is the Management Mode(MM)
|
|
interface.
|
|
- FF-A - Firmware Framework for Arm A-profile
|
|
|
|
@par Reference(s):
|
|
- Secure Partition Manager
|
|
[https://trustedfirmware-a.readthedocs.io/en/latest/components/secure-partition-manager-mm.html]
|
|
- Arm Firmware Framework for Arm A-Profile
|
|
[https://developer.arm.com/documentation/den0077/latest]
|
|
|
|
**/
|
|
|
|
#include <PiMm.h>
|
|
|
|
#include <Library/Arm/StandaloneMmCoreEntryPoint.h>
|
|
|
|
#include <PiPei.h>
|
|
#include <Guid/MmramMemoryReserve.h>
|
|
#include <Guid/MpInformation.h>
|
|
|
|
#include <Library/ArmLib.h>
|
|
#include <Library/ArmSvcLib.h>
|
|
#include <Library/ArmFfaLib.h>
|
|
#include <Library/ArmTransferListLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/HobLib.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/SerialPortLib.h>
|
|
#include <Library/StandaloneMmMmuLib.h>
|
|
#include <Library/PcdLib.h>
|
|
|
|
#include <IndustryStandard/ArmStdSmc.h>
|
|
#include <IndustryStandard/ArmMmSvc.h>
|
|
#include <IndustryStandard/ArmFfaSvc.h>
|
|
#include <IndustryStandard/ArmFfaBootInfo.h>
|
|
|
|
#include <Protocol/PiMmCpuDriverEp.h>
|
|
|
|
extern EFI_MM_SYSTEM_TABLE gMmCoreMmst;
|
|
|
|
VOID *gHobList = NULL;
|
|
|
|
STATIC MP_INFORMATION_HOB_DATA *mMpInfo = NULL;
|
|
STATIC MISC_MM_COMMUNICATE_BUFFER *mMiscMmCommunicateBuffer = NULL;
|
|
|
|
/**
|
|
Get communication ABI protocol.
|
|
|
|
@param [out] CommProtocol Communication protocol.
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_UNSUPPORTED Not supported
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetCommProtocol (
|
|
OUT COMM_PROTOCOL *CommProtocol
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT16 RequestMajorVersion;
|
|
UINT16 RequestMinorVersion;
|
|
UINT16 CurrentMajorVersion;
|
|
UINT16 CurrentMinorVersion;
|
|
ARM_SVC_ARGS SvcArgs;
|
|
|
|
RequestMajorVersion = ARM_FFA_MAJOR_VERSION;
|
|
RequestMinorVersion = ARM_FFA_MINOR_VERSION;
|
|
|
|
Status = ArmFfaLibGetVersion (
|
|
RequestMajorVersion,
|
|
RequestMinorVersion,
|
|
&CurrentMajorVersion,
|
|
&CurrentMinorVersion
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
*CommProtocol = CommProtocolFfa;
|
|
} else {
|
|
ZeroMem (&SvcArgs, sizeof (ARM_SVC_ARGS));
|
|
SvcArgs.Arg0 = ARM_FID_SPM_MM_VERSION_AARCH32;
|
|
|
|
ArmCallSvc (&SvcArgs);
|
|
|
|
if (SvcArgs.Arg0 == ARM_SPM_MM_RET_NOT_SUPPORTED) {
|
|
*CommProtocol = CommProtocolUnknown;
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
*CommProtocol = CommProtocolSpmMm;
|
|
RequestMajorVersion = ARM_SPM_MM_SUPPORT_MAJOR_VERSION;
|
|
RequestMinorVersion = ARM_SPM_MM_SUPPORT_MINOR_VERSION;
|
|
CurrentMajorVersion =
|
|
((SvcArgs.Arg0 >> ARM_SPM_MM_MAJOR_VERSION_SHIFT) & ARM_SPM_MM_VERSION_MASK);
|
|
CurrentMinorVersion =
|
|
((SvcArgs.Arg0 >> ARM_SPM_MM_MINOR_VERSION_SHIFT) & ARM_SPM_MM_VERSION_MASK);
|
|
}
|
|
|
|
// 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 ((RequestMajorVersion != CurrentMajorVersion) ||
|
|
(RequestMinorVersion > CurrentMinorVersion))
|
|
{
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"Incompatible %s Versions.\n" \
|
|
"Request Version: Major=0x%x, Minor>=0x%x.\n" \
|
|
"Current Version: Major=0x%x, Minor=0x%x.\n",
|
|
(*CommProtocol == CommProtocolFfa) ? L"FF-A" : L"SPM_MM",
|
|
RequestMajorVersion,
|
|
RequestMinorVersion,
|
|
CurrentMajorVersion,
|
|
CurrentMinorVersion
|
|
));
|
|
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%s Version: Major=0x%x, Minor=0x%x\n",
|
|
(*CommProtocol == CommProtocolFfa) ? L"FF-A" : L"SPM_MM",
|
|
CurrentMajorVersion,
|
|
CurrentMinorVersion
|
|
));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Validate Boot information when using SpmMm.
|
|
It should use Transfer list according to firmware handoff specification.
|
|
|
|
@param [in] Arg0 Should be 0x00 because we don't use device tree
|
|
@param [in] Fields Signature and register convention version
|
|
@param [in] Arg2 Should be 0x00 because we don't use device tree
|
|
@param [in] TlhAddr Address of transfer list
|
|
|
|
@retval EFI_SUCCESS Valid boot information
|
|
@retval EFI_INVALID_PARAMETER Invalid boot information
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ValidateSpmMmBootInfo (
|
|
IN UINTN Arg0,
|
|
IN UINT64 Fields,
|
|
IN UINTN Arg2,
|
|
IN UINTN TlhAddr
|
|
)
|
|
{
|
|
UINT64 RegVersion;
|
|
|
|
/*
|
|
* The signature value in x1's [23:0] bits is the same regardless of
|
|
* architecture when using Transfer list.
|
|
* That's why it need to check signature value in x1 again with [31:0] bits
|
|
* to discern 32 or 64 bits architecture after checking x1 value in [23:0].
|
|
* Please see:
|
|
* https://github.com/FirmwareHandoff/firmware_handoff/blob/main/source/register_conventions.rst
|
|
*/
|
|
if ((Fields & TRANSFER_LIST_SIGNATURE_MASK_64) == TRANSFER_LIST_SIGNATURE_64) {
|
|
RegVersion = (Fields >> REGISTER_CONVENTION_VERSION_SHIFT_64) &
|
|
REGISTER_CONVENTION_VERSION_MASK;
|
|
if ((RegVersion != 1) || (Arg2 != 0x00) || (TlhAddr == 0x00)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
} else if ((Fields & TRANSFER_LIST_SIGNATURE_MASK_32) == TRANSFER_LIST_SIGNATURE_32) {
|
|
RegVersion = (Fields >> REGISTER_CONVENTION_VERSION_SHIFT_32) &
|
|
REGISTER_CONVENTION_VERSION_MASK;
|
|
if ((RegVersion != 1) || (Arg0 != 0x00) || (TlhAddr == 0x00)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Validate Boot information when using FF-A.
|
|
|
|
@param [in] FfaBootInfoHeaderAddr Address of FF-A boot information
|
|
|
|
@retval EFI_SUCCESS Valid boot information
|
|
@retval EFI_INVALID_PARAMETER Invalid boot information
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ValidateFfaBootInfo (
|
|
IN UINTN FfaBootInfoHeaderAddr
|
|
)
|
|
{
|
|
EFI_FFA_BOOT_INFO_HEADER *FfaBootInfoHeader;
|
|
|
|
FfaBootInfoHeader = (EFI_FFA_BOOT_INFO_HEADER *)FfaBootInfoHeaderAddr;
|
|
if (FfaBootInfoHeader == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Error: No FF-A boot information...\n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((FfaBootInfoHeader->Magic != FFA_BOOT_INFO_SIGNATURE) ||
|
|
(ARM_FFA_MAJOR_VERSION_GET (FfaBootInfoHeader->Version) <
|
|
ARM_FFA_MAJOR_VERSION) ||
|
|
(ARM_FFA_MINOR_VERSION_GET (FfaBootInfoHeader->Version) <
|
|
ARM_FFA_MINOR_VERSION))
|
|
{
|
|
DEBUG ((DEBUG_ERROR, "Error: Invalid FF-A boot information...\n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Validate Boot information.
|
|
|
|
@param [in] CommProtocol Communication ABI protocol
|
|
@param [in] Arg0 In case of FF-A, address of FF-A boot information
|
|
In case of SPM_MM, 0x00
|
|
@param [in] Arg1 In case of FF-A, 0x00
|
|
In case of SPM_MM, Signature and register convention version
|
|
@param [in] Arg2 should be 0x00
|
|
@param [in] Arg3 In case of FF-A, it's 0x00
|
|
In case of SPM_MM, address of transfer list
|
|
|
|
@retval EFI_SUCCESS Valid boot information
|
|
@retval EFI_INVALID_PARAMETER Invalid boot information
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ValidateBootInfo (
|
|
IN COMM_PROTOCOL CommProtocol,
|
|
IN UINTN Arg0,
|
|
IN UINTN Arg1,
|
|
IN UINTN Arg2,
|
|
IN UINTN Arg3
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_INVALID_PARAMETER;
|
|
|
|
if (CommProtocol == CommProtocolSpmMm) {
|
|
Status = ValidateSpmMmBootInfo (Arg0, Arg1, Arg2, Arg3);
|
|
} else if (CommProtocol == CommProtocolFfa) {
|
|
/*
|
|
* In case of FF-A, Arg0 is set as FFA_BOOT_INFO address.
|
|
*/
|
|
Status = ValidateFfaBootInfo (Arg0);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Error: Failed to validate boot information!\n"));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Get PHIT hob information from firmware handoff transfer list protocol.
|
|
|
|
@param[in] TlhAddr Transfer list header address
|
|
|
|
@retval NULL Failed to get PHIT hob
|
|
@retval Address PHIT hob address
|
|
|
|
**/
|
|
STATIC
|
|
VOID *
|
|
EFIAPI
|
|
GetPhitHobFromTransferList (
|
|
IN UINTN TlhAddr
|
|
)
|
|
{
|
|
TRANSFER_LIST_HEADER *Tlh;
|
|
TRANSFER_ENTRY_HEADER *Te;
|
|
VOID *HobStart;
|
|
|
|
Tlh = (TRANSFER_LIST_HEADER *)TlhAddr;
|
|
|
|
Te = TlFindFirstEntry (Tlh, TRANSFER_ENTRY_TAG_ID_HOB_LIST);
|
|
if (Te == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Error: No Phit hob is present in transfer list...\n"));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
HobStart = TlGetEntryData (Te);
|
|
|
|
return HobStart;
|
|
}
|
|
|
|
/**
|
|
Get PHIT hob information from FF-A boot information.
|
|
|
|
@param[in] FfaBootInfoHeaderAddr FF-A boot information header address
|
|
|
|
@retval NULL Failed to get PHIT hob
|
|
@retval Address PHIT hob address
|
|
|
|
**/
|
|
STATIC
|
|
VOID *
|
|
EFIAPI
|
|
GetPhitHobFromFfaBootInfo (
|
|
IN UINTN FfaBootInfoHeaderAddr
|
|
)
|
|
{
|
|
EFI_FFA_BOOT_INFO_HEADER *FfaBootInfoHeader;
|
|
EFI_FFA_BOOT_INFO_DESC *FfaBootInfoDesc;
|
|
UINT32 Idx;
|
|
|
|
FfaBootInfoHeader = (EFI_FFA_BOOT_INFO_HEADER *)FfaBootInfoHeaderAddr;
|
|
|
|
for (Idx = 0; Idx < FfaBootInfoHeader->CountBootInfoDesc; Idx++) {
|
|
FfaBootInfoDesc = (EFI_FFA_BOOT_INFO_DESC *)((FfaBootInfoHeaderAddr +
|
|
FfaBootInfoHeader->OffsetBootInfoDesc) +
|
|
(Idx * FfaBootInfoHeader->SizeBootInfoDesc));
|
|
|
|
if ((FFA_BOOT_INFO_TYPE (FfaBootInfoDesc->Type) != FFA_BOOT_INFO_TYPE_STD) ||
|
|
(FFA_BOOT_INFO_TYPE_ID (FfaBootInfoDesc->Type) != FFA_BOOT_INFO_TYPE_ID_HOB) ||
|
|
(FFA_BOOT_INFO_FLAG_CONTENT (FfaBootInfoDesc->Flags) != FFA_BOOT_INFO_FLAG_CONTENT_ADDR))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
return (VOID *)(UINTN)FfaBootInfoDesc->Content;
|
|
}
|
|
|
|
DEBUG ((DEBUG_ERROR, "Error: No Phit hob is present in FfaBootInfo...\n"));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Get PHIT Hob from Boot information.
|
|
|
|
@param [in] CommProtocol Communication ABI protocol
|
|
@param [in] Arg0 In case of FF-A, address of FF-A boot information
|
|
In case of SPM_MM, 0x00 because we don't use device tree.
|
|
@param [in] Arg1 In case of FF-A, 0x00
|
|
In case of SPM_MM, Signature and register convention version
|
|
@param [in] Arg2 Should be 0x00 because we don't use device tree.
|
|
@param [in] Arg3 In case of FF-A, it's 0x00
|
|
In case of SPM_MM, address of transfer list
|
|
|
|
@retval NULL Failed to get PHIT hob
|
|
@retval Address PHIT hob address
|
|
|
|
**/
|
|
STATIC
|
|
VOID *
|
|
EFIAPI
|
|
GetPhitHobFromBootInfo (
|
|
IN COMM_PROTOCOL CommProtocol,
|
|
IN UINTN Arg0,
|
|
IN UINTN Arg1,
|
|
IN UINTN Arg2,
|
|
IN UINTN Arg3
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *HobStart;
|
|
|
|
Status = ValidateBootInfo (CommProtocol, Arg0, Arg1, Arg2, Arg3);
|
|
if (EFI_ERROR (Status)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (CommProtocol == CommProtocolFfa) {
|
|
HobStart = GetPhitHobFromFfaBootInfo (Arg0);
|
|
} else {
|
|
HobStart = GetPhitHobFromTransferList (Arg3);
|
|
}
|
|
|
|
return HobStart;
|
|
}
|
|
|
|
/**
|
|
Get service type.
|
|
When using FF-A ABI, there're ways to request service to StandaloneMm
|
|
- FF-A with MmCommunication protocol.
|
|
- FF-A service with each specification.
|
|
MmCommunication Protocol can use FFA_MSG_SEND_DIRECT_REQ or REQ2,
|
|
Other FF-A services should use FFA_MSG_SEND_DIRECT_REQ2.
|
|
In case of FF-A with MmCommunication protocol via FFA_MSG_SEND_DIRECT_REQ,
|
|
register x3 saves Communication Buffer with gEfiMmCommunication2ProtocolGuid.
|
|
In case of FF-A with MmCommunication protocol via FFA_MSG_SEND_DIRECT_REQ2,
|
|
register x2/x3 save gEfiMmCommunication2ProtocolGuid and
|
|
register x4 saves Communication Buffer with Service Guid.
|
|
|
|
Other FF-A services (ServiceTypeMisc) delivers register values according to
|
|
there own service specification.
|
|
That means it doesn't use MmCommunication Buffer with MmCommunication Header
|
|
format.
|
|
(i.e) Tpm service via FF-A or Firmware Update service via FF-A.
|
|
To support latter services by StandaloneMm, it defines SERVICE_TYPE_MISC.
|
|
So that StandaloneMmEntryPointCore.c generates MmCommunication Header
|
|
with delivered register values to dispatch service provided StandaloneMmCore.
|
|
So that service handler can get proper information from delivered register.
|
|
|
|
In case of SPM_MM Abi, it only supports MmCommunication service.
|
|
|
|
|
|
@param[in] ServiceGuid Service Guid
|
|
|
|
@retval ServiceTypeMmCommunication Mm communication service
|
|
@retval ServiceTypeMisc Service via implemented defined
|
|
register ABI.
|
|
This will generate internal
|
|
MmCommunication Header
|
|
to dispatch service implemented
|
|
in standaloneMm
|
|
@retval ServiceTypeUnknown Not supported service.
|
|
|
|
**/
|
|
STATIC
|
|
SERVICE_TYPE
|
|
EFIAPI
|
|
GetServiceType (
|
|
IN EFI_GUID *ServiceGuid
|
|
)
|
|
{
|
|
if (CompareGuid (ServiceGuid, &gEfiMmCommunication2ProtocolGuid)) {
|
|
return ServiceTypeMmCommunication;
|
|
}
|
|
|
|
return ServiceTypeMisc;
|
|
}
|
|
|
|
/**
|
|
Get logical Cpu Number based on MpInformation hob data.
|
|
|
|
@param [in] CommProtocol Abi Protocol.
|
|
@param [in] EventCompleteSvcArgs Pointer to the event completion arguments.
|
|
|
|
@retval CpuNumber Cpu Number
|
|
**/
|
|
STATIC
|
|
UINTN
|
|
EFIAPI
|
|
GetCpuNumber (
|
|
IN COMM_PROTOCOL CommProtocol,
|
|
IN ARM_SVC_ARGS *EventCompleteSvcArgs
|
|
)
|
|
{
|
|
UINTN Idx;
|
|
|
|
if (CommProtocol == CommProtocolSpmMm) {
|
|
Idx = EventCompleteSvcArgs->Arg3;
|
|
} else {
|
|
/*
|
|
* There's no way to find out CPU number in StandaloneMm via FF-A v1.2.
|
|
* Because StandaloneMm is S-EL0 partition, it couldn't read mpidr.
|
|
* Currently, StandaloneMm is UP migratable SP so, just return idx 0.
|
|
*/
|
|
Idx = 0;
|
|
}
|
|
|
|
ASSERT (Idx < mMpInfo->NumberOfProcessors);
|
|
|
|
return Idx;
|
|
}
|
|
|
|
/**
|
|
Dump mp information descriptor.
|
|
|
|
@param[in] ProcessorInfo Mp information
|
|
@param[in] Idx Cpu index
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
DumpMpInfoDescriptor (
|
|
EFI_PROCESSOR_INFORMATION *ProcessorInfo,
|
|
UINTN Idx
|
|
)
|
|
{
|
|
if (ProcessorInfo == NULL) {
|
|
return;
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"CPU[%d]: MpIdr - 0x%lx\n",
|
|
Idx,
|
|
ProcessorInfo->ProcessorId
|
|
));
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"CPU[%d]: StatusFlag - 0x%lx\n",
|
|
Idx,
|
|
ProcessorInfo->StatusFlag
|
|
));
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"CPU[%d]: Location[P:C:T] - :%d:%d:%d\n",
|
|
Idx,
|
|
ProcessorInfo->Location.Package,
|
|
ProcessorInfo->Location.Core,
|
|
ProcessorInfo->Location.Thread
|
|
));
|
|
}
|
|
|
|
/**
|
|
Dump mmram descriptor.
|
|
|
|
@param[in] Name Name
|
|
@param[in] MmramDesc Mmram descriptor
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
DumpMmramDescriptor (
|
|
IN CHAR16 *Name,
|
|
IN EFI_MMRAM_DESCRIPTOR *MmramDesc
|
|
)
|
|
{
|
|
if (MmramDesc == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (Name == NULL) {
|
|
Name = L"Unknown";
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"MmramDescriptor[%s]: PhysicalStart - 0x%lx\n",
|
|
Name,
|
|
MmramDesc->PhysicalStart
|
|
));
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"MmramDescriptors[%s]: CpuStart - 0x%lx\n",
|
|
Name,
|
|
MmramDesc->CpuStart
|
|
));
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"MmramDescriptors[%s]: PhysicalSize - %ld\n",
|
|
Name,
|
|
MmramDesc->PhysicalSize
|
|
));
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"MmramDescriptors[%s]: RegionState - 0x%lx\n",
|
|
Name,
|
|
MmramDesc->RegionState
|
|
));
|
|
}
|
|
|
|
/**
|
|
Dump PHIT hob information.
|
|
|
|
@param[in] HobStart PHIT hob start address.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
DumpPhitHob (
|
|
IN VOID *HobStart
|
|
)
|
|
{
|
|
EFI_HOB_FIRMWARE_VOLUME *FvHob;
|
|
EFI_HOB_GUID_TYPE *GuidHob;
|
|
MP_INFORMATION_HOB_DATA *MpInfo;
|
|
EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *MmramRangesHobData;
|
|
EFI_MMRAM_DESCRIPTOR *MmramDesc;
|
|
UINTN Idx;
|
|
|
|
FvHob = GetNextHob (EFI_HOB_TYPE_FV, HobStart);
|
|
if (FvHob == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Error: No Firmware Volume Hob is present.\n"));
|
|
return;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "FvHob: BaseAddress - 0x%lx\n", FvHob->BaseAddress));
|
|
DEBUG ((DEBUG_INFO, "FvHob: Length - %ld\n", FvHob->Length));
|
|
|
|
GuidHob = GetNextGuidHob (&gMpInformationHobGuid, HobStart);
|
|
if (GuidHob == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Error: No MpInformation Guid Hob is present.\n"));
|
|
return;
|
|
}
|
|
|
|
MpInfo = GET_GUID_HOB_DATA (GuidHob);
|
|
DEBUG ((DEBUG_INFO, "Number of Cpus - %d\n", MpInfo->NumberOfProcessors));
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"Number of Enabled Cpus - %d\n",
|
|
MpInfo->NumberOfEnabledProcessors
|
|
));
|
|
for (Idx = 0; Idx < MpInfo->NumberOfProcessors; Idx++) {
|
|
DumpMpInfoDescriptor (&MpInfo->ProcessorInfoBuffer[Idx], Idx);
|
|
}
|
|
|
|
GuidHob = GetNextGuidHob (&gEfiStandaloneMmNonSecureBufferGuid, HobStart);
|
|
if (GuidHob == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Error: No Ns Buffer Guid Hob is present.\n"));
|
|
return;
|
|
}
|
|
|
|
DumpMmramDescriptor (L"NsBuffer", GET_GUID_HOB_DATA (GuidHob));
|
|
|
|
GuidHob = GetNextGuidHob (&gEfiMmPeiMmramMemoryReserveGuid, HobStart);
|
|
if (GuidHob == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Error: No Pei Mmram Memory Reserved Guid Hob is present.\n"));
|
|
return;
|
|
}
|
|
|
|
MmramRangesHobData = GET_GUID_HOB_DATA (GuidHob);
|
|
if ((MmramRangesHobData == NULL) ||
|
|
(MmramRangesHobData->NumberOfMmReservedRegions == 0))
|
|
{
|
|
DEBUG ((DEBUG_ERROR, "Error: No Pei Mmram Memory Reserved information is present.\n"));
|
|
return;
|
|
}
|
|
|
|
for (Idx = 0; Idx < MmramRangesHobData->NumberOfMmReservedRegions; Idx++) {
|
|
MmramDesc = &MmramRangesHobData->Descriptor[Idx];
|
|
DumpMmramDescriptor (L"PeiMemReserved", MmramDesc);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Convert EFI_STATUS to MM SPM return code.
|
|
|
|
@param [in] Status edk2 status code.
|
|
|
|
@retval ARM_SPM_MM_RET_* return value correspond to EFI_STATUS.
|
|
|
|
**/
|
|
STATIC
|
|
UINTN
|
|
EFIAPI
|
|
EfiStatusToSpmMmStatus (
|
|
IN EFI_STATUS Status
|
|
)
|
|
{
|
|
switch (Status) {
|
|
case EFI_SUCCESS:
|
|
return ARM_SPM_MM_RET_SUCCESS;
|
|
case EFI_INVALID_PARAMETER:
|
|
return ARM_SPM_MM_RET_INVALID_PARAMS;
|
|
case EFI_ACCESS_DENIED:
|
|
return ARM_SPM_MM_RET_DENIED;
|
|
case EFI_OUT_OF_RESOURCES:
|
|
return ARM_SPM_MM_RET_NO_MEMORY;
|
|
default:
|
|
return ARM_SPM_MM_RET_NOT_SUPPORTED;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Set svc arguments to report initialization status of StandaloneMm.
|
|
|
|
@param[in] CommProtocol ABI Protocol.
|
|
@param[in] Status Result of initializing StandaloneMm.
|
|
@param[out] EventCompleteSvcArgs Args structure.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
ReturnInitStatusToSpmc (
|
|
IN COMM_PROTOCOL CommProtocol,
|
|
IN EFI_STATUS Status,
|
|
OUT ARM_SVC_ARGS *EventCompleteSvcArgs
|
|
)
|
|
{
|
|
ZeroMem (EventCompleteSvcArgs, sizeof (ARM_SVC_ARGS));
|
|
|
|
if (CommProtocol == CommProtocolFfa) {
|
|
if (EFI_ERROR (Status)) {
|
|
EventCompleteSvcArgs->Arg0 = ARM_FID_FFA_ERROR;
|
|
|
|
/*
|
|
* In case SvcConduit, this must be zero.
|
|
*/
|
|
EventCompleteSvcArgs->Arg1 = 0x00;
|
|
EventCompleteSvcArgs->Arg2 = EfiStatusToFfaStatus (Status);
|
|
} else {
|
|
/*
|
|
* For completion of initialization, It should use FFA_MSG_WAIT.
|
|
* See FF-A specification 5.5 Protocol for completing execution context
|
|
* initialization
|
|
*/
|
|
EventCompleteSvcArgs->Arg0 = ARM_FID_FFA_WAIT;
|
|
}
|
|
} else if (CommProtocol == CommProtocolSpmMm) {
|
|
EventCompleteSvcArgs->Arg0 = ARM_FID_SPM_MM_SP_EVENT_COMPLETE;
|
|
EventCompleteSvcArgs->Arg1 = EfiStatusToSpmMmStatus (Status);
|
|
} else {
|
|
/*
|
|
* We don't know what communication abi protocol is using.
|
|
* Set Arg0 as MAX_UINTN to make SPMC know it's error situation.
|
|
*/
|
|
EventCompleteSvcArgs->Arg0 = MAX_UINTN;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Set Event Complete arguments to be returned via SVC call.
|
|
|
|
@param[in] CommProtocol Communication Protocol.
|
|
@param[in] CommData Communication Abi specific data.
|
|
@param[in] Status Result of StandaloneMm service.
|
|
@param[out] EventCompleteSvcArgs Args structure.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
SetEventCompleteSvcArgs (
|
|
IN COMM_PROTOCOL CommProtocol,
|
|
IN VOID *CommData,
|
|
IN EFI_STATUS Status,
|
|
OUT ARM_SVC_ARGS *EventCompleteSvcArgs
|
|
)
|
|
{
|
|
FFA_MSG_INFO *FfaMsgInfo;
|
|
|
|
ZeroMem (EventCompleteSvcArgs, sizeof (ARM_SVC_ARGS));
|
|
|
|
if (CommProtocol == CommProtocolFfa) {
|
|
FfaMsgInfo = CommData;
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
EventCompleteSvcArgs->Arg0 = ARM_FID_FFA_ERROR;
|
|
|
|
/*
|
|
* StandaloneMm is secure instance. So set as 0x00.
|
|
*/
|
|
EventCompleteSvcArgs->Arg1 = 0x00;
|
|
EventCompleteSvcArgs->Arg2 = EfiStatusToFfaStatus (Status);
|
|
} else {
|
|
if (FfaMsgInfo->DirectMsgVersion == DirectMsgV1) {
|
|
EventCompleteSvcArgs->Arg0 = ARM_FID_FFA_MSG_SEND_DIRECT_RESP;
|
|
EventCompleteSvcArgs->Arg3 = ARM_FID_SPM_MM_SP_EVENT_COMPLETE;
|
|
} else {
|
|
EventCompleteSvcArgs->Arg0 = ARM_FID_FFA_MSG_SEND_DIRECT_RESP2;
|
|
|
|
if (FfaMsgInfo->ServiceType == ServiceTypeMisc) {
|
|
EventCompleteSvcArgs->Arg4 = mMiscMmCommunicateBuffer->DirectMsgArgs.Arg0;
|
|
EventCompleteSvcArgs->Arg5 = mMiscMmCommunicateBuffer->DirectMsgArgs.Arg1;
|
|
EventCompleteSvcArgs->Arg6 = mMiscMmCommunicateBuffer->DirectMsgArgs.Arg2;
|
|
EventCompleteSvcArgs->Arg7 = mMiscMmCommunicateBuffer->DirectMsgArgs.Arg3;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Swap source & dest partition id.
|
|
*/
|
|
EventCompleteSvcArgs->Arg1 = PACK_PARTITION_ID_INFO (
|
|
FfaMsgInfo->DestPartId,
|
|
FfaMsgInfo->SourcePartId
|
|
);
|
|
}
|
|
} else {
|
|
EventCompleteSvcArgs->Arg0 = ARM_FID_SPM_MM_SP_EVENT_COMPLETE;
|
|
EventCompleteSvcArgs->Arg1 = EfiStatusToSpmMmStatus (Status);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Wrap Misc service buffer with MmCommunication Header to
|
|
patch event handler via MmCommunication protocol.
|
|
|
|
@param[in] EventSvcArgs Passed arguments
|
|
@param[in] ServiceGuid Service Guid
|
|
@param[out] Buffer Misc service data
|
|
wrapped with MmCommunication Header.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
InitializeMiscMmCommunicateBuffer (
|
|
IN ARM_SVC_ARGS *EventSvcArgs,
|
|
IN EFI_GUID *ServiceGuid,
|
|
OUT MISC_MM_COMMUNICATE_BUFFER *Buffer
|
|
)
|
|
{
|
|
ZeroMem (Buffer, sizeof (MISC_MM_COMMUNICATE_BUFFER));
|
|
|
|
Buffer->MessageLength = sizeof (DIRECT_MSG_ARGS);
|
|
Buffer->DirectMsgArgs.Arg0 = EventSvcArgs->Arg4;
|
|
Buffer->DirectMsgArgs.Arg1 = EventSvcArgs->Arg5;
|
|
Buffer->DirectMsgArgs.Arg2 = EventSvcArgs->Arg6;
|
|
Buffer->DirectMsgArgs.Arg3 = EventSvcArgs->Arg7;
|
|
CopyGuid (&Buffer->HeaderGuid, ServiceGuid);
|
|
}
|
|
|
|
/**
|
|
Convert UUID to EFI_GUID format.
|
|
for example, If there is EFI_GUID named
|
|
"378daedc-f06b-4446-8314-40ab933c87a3",
|
|
|
|
EFI_GUID is saved in memory like:
|
|
dc ae 8d 37
|
|
6b f0 46 44
|
|
83 14 40 ab
|
|
93 3c 87 a3
|
|
|
|
However, UUID should be saved like:
|
|
37 8d ae dc
|
|
f0 6b 44 46
|
|
83 14 40 ab
|
|
93 3c 87 a3
|
|
|
|
FF-A and other software components (i.e. linux-kernel)
|
|
uses below format.
|
|
|
|
To patch mm-service properly, the passed uuid should be converted to
|
|
EFI_GUID format.
|
|
|
|
@param [in] Uuid Uuid
|
|
@param [out] Guid EFI_GUID
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
ConvertUuidToEfiGuid (
|
|
IN UINT64 *Uuid,
|
|
OUT EFI_GUID *Guid
|
|
)
|
|
{
|
|
UINT32 *Data32;
|
|
UINT16 *Data16;
|
|
|
|
Data32 = (UINT32 *)Uuid;
|
|
Data32[0] = SwapBytes32 (Data32[0]);
|
|
Data16 = (UINT16 *)&Data32[1];
|
|
Data16[0] = SwapBytes16 (Data16[0]);
|
|
Data16[1] = SwapBytes16 (Data16[1]);
|
|
CopyGuid (Guid, (EFI_GUID *)Uuid);
|
|
}
|
|
|
|
/**
|
|
A loop to delegate events from SPMC.
|
|
DelegatedEventLoop() calls ArmCallSvc() to exit to SPMC.
|
|
When an event is delegated to StandaloneMm the SPMC returns control
|
|
to StandaloneMm by returning from the SVC call.
|
|
|
|
@param [in] CommProtocol Abi Protocol.
|
|
@param [in] CpuDriverEntryPoint Entry point to handle request.
|
|
@param [in] EventCompleteSvcArgs Pointer to the event completion arguments.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
DelegatedEventLoop (
|
|
IN COMM_PROTOCOL CommProtocol,
|
|
IN EDKII_PI_MM_CPU_DRIVER_ENTRYPOINT CpuDriverEntryPoint,
|
|
IN ARM_SVC_ARGS *EventCompleteSvcArgs
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN CpuNumber;
|
|
UINT64 Uuid[2];
|
|
VOID *CommData;
|
|
FFA_MSG_INFO FfaMsgInfo;
|
|
EFI_GUID ServiceGuid;
|
|
SERVICE_TYPE ServiceType;
|
|
UINTN CommBufferAddr;
|
|
|
|
CommData = NULL;
|
|
|
|
while (TRUE) {
|
|
// Exit to SPMC.
|
|
ArmCallSvc (EventCompleteSvcArgs);
|
|
// Enter from SPMC.
|
|
|
|
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));
|
|
DEBUG ((DEBUG_INFO, "X4 : 0x%x\n", (UINT32)EventCompleteSvcArgs->Arg4));
|
|
DEBUG ((DEBUG_INFO, "X5 : 0x%x\n", (UINT32)EventCompleteSvcArgs->Arg5));
|
|
DEBUG ((DEBUG_INFO, "X6 : 0x%x\n", (UINT32)EventCompleteSvcArgs->Arg6));
|
|
DEBUG ((DEBUG_INFO, "X7 : 0x%x\n", (UINT32)EventCompleteSvcArgs->Arg7));
|
|
|
|
CpuNumber = GetCpuNumber (CommProtocol, EventCompleteSvcArgs);
|
|
DEBUG ((DEBUG_INFO, "CpuNumber: %d\n", CpuNumber));
|
|
|
|
if (CommProtocol == CommProtocolFfa) {
|
|
/*
|
|
* Register Convention for FF-A
|
|
* Arg0: ARM_FID_FFA_MSG_SEND_DIRECT_REQ/REQ2
|
|
* Arg1: Sender and Receiver endpoint IDs.
|
|
* Arg2: Message Flags for ARM_FID_FFA_MSG_SEND_DIRECT_REQ
|
|
* Low 8 bytes of UUID for ARM_FID_FFA_MSG_SEND_DIRECT_REQ2
|
|
* Arg3: Implementation Defined for ARM_FID_FFA_MSG_SEND_DIRECT_REQ
|
|
* High 8 bytes of UUID for ARM_FID_FFA_MSG_SEND_DIRECT_REQ2
|
|
* Others: Implementation Defined.
|
|
*
|
|
* See Arm Firmware Framework for Arm A-Profile for detail.
|
|
*/
|
|
FfaMsgInfo.SourcePartId = GET_SOURCE_PARTITION_ID (EventCompleteSvcArgs->Arg1);
|
|
FfaMsgInfo.DestPartId = GET_DEST_PARTITION_ID (EventCompleteSvcArgs->Arg1);
|
|
CommData = &FfaMsgInfo;
|
|
|
|
if (EventCompleteSvcArgs->Arg0 == ARM_FID_FFA_MSG_SEND_DIRECT_REQ) {
|
|
FfaMsgInfo.DirectMsgVersion = DirectMsgV1;
|
|
ServiceType = ServiceTypeMmCommunication;
|
|
} else if (EventCompleteSvcArgs->Arg0 == ARM_FID_FFA_MSG_SEND_DIRECT_REQ2) {
|
|
FfaMsgInfo.DirectMsgVersion = DirectMsgV2;
|
|
Uuid[0] = EventCompleteSvcArgs->Arg2;
|
|
Uuid[1] = EventCompleteSvcArgs->Arg3;
|
|
ConvertUuidToEfiGuid (Uuid, &ServiceGuid);
|
|
ServiceType = GetServiceType (&ServiceGuid);
|
|
} else {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"Error: Unrecognized FF-A Id: 0x%x\n",
|
|
EventCompleteSvcArgs->Arg0
|
|
));
|
|
goto ExitHandler;
|
|
}
|
|
|
|
FfaMsgInfo.ServiceType = ServiceType;
|
|
|
|
if (ServiceType == ServiceTypeMmCommunication) {
|
|
if (FfaMsgInfo.DirectMsgVersion == DirectMsgV1) {
|
|
CommBufferAddr = EventCompleteSvcArgs->Arg3;
|
|
} else {
|
|
CommBufferAddr = EventCompleteSvcArgs->Arg4;
|
|
}
|
|
} else if (ServiceType == ServiceTypeMisc) {
|
|
/*
|
|
* In case of Misc service, generate mm communication header
|
|
* to dispatch service via StandaloneMmCore.
|
|
*/
|
|
InitializeMiscMmCommunicateBuffer (
|
|
EventCompleteSvcArgs,
|
|
&ServiceGuid,
|
|
mMiscMmCommunicateBuffer
|
|
);
|
|
CommBufferAddr = (UINTN)mMiscMmCommunicateBuffer;
|
|
} else {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
DEBUG ((DEBUG_ERROR, "Error: Invalid FF-A Service...\n"));
|
|
goto ExitHandler;
|
|
}
|
|
} else if (CommProtocol == CommProtocolSpmMm) {
|
|
/*
|
|
* Register Convention for SPM_MM
|
|
* Arg0: ARM_SMC_ID_MM_COMMUNICATE
|
|
* Arg1: Communication Buffer
|
|
* Arg2: Size of Communication Buffer
|
|
* Arg3: Cpu number where StandaloneMm running on.
|
|
*
|
|
* See tf-a/services/std_svc/spm/spm_mm/spm_mm_main.c
|
|
*/
|
|
if (EventCompleteSvcArgs->Arg0 != ARM_SMC_ID_MM_COMMUNICATE) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"Error: Unrecognized SPM_MM Id: 0x%x\n",
|
|
EventCompleteSvcArgs->Arg0
|
|
));
|
|
goto ExitHandler;
|
|
}
|
|
|
|
CommBufferAddr = EventCompleteSvcArgs->Arg1;
|
|
ServiceType = ServiceTypeMmCommunication;
|
|
}
|
|
|
|
Status = CpuDriverEntryPoint ((UINTN)ServiceType, CpuNumber, CommBufferAddr);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"Error: Failed delegated event 0x%x, Status 0x%x\n",
|
|
CommBufferAddr,
|
|
Status
|
|
));
|
|
}
|
|
|
|
ExitHandler:
|
|
SetEventCompleteSvcArgs (
|
|
CommProtocol,
|
|
CommData,
|
|
Status,
|
|
EventCompleteSvcArgs
|
|
);
|
|
} // while
|
|
}
|
|
|
|
/**
|
|
The handoff between the SPMC to StandaloneMM depends on the
|
|
communication interface between the SPMC and StandaloneMM.
|
|
When SpmMM is used, the handoff is implemented using the
|
|
Firmware Handoff protocol. When FF-A is used the FF-A boot
|
|
protocol is used.
|
|
|
|
@param [in] Arg0 In case of FF-A, address of FF-A boot information
|
|
In case of SPM_MM, this parameter must be zero
|
|
@param [in] Arg1 In case of FF-A, this parameter must be zero
|
|
In case of SPM_MM, Signature and register convention version
|
|
@param [in] Arg2 Must be zero
|
|
@param [in] Arg3 In case of FF-A, this parameter must be zero
|
|
In case of SPM_MM, address of transfer list
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
CEntryPoint (
|
|
IN UINTN Arg0,
|
|
IN UINTN Arg1,
|
|
IN UINTN Arg2,
|
|
IN UINTN Arg3
|
|
)
|
|
{
|
|
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
|
|
ARM_SVC_ARGS EventCompleteSvcArgs;
|
|
EFI_STATUS Status;
|
|
UINT32 SectionHeaderOffset;
|
|
UINT16 NumberOfSections;
|
|
COMM_PROTOCOL CommProtocol;
|
|
VOID *HobStart;
|
|
VOID *TeData;
|
|
UINTN TeDataSize;
|
|
EFI_PHYSICAL_ADDRESS ImageBase;
|
|
EDKII_PI_MM_CPU_DRIVER_EP_PROTOCOL *PiMmCpuDriverEpProtocol;
|
|
EDKII_PI_MM_CPU_DRIVER_ENTRYPOINT CpuDriverEntryPoint;
|
|
EFI_HOB_FIRMWARE_VOLUME *FvHob;
|
|
EFI_HOB_GUID_TYPE *GuidHob;
|
|
EFI_CONFIGURATION_TABLE *ConfigurationTable;
|
|
UINTN Idx;
|
|
|
|
CpuDriverEntryPoint = NULL;
|
|
|
|
Status = GetCommProtocol (&CommProtocol);
|
|
if (EFI_ERROR (Status)) {
|
|
goto finish;
|
|
}
|
|
|
|
HobStart = GetPhitHobFromBootInfo (CommProtocol, Arg0, Arg1, Arg2, Arg3);
|
|
if (HobStart == NULL) {
|
|
Status = EFI_UNSUPPORTED;
|
|
goto finish;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "Start Dump Hob: %lx\n", (unsigned long)HobStart));
|
|
DumpPhitHob (HobStart);
|
|
DEBUG ((DEBUG_INFO, "End Dump Hob: %lx\n", (unsigned long)HobStart));
|
|
|
|
FvHob = GetNextHob (EFI_HOB_TYPE_FV, HobStart);
|
|
if (FvHob == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Error: No Firmware Volume Hob is present.\n"));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
|
|
goto finish;
|
|
}
|
|
|
|
// Locate PE/COFF File information for the Standalone MM core module
|
|
Status = LocateStandaloneMmCorePeCoffData (
|
|
(EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHob->BaseAddress,
|
|
&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);
|
|
}
|
|
|
|
// Set the gHobList to point to the HOB list passed by TF-A.
|
|
// This will be used by StandaloneMmCoreHobLib in early stage.
|
|
gHobList = HobStart;
|
|
|
|
//
|
|
// Call the MM Core entry point
|
|
//
|
|
ProcessModuleEntryPointList (HobStart);
|
|
|
|
// ProcessModuleEntryPointList() copies the HOB List passed
|
|
// by TF-A, i.e. HobStart, in the ConfigurationTable[].
|
|
// Therefore, find the HobList in the ConfigurationTable[] by
|
|
// searching for the gEfiHobListGuid.
|
|
// Also update the gHobList to point to the HobList in the
|
|
// ConfigurationTable[] as the HobList passed by TF-A can
|
|
// be overwritten by StMM after StMM Core is initialised, i.e.
|
|
// after the MM Core entry point is called.
|
|
Status = EFI_NOT_FOUND;
|
|
ConfigurationTable = gMmCoreMmst.MmConfigurationTable;
|
|
for (Idx = 0; Idx < gMmCoreMmst.NumberOfTableEntries; Idx++) {
|
|
if (CompareGuid (&gEfiHobListGuid, &ConfigurationTable[Idx].VendorGuid)) {
|
|
Status = EFI_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Error: Hoblist not found in MmConfigurationTable\n"));
|
|
goto finish;
|
|
}
|
|
|
|
// Set the gHobList to point to the HOB list saved in ConfigurationTable[].
|
|
gHobList = ConfigurationTable[Idx].VendorTable;
|
|
|
|
//
|
|
// Find MpInformation Hob in HobList.
|
|
// It couldn't save address of mp information in gHobList
|
|
// because that memory area will be reused after StandaloneMm finishing
|
|
// initialization.
|
|
//
|
|
GuidHob = GetNextGuidHob (&gMpInformationHobGuid, gHobList);
|
|
if (GuidHob == NULL) {
|
|
Status = EFI_NOT_FOUND;
|
|
DEBUG ((DEBUG_ERROR, "Error: No MpInformation hob ...\n"));
|
|
goto finish;
|
|
}
|
|
|
|
mMpInfo = GET_GUID_HOB_DATA (GuidHob);
|
|
|
|
//
|
|
// Find out cpu driver entry point used in DelegatedEventLoop
|
|
// to handle MMI request.
|
|
//
|
|
Status = gMmCoreMmst.MmLocateProtocol (
|
|
&gEdkiiPiMmCpuDriverEpProtocolGuid,
|
|
NULL,
|
|
(VOID **)&PiMmCpuDriverEpProtocol
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto finish;
|
|
}
|
|
|
|
CpuDriverEntryPoint = PiMmCpuDriverEpProtocol->PiMmCpuDriverEntryPoint;
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"Shared Cpu Driver EP %p\n",
|
|
CpuDriverEntryPoint
|
|
));
|
|
|
|
if (CommProtocol == CommProtocolFfa) {
|
|
Status = gMmCoreMmst.MmAllocatePool (
|
|
EfiRuntimeServicesData,
|
|
sizeof (MISC_MM_COMMUNICATE_BUFFER),
|
|
(VOID **)&mMiscMmCommunicateBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"Error: Failed to allocate misc mm communication buffer...\n"
|
|
));
|
|
goto finish;
|
|
}
|
|
}
|
|
|
|
finish:
|
|
ReturnInitStatusToSpmc (CommProtocol, Status, &EventCompleteSvcArgs);
|
|
|
|
// Call DelegateEventLoop(), this function never returns.
|
|
DelegatedEventLoop (CommProtocol, CpuDriverEntryPoint, &EventCompleteSvcArgs);
|
|
}
|