2011-02-01 06:41:42 +01:00
|
|
|
/** @file
|
|
|
|
* Main file supporting the transition to PEI Core in Normal World for Versatile Express
|
|
|
|
*
|
2014-07-15 11:24:25 +02:00
|
|
|
* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
|
2011-02-01 06:41:42 +01:00
|
|
|
*
|
2019-04-04 01:03:21 +02:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause-Patent
|
2011-02-01 06:41:42 +01:00
|
|
|
*
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include <Library/BaseLib.h>
|
ArmPlatformPkg/PrePeiCore: 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 temporary RAM
region by virtual address, which is the only memory region we will
be touching with the caches and MMU both disabled and enabled,
which 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@arm.com>
Reviewed-by: Leif Lindholm <leif@nuviainc.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
2020-02-21 11:30:31 +01:00
|
|
|
#include <Library/CacheMaintenanceLib.h>
|
2011-07-06 18:07:54 +02:00
|
|
|
#include <Library/DebugAgentLib.h>
|
2011-02-01 06:41:42 +01:00
|
|
|
#include <Library/ArmLib.h>
|
2011-09-23 01:11:03 +02:00
|
|
|
|
2011-06-11 14:10:19 +02:00
|
|
|
#include "PrePeiCore.h"
|
2011-02-01 06:41:42 +01:00
|
|
|
|
2015-08-07 19:27:24 +02:00
|
|
|
CONST EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mTemporaryRamSupportPpi = { PrePeiCoreTemporaryRamSupport };
|
2011-02-01 06:41:42 +01:00
|
|
|
|
2015-08-07 19:27:24 +02:00
|
|
|
CONST EFI_PEI_PPI_DESCRIPTOR gCommonPpiTable[] = {
|
2011-02-01 06:41:42 +01:00
|
|
|
{
|
2011-09-23 01:11:03 +02:00
|
|
|
EFI_PEI_PPI_DESCRIPTOR_PPI,
|
2011-02-01 06:41:42 +01:00
|
|
|
&gEfiTemporaryRamSupportPpiGuid,
|
2015-08-07 19:27:24 +02:00
|
|
|
(VOID *) &mTemporaryRamSupportPpi
|
2011-02-01 06:41:42 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-09-23 01:12:23 +02:00
|
|
|
VOID
|
|
|
|
CreatePpiList (
|
|
|
|
OUT UINTN *PpiListSize,
|
|
|
|
OUT EFI_PEI_PPI_DESCRIPTOR **PpiList
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_PEI_PPI_DESCRIPTOR *PlatformPpiList;
|
|
|
|
UINTN PlatformPpiListSize;
|
|
|
|
UINTN ListBase;
|
|
|
|
EFI_PEI_PPI_DESCRIPTOR *LastPpi;
|
|
|
|
|
|
|
|
// Get the Platform PPIs
|
|
|
|
PlatformPpiListSize = 0;
|
|
|
|
ArmPlatformGetPlatformPpiList (&PlatformPpiListSize, &PlatformPpiList);
|
|
|
|
|
2019-02-06 16:40:38 +01:00
|
|
|
// Copy the Common and Platform PPis in Temporary Memory
|
2014-11-11 01:43:03 +01:00
|
|
|
ListBase = PcdGet64 (PcdCPUCoresStackBase);
|
2011-09-23 01:12:23 +02:00
|
|
|
CopyMem ((VOID*)ListBase, gCommonPpiTable, sizeof(gCommonPpiTable));
|
|
|
|
CopyMem ((VOID*)(ListBase + sizeof(gCommonPpiTable)), PlatformPpiList, PlatformPpiListSize);
|
|
|
|
|
|
|
|
// Set the Terminate flag on the last PPI entry
|
|
|
|
LastPpi = (EFI_PEI_PPI_DESCRIPTOR*)ListBase + ((sizeof(gCommonPpiTable) + PlatformPpiListSize) / sizeof(EFI_PEI_PPI_DESCRIPTOR)) - 1;
|
|
|
|
LastPpi->Flags |= EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
|
|
|
|
|
|
|
|
*PpiList = (EFI_PEI_PPI_DESCRIPTOR*)ListBase;
|
|
|
|
*PpiListSize = sizeof(gCommonPpiTable) + PlatformPpiListSize;
|
|
|
|
}
|
|
|
|
|
2011-02-01 06:41:42 +01:00
|
|
|
VOID
|
|
|
|
CEntryPoint (
|
2011-09-23 01:01:13 +02:00
|
|
|
IN UINTN MpId,
|
2011-02-01 06:41:42 +01:00
|
|
|
IN EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint
|
|
|
|
)
|
|
|
|
{
|
2013-08-06 19:41:53 +02:00
|
|
|
// Data Cache enabled on Primary core when MMU is enabled.
|
|
|
|
ArmDisableDataCache ();
|
|
|
|
// Invalidate instruction cache
|
2013-03-12 01:54:02 +01:00
|
|
|
ArmInvalidateInstructionCache ();
|
2013-08-06 19:41:53 +02:00
|
|
|
// Enable Instruction Caches on all cores.
|
2011-06-11 14:10:19 +02:00
|
|
|
ArmEnableInstructionCache ();
|
2011-02-01 06:41:42 +01:00
|
|
|
|
ArmPlatformPkg/PrePeiCore: 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 temporary RAM
region by virtual address, which is the only memory region we will
be touching with the caches and MMU both disabled and enabled,
which 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@arm.com>
Reviewed-by: Leif Lindholm <leif@nuviainc.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
2020-02-21 11:30:31 +01:00
|
|
|
InvalidateDataCacheRange ((VOID *)(UINTN)PcdGet64 (PcdCPUCoresStackBase),
|
|
|
|
PcdGet32 (PcdCPUCorePrimaryStackSize));
|
|
|
|
|
2011-02-01 06:41:42 +01:00
|
|
|
//
|
|
|
|
// Note: Doesn't have to Enable CPU interface in non-secure world,
|
|
|
|
// as Non-secure interface is already enabled in Secure world.
|
|
|
|
//
|
|
|
|
|
2013-03-12 01:54:02 +01:00
|
|
|
// Write VBAR - The Exception Vector table must be aligned to its requirement
|
2014-07-15 11:24:25 +02:00
|
|
|
// Note: The AArch64 Vector table must be 2k-byte aligned - if this assertion fails ensure
|
|
|
|
// 'Align=4K' is defined into your FDF for this module.
|
|
|
|
ASSERT (((UINTN)PeiVectorTable & ARM_VECTOR_TABLE_ALIGNMENT) == 0);
|
2013-03-12 01:54:02 +01:00
|
|
|
ArmWriteVBar ((UINTN)PeiVectorTable);
|
2011-02-01 06:41:42 +01:00
|
|
|
|
2020-01-06 12:38:29 +01:00
|
|
|
// Enable Floating Point
|
|
|
|
if (FixedPcdGet32 (PcdVFPEnabled)) {
|
|
|
|
ArmEnableVFP ();
|
|
|
|
}
|
|
|
|
|
2011-02-01 06:41:42 +01:00
|
|
|
//Note: The MMU will be enabled by MemoryPeim. Only the primary core will have the MMU on.
|
|
|
|
|
2011-09-23 01:12:23 +02:00
|
|
|
// If not primary Jump to Secondary Main
|
2013-05-10 14:41:27 +02:00
|
|
|
if (ArmPlatformIsPrimaryCore (MpId)) {
|
2011-07-06 18:07:54 +02:00
|
|
|
// Initialize the Debug Agent for Source Level Debugging
|
|
|
|
InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, NULL, NULL);
|
|
|
|
SaveAndSetDebugTimerInterrupt (TRUE);
|
|
|
|
|
2012-05-02 21:49:35 +02:00
|
|
|
// Initialize the platform specific controllers
|
|
|
|
ArmPlatformInitialize (MpId);
|
|
|
|
|
2011-07-06 18:07:54 +02:00
|
|
|
// Goto primary Main.
|
2011-06-11 14:10:19 +02:00
|
|
|
PrimaryMain (PeiCoreEntryPoint);
|
2011-02-01 06:41:42 +01:00
|
|
|
} else {
|
2011-09-23 01:01:13 +02:00
|
|
|
SecondaryMain (MpId);
|
2011-02-01 06:41:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// PEI Core should always load and never return
|
|
|
|
ASSERT (FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
2011-09-23 01:11:34 +02:00
|
|
|
PrePeiCoreTemporaryRamSupport (
|
2011-02-01 06:41:42 +01:00
|
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
|
|
IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
|
|
|
|
IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
|
|
|
|
IN UINTN CopySize
|
|
|
|
)
|
|
|
|
{
|
2011-09-23 01:11:34 +02:00
|
|
|
VOID *OldHeap;
|
|
|
|
VOID *NewHeap;
|
|
|
|
VOID *OldStack;
|
|
|
|
VOID *NewStack;
|
2015-12-10 17:07:03 +01:00
|
|
|
UINTN HeapSize;
|
|
|
|
|
|
|
|
HeapSize = ALIGN_VALUE (CopySize / 2, CPU_STACK_ALIGNMENT);
|
2011-09-23 01:11:34 +02:00
|
|
|
|
|
|
|
OldHeap = (VOID*)(UINTN)TemporaryMemoryBase;
|
2015-12-10 17:07:03 +01:00
|
|
|
NewHeap = (VOID*)((UINTN)PermanentMemoryBase + (CopySize - HeapSize));
|
2011-09-23 01:11:34 +02:00
|
|
|
|
2015-12-10 17:07:03 +01:00
|
|
|
OldStack = (VOID*)((UINTN)TemporaryMemoryBase + HeapSize);
|
2011-09-23 01:11:34 +02:00
|
|
|
NewStack = (VOID*)(UINTN)PermanentMemoryBase;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Migrate the temporary memory stack to permanent memory stack.
|
2011-02-01 06:41:42 +01:00
|
|
|
//
|
2015-12-10 17:07:03 +01:00
|
|
|
CopyMem (NewStack, OldStack, CopySize - HeapSize);
|
2011-09-23 01:11:34 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// Migrate the temporary memory heap to permanent memory heap.
|
2011-06-11 14:10:19 +02:00
|
|
|
//
|
2015-12-10 17:07:03 +01:00
|
|
|
CopyMem (NewHeap, OldHeap, HeapSize);
|
2014-08-19 15:29:52 +02:00
|
|
|
|
2011-09-23 01:11:34 +02:00
|
|
|
SecSwitchStack ((UINTN)NewStack - (UINTN)OldStack);
|
2011-02-01 06:41:42 +01:00
|
|
|
|
2011-09-23 01:11:34 +02:00
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|