2011-07-01 13:09:00 +02:00
|
|
|
/** @file
|
|
|
|
*
|
2017-06-08 16:40:09 +02:00
|
|
|
* Copyright (c) 2011-2017, ARM Limited. All rights reserved.
|
2011-07-01 13:09:00 +02:00
|
|
|
*
|
2019-04-04 01:03:21 +02:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause-Patent
|
2011-07-01 13:09:00 +02:00
|
|
|
*
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include <PiPei.h>
|
|
|
|
|
ArmPlatformPkg/PrePi: replace set/way cache ops with by-VA ones
Cache maintenance operations by set/way are only intended to be used
in the context of on/offlining a core, while it has been taken out of
the coherency domain. Any use intended to ensure that the contents of
the cache have made it to main memory is unreliable, since cacheline
migration and non-architected system caches may cause these contents
to linger elsewhere, without being visible in main memory once the
MMU and caches are disabled.
In KVM on Linux, there are horrid hacks in place to ensure that such
set/way operations are trapped, and replaced with a single by-VA
clean/invalidate of the entire guest VA space once the MMU state
changes, which can be costly, and is unnecessary if we manage the
caches a bit more carefully, and perform maintenance by virtual
address only.
So let's get rid of the call to ArmInvalidateDataCache () in the
PrePeiCore startup code, and instead, invalidate the UEFI memory
region by virtual address, which is the only memory region we will
be touching with the caches and MMU both disabled and enabled.
(This will lead to data corruption if data written with the MMU off
is shadowed by clean, stale cachelines that stick around when the
MMU is enabled again.)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Acked-by: Laszlo Ersek <lersek@redhat.com>
Tested-by: Pete Batard <pete@akeo.ie>
Reviewed-by: Leif Lindholm <leif@nuviainc.com>
2020-02-25 19:28:34 +01:00
|
|
|
#include <Library/CacheMaintenanceLib.h>
|
2011-07-01 13:09:00 +02:00
|
|
|
#include <Library/DebugAgentLib.h>
|
|
|
|
#include <Library/PrePiLib.h>
|
|
|
|
#include <Library/PrintLib.h>
|
2011-08-18 13:17:09 +02:00
|
|
|
#include <Library/PrePiHobListPointerLib.h>
|
2011-07-01 13:09:00 +02:00
|
|
|
#include <Library/TimerLib.h>
|
|
|
|
#include <Library/PerformanceLib.h>
|
|
|
|
|
|
|
|
#include <Ppi/GuidedSectionExtraction.h>
|
2012-07-04 22:17:46 +02:00
|
|
|
#include <Ppi/ArmMpCoreInfo.h>
|
2017-06-08 16:40:09 +02:00
|
|
|
#include <Ppi/SecPerformance.h>
|
2011-07-01 13:09:00 +02:00
|
|
|
|
|
|
|
#include "PrePi.h"
|
|
|
|
|
2016-03-24 21:30:08 +01:00
|
|
|
#define IS_XIP() (((UINT64)FixedPcdGet64 (PcdFdBaseAddress) > mSystemMemoryEnd) || \
|
2020-03-05 08:55:58 +01:00
|
|
|
((FixedPcdGet64 (PcdFdBaseAddress) + FixedPcdGet32 (PcdFdSize)) <= FixedPcdGet64 (PcdSystemMemoryBase)))
|
2011-09-23 01:11:03 +02:00
|
|
|
|
2016-10-24 10:48:32 +02:00
|
|
|
UINT64 mSystemMemoryEnd = FixedPcdGet64(PcdSystemMemoryBase) +
|
|
|
|
FixedPcdGet64(PcdSystemMemorySize) - 1;
|
|
|
|
|
2012-07-04 22:17:46 +02:00
|
|
|
EFI_STATUS
|
|
|
|
GetPlatformPpi (
|
|
|
|
IN EFI_GUID *PpiGuid,
|
|
|
|
OUT VOID **Ppi
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN PpiListSize;
|
|
|
|
UINTN PpiListCount;
|
|
|
|
EFI_PEI_PPI_DESCRIPTOR *PpiList;
|
|
|
|
UINTN Index;
|
|
|
|
|
|
|
|
PpiListSize = 0;
|
|
|
|
ArmPlatformGetPlatformPpiList (&PpiListSize, &PpiList);
|
|
|
|
PpiListCount = PpiListSize / sizeof(EFI_PEI_PPI_DESCRIPTOR);
|
|
|
|
for (Index = 0; Index < PpiListCount; Index++, PpiList++) {
|
|
|
|
if (CompareGuid (PpiList->Guid, PpiGuid) == TRUE) {
|
|
|
|
*Ppi = PpiList->Ppi;
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
2011-07-01 13:09:00 +02:00
|
|
|
VOID
|
|
|
|
PrePiMain (
|
|
|
|
IN UINTN UefiMemoryBase,
|
2011-09-23 01:07:55 +02:00
|
|
|
IN UINTN StacksBase,
|
2011-07-01 13:09:00 +02:00
|
|
|
IN UINT64 StartTimeStamp
|
|
|
|
)
|
|
|
|
{
|
2011-08-18 13:17:09 +02:00
|
|
|
EFI_HOB_HANDOFF_INFO_TABLE* HobList;
|
2012-07-04 22:17:46 +02:00
|
|
|
ARM_MP_CORE_INFO_PPI* ArmMpCoreInfoPpi;
|
|
|
|
UINTN ArmCoreCount;
|
|
|
|
ARM_CORE_INFO* ArmCoreInfoTable;
|
2011-07-01 13:09:00 +02:00
|
|
|
EFI_STATUS Status;
|
|
|
|
CHAR8 Buffer[100];
|
|
|
|
UINTN CharCount;
|
2011-07-06 18:27:21 +02:00
|
|
|
UINTN StacksSize;
|
2017-06-08 16:40:09 +02:00
|
|
|
FIRMWARE_SEC_PERFORMANCE Performance;
|
2011-07-01 13:09:00 +02:00
|
|
|
|
2011-09-23 01:11:03 +02:00
|
|
|
// If ensure the FD is either part of the System Memory or totally outside of the System Memory (XIP)
|
2014-08-19 15:29:52 +02:00
|
|
|
ASSERT (IS_XIP() ||
|
2016-03-24 21:30:08 +01:00
|
|
|
((FixedPcdGet64 (PcdFdBaseAddress) >= FixedPcdGet64 (PcdSystemMemoryBase)) &&
|
|
|
|
((UINT64)(FixedPcdGet64 (PcdFdBaseAddress) + FixedPcdGet32 (PcdFdSize)) <= (UINT64)mSystemMemoryEnd)));
|
2011-09-23 01:11:03 +02:00
|
|
|
|
2013-07-18 21:06:52 +02:00
|
|
|
// Initialize the architecture specific bits
|
|
|
|
ArchInitialize ();
|
2011-07-01 13:09:00 +02:00
|
|
|
|
|
|
|
// Initialize the Serial Port
|
|
|
|
SerialPortInitialize ();
|
2012-03-26 13:08:32 +02:00
|
|
|
CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"UEFI firmware (version %s built at %a on %a)\n\r",
|
|
|
|
(CHAR16*)PcdGetPtr(PcdFirmwareVersionString), __TIME__, __DATE__);
|
2011-07-01 13:09:00 +02:00
|
|
|
SerialPortWrite ((UINT8 *) Buffer, CharCount);
|
|
|
|
|
|
|
|
// Initialize the Debug Agent for Source Level Debugging
|
|
|
|
InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, NULL, NULL);
|
|
|
|
SaveAndSetDebugTimerInterrupt (TRUE);
|
2014-08-19 15:29:52 +02:00
|
|
|
|
2011-07-06 18:27:21 +02:00
|
|
|
// Declare the PI/UEFI memory region
|
2011-08-18 13:17:09 +02:00
|
|
|
HobList = HobConstructor (
|
2011-07-01 13:09:00 +02:00
|
|
|
(VOID*)UefiMemoryBase,
|
|
|
|
FixedPcdGet32 (PcdSystemMemoryUefiRegionSize),
|
|
|
|
(VOID*)UefiMemoryBase,
|
2011-07-06 18:27:21 +02:00
|
|
|
(VOID*)StacksBase // The top of the UEFI Memory is reserved for the stacks
|
|
|
|
);
|
2011-08-18 13:17:09 +02:00
|
|
|
PrePeiSetHobList (HobList);
|
2011-07-01 13:09:00 +02:00
|
|
|
|
|
|
|
// Initialize MMU and Memory HOBs (Resource Descriptor HOBs)
|
|
|
|
Status = MemoryPeim (UefiMemoryBase, FixedPcdGet32 (PcdSystemMemoryUefiRegionSize));
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
2011-07-06 18:27:21 +02:00
|
|
|
// Create the Stacks HOB (reserve the memory for all stacks)
|
2011-11-02 00:41:52 +01:00
|
|
|
if (ArmIsMpCore ()) {
|
2014-04-03 22:05:30 +02:00
|
|
|
StacksSize = PcdGet32 (PcdCPUCorePrimaryStackSize) +
|
|
|
|
((FixedPcdGet32 (PcdCoreCount) - 1) * FixedPcdGet32 (PcdCPUCoreSecondaryStackSize));
|
2011-11-02 00:41:52 +01:00
|
|
|
} else {
|
|
|
|
StacksSize = PcdGet32 (PcdCPUCorePrimaryStackSize);
|
|
|
|
}
|
2011-07-06 18:27:21 +02:00
|
|
|
BuildStackHob (StacksBase, StacksSize);
|
2011-07-01 13:09:00 +02:00
|
|
|
|
2011-09-23 01:14:01 +02:00
|
|
|
//TODO: Call CpuPei as a library
|
2018-11-26 22:34:05 +01:00
|
|
|
BuildCpuHob (ArmGetPhysicalAddressBits (), PcdGet8 (PcdPrePiCpuIoSize));
|
2011-09-23 01:14:01 +02:00
|
|
|
|
2012-07-04 22:17:46 +02:00
|
|
|
if (ArmIsMpCore ()) {
|
|
|
|
// Only MP Core platform need to produce gArmMpCoreInfoPpiGuid
|
|
|
|
Status = GetPlatformPpi (&gArmMpCoreInfoPpiGuid, (VOID**)&ArmMpCoreInfoPpi);
|
|
|
|
|
|
|
|
// On MP Core Platform we must implement the ARM MP Core Info PPI (gArmMpCoreInfoPpiGuid)
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
// Build the MP Core Info Table
|
|
|
|
ArmCoreCount = 0;
|
|
|
|
Status = ArmMpCoreInfoPpi->GetMpCoreInfo (&ArmCoreCount, &ArmCoreInfoTable);
|
|
|
|
if (!EFI_ERROR(Status) && (ArmCoreCount > 0)) {
|
|
|
|
// Build MPCore Info HOB
|
|
|
|
BuildGuidDataHob (&gArmMpCoreInfoGuid, ArmCoreInfoTable, sizeof (ARM_CORE_INFO) * ArmCoreCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-08 16:40:09 +02:00
|
|
|
// Store timer value logged at the beginning of firmware image execution
|
|
|
|
Performance.ResetEnd = GetTimeInNanoSecond (StartTimeStamp);
|
|
|
|
|
|
|
|
// Build SEC Performance Data Hob
|
|
|
|
BuildGuidDataHob (&gEfiFirmwarePerformanceGuid, &Performance, sizeof (Performance));
|
|
|
|
|
2011-07-01 13:09:00 +02:00
|
|
|
// Set the Boot Mode
|
|
|
|
SetBootMode (ArmPlatformGetBootMode ());
|
|
|
|
|
|
|
|
// Initialize Platform HOBs (CpuHob and FvHob)
|
|
|
|
Status = PlatformPeim ();
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
// Now, the HOB List has been initialized, we can register performance information
|
|
|
|
PERF_START (NULL, "PEI", NULL, StartTimeStamp);
|
|
|
|
|
|
|
|
// SEC phase needs to run library constructors by hand.
|
2017-11-30 16:09:48 +01:00
|
|
|
ProcessLibraryConstructorList ();
|
2011-07-01 13:09:00 +02:00
|
|
|
|
|
|
|
// Assume the FV that contains the SEC (our code) also contains a compressed FV.
|
|
|
|
Status = DecompressFirstFv ();
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
// Load the DXE Core and transfer control to it
|
|
|
|
Status = LoadDxeCoreFromFv (NULL, 0);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
CEntryPoint (
|
2011-09-23 01:01:13 +02:00
|
|
|
IN UINTN MpId,
|
2011-09-23 01:07:55 +02:00
|
|
|
IN UINTN UefiMemoryBase,
|
2015-11-27 18:07:06 +01:00
|
|
|
IN UINTN StacksBase
|
2011-07-01 13:09:00 +02:00
|
|
|
)
|
|
|
|
{
|
|
|
|
UINT64 StartTimeStamp;
|
2014-08-19 15:29:52 +02:00
|
|
|
|
2012-05-02 21:49:35 +02:00
|
|
|
// Initialize the platform specific controllers
|
|
|
|
ArmPlatformInitialize (MpId);
|
|
|
|
|
2013-05-10 14:41:27 +02:00
|
|
|
if (ArmPlatformIsPrimaryCore (MpId) && PerformanceMeasurementEnabled ()) {
|
2011-07-01 13:09:00 +02:00
|
|
|
// Initialize the Timer Library to setup the Timer HW controller
|
|
|
|
TimerConstructor ();
|
|
|
|
// We cannot call yet the PerformanceLib because the HOB List has not been initialized
|
|
|
|
StartTimeStamp = GetPerformanceCounter ();
|
2011-07-07 12:52:07 +02:00
|
|
|
} else {
|
|
|
|
StartTimeStamp = 0;
|
2011-07-01 13:09:00 +02:00
|
|
|
}
|
|
|
|
|
2013-08-06 19:41:53 +02:00
|
|
|
// Data Cache enabled on Primary core when MMU is enabled.
|
|
|
|
ArmDisableDataCache ();
|
2011-07-06 18:27:21 +02:00
|
|
|
// Invalidate instruction cache
|
|
|
|
ArmInvalidateInstructionCache ();
|
2013-08-06 19:41:53 +02:00
|
|
|
// Enable Instruction Caches on all cores.
|
2011-07-06 18:27:21 +02:00
|
|
|
ArmEnableInstructionCache ();
|
2011-07-01 13:09:00 +02:00
|
|
|
|
2011-11-02 00:41:52 +01:00
|
|
|
// Define the Global Variable region when we are not running in XIP
|
|
|
|
if (!IS_XIP()) {
|
2013-05-10 14:41:27 +02:00
|
|
|
if (ArmPlatformIsPrimaryCore (MpId)) {
|
2011-11-16 13:53:25 +01:00
|
|
|
if (ArmIsMpCore()) {
|
2012-05-02 21:55:32 +02:00
|
|
|
// Signal the Global Variable Region is defined (event: ARM_CPU_EVENT_DEFAULT)
|
|
|
|
ArmCallSEV ();
|
2011-11-16 13:53:25 +01:00
|
|
|
}
|
2011-11-02 00:41:52 +01:00
|
|
|
} else {
|
2019-02-06 16:40:38 +01:00
|
|
|
// Wait the Primary core has defined the address of the Global Variable region (event: ARM_CPU_EVENT_DEFAULT)
|
2012-05-02 21:55:32 +02:00
|
|
|
ArmCallWFE ();
|
2011-11-02 00:41:52 +01:00
|
|
|
}
|
|
|
|
}
|
2014-08-19 15:29:52 +02:00
|
|
|
|
2011-07-06 18:27:21 +02:00
|
|
|
// If not primary Jump to Secondary Main
|
2013-05-10 14:41:27 +02:00
|
|
|
if (ArmPlatformIsPrimaryCore (MpId)) {
|
ArmPlatformPkg/PrePi: replace set/way cache ops with by-VA ones
Cache maintenance operations by set/way are only intended to be used
in the context of on/offlining a core, while it has been taken out of
the coherency domain. Any use intended to ensure that the contents of
the cache have made it to main memory is unreliable, since cacheline
migration and non-architected system caches may cause these contents
to linger elsewhere, without being visible in main memory once the
MMU and caches are disabled.
In KVM on Linux, there are horrid hacks in place to ensure that such
set/way operations are trapped, and replaced with a single by-VA
clean/invalidate of the entire guest VA space once the MMU state
changes, which can be costly, and is unnecessary if we manage the
caches a bit more carefully, and perform maintenance by virtual
address only.
So let's get rid of the call to ArmInvalidateDataCache () in the
PrePeiCore startup code, and instead, invalidate the UEFI memory
region by virtual address, which is the only memory region we will
be touching with the caches and MMU both disabled and enabled.
(This will lead to data corruption if data written with the MMU off
is shadowed by clean, stale cachelines that stick around when the
MMU is enabled again.)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Acked-by: Laszlo Ersek <lersek@redhat.com>
Tested-by: Pete Batard <pete@akeo.ie>
Reviewed-by: Leif Lindholm <leif@nuviainc.com>
2020-02-25 19:28:34 +01:00
|
|
|
|
|
|
|
InvalidateDataCacheRange ((VOID *)UefiMemoryBase,
|
|
|
|
FixedPcdGet32 (PcdSystemMemoryUefiRegionSize));
|
|
|
|
|
2011-07-01 13:09:00 +02:00
|
|
|
// Goto primary Main.
|
2015-11-27 18:07:06 +01:00
|
|
|
PrimaryMain (UefiMemoryBase, StacksBase, StartTimeStamp);
|
2011-07-01 13:09:00 +02:00
|
|
|
} else {
|
2011-09-23 01:01:13 +02:00
|
|
|
SecondaryMain (MpId);
|
2011-07-01 13:09:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// DXE Core should always load and never return
|
|
|
|
ASSERT (FALSE);
|
|
|
|
}
|