ArmPkg: implement EFI_MP_SERVICES_PROTOCOL based on PSCI calls

Add support for EFI_MP_SERVICES_PROTOCOL during the DXE phase under
AArch64.

PSCI_CPU_ON is called to power on the core, the supplied procedure is
executed and PSCI_CPU_OFF is called to power off the core.

Fixes contributed by Ard Biesheuvel.

Signed-off-by: Rebecca Cran <rebecca@quicinc.com>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Tested-by: Kun Qin <kun.qin@microsoft.com>
This commit is contained in:
Rebecca Cran 2023-01-16 21:57:31 -07:00 committed by mergify[bot]
parent d1855afc6e
commit e7aac7fc13
5 changed files with 2335 additions and 0 deletions

View File

@ -164,6 +164,7 @@
ArmPkg/Universal/Smbios/OemMiscLibNull/OemMiscLibNull.inf
[Components.AARCH64]
ArmPkg/Drivers/ArmPsciMpServicesDxe/ArmPsciMpServicesDxe.inf
ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.inf
ArmPkg/Library/ArmMmuLib/ArmMmuPeiLib.inf

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,56 @@
## @file
# ARM MP services protocol driver
#
# Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
[Defines]
INF_VERSION = 1.27
BASE_NAME = ArmPsciMpServicesDxe
FILE_GUID = 007ab472-dc4a-4df8-a5c2-abb4a327278c
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = ArmPsciMpServicesDxeInitialize
[Sources.Common]
ArmPsciMpServicesDxe.c
MpFuncs.S
MpServicesInternal.h
[Packages]
ArmPkg/ArmPkg.dec
ArmPlatformPkg/ArmPlatformPkg.dec
EmbeddedPkg/EmbeddedPkg.dec
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
ArmLib
ArmMmuLib
ArmSmcLib
BaseMemoryLib
CacheMaintenanceLib
CpuExceptionHandlerLib
DebugLib
HobLib
MemoryAllocationLib
UefiBootServicesTableLib
UefiDriverEntryPoint
UefiLib
[Protocols]
gEfiMpServiceProtocolGuid ## PRODUCES
gEfiLoadedImageProtocolGuid ## CONSUMES
[Guids]
gArmMpCoreInfoGuid
[Depex]
TRUE
[BuildOptions]
GCC:*_*_*_CC_FLAGS = -mstrict-align

View File

@ -0,0 +1,74 @@
#===============================================================================
# Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#===============================================================================
.text
.align 3
#include <AsmMacroIoLibV8.h>
#include <IndustryStandard/ArmStdSmc.h>
#include <Library/ArmLib.h>
#include "MpServicesInternal.h"
GCC_ASM_IMPORT (gApStacksBase)
GCC_ASM_IMPORT (gProcessorIDs)
GCC_ASM_IMPORT (ApProcedure)
GCC_ASM_IMPORT (gApStackSize)
GCC_ASM_IMPORT (gTcr)
GCC_ASM_IMPORT (gTtbr0)
GCC_ASM_IMPORT (gMair)
GCC_ASM_EXPORT (ApEntryPoint)
// Entry-point for the AP
// VOID
// ApEntryPoint (
// VOID
// );
ASM_PFX(ApEntryPoint):
// Configure the MMU and caches
ldr x0, gTcr
bl ArmSetTCR
ldr x0, gTtbr0
bl ArmSetTTBR0
ldr x0, gMair
bl ArmSetMAIR
bl ArmDisableAlignmentCheck
bl ArmEnableStackAlignmentCheck
bl ArmEnableInstructionCache
bl ArmEnableDataCache
bl ArmEnableMmu
mrs x0, mpidr_el1
// Mask the non-affinity bits
bic x0, x0, 0x00ff000000
and x0, x0, 0xffffffffff
ldr x1, gProcessorIDs
mov x2, 0 // x2 = processor index
// Find index in gProcessorIDs for current processor
1:
ldr x3, [x1, x2, lsl #3] // x4 = gProcessorIDs + x2 * 8
cmp x3, #-1 // check if we've reached the end of gProcessorIDs
beq ProcessorNotFound
add x2, x2, 1 // x2++
cmp x0, x3 // if mpidr_el1 != gProcessorIDs[x] then loop
bne 1b
// Calculate stack address
// x2 contains the index for the current processor plus 1
ldr x0, gApStacksBase
ldr x1, gApStackSize
mul x3, x2, x1 // x3 = (ProcessorIndex + 1) * gApStackSize
add sp, x0, x3 // sp = gApStacksBase + x3
mov x29, xzr
bl ApProcedure // doesn't return
ProcessorNotFound:
// Turn off the processor
MOV32 (w0, ARM_SMC_ID_PSCI_CPU_OFF)
smc #0
b .

View File

@ -0,0 +1,345 @@
/** @file
Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.<BR>
Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
Portions copyright (c) 2011, Apple Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef MP_SERVICES_INTERNAL_H_
#define MP_SERVICES_INTERNAL_H_
#include <Protocol/Cpu.h>
#include <Protocol/MpService.h>
#include <Library/BaseLib.h>
#include <Library/UefiLib.h>
#define AP_STACK_SIZE 0x1000
//
// Internal Data Structures
//
//
// AP state
//
// The state transitions for an AP when it processes a procedure are:
// Idle ----> Ready ----> Busy ----> Finished ----> Idle
// [BSP] [BSP] [AP] [BSP]
//
typedef enum {
CpuStateIdle,
CpuStateReady,
CpuStateBlocked,
CpuStateBusy,
CpuStateFinished,
CpuStateDisabled
} CPU_STATE;
//
// Define Individual Processor Data block.
//
typedef struct {
EFI_PROCESSOR_INFORMATION Info;
EFI_AP_PROCEDURE Procedure;
VOID *Parameter;
CPU_STATE State;
EFI_EVENT CheckThisAPEvent;
EFI_EVENT WaitEvent;
UINTN Timeout;
UINTN TimeTaken;
BOOLEAN TimeoutActive;
BOOLEAN *SingleApFinished;
} CPU_AP_DATA;
//
// Define MP data block which consumes individual processor block.
//
typedef struct {
UINTN NumberOfProcessors;
UINTN NumberOfEnabledProcessors;
EFI_EVENT CheckAllAPsEvent;
EFI_EVENT AllWaitEvent;
UINTN FinishCount;
UINTN StartCount;
EFI_AP_PROCEDURE Procedure;
VOID *ProcedureArgument;
BOOLEAN SingleThread;
UINTN StartedNumber;
CPU_AP_DATA *CpuData;
UINTN *FailedList;
UINTN FailedListIndex;
UINTN AllTimeout;
UINTN AllTimeTaken;
BOOLEAN AllTimeoutActive;
} CPU_MP_DATA;
/** Secondary core entry point.
**/
VOID
ApEntryPoint (
VOID
);
/** C entry-point for the AP.
This function gets called from the assembly function ApEntryPoint.
**/
VOID
ApProcedure (
VOID
);
/** Turns on the specified core using PSCI and executes the user-supplied
function that's been configured via a previous call to SetApProcedure.
@param ProcessorIndex The index of the core to turn on.
@retval EFI_SUCCESS The processor was successfully turned on.
@retval EFI_DEVICE_ERROR An error occurred turning the processor on.
**/
STATIC
EFI_STATUS
EFIAPI
DispatchCpu (
IN UINTN ProcessorIndex
);
/** Returns whether the specified processor is the BSP.
@param[in] ProcessorIndex The index the processor to check.
@return TRUE if the processor is the BSP, FALSE otherwise.
**/
STATIC
BOOLEAN
IsProcessorBSP (
UINTN ProcessorIndex
);
/** Returns whether the processor executing this function is the BSP.
@return Whether the current processor is the BSP.
**/
STATIC
BOOLEAN
IsCurrentProcessorBSP (
VOID
);
/** Returns whether the specified processor is enabled.
@param[in] ProcessorIndex The index of the processor to check.
@return TRUE if the processor is enabled, FALSE otherwise.
**/
STATIC
BOOLEAN
IsProcessorEnabled (
UINTN ProcessorIndex
);
/** Configures the processor context with the user-supplied procedure and
argument.
@param CpuData The processor context.
@param Procedure The user-supplied procedure.
@param ProcedureArgument The user-supplied procedure argument.
**/
STATIC
VOID
SetApProcedure (
IN CPU_AP_DATA *CpuData,
IN EFI_AP_PROCEDURE Procedure,
IN VOID *ProcedureArgument
);
/**
Get the Application Processors state.
@param[in] CpuData The pointer to CPU_AP_DATA of specified AP
@return The AP status
**/
CPU_STATE
GetApState (
IN CPU_AP_DATA *CpuData
);
/** Returns the index of the next processor that is blocked.
@param[out] NextNumber The index of the next blocked processor.
@retval EFI_SUCCESS Successfully found the next blocked processor.
@retval EFI_NOT_FOUND There are no blocked processors.
**/
STATIC
EFI_STATUS
GetNextBlockedNumber (
OUT UINTN *NextNumber
);
/** Stalls the BSP for the minimum of gPollInterval and Timeout.
@param[in] Timeout The time limit in microseconds remaining for
APs to return from Procedure.
@retval StallTime Time of execution stall.
**/
STATIC
UINTN
CalculateAndStallInterval (
IN UINTN Timeout
);
/** Sets up the state for the StartupAllAPs function.
@param SingleThread Whether the APs will execute sequentially.
**/
STATIC
VOID
StartupAllAPsPrepareState (
IN BOOLEAN SingleThread
);
/** Handles execution of StartupAllAPs when a WaitEvent has been specified.
@param Procedure The user-supplied procedure.
@param ProcedureArgument The user-supplied procedure argument.
@param WaitEvent The wait event to be signaled when the work is
complete or a timeout has occurred.
@param TimeoutInMicroseconds The timeout for the work to be completed. Zero
indicates an infinite timeout.
@param SingleThread Whether the APs will execute sequentially.
@param FailedCpuList User-supplied pointer for list of failed CPUs.
@return EFI_SUCCESS on success.
**/
STATIC
EFI_STATUS
StartupAllAPsWithWaitEvent (
IN EFI_AP_PROCEDURE Procedure,
IN VOID *ProcedureArgument,
IN EFI_EVENT WaitEvent,
IN UINTN TimeoutInMicroseconds,
IN BOOLEAN SingleThread,
IN UINTN **FailedCpuList
);
/** Handles execution of StartupAllAPs when no wait event has been specified.
@param Procedure The user-supplied procedure.
@param ProcedureArgument The user-supplied procedure argument.
@param TimeoutInMicroseconds The timeout for the work to be completed. Zero
indicates an infinite timeout.
@param SingleThread Whether the APs will execute sequentially.
@param FailedCpuList User-supplied pointer for list of failed CPUs.
@return EFI_SUCCESS on success.
**/
STATIC
EFI_STATUS
StartupAllAPsNoWaitEvent (
IN EFI_AP_PROCEDURE Procedure,
IN VOID *ProcedureArgument,
IN UINTN TimeoutInMicroseconds,
IN BOOLEAN SingleThread,
IN UINTN **FailedCpuList
);
/** Adds the specified processor the list of failed processors.
@param ProcessorIndex The processor index to add.
@param ApState Processor state.
**/
STATIC
VOID
AddProcessorToFailedList (
UINTN ProcessorIndex,
CPU_STATE ApState
);
/** Handles the StartupAllAPs case where the timeout has occurred.
**/
STATIC
VOID
ProcessStartupAllAPsTimeout (
VOID
);
/**
If a timeout is specified in StartupAllAps(), a timer is set, which invokes
this procedure periodically to check whether all APs have finished.
@param[in] Event The WaitEvent the user supplied.
@param[in] Context The event context.
**/
STATIC
VOID
EFIAPI
CheckAllAPsStatus (
IN EFI_EVENT Event,
IN VOID *Context
);
/** Invoked periodically via a timer to check the state of the processor.
@param Event The event supplied by the timer expiration.
@param Context The processor context.
**/
STATIC
VOID
EFIAPI
CheckThisAPStatus (
IN EFI_EVENT Event,
IN VOID *Context
);
/**
This function is called by all processors (both BSP and AP) once and collects
MP related data.
@param BSP TRUE if the processor is the BSP.
@param Mpidr The MPIDR for the specified processor. This should be
the full MPIDR and not only the affinity bits.
@param ProcessorIndex The index of the processor.
@return EFI_SUCCESS if the data for the processor collected and filled in.
**/
STATIC
EFI_STATUS
FillInProcessorInformation (
IN BOOLEAN BSP,
IN UINTN Mpidr,
IN UINTN ProcessorIndex
);
/**
Event notification function called when the EFI_EVENT_GROUP_READY_TO_BOOT is
signaled. After this point, non-blocking mode is no longer allowed.
@param Event Event whose notification function is being invoked.
@param Context The pointer to the notification function's context,
which is implementation-dependent.
**/
STATIC
VOID
EFIAPI
ReadyToBootSignaled (
IN EFI_EVENT Event,
IN VOID *Context
);
#endif /* MP_SERVICES_INTERNAL_H_ */