audk/MdeModulePkg/Core/Dxe/SysCall/AARCH64/InitializeAARCH64.c

235 lines
5.6 KiB
C

/** @file
Copyright (c) 2024 - 2025, Mikhail Krichanov. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#include <Guid/EarlyPL011BaseAddress.h>
#include <Library/ArmLib.h>
#include <Library/ArmMmuLib.h>
#include <Library/DefaultExceptionHandlerLib.h>
#include "DxeMain.h"
UINTN gUserPageTable;
STATIC UINTN mConfigurationTable;
STATIC UINTN mConfigurationTableSize;
STATIC UINTN mUartBaseAddress;
EFI_STATUS
EFIAPI
ArmCallUserSpace (
IN USER_SPACE_CALL_DATA *Data,
IN UINTN UserStackTop,
IN VOID *EntryPoint,
IN UINTN UserPageTable
);
STATIC
EFI_STATUS
EFIAPI
SysCallBootService (
IN EFI_SYSTEM_CONTEXT Context
)
{
EFI_STATUS Status;
UINTN *UserArguments;
UINT64 Attributes;
ArmEnableInterrupts ();
gCpu->GetMemoryAttributes (gCpu, (EFI_PHYSICAL_ADDRESS)Context.SystemContextAArch64->SP_EL0, &Attributes);
ASSERT ((Attributes & EFI_MEMORY_USER) != 0);
UserArguments = (UINTN *)(Context.SystemContextAArch64->SP_EL0 - 7 * sizeof (UINTN));
gCpu->GetMemoryAttributes (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)UserArguments, &Attributes);
ASSERT ((Attributes & EFI_MEMORY_USER) != 0);
AllowSupervisorAccessToUserMemory ();
//
// First 6 arguments are passed through X2-X7 and copied to Core stack,
// all the others are on User stack.
//
CopyMem (
(VOID *)UserArguments,
(VOID *)&(Context.SystemContextAArch64->X1),
7 * sizeof (UINTN)
);
ForbidSupervisorAccessToUserMemory ();
Status = CallBootService (
Context.SystemContextAArch64->X0,
Context.SystemContextAArch64->X1,
UserArguments,
Context.SystemContextAArch64->SP
);
ArmDisableInterrupts ();
return Status;
}
EFI_STATUS
EFIAPI
MakeUserPageTableTemplate (
OUT UINTN *UserPageTableTemplate,
OUT UINTN *UserPageTableTemplateSize
)
{
ARM_MEMORY_REGION_DESCRIPTOR Descriptor;
VOID *MemorySizeHob;
MemorySizeHob = GetFirstGuidHob (&gArmVirtSystemMemorySizeGuid);
if (MemorySizeHob == NULL) {
return EFI_NOT_FOUND;
}
Descriptor.PhysicalBase = PcdGet64 (PcdSystemMemoryBase);
Descriptor.VirtualBase = Descriptor.PhysicalBase;
Descriptor.Length = *(UINT64 *)GET_GUID_HOB_DATA (MemorySizeHob);
Descriptor.Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK;
return ArmMakeUserPageTableTemplate (
&Descriptor,
UserPageTableTemplate,
UserPageTableTemplateSize
);
}
EFI_STATUS
EFIAPI
InitializePlatform (
IN OUT EFI_SYSTEM_TABLE *System
)
{
EFI_STATUS Status;
UINTN Tcr;
UINTN Sctlr;
EFI_PHYSICAL_ADDRESS Physical;
UINTN Index;
EFI_CONFIGURATION_TABLE *Conf;
EARLY_PL011_BASE_ADDRESS *UartBase;
CONST VOID *Hob;
mConfigurationTableSize = (System->NumberOfTableEntries + 1) * sizeof (EFI_CONFIGURATION_TABLE);
Status = CoreAllocatePages (
AllocateAnyPages,
EfiUserSpaceMemoryType,
EFI_SIZE_TO_PAGES (mConfigurationTableSize),
&Physical
);
if (EFI_ERROR (Status)) {
return Status;
}
Conf = (EFI_CONFIGURATION_TABLE *)(UINTN)Physical;
for (Index = 0; Index < System->NumberOfTableEntries; ++Index) {
CopyGuid (&Conf->VendorGuid, &System->ConfigurationTable[Index].VendorGuid);
Conf->VendorTable = System->ConfigurationTable[Index].VendorTable;
++Conf;
}
Hob = GetFirstGuidHob (&gEarlyPL011BaseAddressGuid);
UartBase = GET_GUID_HOB_DATA (Hob);
mUartBaseAddress = (UINTN)UartBase->DebugAddress;
CopyGuid (&(Conf->VendorGuid), &gEarlyPL011BaseAddressGuid);
Conf->VendorTable = (VOID *)mUartBaseAddress;
++System->NumberOfTableEntries;
System->ConfigurationTable = (EFI_CONFIGURATION_TABLE *)(UINTN)Physical;
mConfigurationTable = (UINTN)Physical;
//
// Disable Hierarchical permissions just in case.
//
Tcr = ArmGetTCR ();
Tcr |= TCR_EL1_HPD0_MASK | TCR_EL1_HPD1_MASK;
ArmSetTCR (Tcr);
if (ArmHasPan ()) {
//
// Enable Privileged Access Never feature.
//
Sctlr = ArmReadSctlr ();
Sctlr |= SCTLR_EPAN;
ArmWriteSctlr (Sctlr);
ArmSetPan ();
}
InitializeSysCallHandler ((VOID *)SysCallBootService);
SetExceptionAddresses (NULL, 0);
return EFI_SUCCESS;
}
VOID
EFIAPI
MapPlatform (
IN OUT UINTN UserPageTable
)
{
gCpu->SetUserMemoryAttributes (
gCpu,
UserPageTable,
mConfigurationTable,
ALIGN_VALUE (mConfigurationTableSize, EFI_PAGE_SIZE),
EFI_MEMORY_XP | EFI_MEMORY_USER
);
//
// Necessary fix for DEBUG printings.
//
gCpu->SetUserMemoryAttributes (
gCpu,
UserPageTable,
mUartBaseAddress,
SIZE_4KB,
EFI_MEMORY_XP | EFI_MEMORY_USER
);
}
VOID
EFIAPI
AllowSupervisorAccessToUserMemory (
VOID
)
{
if (ArmHasPan ()) {
ArmClearPan ();
}
}
VOID
EFIAPI
ForbidSupervisorAccessToUserMemory (
VOID
)
{
if (ArmHasPan ()) {
ArmSetPan ();
}
}
EFI_STATUS
EFIAPI
CallUserSpace (
IN USER_SPACE_CALL_DATA *Data,
IN UINTN UserStackTop
)
{
return ArmCallUserSpace (
Data,
UserStackTop,
gUserSpaceEntryPoint,
gUserPageTable
);
}