From: Harry Liebel Date: Thu, 18 Jul 2013 18:07:46 +0000 (+0000) Subject: ArmPkg: Added Aarch64 support X-Git-Tag: edk2-stable201903~12420 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=25402f5d0660acde3ee382a36b065945251990dc ArmPkg: Added Aarch64 support Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Harry Liebel Signed-off-by: Olivier Martin git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14486 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/ArmPkg/ArmPkg.dec b/ArmPkg/ArmPkg.dec index 145c6b08f9..1012329013 100644 --- a/ArmPkg/ArmPkg.dec +++ b/ArmPkg/ArmPkg.dec @@ -181,3 +181,12 @@ gArmTokenSpaceGuid.PcdArmLinuxFdtMaxOffset|0x4000|UINT32|0x00000023 # The FDT blob must be loaded at a 64bit aligned address. gArmTokenSpaceGuid.PcdArmLinuxFdtAlignment|0x8|UINT32|0x00000026 + +[PcdsFixedAtBuild.AARCH64] + # By default we do transition to EL2 non-secure mode with Stack for EL2. + # Mode Description Bits + # NS EL2 SP2 all interupts disabled = 0x3c9 + # NS EL1 SP1 all interupts disabled = 0x3c5 + # Other modes include using SP0 or switching to Aarch32, but these are + # not currently supported. + gArmTokenSpaceGuid.PcdArmNonSecModeTransition|0x3c9|UINT32|0x0000003E diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc index 1b8cff110f..638054d325 100644 --- a/ArmPkg/ArmPkg.dsc +++ b/ArmPkg/ArmPkg.dsc @@ -25,7 +25,7 @@ PLATFORM_VERSION = 0.1 DSC_SPECIFICATION = 0x00010005 OUTPUT_DIRECTORY = Build/Arm - SUPPORTED_ARCHITECTURES = ARM + SUPPORTED_ARCHITECTURES = ARM|AARCH64 BUILD_TARGETS = DEBUG|RELEASE SKUID_IDENTIFIER = DEFAULT @@ -61,8 +61,8 @@ DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf DefaultExceptionHandlerLib|ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf - ArmLib|ArmPkg/Library/ArmLib/ArmV7/ArmV7Lib.inf CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf + ArmGicLib|ArmPkg/Drivers/PL390Gic/PL390GicLib.inf ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf ArmDisassemblerLib|ArmPkg/Library/ArmDisassemblerLib/ArmDisassemblerLib.inf DmaLib|ArmPkg/Library/ArmDmaLib/ArmDmaLib.inf @@ -76,6 +76,12 @@ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf +[LibraryClasses.ARM] + ArmLib|ArmPkg/Library/ArmLib/ArmV7/ArmV7Lib.inf + +[LibraryClasses.AARCH64] + ArmLib|ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf + [LibraryClasses.common.PEIM] HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf @@ -89,20 +95,15 @@ [LibraryClasses.ARM] NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf +[LibraryClasses.AARCH64] + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf + [Components.common] ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.inf ArmPkg/Library/ArmDisassemblerLib/ArmDisassemblerLib.inf ArmPkg/Library/ArmDmaLib/ArmDmaLib.inf -# ArmPkg/Library/ArmLib/Arm11/Arm11ArmLib.inf -# ArmPkg/Library/ArmLib/Arm11/Arm11ArmLibPrePi.inf -# ArmPkg/Library/ArmLib/Arm9/Arm9ArmLib.inf -# ArmPkg/Library/ArmLib/Arm9/Arm9ArmLibPrePi.inf - ArmPkg/Library/ArmLib/ArmV7/ArmV7Lib.inf - ArmPkg/Library/ArmLib/ArmV7/ArmV7LibPrePi.inf - ArmPkg/Library/ArmLib/ArmV7/ArmV7LibSec.inf ArmPkg/Library/ArmLib/Null/NullArmLib.inf ArmPkg/Library/BaseMemoryLibStm/BaseMemoryLibStm.inf - ArmPkg/Library/BaseMemoryLibVstm/BaseMemoryLibVstm.inf ArmPkg/Library/BasePeCoffLib/BasePeCoffLib.inf ArmPkg/Library/BdsLib/BdsLib.inf ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf @@ -116,9 +117,6 @@ ArmPkg/Library/SemihostLib/SemihostLib.inf ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf - ArmPkg/Drivers/ArmCpuLib/ArmCortexA8Lib/ArmCortexA8Lib.inf - ArmPkg/Drivers/ArmCpuLib/ArmCortexA9Lib/ArmCortexA9Lib.inf - ArmPkg/Drivers/ArmCpuLib/ArmCortexA15Lib/ArmCortexA15Lib.inf ArmPkg/Drivers/CpuDxe/CpuDxe.inf ArmPkg/Drivers/CpuPei/CpuPei.inf ArmPkg/Drivers/PL390Gic/PL390GicDxe.inf @@ -133,3 +131,24 @@ ArmPkg/Application/LinuxLoader/LinuxAtagLoader.inf ArmPkg/Application/LinuxLoader/LinuxFdtLoader.inf + +[Components.ARM] + ArmPkg/Library/BaseMemoryLibVstm/BaseMemoryLibVstm.inf + + ArmPkg/Drivers/ArmCpuLib/ArmCortexA8Lib/ArmCortexA8Lib.inf + ArmPkg/Drivers/ArmCpuLib/ArmCortexA9Lib/ArmCortexA9Lib.inf + ArmPkg/Drivers/ArmCpuLib/ArmCortexA15Lib/ArmCortexA15Lib.inf + +# ArmPkg/Library/ArmLib/Arm11/Arm11ArmLib.inf +# ArmPkg/Library/ArmLib/Arm11/Arm11ArmLibPrePi.inf +# ArmPkg/Library/ArmLib/Arm9/Arm9ArmLib.inf +# ArmPkg/Library/ArmLib/Arm9/Arm9ArmLibPrePi.inf + ArmPkg/Library/ArmLib/ArmV7/ArmV7LibSec.inf + ArmPkg/Library/ArmLib/ArmV7/ArmV7LibPrePi.inf + +[Components.AARCH64] + ArmPkg/Drivers/ArmCpuLib/ArmCortexAEMv8Lib/ArmCortexAEMv8Lib.inf + ArmPkg/Drivers/ArmCpuLib/ArmCortexA5xLib/ArmCortexA5xLib.inf + + ArmPkg/Library/ArmLib/AArch64/AArch64LibSec.inf + ArmPkg/Library/ArmLib/AArch64/AArch64LibPrePi.inf diff --git a/ArmPkg/Drivers/ArmCpuLib/ArmCortexA15Lib/ArmCortexA15Lib.c b/ArmPkg/Drivers/ArmCpuLib/ArmCortexA15Lib/ArmCortexA15Lib.c index b15597893a..2e62a4f774 100644 --- a/ArmPkg/Drivers/ArmCpuLib/ArmCortexA15Lib/ArmCortexA15Lib.c +++ b/ArmPkg/Drivers/ArmCpuLib/ArmCortexA15Lib/ArmCortexA15Lib.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/ArmPkg/Drivers/ArmCpuLib/ArmCortexA5xLib/ArmCortexA5xLib.c b/ArmPkg/Drivers/ArmCpuLib/ArmCortexA5xLib/ArmCortexA5xLib.c new file mode 100644 index 0000000000..d13c7fd6fa --- /dev/null +++ b/ArmPkg/Drivers/ArmCpuLib/ArmCortexA5xLib/ArmCortexA5xLib.c @@ -0,0 +1,50 @@ +/** @file + + Copyright (c) 2011-2013, ARM Limited. All rights reserved. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +VOID +ArmCpuSetup ( + IN UINTN MpId + ) +{ + // Check if Architectural Timer frequency is valid number (should not be 0) + ASSERT (PcdGet32 (PcdArmArchTimerFreqInHz)); + ASSERT (ArmIsArchTimerImplemented () != 0); + + // Note: System Counter frequency can only be set in Secure privileged mode, + // if security extensions are implemented. + ArmArchTimerSetTimerFreq (PcdGet32 (PcdArmArchTimerFreqInHz)); + + if (ArmIsMpCore ()) { + // Turn on SMP coherency + ArmSetAuxCrBit (A5X_FEATURE_SMP); + } + +} + +VOID +ArmCpuSetupSmpNonSecure ( + IN UINTN MpId + ) +{ +} diff --git a/ArmPkg/Drivers/ArmCpuLib/ArmCortexA5xLib/ArmCortexA5xLib.inf b/ArmPkg/Drivers/ArmCpuLib/ArmCortexA5xLib/ArmCortexA5xLib.inf new file mode 100644 index 0000000000..486aba74a3 --- /dev/null +++ b/ArmPkg/Drivers/ArmCpuLib/ArmCortexA5xLib/ArmCortexA5xLib.inf @@ -0,0 +1,35 @@ +#/* @file +# Copyright (c) 2011-2013, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ArmCortexA5xLib + FILE_GUID = 08107938-85d8-4967-ba65-b673f708fcb2 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ArmCpuLib + +[Packages] + MdePkg/MdePkg.dec + ArmPkg/ArmPkg.dec + +[LibraryClasses] + ArmLib + IoLib + PcdLib + +[Sources.common] + ArmCortexA5xLib.c + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerFreqInHz diff --git a/ArmPkg/Drivers/ArmCpuLib/ArmCortexAEMv8Lib/ArmCortexAEMv8Lib.c b/ArmPkg/Drivers/ArmCpuLib/ArmCortexAEMv8Lib/ArmCortexAEMv8Lib.c new file mode 100644 index 0000000000..d38723f4b2 --- /dev/null +++ b/ArmPkg/Drivers/ArmCpuLib/ArmCortexAEMv8Lib/ArmCortexAEMv8Lib.c @@ -0,0 +1,42 @@ +/** @file + + Copyright (c) 2011 - 2013, ARM Limited. All rights reserved. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +VOID +ArmCpuSetup ( + IN UINTN MpId + ) +{ + // Note: System Counter frequency can only be set in Secure privileged mode, + // if security extensions are implemented. + ArmArchTimerSetTimerFreq (PcdGet32 (PcdArmArchTimerFreqInHz)); +} + + +VOID +ArmCpuSetupSmpNonSecure ( + IN UINTN MpId + ) +{ + // Nothing to do +} diff --git a/ArmPkg/Drivers/ArmCpuLib/ArmCortexAEMv8Lib/ArmCortexAEMv8Lib.inf b/ArmPkg/Drivers/ArmCpuLib/ArmCortexAEMv8Lib/ArmCortexAEMv8Lib.inf new file mode 100644 index 0000000000..0b21991a55 --- /dev/null +++ b/ArmPkg/Drivers/ArmCpuLib/ArmCortexAEMv8Lib/ArmCortexAEMv8Lib.inf @@ -0,0 +1,38 @@ +#/* @file +# Copyright (c) 2011 - 2013, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ArmCortexAEMv8Lib + FILE_GUID = 8ab5a7e3-86b1-4dd3-a092-09ee801e774b + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ArmCpuLib + +[Packages] + MdePkg/MdePkg.dec + ArmPkg/ArmPkg.dec + +[LibraryClasses] + ArmLib + IoLib + PcdLib + +[Sources.common] + ArmCortexAEMv8Lib.c + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmPrimaryCoreMask + gArmTokenSpaceGuid.PcdArmPrimaryCore + + gArmTokenSpaceGuid.PcdArmArchTimerFreqInHz diff --git a/ArmPkg/Drivers/CpuDxe/AArch64/Exception.c b/ArmPkg/Drivers/CpuDxe/AArch64/Exception.c new file mode 100644 index 0000000000..1aac6a5a91 --- /dev/null +++ b/ArmPkg/Drivers/CpuDxe/AArch64/Exception.c @@ -0,0 +1,153 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuDxe.h" + +#include + +VOID +ExceptionHandlersStart ( + VOID + ); + +VOID +ExceptionHandlersEnd ( + VOID + ); + +VOID +CommonExceptionEntry ( + VOID + ); + +VOID +AsmCommonExceptionEntry ( + VOID + ); + + +EFI_EXCEPTION_CALLBACK gExceptionHandlers[MAX_ARM_EXCEPTION + 1]; +EFI_EXCEPTION_CALLBACK gDebuggerExceptionHandlers[MAX_ARM_EXCEPTION + 1]; + + + +/** + This function registers and enables the handler specified by InterruptHandler for a processor + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. + The installed handler is called once for each processor interrupt or exception. + + @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts + are enabled and FALSE if interrupts are disabled. + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. + +**/ +EFI_STATUS +RegisterInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + if (InterruptType > MAX_ARM_EXCEPTION) { + return EFI_UNSUPPORTED; + } + + if ((InterruptHandler != NULL) && (gExceptionHandlers[InterruptType] != NULL)) { + return EFI_ALREADY_STARTED; + } + + gExceptionHandlers[InterruptType] = InterruptHandler; + + return EFI_SUCCESS; +} + + + +VOID +EFIAPI +CommonCExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + if (ExceptionType <= MAX_AARCH64_EXCEPTION) { + if (gExceptionHandlers[ExceptionType]) { + gExceptionHandlers[ExceptionType] (ExceptionType, SystemContext); + return; + } + } else { + DEBUG ((EFI_D_ERROR, "Unknown exception type %d from %016lx\n", ExceptionType, SystemContext.SystemContextAArch64->ELR)); + ASSERT (FALSE); + } + + DefaultExceptionHandler (ExceptionType, SystemContext); +} + + + +EFI_STATUS +InitializeExceptions ( + IN EFI_CPU_ARCH_PROTOCOL *Cpu + ) +{ + EFI_STATUS Status; + BOOLEAN IrqEnabled; + BOOLEAN FiqEnabled; + + Status = EFI_SUCCESS; + ZeroMem (gExceptionHandlers,sizeof(*gExceptionHandlers)); + + // + // Disable interrupts + // + Cpu->GetInterruptState (Cpu, &IrqEnabled); + Cpu->DisableInterrupt (Cpu); + + // + // EFI does not use the FIQ, but a debugger might so we must disable + // as we take over the exception vectors. + // + FiqEnabled = ArmGetFiqState (); + ArmDisableFiq (); + + // AArch64 alignment? The Vector table must be 2k-byte aligned (bottom 11 bits zero)? + //DEBUG ((EFI_D_ERROR, "vbar set addr: 0x%016lx\n",(UINTN)ExceptionHandlersStart)); + //ASSERT(((UINTN)ExceptionHandlersStart & ((1 << 11)-1)) == 0); + + // We do not copy the Exception Table at PcdGet32(PcdCpuVectorBaseAddress). We just set Vector Base Address to point into CpuDxe code. + ArmWriteVBar ((UINTN)ExceptionHandlersStart); + + if (FiqEnabled) { + ArmEnableFiq (); + } + + if (IrqEnabled) { + // + // Restore interrupt state + // + Status = Cpu->EnableInterrupt (Cpu); + } + + return Status; +} diff --git a/ArmPkg/Drivers/CpuDxe/AArch64/ExceptionSupport.S b/ArmPkg/Drivers/CpuDxe/AArch64/ExceptionSupport.S new file mode 100644 index 0000000000..981ffd5c3c --- /dev/null +++ b/ArmPkg/Drivers/CpuDxe/AArch64/ExceptionSupport.S @@ -0,0 +1,381 @@ +// +// Copyright (c) 2011 - 2013 ARM LTD. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +//------------------------------------------------------------------------------ + +#include +#include + +/* + This is the stack constructed by the exception handler (low address to high address). + X0 to FAR makes up the EFI_SYSTEM_CONTEXT for AArch64. + + UINT64 X0; 0x000 + UINT64 X1; 0x008 + UINT64 X2; 0x010 + UINT64 X3; 0x018 + UINT64 X4; 0x020 + UINT64 X5; 0x028 + UINT64 X6; 0x030 + UINT64 X7; 0x038 + UINT64 X8; 0x040 + UINT64 X9; 0x048 + UINT64 X10; 0x050 + UINT64 X11; 0x058 + UINT64 X12; 0x060 + UINT64 X13; 0x068 + UINT64 X14; 0x070 + UINT64 X15; 0x078 + UINT64 X16; 0x080 + UINT64 X17; 0x088 + UINT64 X18; 0x090 + UINT64 X19; 0x098 + UINT64 X20; 0x0a0 + UINT64 X21; 0x0a8 + UINT64 X22; 0x0b0 + UINT64 X23; 0x0b8 + UINT64 X24; 0x0c0 + UINT64 X25; 0x0c8 + UINT64 X26; 0x0d0 + UINT64 X27; 0x0d8 + UINT64 X28; 0x0e0 + UINT64 FP; 0x0e8 // x29 - Frame Pointer + UINT64 LR; 0x0f0 // x30 - Link Register + UINT64 SP; 0x0f8 // x31 - Stack Pointer + + // FP/SIMD Registers. 128bit if used as Q-regs. + UINT64 V0[2]; 0x100 + UINT64 V1[2]; 0x110 + UINT64 V2[2]; 0x120 + UINT64 V3[2]; 0x130 + UINT64 V4[2]; 0x140 + UINT64 V5[2]; 0x150 + UINT64 V6[2]; 0x160 + UINT64 V7[2]; 0x170 + UINT64 V8[2]; 0x180 + UINT64 V9[2]; 0x190 + UINT64 V10[2]; 0x1a0 + UINT64 V11[2]; 0x1b0 + UINT64 V12[2]; 0x1c0 + UINT64 V13[2]; 0x1d0 + UINT64 V14[2]; 0x1e0 + UINT64 V15[2]; 0x1f0 + UINT64 V16[2]; 0x200 + UINT64 V17[2]; 0x210 + UINT64 V18[2]; 0x220 + UINT64 V19[2]; 0x230 + UINT64 V20[2]; 0x240 + UINT64 V21[2]; 0x250 + UINT64 V22[2]; 0x260 + UINT64 V23[2]; 0x270 + UINT64 V24[2]; 0x280 + UINT64 V25[2]; 0x290 + UINT64 V26[2]; 0x2a0 + UINT64 V27[2]; 0x2b0 + UINT64 V28[2]; 0x2c0 + UINT64 V29[2]; 0x2d0 + UINT64 V30[2]; 0x2e0 + UINT64 V31[2]; 0x2f0 + + // System Context + UINT64 ELR; 0x300 // Exception Link Register + UINT64 SPSR; 0x308 // Saved Processor Status Register + UINT64 FPSR; 0x310 // Floating Point Status Register + UINT64 ESR; 0x318 // EL1 Fault Address Register + UINT64 FAR; 0x320 // EL1 Exception syndrome register + UINT64 Padding;0x328 // Required for stack alignment +*/ + +ASM_GLOBAL ASM_PFX(ExceptionHandlersStart) +ASM_GLOBAL ASM_PFX(ExceptionHandlersEnd) +ASM_GLOBAL ASM_PFX(CommonExceptionEntry) +ASM_GLOBAL ASM_PFX(AsmCommonExceptionEntry) +ASM_GLOBAL ASM_PFX(CommonCExceptionHandler) + +.text +.align 11 + +#define GP_CONTEXT_SIZE (32 * 8) +#define FP_CONTEXT_SIZE (32 * 16) +#define SYS_CONTEXT_SIZE ( 6 * 8) // 5 SYS regs + Alignment requirement (ie: the stack must be aligned on 0x10) + +// Cannot str x31 directly +#define ALL_GP_REGS \ + REG_PAIR (x0, x1, 0x000, GP_CONTEXT_SIZE); \ + REG_PAIR (x2, x3, 0x010, GP_CONTEXT_SIZE); \ + REG_PAIR (x4, x5, 0x020, GP_CONTEXT_SIZE); \ + REG_PAIR (x6, x7, 0x030, GP_CONTEXT_SIZE); \ + REG_PAIR (x8, x9, 0x040, GP_CONTEXT_SIZE); \ + REG_PAIR (x10, x11, 0x050, GP_CONTEXT_SIZE); \ + REG_PAIR (x12, x13, 0x060, GP_CONTEXT_SIZE); \ + REG_PAIR (x14, x15, 0x070, GP_CONTEXT_SIZE); \ + REG_PAIR (x16, x17, 0x080, GP_CONTEXT_SIZE); \ + REG_PAIR (x18, x19, 0x090, GP_CONTEXT_SIZE); \ + REG_PAIR (x20, x21, 0x0a0, GP_CONTEXT_SIZE); \ + REG_PAIR (x22, x23, 0x0b0, GP_CONTEXT_SIZE); \ + REG_PAIR (x24, x25, 0x0c0, GP_CONTEXT_SIZE); \ + REG_PAIR (x26, x27, 0x0d0, GP_CONTEXT_SIZE); \ + REG_PAIR (x28, x29, 0x0e0, GP_CONTEXT_SIZE); \ + REG_ONE (x30, 0x0f0, GP_CONTEXT_SIZE); + +// In order to save the SP we need to put it somwhere else first. +// STR only works with XZR/WZR directly +#define SAVE_SP \ + add x1, sp, FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE; \ + REG_ONE (x1, 0x0f8, GP_CONTEXT_SIZE); + +#define ALL_FP_REGS \ + REG_PAIR (q0, q1, 0x000, FP_CONTEXT_SIZE); \ + REG_PAIR (q2, q3, 0x020, FP_CONTEXT_SIZE); \ + REG_PAIR (q4, q5, 0x040, FP_CONTEXT_SIZE); \ + REG_PAIR (q6, q7, 0x060, FP_CONTEXT_SIZE); \ + REG_PAIR (q8, q9, 0x080, FP_CONTEXT_SIZE); \ + REG_PAIR (q10, q11, 0x0a0, FP_CONTEXT_SIZE); \ + REG_PAIR (q12, q13, 0x0c0, FP_CONTEXT_SIZE); \ + REG_PAIR (q14, q15, 0x0e0, FP_CONTEXT_SIZE); \ + REG_PAIR (q16, q17, 0x100, FP_CONTEXT_SIZE); \ + REG_PAIR (q18, q19, 0x120, FP_CONTEXT_SIZE); \ + REG_PAIR (q20, q21, 0x140, FP_CONTEXT_SIZE); \ + REG_PAIR (q22, q23, 0x160, FP_CONTEXT_SIZE); \ + REG_PAIR (q24, q25, 0x180, FP_CONTEXT_SIZE); \ + REG_PAIR (q26, q27, 0x1a0, FP_CONTEXT_SIZE); \ + REG_PAIR (q28, q29, 0x1c0, FP_CONTEXT_SIZE); \ + REG_PAIR (q30, q31, 0x1e0, FP_CONTEXT_SIZE); + +#define ALL_SYS_REGS \ + REG_PAIR (x1, x2, 0x000, SYS_CONTEXT_SIZE); \ + REG_PAIR (x3, x4, 0x010, SYS_CONTEXT_SIZE); \ + REG_ONE (x5, 0x020, SYS_CONTEXT_SIZE); + +// +// This code gets copied to the ARM vector table +// VectorTableStart - VectorTableEnd gets copied +// +ASM_PFX(ExceptionHandlersStart): + +// +// Current EL with SP0 : 0x0 - 0x180 +// +.align 7 +ASM_PFX(SynchronousExceptionSP0): + b ASM_PFX(SynchronousExceptionEntry) + +.align 7 +ASM_PFX(IrqSP0): + b ASM_PFX(IrqEntry) + +.align 7 +ASM_PFX(FiqSP0): + b ASM_PFX(FiqEntry) + +.align 7 +ASM_PFX(SErrorSP0): + b ASM_PFX(SErrorEntry) + +// +// Current EL with SPx: 0x200 - 0x380 +// +.align 7 +ASM_PFX(SynchronousExceptionSPx): + b ASM_PFX(SynchronousExceptionEntry) + +.align 7 +ASM_PFX(IrqSPx): + b ASM_PFX(IrqEntry) + +.align 7 +ASM_PFX(FiqSPx): + b ASM_PFX(FiqEntry) + +.align 7 +ASM_PFX(SErrorSPx): + b ASM_PFX(SErrorEntry) + +// +// Lower EL using AArch64 : 0x400 - 0x580 +// +.align 7 +ASM_PFX(SynchronousExceptionA64): + b ASM_PFX(SynchronousExceptionEntry) + +.align 7 +ASM_PFX(IrqA64): + b ASM_PFX(IrqEntry) + +.align 7 +ASM_PFX(FiqA64): + b ASM_PFX(FiqEntry) + +.align 7 +ASM_PFX(SErrorA64): + b ASM_PFX(SErrorEntry) + +// +// Lower EL using AArch32 : 0x0 - 0x180 +// +.align 7 +ASM_PFX(SynchronousExceptionA32): + b ASM_PFX(SynchronousExceptionEntry) + +.align 7 +ASM_PFX(IrqA32): + b ASM_PFX(IrqEntry) + +.align 7 +ASM_PFX(FiqA32): + b ASM_PFX(FiqEntry) + +.align 7 +ASM_PFX(SErrorA32): + b ASM_PFX(SErrorEntry) + + +#undef REG_PAIR +#undef REG_ONE +#define REG_PAIR(REG1, REG2, OFFSET, CONTEXT_SIZE) stp REG1, REG2, [sp, #(OFFSET-CONTEXT_SIZE)] +#define REG_ONE(REG1, OFFSET, CONTEXT_SIZE) str REG1, [sp, #(OFFSET-CONTEXT_SIZE)] + +ASM_PFX(SynchronousExceptionEntry): + // Move the stackpointer so we can reach our structure with the str instruction. + sub sp, sp, FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE + + // Save all the General regs before touching x0 and x1. + // This does not save r31(SP) as it is special. We do that later. + ALL_GP_REGS + + // Record the tipe of exception that occured. + mov x0, #EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS + + // Jump to our general handler to deal with all the common parts and process the exception. + ldr x1, ASM_PFX(CommonExceptionEntry) + br x1 + +ASM_PFX(IrqEntry): + sub sp, sp, FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE + ALL_GP_REGS + mov x0, #EXCEPT_AARCH64_IRQ + ldr x1, ASM_PFX(CommonExceptionEntry) + br x1 + +ASM_PFX(FiqEntry): + sub sp, sp, FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE + ALL_GP_REGS + mov x0, #EXCEPT_AARCH64_FIQ + ldr x1, ASM_PFX(CommonExceptionEntry) + br x1 + +ASM_PFX(SErrorEntry): + sub sp, sp, FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE + ALL_GP_REGS + mov x0, #EXCEPT_AARCH64_SERROR + ldr x1, ASM_PFX(CommonExceptionEntry) + br x1 + + +// +// This gets patched by the C code that patches in the vector table +// +.align 3 +ASM_PFX(CommonExceptionEntry): + .dword ASM_PFX(AsmCommonExceptionEntry) + +ASM_PFX(ExceptionHandlersEnd): + + + +// +// This code runs from CpuDxe driver loaded address. It is patched into +// CommonExceptionEntry. +// +ASM_PFX(AsmCommonExceptionEntry): + /* NOTE: + We have to break up the save code because the immidiate value to be used + with the SP is to big to do it all in one step so we need to shuffle the SP + along as we go. (we only have 9bits of immediate to work with) */ + + // Save the current Stack pointer before we start modifying it. + SAVE_SP + + // Preserve the stack pointer we came in with before we modify it + EL1_OR_EL2(x1) +1:mrs x1, elr_el1 // Exception Link Register + mrs x2, spsr_el1 // Saved Processor Status Register 32bit + mrs x3, fpsr // Floating point Status Register 32bit + mrs x4, esr_el1 // EL1 Exception syndrome register 32bit + mrs x5, far_el1 // EL1 Fault Address Register + b 3f + +2:mrs x1, elr_el2 // Exception Link Register + mrs x2, spsr_el2 // Saved Processor Status Register 32bit + mrs x3, fpsr // Floating point Status Register 32bit + mrs x4, esr_el2 // EL1 Exception syndrome register 32bit + mrs x5, far_el2 // EL1 Fault Address Register + + // Adjust SP to save next set +3:add sp, sp, FP_CONTEXT_SIZE + + // Push FP regs to Stack. + ALL_FP_REGS + + // Adjust SP to save next set + add sp, sp, SYS_CONTEXT_SIZE + + // Save the SYS regs + ALL_SYS_REGS + + // Point to top of struct after all regs saved + sub sp, sp, GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE + + // x0 still holds the exception type. + // Set x1 to point to the top of our struct on the Stack + mov x1, sp + +// CommonCExceptionHandler ( +// IN EFI_EXCEPTION_TYPE ExceptionType, R0 +// IN OUT EFI_SYSTEM_CONTEXT SystemContext R1 +// ) + + // Call the handler as defined above + + // For now we spin in the handler if we received an abort of some kind. + // We do not try to recover. + bl ASM_PFX(CommonCExceptionHandler) // Call exception handler + + +// Defines for popping from stack + +#undef REG_PAIR +#undef REG_ONE +#define REG_PAIR(REG1, REG2, OFFSET, CONTEXT_SIZE) ldp REG1, REG2, [sp, #(OFFSET-CONTEXT_SIZE)] + +#define REG_ONE(REG1, OFFSET, CONTEXT_SIZE) ldr REG1, [sp, #(OFFSET-CONTEXT_SIZE)] + + + // pop all regs and return from exception. + add sp, sp, GP_CONTEXT_SIZE + ALL_GP_REGS + + // Adjust SP to pop next set + add sp, sp, FP_CONTEXT_SIZE + // Pop FP regs to Stack. + ALL_FP_REGS + + // Adjust SP to be where we started from when we came into the handler. + // The handler can not change the SP. + add sp, sp, SYS_CONTEXT_SIZE + + eret + +#undef REG_PAIR +#undef REG_ONE + +dead: + b dead diff --git a/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c b/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c new file mode 100644 index 0000000000..9043afaffa --- /dev/null +++ b/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c @@ -0,0 +1,189 @@ +/*++ + +Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.
+Portions copyright (c) 2010, Apple Inc. All rights reserved.
+Portions copyright (c) 2011-2013, ARM Ltd. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +--*/ + +#include "CpuDxe.h" + +#define TT_ATTR_INDX_INVALID ((UINT32)~0) + +STATIC +UINT64 +GetFirstPageAttribute ( + IN UINT64 *FirstLevelTableAddress, + IN UINTN TableLevel + ) +{ + UINT64 FirstEntry; + + // Get the first entry of the table + FirstEntry = *FirstLevelTableAddress; + + if ((FirstEntry & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY) { + // Only valid for Levels 0, 1 and 2 + ASSERT (TableLevel < 3); + + // Get the attribute of the subsequent table + return GetFirstPageAttribute ((UINT64*)(FirstEntry & TT_ADDRESS_MASK_DESCRIPTION_TABLE), TableLevel + 1); + } else if (((FirstEntry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY) || + ((TableLevel == 3) && ((FirstEntry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY_LEVEL3))) + { + return FirstEntry & TT_ATTR_INDX_MASK; + } else { + return TT_ATTR_INDX_INVALID; + } +} + +STATIC +UINT64 +GetNextEntryAttribute ( + IN UINT64 *TableAddress, + IN UINTN EntryCount, + IN UINTN TableLevel, + IN UINT64 BaseAddress, + IN OUT UINT32 *PrevEntryAttribute, + IN OUT UINT64 *StartGcdRegion + ) +{ + UINTN Index; + UINT64 Entry; + UINT32 EntryAttribute; + UINT32 EntryType; + EFI_STATUS Status; + UINTN NumberOfDescriptors; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; + + // Get the memory space map from GCD + MemorySpaceMap = NULL; + Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap); + ASSERT_EFI_ERROR (Status); + + // We cannot get more than 3-level page table + ASSERT (TableLevel <= 3); + + // While the top level table might not contain TT_ENTRY_COUNT entries; + // the subsequent ones should be filled up + for (Index = 0; Index < EntryCount; Index++) { + Entry = TableAddress[Index]; + EntryType = Entry & TT_TYPE_MASK; + EntryAttribute = Entry & TT_ATTR_INDX_MASK; + + // If Entry is a Table Descriptor type entry then go through the sub-level table + if ((EntryType == TT_TYPE_BLOCK_ENTRY) || + ((TableLevel == 3) && (EntryType == TT_TYPE_BLOCK_ENTRY_LEVEL3))) { + if ((*PrevEntryAttribute == TT_ATTR_INDX_INVALID) || (EntryAttribute != *PrevEntryAttribute)) { + if (*PrevEntryAttribute != TT_ATTR_INDX_INVALID) { + // Update GCD with the last region + SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, + *StartGcdRegion, + (BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel)) - 1) - *StartGcdRegion, + PageAttributeToGcdAttribute (EntryAttribute)); + } + + // Start of the new region + *StartGcdRegion = BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel)); + *PrevEntryAttribute = EntryAttribute; + } else { + continue; + } + } else if (EntryType == TT_TYPE_TABLE_ENTRY) { + // Table Entry type is only valid for Level 0, 1, 2 + ASSERT (TableLevel < 3); + + // Increase the level number and scan the sub-level table + GetNextEntryAttribute ((UINT64*)(Entry & TT_ADDRESS_MASK_DESCRIPTION_TABLE), + TT_ENTRY_COUNT, TableLevel + 1, + (BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel))), + PrevEntryAttribute, StartGcdRegion); + } else { + if (*PrevEntryAttribute != TT_ATTR_INDX_INVALID) { + // Update GCD with the last region + SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, + *StartGcdRegion, + (BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel)) - 1) - *StartGcdRegion, + PageAttributeToGcdAttribute (EntryAttribute)); + + // Start of the new region + *StartGcdRegion = BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel)); + *PrevEntryAttribute = TT_ATTR_INDX_INVALID; + } + } + } + + return BaseAddress + (EntryCount * TT_ADDRESS_AT_LEVEL(TableLevel)); +} + +EFI_STATUS +SyncCacheConfig ( + IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol + ) +{ + EFI_STATUS Status; + UINT32 PageAttribute = 0; + UINT64 *FirstLevelTableAddress; + UINTN TableLevel; + UINTN TableCount; + UINTN NumberOfDescriptors; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; + UINTN Tcr; + UINTN T0SZ; + UINT64 BaseAddressGcdRegion; + UINT64 EndAddressGcdRegion; + + // This code assumes MMU is enabled and filed with section translations + ASSERT (ArmMmuEnabled ()); + + // + // Get the memory space map from GCD + // + MemorySpaceMap = NULL; + Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap); + ASSERT_EFI_ERROR (Status); + + // The GCD implementation maintains its own copy of the state of memory space attributes. GCD needs + // to know what the initial memory space attributes are. The CPU Arch. Protocol does not provide a + // GetMemoryAttributes function for GCD to get this so we must resort to calling GCD (as if we were + // a client) to update its copy of the attributes. This is bad architecture and should be replaced + // with a way for GCD to query the CPU Arch. driver of the existing memory space attributes instead. + + // Obtain page table base + FirstLevelTableAddress = (UINT64*)(ArmGetTTBR0BaseAddress ()); + + // Get Translation Control Register value + Tcr = ArmGetTCR (); + // Get Address Region Size + T0SZ = Tcr & TCR_T0SZ_MASK; + + // Get the level of the first table for the indicated Address Region Size + GetRootTranslationTableInfo (T0SZ, &TableLevel, &TableCount); + + // First Attribute of the Page Tables + PageAttribute = GetFirstPageAttribute (FirstLevelTableAddress, TableLevel); + + // We scan from the start of the memory map (ie: at the address 0x0) + BaseAddressGcdRegion = 0x0; + EndAddressGcdRegion = GetNextEntryAttribute (FirstLevelTableAddress, + TableCount, TableLevel, + BaseAddressGcdRegion, + &PageAttribute, &BaseAddressGcdRegion); + + // Update GCD with the last region + SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, + BaseAddressGcdRegion, + EndAddressGcdRegion - BaseAddressGcdRegion, + PageAttributeToGcdAttribute (PageAttribute)); + + return EFI_SUCCESS; +} diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h index 7f59ca653c..075f2a18bf 100644 --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.h +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h @@ -148,9 +148,16 @@ SetMemoryAttributes ( IN EFI_PHYSICAL_ADDRESS VirtualMask ); +VOID +GetRootTranslationTableInfo ( + IN UINTN T0SZ, + OUT UINTN *TableLevel, + OUT UINTN *TableEntryCount + ); + EFI_STATUS SetGcdMemorySpaceAttributes ( - IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap, + IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap, IN UINTN NumberOfDescriptors, IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length, diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf index 6068a0fcec..c30cec6090 100644 --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf @@ -46,6 +46,10 @@ ArmV6/ExceptionSupport.asm | RVCT ArmV6/ExceptionSupport.S | GCC +[Sources.AARCH64] + AArch64/Mmu.c + AArch64/Exception.c + AArch64/ExceptionSupport.S | GCC [Packages] ArmPkg/ArmPkg.dec diff --git a/ArmPkg/Drivers/TimerDxe/TimerDxe.c b/ArmPkg/Drivers/TimerDxe/TimerDxe.c index dabcc8313b..a43a10f48c 100644 --- a/ArmPkg/Drivers/TimerDxe/TimerDxe.c +++ b/ArmPkg/Drivers/TimerDxe/TimerDxe.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include diff --git a/ArmPkg/Filesystem/SemihostFs/SemihostFs.inf b/ArmPkg/Filesystem/SemihostFs/SemihostFs.inf index 30ce6665f0..fdf669be56 100644 --- a/ArmPkg/Filesystem/SemihostFs/SemihostFs.inf +++ b/ArmPkg/Filesystem/SemihostFs/SemihostFs.inf @@ -2,6 +2,8 @@ # Support a Semi Host file system over a debuggers JTAG # # Copyright (c) 2009, Apple Inc. All rights reserved.
+# Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved. +# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -21,7 +23,7 @@ ENTRY_POINT = SemihostFsEntryPoint -[Sources.ARM] +[Sources.ARM, Sources.AARCH64] Arm/SemihostFs.c [Packages] diff --git a/ArmPkg/Include/AsmMacroIoLibV8.h b/ArmPkg/Include/AsmMacroIoLibV8.h new file mode 100644 index 0000000000..933ef7043b --- /dev/null +++ b/ArmPkg/Include/AsmMacroIoLibV8.h @@ -0,0 +1,200 @@ +/** @file + Macros to work around lack of Apple support for LDR register, =expr + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#ifndef __MACRO_IO_LIBV8_H__ +#define __MACRO_IO_LIBV8_H__ + +#if defined (__GNUC__) + +#define MmioWrite32(Address, Data) \ + ldr x1, =Address ; \ + ldr x0, =Data ; \ + str x0, [x1] + +#define MmioOr32(Address, OrData) \ + ldr x1, =Address ; \ + ldr x2, =OrData ; \ + ldr x0, [x1] ; \ + orr x0, x0, x2 ; \ + str x0, [x1] + +#define MmioAnd32(Address, AndData) \ + ldr x1, =Address ; \ + ldr x2, =AndData ; \ + ldr x0, [x1] ; \ + and x0, x0, x2 ; \ + str x0, [x1] + +#define MmioAndThenOr32(Address, AndData, OrData) \ + ldr x1, =Address ; \ + ldr x0, [x1] ; \ + ldr x2, =AndData ; \ + and x0, x0, x2 ; \ + ldr x2, =OrData ; \ + orr x0, x0, x2 ; \ + str x0, [x1] + +#define MmioWriteFromReg32(Address, Reg) \ + ldr x1, =Address ; \ + str Reg, [x1] + +#define MmioRead32(Address) \ + ldr x1, =Address ; \ + ldr x0, [x1] + +#define MmioReadToReg32(Address, Reg) \ + ldr x1, =Address ; \ + ldr Reg, [x1] + +#define LoadConstant(Data) \ + ldr x0, =Data + +#define LoadConstantToReg(Data, Reg) \ + ldr Reg, =Data + +#define SetPrimaryStack(StackTop, GlobalSize, Tmp, Tmp1) \ + ands Tmp, GlobalSize, #15 ; \ + mov Tmp1, #16 ; \ + sub Tmp1, Tmp1, Tmp ; \ + csel Tmp, Tmp1, Tmp, ne ; \ + add GlobalSize, GlobalSize, Tmp ; \ + sub sp, StackTop, GlobalSize ; \ + ; \ + mov Tmp, sp ; \ + mov GlobalSize, #0x0 ; \ +_SetPrimaryStackInitGlobals: ; \ + cmp Tmp, StackTop ; \ + b.eq _SetPrimaryStackEnd ; \ + str GlobalSize, [Tmp], #8 ; \ + b _SetPrimaryStackInitGlobals ; \ +_SetPrimaryStackEnd: + +// Initialize the Global Variable with '0' +#define InitializePrimaryStack(GlobalSize, Tmp1, Tmp2) \ + and Tmp1, GlobalSize, #15 ; \ + mov Tmp2, #16 ; \ + sub Tmp2, Tmp2, Tmp1 ; \ + add GlobalSize, GlobalSize, Tmp2 ; \ + ; \ + mov Tmp1, sp ; \ + sub sp, sp, GlobalSize ; \ + mov GlobalSize, #0x0 ; \ +_InitializePrimaryStackLoop: ; \ + mov Tmp2, sp ; \ + cmp Tmp1, Tmp2 ; \ + bls _InitializePrimaryStackEnd ; \ + str GlobalSize, [Tmp1, #-8]! ; \ + b _InitializePrimaryStackLoop ; \ +_InitializePrimaryStackEnd: + +// CurrentEL : 0xC = EL3; 8 = EL2; 4 = EL1 +// This only selects between EL1 and EL2, else we die. +// Provide the Macro with a safe temp xreg to use. +#define EL1_OR_EL2(SAFE_XREG) \ + mrs SAFE_XREG, CurrentEL ;\ + cmp SAFE_XREG, #0x4 ;\ + b.eq 1f ;\ + cmp SAFE_XREG, #0x8 ;\ + b.eq 2f ;\ + b dead ;// We should never get here. + +// CurrentEL : 0xC = EL3; 8 = EL2; 4 = EL1 +// This only selects between EL1 and EL2 and EL3, else we die. +// Provide the Macro with a safe temp xreg to use. +#define EL1_OR_EL2_OR_EL3(SAFE_XREG) \ + mrs SAFE_XREG, CurrentEL ;\ + cmp SAFE_XREG, #0x4 ;\ + b.eq 1f ;\ + cmp SAFE_XREG, #0x8 ;\ + b.eq 2f ;\ + cmp SAFE_XREG, #0xC ;\ + b.eq 3f ;\ + b dead ;// We should never get here. + +#else + +// +// Use ARM assembly macros, form armasm +// +// Less magic in the macros if ldr reg, =expr works +// + +// returns _Data in X0 and _Address in X1 + + + +#define MmioWrite32(Address, Data) MmioWrite32Macro Address, Data + + + + +// returns Data in X0 and Address in X1, and OrData in X2 +#define MmioOr32(Address, OrData) MmioOr32Macro Address, OrData + + +// returns _Data in X0 and _Address in X1, and _OrData in X2 + + +#define MmioAnd32(Address, AndData) MmioAnd32Macro Address, AndData + +// returns result in X0, _Address in X1, and _OrData in X2 + + +#define MmioAndThenOr32(Address, AndData, OrData) MmioAndThenOr32Macro Address, AndData, OrData + + +// returns _Data in _Reg and _Address in X1 + + +#define MmioWriteFromReg32(Address, Reg) MmioWriteFromReg32Macro Address, Reg + +// returns _Data in X0 and _Address in X1 + + +#define MmioRead32(Address) MmioRead32Macro Address + +// returns _Data in Reg and _Address in X1 + + +#define MmioReadToReg32(Address, Reg) MmioReadToReg32Macro Address, Reg + + +// load X0 with _Data + + +#define LoadConstant(Data) LoadConstantMacro Data + +// load _Reg with _Data + + +#define LoadConstantToReg(Data, Reg) LoadConstantToRegMacro Data, Reg + +// conditional load testing eq flag +#define LoadConstantToRegIfEq(Data, Reg) LoadConstantToRegIfEqMacro Data, Reg + +#define SetPrimaryStack(StackTop,GlobalSize,Tmp, Tmp1) SetPrimaryStack StackTop, GlobalSize, Tmp, Tmp1 + +#define InitializePrimaryStack(GlobalSize, Tmp1, Tmp2) InitializePrimaryStack GlobalSize, Tmp1, Tmp2 + +#define EL1_OR_EL2(SAFE_XREG) EL1_OR_EL2 SAFE_XREG + +#define EL1_OR_EL2_OR_EL3(SAFE_XREG) EL1_OR_EL2_OR_EL3 SAFE_XREG + +#endif + +#endif // __MACRO_IO_LIBV8_H__ + diff --git a/ArmPkg/Include/Chipset/AArch64.h b/ArmPkg/Include/Chipset/AArch64.h new file mode 100644 index 0000000000..7f1f44ccc3 --- /dev/null +++ b/ArmPkg/Include/Chipset/AArch64.h @@ -0,0 +1,179 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __AARCH64_H__ +#define __AARCH64_H__ + +#include +#include + +// ARM Interrupt ID in Exception Table +#define ARM_ARCH_EXCEPTION_IRQ EXCEPT_AARCH64_IRQ + +// CPACR - Coprocessor Access Control Register definitions +#define CPACR_TTA_EN (1UL << 28) +#define CPACR_FPEN_EL1 (1UL << 20) +#define CPACR_FPEN_FULL (3UL << 20) +#define CPACR_CP_FULL_ACCESS 0x300000 + +// Coprocessor Trap Register (CPTR) +#define AARCH64_CPTR_TFP (1 << 10) + +// ID_AA64PFR0 - AArch64 Processor Feature Register 0 definitions +#define AARCH64_PFR0_FP (0xF << 16) + +// NSACR - Non-Secure Access Control Register definitions +#define NSACR_CP(cp) ((1 << (cp)) & 0x3FFF) +#define NSACR_NSD32DIS (1 << 14) +#define NSACR_NSASEDIS (1 << 15) +#define NSACR_PLE (1 << 16) +#define NSACR_TL (1 << 17) +#define NSACR_NS_SMP (1 << 18) +#define NSACR_RFR (1 << 19) + +// SCR - Secure Configuration Register definitions +#define SCR_NS (1 << 0) +#define SCR_IRQ (1 << 1) +#define SCR_FIQ (1 << 2) +#define SCR_EA (1 << 3) +#define SCR_FW (1 << 4) +#define SCR_AW (1 << 5) + +// MIDR - Main ID Register definitions +#define ARM_CPU_TYPE_MASK 0xFFF +#define ARM_CPU_TYPE_AEMv8 0xD0F +#define ARM_CPU_TYPE_A15 0xC0F +#define ARM_CPU_TYPE_A9 0xC09 +#define ARM_CPU_TYPE_A5 0xC05 + +// Hypervisor Configuration Register +#define ARM_HCR_FMO BIT3 +#define ARM_HCR_IMO BIT4 +#define ARM_HCR_AMO BIT5 +#define ARM_HCR_TGE BIT27 + +// AArch64 Exception Level +#define AARCH64_EL3 0xC +#define AARCH64_EL2 0x8 +#define AARCH64_EL1 0x4 + +#define ARM_VECTOR_TABLE_ALIGNMENT ((1 << 11)-1) + +VOID +EFIAPI +ArmEnableSWPInstruction ( + VOID + ); + +UINTN +EFIAPI +ArmReadCbar ( + VOID + ); + +UINTN +EFIAPI +ArmReadTpidrurw ( + VOID + ); + +VOID +EFIAPI +ArmWriteTpidrurw ( + UINTN Value + ); + +UINTN +EFIAPI +ArmIsArchTimerImplemented ( + VOID + ); + +UINTN +EFIAPI +ArmReadIdPfr0 ( + VOID + ); + +UINTN +EFIAPI +ArmReadIdPfr1 ( + VOID + ); + +UINTN +EFIAPI +ArmGetTCR ( + VOID + ); + +VOID +EFIAPI +ArmSetTCR ( + UINTN Value + ); + +UINTN +EFIAPI +ArmGetMAIR ( + VOID + ); + +VOID +EFIAPI +ArmSetMAIR ( + UINTN Value + ); + +VOID +EFIAPI +ArmDisableAlignmentCheck ( + VOID + ); + + +VOID +EFIAPI +ArmEnableAlignmentCheck ( + VOID + ); + +VOID +EFIAPI +ArmDisableAllExceptions ( + VOID + ); + +VOID +ArmWriteHcr ( + IN UINTN Hcr + ); + +UINTN +ArmReadCurrentEL ( + VOID + ); + +UINT64 +PageAttributeToGcdAttribute ( + IN UINT64 PageAttributes + ); + +UINT64 +GcdAttributeToPageAttribute ( + IN UINT64 GcdAttributes + ); + +#endif // __AARCH64_H__ diff --git a/ArmPkg/Include/Chipset/AArch64Mmu.h b/ArmPkg/Include/Chipset/AArch64Mmu.h new file mode 100644 index 0000000000..0799734a19 --- /dev/null +++ b/ArmPkg/Include/Chipset/AArch64Mmu.h @@ -0,0 +1,208 @@ +/** @file +* +* Copyright (c) 2011-2013, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#ifndef __AARCH64_MMU_H_ +#define __AARCH64_MMU_H_ + +// +// Memory Attribute Indirection register Definitions +// +#define MAIR_ATTR_DEVICE_MEMORY 0x0ULL +#define MAIR_ATTR_NORMAL_MEMORY_NON_CACHEABLE 0x44ULL +#define MAIR_ATTR_NORMAL_MEMORY_WRITE_THROUGH 0xBBULL +#define MAIR_ATTR_NORMAL_MEMORY_WRITE_BACK 0xFFULL + +#define MAIR_ATTR(n,value) ((value) << (((n) >> 2)*8)) + +// +// Long-descriptor Translation Table format +// + +// Return the smallest offset from the table level. +// The first offset starts at 12bit. There are 4 levels of 9-bit address range from level 3 to level 0 +#define TT_ADDRESS_OFFSET_AT_LEVEL(TableLevel) (12 + ((3 - (TableLevel)) * 9)) + +#define TT_BLOCK_ENTRY_SIZE_AT_LEVEL(Level) (1 << TT_ADDRESS_OFFSET_AT_LEVEL(Level)) + +// Get the associated entry in the given Translation Table +#define TT_GET_ENTRY_FOR_ADDRESS(TranslationTable, Level, Address) \ + ((UINTN)(TranslationTable) + ((((Address) >> TT_ADDRESS_OFFSET_AT_LEVEL(Level)) & (BIT9-1)) * sizeof(UINT64))) + +// Return the smallest address granularity from the table level. +// The first offset starts at 12bit. There are 4 levels of 9-bit address range from level 3 to level 0 +#define TT_ADDRESS_AT_LEVEL(TableLevel) (1 << TT_ADDRESS_OFFSET_AT_LEVEL(TableLevel)) + +// There are 512 entries per table when 4K Granularity +#define TT_ENTRY_COUNT 512 +#define TT_ALIGNMENT_BLOCK_ENTRY BIT12 +#define TT_ALIGNMENT_DESCRIPTION_TABLE BIT12 + +#define TT_ADDRESS_MASK_BLOCK_ENTRY (0xFFFFFFFULL << 12) +#define TT_ADDRESS_MASK_DESCRIPTION_TABLE (0xFFFFFFFULL << 12) + +#define TT_TYPE_MASK 0x3 +#define TT_TYPE_TABLE_ENTRY 0x3 +#define TT_TYPE_BLOCK_ENTRY 0x1 +#define TT_TYPE_BLOCK_ENTRY_LEVEL3 0x3 + +#define TT_ATTR_INDX_MASK (0x7 << 2) +#define TT_ATTR_INDX_DEVICE_MEMORY (0x0 << 2) +#define TT_ATTR_INDX_MEMORY_NON_CACHEABLE (0x1 << 2) +#define TT_ATTR_INDX_MEMORY_WRITE_THROUGH (0x2 << 2) +#define TT_ATTR_INDX_MEMORY_WRITE_BACK (0x3 << 2) + +#define TT_AP_MASK (0x3UL << 6) +#define TT_AP_NO_RW (0x0UL << 6) +#define TT_AP_RW_RW (0x1UL << 6) +#define TT_AP_NO_RO (0x2UL << 6) +#define TT_AP_RO_RO (0x3UL << 6) + +#define TT_NS BIT5 +#define TT_AF BIT10 + +#define TT_PXN_MASK BIT53 +#define TT_UXN_MASK BIT54 + +#define TT_ATTRIBUTES_MASK ((0xFFFULL << 52) | (0x3FFULL << 2)) + +#define TT_TABLE_PXN BIT59 +#define TT_TABLE_XN BIT60 +#define TT_TABLE_NS BIT63 + +#define TT_TABLE_AP_MASK (BIT62 | BIT61) +#define TT_TABLE_AP_NO_PERMISSION (0x0ULL << 61) +#define TT_TABLE_AP_EL0_NO_ACCESS (0x1ULL << 61) +#define TT_TABLE_AP_NO_WRITE_ACCESS (0x2ULL << 61) + +// +// Translation Control Register +// +#define TCR_T0SZ_MASK 0x3F + +#define TCR_PS_4GB (0 << 16) +#define TCR_PS_64GB (1 << 16) +#define TCR_PS_1TB (2 << 16) +#define TCR_PS_4TB (3 << 16) +#define TCR_PS_16TB (4 << 16) +#define TCR_PS_256TB (5 << 16) + +#define TCR_TG0_4KB (0 << 14) + +#define TCR_IPS_4GB (0UL << 32) +#define TCR_IPS_64GB (1UL << 32) +#define TCR_IPS_1TB (2UL << 32) +#define TCR_IPS_4TB (3UL << 32) +#define TCR_IPS_16TB (4UL << 32) +#define TCR_IPS_256TB (5UL << 32) + + +#define TTBR_ASID_FIELD (48) +#define TTBR_ASID_MASK (0xFF << TTBR_ASID_FIELD) +#define TTBR_BADDR_MASK (0xFFFFFFFFFFFF ) // The width of this field depends on the values in TxSZ. Addr occupies bottom 48bits + +#define TCR_EL1_T0SZ_FIELD (0) +#define TCR_EL1_EPD0_FIELD (7) +#define TCR_EL1_IRGN0_FIELD (8) +#define TCR_EL1_ORGN0_FIELD (10) +#define TCR_EL1_SH0_FIELD (12) +#define TCR_EL1_TG0_FIELD (14) +#define TCR_EL1_T1SZ_FIELD (16) +#define TCR_EL1_A1_FIELD (22) +#define TCR_EL1_EPD1_FIELD (23) +#define TCR_EL1_IRGN1_FIELD (24) +#define TCR_EL1_ORGN1_FIELD (26) +#define TCR_EL1_SH1_FIELD (28) +#define TCR_EL1_TG1_FIELD (30) +#define TCR_EL1_IPS_FIELD (32) +#define TCR_EL1_AS_FIELD (36) +#define TCR_EL1_TBI0_FIELD (37) +#define TCR_EL1_TBI1_FIELD (38) +#define TCR_EL1_T0SZ_MASK (0x1F << TCR_EL1_T0SZ_FIELD) +#define TCR_EL1_EPD0_MASK (0x1 << TCR_EL1_EPD0_FIELD) +#define TCR_EL1_IRGN0_MASK (0x3 << TCR_EL1_IRGN0_FIELD) +#define TCR_EL1_ORGN0_MASK (0x3 << TCR_EL1_ORGN0_FIELD) +#define TCR_EL1_SH0_MASK (0x3 << TCR_EL1_SH0_FIELD) +#define TCR_EL1_TG0_MASK (0x1 << TCR_EL1_TG0_FIELD) +#define TCR_EL1_T1SZ_MASK (0x1F << TCR_EL1_T1SZ_FIELD) +#define TCR_EL1_A1_MASK (0x1 << TCR_EL1_A1_FIELD) +#define TCR_EL1_EPD1_MASK (0x1 << TCR_EL1_EPD1_FIELD) +#define TCR_EL1_IRGN1_MASK (0x3 << TCR_EL1_IRGN1_FIELD) +#define TCR_EL1_ORGN1_MASK (0x3 << TCR_EL1_ORGN1_FIELD) +#define TCR_EL1_SH1_MASK (0x3 << TCR_EL1_SH1_FIELD) +#define TCR_EL1_TG1_MASK (0x1 << TCR_EL1_TG1_FIELD) +#define TCR_EL1_IPS_MASK (0x7 << TCR_EL1_IPS_FIELD) +#define TCR_EL1_AS_MASK (0x1 << TCR_EL1_AS_FIELD) +#define TCR_EL1_TBI0_MASK (0x1 << TCR_EL1_TBI0_FIELD) +#define TCR_EL1_TBI1_MASK (0x1 << TCR_EL1_TBI1_FIELD) + + +#define VTCR_EL23_T0SZ_FIELD (0) +#define VTCR_EL23_IRGN0_FIELD (8) +#define VTCR_EL23_ORGN0_FIELD (10) +#define VTCR_EL23_SH0_FIELD (12) +#define TCR_EL23_TG0_FIELD (14) +#define VTCR_EL23_PS_FIELD (16) +#define TCR_EL23_T0SZ_MASK (0x1F << VTCR_EL23_T0SZ_FIELD) +#define TCR_EL23_IRGN0_MASK (0x3 << VTCR_EL23_IRGN0_FIELD) +#define TCR_EL23_ORGN0_MASK (0x3 << VTCR_EL23_ORGN0_FIELD) +#define TCR_EL23_SH0_MASK (0x3 << VTCR_EL23_SH0_FIELD) +#define TCR_EL23_TG0_MASK (0x1 << TCR_EL23_TG0_FIELD) +#define TCR_EL23_PS_MASK (0x7 << VTCR_EL23_PS_FIELD) + + +#define VTCR_EL2_T0SZ_FIELD (0) +#define VTCR_EL2_SL0_FIELD (6) +#define VTCR_EL2_IRGN0_FIELD (8) +#define VTCR_EL2_ORGN0_FIELD (10) +#define VTCR_EL2_SH0_FIELD (12) +#define VTCR_EL2_TG0_FIELD (14) +#define VTCR_EL2_PS_FIELD (16) +#define VTCR_EL2_T0SZ_MASK (0x1F << VTCR_EL2_T0SZ_FIELD) +#define VTCR_EL2_SL0_MASK (0x1F << VTCR_EL2_SL0_FIELD) +#define VTCR_EL2_IRGN0_MASK (0x3 << VTCR_EL2_IRGN0_FIELD) +#define VTCR_EL2_ORGN0_MASK (0x3 << VTCR_EL2_ORGN0_FIELD) +#define VTCR_EL2_SH0_MASK (0x3 << VTCR_EL2_SH0_FIELD) +#define VTCR_EL2_TG0_MASK (0x1 << VTCR_EL2_TG0_FIELD) +#define VTCR_EL2_PS_MASK (0x7 << VTCR_EL2_PS_FIELD) + + +#define TCR_RGN_OUTER_NON_CACHEABLE (0x0 << 10) +#define TCR_RGN_OUTER_WRITE_BACK_ALLOC (0x1 << 10) +#define TCR_RGN_OUTER_WRITE_THROUGH (0x2 << 10) +#define TCR_RGN_OUTER_WRITE_BACK_NO_ALLOC (0x3 << 10) + +#define TCR_RGN_INNER_NON_CACHEABLE (0x0 << 8) +#define TCR_RGN_INNER_WRITE_BACK_ALLOC (0x1 << 8) +#define TCR_RGN_INNER_WRITE_THROUGH (0x2 << 8) +#define TCR_RGN_INNER_WRITE_BACK_NO_ALLOC (0x3 << 8) + +#define TCR_SH_NON_SHAREABLE (0x0 << 12) +#define TCR_SH_OUTER_SHAREABLE (0x2 << 12) +#define TCR_SH_INNER_SHAREABLE (0x3 << 12) + +#define TCR_PASZ_32BITS_4GB (0x0) +#define TCR_PASZ_36BITS_64GB (0x1) +#define TCR_PASZ_40BITS_1TB (0x2) +#define TCR_PASZ_42BITS_4TB (0x3) +#define TCR_PASZ_44BITS_16TB (0x4) +#define TCR_PASZ_48BITS_256TB (0x5) + +// The value written to the T*SZ fields are defined as 2^(64-T*SZ). So a 39Bit +// Virtual address range for 512GB of virtual space sets T*SZ to 25 +#define INPUT_ADDRESS_SIZE_TO_TxSZ(a) (64 - a) + +// Uses LPAE Page Table format + +#endif // __AARCH64_MMU_H_ + diff --git a/ArmPkg/Include/Chipset/ArmAemV8.h b/ArmPkg/Include/Chipset/ArmAemV8.h new file mode 100644 index 0000000000..a64a92124e --- /dev/null +++ b/ArmPkg/Include/Chipset/ArmAemV8.h @@ -0,0 +1,21 @@ +/** @file + + Copyright (c) 2011 - 2013, ARM Limited. All rights reserved. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __ARM_AEM_V8_H__ +#define __ARM_AEM_V8_H__ + +#include + +#endif //__ARM_AEM_V8_H__ + diff --git a/ArmPkg/Include/Chipset/ArmArchTimer.h b/ArmPkg/Include/Chipset/ArmArchTimer.h new file mode 100644 index 0000000000..fcc03ca921 --- /dev/null +++ b/ArmPkg/Include/Chipset/ArmArchTimer.h @@ -0,0 +1,139 @@ +/** @file +* +* Copyright (c) 2011-2013, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#ifndef __ARM_ARCH_TIMER_H_ +#define __ARM_ARCH_TIMER_H_ + +UINTN +EFIAPI +ArmReadCntFrq ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntFrq ( + UINTN FreqInHz + ); + +UINT64 +EFIAPI +ArmReadCntPct ( + VOID + ); + +UINTN +EFIAPI +ArmReadCntkCtl ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntkCtl ( + UINTN Val + ); + +UINTN +EFIAPI +ArmReadCntpTval ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntpTval ( + UINTN Val + ); + +UINTN +EFIAPI +ArmReadCntpCtl ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntpCtl ( + UINTN Val + ); + +UINTN +EFIAPI +ArmReadCntvTval ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntvTval ( + UINTN Val + ); + +UINTN +EFIAPI +ArmReadCntvCtl ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntvCtl ( + UINTN Val + ); + +UINT64 +EFIAPI +ArmReadCntvCt ( + VOID + ); + +UINT64 +EFIAPI +ArmReadCntpCval ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntpCval ( + UINT64 Val + ); + +UINT64 +EFIAPI +ArmReadCntvCval ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntvCval ( + UINT64 Val + ); + +UINT64 +EFIAPI +ArmReadCntvOff ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntvOff ( + UINT64 Val + ); + +#endif // __ARM_ARCH_TIMER_H_ + diff --git a/ArmPkg/Include/Chipset/ArmCortexA5x.h b/ArmPkg/Include/Chipset/ArmCortexA5x.h new file mode 100644 index 0000000000..e2217e3f3a --- /dev/null +++ b/ArmPkg/Include/Chipset/ArmCortexA5x.h @@ -0,0 +1,23 @@ +/** @file + + Copyright (c) 2012-2013, ARM Limited. All rights reserved. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __ARM_CORTEX_A5x_H__ +#define __ARM_CORTEX_A5x_H__ + +// +// Cortex A5x feature bit definitions +// +#define A5X_FEATURE_SMP (1 << 6) + +#endif diff --git a/ArmPkg/Include/Chipset/ArmV7.h b/ArmPkg/Include/Chipset/ArmV7.h index e64deb141b..479e8d05e1 100644 --- a/ArmPkg/Include/Chipset/ArmV7.h +++ b/ArmPkg/Include/Chipset/ArmV7.h @@ -17,7 +17,7 @@ #define __ARM_V7_H__ #include -#include +#include // ARM Interrupt ID in Exception Table #define ARM_ARCH_EXCEPTION_IRQ EXCEPT_ARM_IRQ diff --git a/ArmPkg/Include/Chipset/ArmV7ArchTimer.h b/ArmPkg/Include/Chipset/ArmV7ArchTimer.h deleted file mode 100644 index 734c8855ee..0000000000 --- a/ArmPkg/Include/Chipset/ArmV7ArchTimer.h +++ /dev/null @@ -1,138 +0,0 @@ -/** @file -* -* Copyright (c) 2011, ARM Limited. All rights reserved. -* -* This program and the accompanying materials -* are licensed and made available under the terms and conditions of the BSD License -* which accompanies this distribution. The full text of the license may be found at -* http://opensource.org/licenses/bsd-license.php -* -* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -* -**/ - -#ifndef __ARMV7_ARCH_TIMER_H_ -#define __ARMV7_ARCH_TIMER_H_ - -UINTN -EFIAPI -ArmReadCntFrq ( - VOID - ); - -VOID -EFIAPI -ArmWriteCntFrq ( - UINTN FreqInHz - ); - -UINT64 -EFIAPI -ArmReadCntPct ( - VOID - ); - -UINTN -EFIAPI -ArmReadCntkCtl ( - VOID - ); - -VOID -EFIAPI -ArmWriteCntkCtl ( - UINTN Val - ); - -UINTN -EFIAPI -ArmReadCntpTval ( - VOID - ); - -VOID -EFIAPI -ArmWriteCntpTval ( - UINTN Val - ); - -UINTN -EFIAPI -ArmReadCntpCtl ( - VOID - ); - -VOID -EFIAPI -ArmWriteCntpCtl ( - UINTN Val - ); - -UINTN -EFIAPI -ArmReadCntvTval ( - VOID - ); - -VOID -EFIAPI -ArmWriteCntvTval ( - UINTN Val - ); - -UINTN -EFIAPI -ArmReadCntvCtl ( - VOID - ); - -VOID -EFIAPI -ArmWriteCntvCtl ( - UINTN Val - ); - -UINT64 -EFIAPI -ArmReadCntvCt ( - VOID - ); - -UINT64 -EFIAPI -ArmReadCntpCval ( - VOID - ); - -VOID -EFIAPI -ArmWriteCntpCval ( - UINT64 Val - ); - -UINT64 -EFIAPI -ArmReadCntvCval ( - VOID - ); - -VOID -EFIAPI -ArmWriteCntvCval ( - UINT64 Val - ); - -UINT64 -EFIAPI -ArmReadCntvOff ( - VOID - ); - -VOID -EFIAPI -ArmWriteCntvOff ( - UINT64 Val - ); - -#endif diff --git a/ArmPkg/Include/Library/ArmArchTimerLib.h b/ArmPkg/Include/Library/ArmArchTimerLib.h new file mode 100644 index 0000000000..1ecada383b --- /dev/null +++ b/ArmPkg/Include/Library/ArmArchTimerLib.h @@ -0,0 +1,115 @@ +/** @file + + Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __ARM_ARCH_TIMER_LIB_H__ +#define __ARM_ARCH_TIMER_LIB_H__ + +#define ARM_ARCH_TIMER_ENABLE (1 << 0) +#define ARM_ARCH_TIMER_IMASK (1 << 1) +#define ARM_ARCH_TIMER_ISTATUS (1 << 2) + +typedef enum { + CntFrq = 0, + CntPct, + CntkCtl, + CntpTval, + CntpCtl, + CntvTval, + CntvCtl, + CntvCt, + CntpCval, + CntvCval, + CntvOff, + CnthCtl, + CnthpTval, + CnthpCtl, + CnthpCval, + RegMaximum +} ARM_ARCH_TIMER_REGS; + +VOID +EFIAPI +ArmArchTimerReadReg ( + IN ARM_ARCH_TIMER_REGS Reg, + OUT VOID *DstBuf + ); + +VOID +EFIAPI +ArmArchTimerWriteReg ( + IN ARM_ARCH_TIMER_REGS Reg, + IN VOID *SrcBuf + ); + +VOID +EFIAPI +ArmArchTimerEnableTimer ( + VOID + ); + +VOID +EFIAPI +ArmArchTimerDisableTimer ( + VOID + ); + +VOID +EFIAPI +ArmArchTimerSetTimerFreq ( + IN UINTN FreqInHz + ); + +UINTN +EFIAPI +ArmArchTimerGetTimerFreq ( + VOID + ); + +VOID +EFIAPI +ArmArchTimerSetTimerVal ( + IN UINTN Val + ); + +UINTN +EFIAPI +ArmArchTimerGetTimerVal ( + VOID + ); + +UINT64 +EFIAPI +ArmArchTimerGetSystemCount ( + VOID + ); + +UINTN +EFIAPI +ArmArchTimerGetTimerCtrlReg ( + VOID + ); + +VOID +EFIAPI +ArmArchTimerSetTimerCtrlReg ( + UINTN Val + ); + +VOID +EFIAPI +ArmArchTimerSetCompareVal ( + IN UINT64 Val + ); + +#endif // __ARM_ARCH_TIMER_LIB_H__ diff --git a/ArmPkg/Include/Library/ArmLib.h b/ArmPkg/Include/Library/ArmLib.h index 8174845c6f..1f1fd9e515 100644 --- a/ArmPkg/Include/Library/ArmLib.h +++ b/ArmPkg/Include/Library/ArmLib.h @@ -18,10 +18,16 @@ #include -#ifdef ARM_CPU_ARMv6 -#include +#ifdef MDE_CPU_ARM + #ifdef ARM_CPU_ARMv6 + #include + #else + #include + #endif +#elif defined(MDE_CPU_AARCH64) + #include #else -#include + #error "Unknown chipset." #endif typedef enum { @@ -501,6 +507,7 @@ ArmCallWFE ( VOID EFIAPI ArmCallWFI ( + VOID ); diff --git a/ArmPkg/Include/Library/ArmV7ArchTimerLib.h b/ArmPkg/Include/Library/ArmV7ArchTimerLib.h deleted file mode 100644 index 983184810f..0000000000 --- a/ArmPkg/Include/Library/ArmV7ArchTimerLib.h +++ /dev/null @@ -1,115 +0,0 @@ -/** @file - - Copyright (c) 2011, ARM Ltd. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef __ARM_V7_ARCH_TIMER_LIB_H__ -#define __ARM_V7_ARCH_TIMER_LIB_H__ - -#define ARM_ARCH_TIMER_ENABLE (1 << 0) -#define ARM_ARCH_TIMER_IMASK (1 << 1) -#define ARM_ARCH_TIMER_ISTATUS (1 << 2) - -typedef enum { - CntFrq = 0, - CntPct, - CntkCtl, - CntpTval, - CntpCtl, - CntvTval, - CntvCtl, - CntvCt, - CntpCval, - CntvCval, - CntvOff, - CnthCtl, - CnthpTval, - CnthpCtl, - CnthpCval, - RegMaximum -}ARM_ARCH_TIMER_REGS; - -VOID -EFIAPI -ArmArchTimerReadReg ( - IN ARM_ARCH_TIMER_REGS Reg, - OUT VOID *DstBuf - ); - -VOID -EFIAPI -ArmArchTimerWriteReg ( - IN ARM_ARCH_TIMER_REGS Reg, - IN VOID *SrcBuf - ); - -VOID -EFIAPI -ArmArchTimerEnableTimer ( - VOID - ); - -VOID -EFIAPI -ArmArchTimerDisableTimer ( - VOID - ); - -VOID -EFIAPI -ArmArchTimerSetTimerFreq ( - IN UINTN FreqInHz - ); - -UINTN -EFIAPI -ArmArchTimerGetTimerFreq ( - VOID - ); - -VOID -EFIAPI -ArmArchTimerSetTimerVal ( - IN UINTN Val - ); - -UINTN -EFIAPI -ArmArchTimerGetTimerVal ( - VOID - ); - -UINT64 -EFIAPI -ArmArchTimerGetSystemCount ( - VOID - ); - -UINTN -EFIAPI -ArmArchTimerGetTimerCtrlReg ( - VOID - ); - -VOID -EFIAPI -ArmArchTimerSetTimerCtrlReg ( - UINTN Val - ); - -VOID -EFIAPI -ArmArchTimerSetCompareVal ( - IN UINT64 Val - ); - -#endif // __ARM_V7_ARCH_TIMER_LIB_H__ diff --git a/ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.c b/ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.c index 8c1fe415dc..970bde34cd 100644 --- a/ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.c +++ b/ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #define TICKS_PER_MICRO_SEC (PcdGet32 (PcdArmArchTimerFreqInHz)/1000000U) @@ -43,15 +43,18 @@ TimerConstructor ( // manual lower bound of the frequency is in the range of 1-10MHz ASSERT (TICKS_PER_MICRO_SEC); +#ifdef MDE_CPU_ARM + // Only set the frequency for ARMv7. We expect the secure firmware to have already do it // If the security extensions are not implemented set Timer Frequency if ((ArmReadIdPfr1 () & 0xF0) == 0x0) { ArmArchTimerSetTimerFreq (PcdGet32 (PcdArmArchTimerFreqInHz)); } +#endif // Architectural Timer Frequency must be set in the Secure privileged(if secure extensions are supported) mode. // If the reset value (0) is returned just ASSERT. TimerFreq = ArmArchTimerGetTimerFreq (); - ASSERT (TimerFreq); + ASSERT (TimerFreq != 0); } else { DEBUG ((EFI_D_ERROR, "ARM Architectural Timer is not available in the CPU, hence this library can not be used.\n")); diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64ArchTimer.c b/ArmPkg/Library/ArmLib/AArch64/AArch64ArchTimer.c new file mode 100644 index 0000000000..fa4f7c741b --- /dev/null +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64ArchTimer.c @@ -0,0 +1,275 @@ +/** @file +* +* Copyright (c) 2011-2013, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include +#include +#include +#include +#include +#include +#include +#include "AArch64Lib.h" +#include "ArmLibPrivate.h" +#include + +VOID +EFIAPI +ArmArchTimerReadReg ( + IN ARM_ARCH_TIMER_REGS Reg, + OUT VOID *DstBuf + ) +{ + // Check if the Generic/Architecture timer is implemented + if (ArmIsArchTimerImplemented ()) { + + switch (Reg) { + + case CntFrq: + *((UINTN *)DstBuf) = ArmReadCntFrq (); + break; + + case CntPct: + *((UINT64 *)DstBuf) = ArmReadCntPct (); + break; + + case CntkCtl: + *((UINTN *)DstBuf) = ArmReadCntkCtl(); + break; + + case CntpTval: + *((UINTN *)DstBuf) = ArmReadCntpTval (); + break; + + case CntpCtl: + *((UINTN *)DstBuf) = ArmReadCntpCtl (); + break; + + case CntvTval: + *((UINTN *)DstBuf) = ArmReadCntvTval (); + break; + + case CntvCtl: + *((UINTN *)DstBuf) = ArmReadCntvCtl (); + break; + + case CntvCt: + *((UINT64 *)DstBuf) = ArmReadCntvCt (); + break; + + case CntpCval: + *((UINT64 *)DstBuf) = ArmReadCntpCval (); + break; + + case CntvCval: + *((UINT64 *)DstBuf) = ArmReadCntvCval (); + break; + + case CntvOff: + *((UINT64 *)DstBuf) = ArmReadCntvOff (); + break; + + case CnthCtl: + case CnthpTval: + case CnthpCtl: + case CnthpCval: + DEBUG ((EFI_D_ERROR, "The register is related to Hypervisor Mode. Can't perform requested operation\n ")); + break; + + default: + DEBUG ((EFI_D_ERROR, "Unknown ARM Generic Timer register %x. \n ", Reg)); + } + } else { + DEBUG ((EFI_D_ERROR, "Attempt to read ARM Generic Timer registers. But ARM Generic Timer extension is not implemented \n ")); + ASSERT (0); + } +} + +VOID +EFIAPI +ArmArchTimerWriteReg ( + IN ARM_ARCH_TIMER_REGS Reg, + IN VOID *SrcBuf + ) +{ + // Check if the Generic/Architecture timer is implemented + if (ArmIsArchTimerImplemented ()) { + + switch (Reg) { + + case CntFrq: + ArmWriteCntFrq (*((UINTN *)SrcBuf)); + break; + + case CntPct: + DEBUG ((EFI_D_ERROR, "Can't write to Read Only Register: CNTPCT \n")); + break; + + case CntkCtl: + ArmWriteCntkCtl (*((UINTN *)SrcBuf)); + break; + + case CntpTval: + ArmWriteCntpTval (*((UINTN *)SrcBuf)); + break; + + case CntpCtl: + ArmWriteCntpCtl (*((UINTN *)SrcBuf)); + break; + + case CntvTval: + ArmWriteCntvTval (*((UINTN *)SrcBuf)); + break; + + case CntvCtl: + ArmWriteCntvCtl (*((UINTN *)SrcBuf)); + break; + + case CntvCt: + DEBUG ((EFI_D_ERROR, "Can't write to Read Only Register: CNTVCT \n")); + break; + + case CntpCval: + ArmWriteCntpCval (*((UINT64 *)SrcBuf) ); + break; + + case CntvCval: + ArmWriteCntvCval (*((UINT64 *)SrcBuf) ); + break; + + case CntvOff: + ArmWriteCntvOff (*((UINT64 *)SrcBuf)); + break; + + case CnthCtl: + case CnthpTval: + case CnthpCtl: + case CnthpCval: + DEBUG ((EFI_D_ERROR, "The register is related to Hypervisor Mode. Can't perform requested operation\n ")); + break; + + default: + DEBUG ((EFI_D_ERROR, "Unknown ARM Generic Timer register %x. \n ", Reg)); + } + } else { + DEBUG ((EFI_D_ERROR, "Attempt to write to ARM Generic Timer registers. But ARM Generic Timer extension is not implemented \n ")); + ASSERT (0); + } +} + +VOID +EFIAPI +ArmArchTimerEnableTimer ( + VOID + ) +{ + UINTN TimerCtrlReg; + + ArmArchTimerReadReg (CntpCtl, (VOID *)&TimerCtrlReg); + TimerCtrlReg |= ARM_ARCH_TIMER_ENABLE; + ArmArchTimerWriteReg (CntpCtl, (VOID *)&TimerCtrlReg); +} + +VOID +EFIAPI +ArmArchTimerDisableTimer ( + VOID + ) +{ + UINTN TimerCtrlReg; + + ArmArchTimerReadReg (CntpCtl, (VOID *)&TimerCtrlReg); + TimerCtrlReg &= ~ARM_ARCH_TIMER_ENABLE; + ArmArchTimerWriteReg (CntpCtl, (VOID *)&TimerCtrlReg); +} + +VOID +EFIAPI +ArmArchTimerSetTimerFreq ( + IN UINTN FreqInHz + ) +{ + ArmArchTimerWriteReg (CntFrq, (VOID *)&FreqInHz); +} + +UINTN +EFIAPI +ArmArchTimerGetTimerFreq ( + VOID + ) +{ + UINTN ArchTimerFreq = 0; + ArmArchTimerReadReg (CntFrq, (VOID *)&ArchTimerFreq); + return ArchTimerFreq; +} + +UINTN +EFIAPI +ArmArchTimerGetTimerVal ( + VOID + ) +{ + UINTN ArchTimerVal; + ArmArchTimerReadReg (CntpTval, (VOID *)&ArchTimerVal); + return ArchTimerVal; +} + + +VOID +EFIAPI +ArmArchTimerSetTimerVal ( + IN UINTN Val + ) +{ + ArmArchTimerWriteReg (CntpTval, (VOID *)&Val); +} + +UINT64 +EFIAPI +ArmArchTimerGetSystemCount ( + VOID + ) +{ + UINT64 SystemCount; + ArmArchTimerReadReg (CntPct, (VOID *)&SystemCount); + return SystemCount; +} + +UINTN +EFIAPI +ArmArchTimerGetTimerCtrlReg ( + VOID + ) +{ + UINTN Val; + ArmArchTimerReadReg (CntpCtl, (VOID *)&Val); + return Val; +} + +VOID +EFIAPI +ArmArchTimerSetTimerCtrlReg ( + UINTN Val + ) +{ + ArmArchTimerWriteReg (CntpCtl, (VOID *)&Val); +} + +VOID +EFIAPI +ArmArchTimerSetCompareVal ( + IN UINT64 Val + ) +{ + ArmArchTimerWriteReg (CntpCval, (VOID *)&Val); +} diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64ArchTimerSupport.S b/ArmPkg/Library/ArmLib/AArch64/AArch64ArchTimerSupport.S new file mode 100644 index 0000000000..c6087aa619 --- /dev/null +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64ArchTimerSupport.S @@ -0,0 +1,140 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2011 - 2013, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#------------------------------------------------------------------------------ + +.text +.align 2 + +ASM_GLOBAL ASM_PFX(ArmReadCntFrq) +ASM_GLOBAL ASM_PFX(ArmWriteCntFrq) +ASM_GLOBAL ASM_PFX(ArmReadCntPct) +ASM_GLOBAL ASM_PFX(ArmReadCntkCtl) +ASM_GLOBAL ASM_PFX(ArmWriteCntkCtl) +ASM_GLOBAL ASM_PFX(ArmReadCntpTval) +ASM_GLOBAL ASM_PFX(ArmWriteCntpTval) +ASM_GLOBAL ASM_PFX(ArmReadCntpCtl) +ASM_GLOBAL ASM_PFX(ArmWriteCntpCtl) +ASM_GLOBAL ASM_PFX(ArmReadCntvTval) +ASM_GLOBAL ASM_PFX(ArmWriteCntvTval) +ASM_GLOBAL ASM_PFX(ArmReadCntvCtl) +ASM_GLOBAL ASM_PFX(ArmWriteCntvCtl) +ASM_GLOBAL ASM_PFX(ArmReadCntvCt) +ASM_GLOBAL ASM_PFX(ArmReadCntpCval) +ASM_GLOBAL ASM_PFX(ArmWriteCntpCval) +ASM_GLOBAL ASM_PFX(ArmReadCntvCval) +ASM_GLOBAL ASM_PFX(ArmWriteCntvCval) +ASM_GLOBAL ASM_PFX(ArmReadCntvOff) +ASM_GLOBAL ASM_PFX(ArmWriteCntvOff) + +ASM_PFX(ArmReadCntFrq): + mrs x0, cntfrq_el0 // Read CNTFRQ + ret + + +# NOTE - Can only write while at highest implemented EL level (EL3 on model). Else ReadOnly (EL2, EL1, EL0) +ASM_PFX(ArmWriteCntFrq): + msr cntfrq_el0, x0 // Write to CNTFRQ + ret + + +ASM_PFX(ArmReadCntPct): + mrs x0, cntpct_el0 // Read CNTPCT (Physical counter register) + ret + + +ASM_PFX(ArmReadCntkCtl): + mrs x0, cntkctl_el1 // Read CNTK_CTL (Timer PL1 Control Register) + ret + + +ASM_PFX(ArmWriteCntkCtl): + mrs x0, cntkctl_el1 // Write to CNTK_CTL (Timer PL1 Control Register) + ret + + +ASM_PFX(ArmReadCntpTval): + mrs x0, cntp_tval_el0 // Read CNTP_TVAL (PL1 physical timer value register) + ret + + +ASM_PFX(ArmWriteCntpTval): + msr cntp_tval_el0, x0 // Write to CNTP_TVAL (PL1 physical timer value register) + ret + + +ASM_PFX(ArmReadCntpCtl): + mrs x0, cntp_ctl_el0 // Read CNTP_CTL (PL1 Physical Timer Control Register) + ret + + +ASM_PFX(ArmWriteCntpCtl): + msr cntp_ctl_el0, x0 // Write to CNTP_CTL (PL1 Physical Timer Control Register) + ret + + +ASM_PFX(ArmReadCntvTval): + mrs x0, cntv_tval_el0 // Read CNTV_TVAL (Virtual Timer Value register) + ret + + +ASM_PFX(ArmWriteCntvTval): + msr cntv_tval_el0, x0 // Write to CNTV_TVAL (Virtual Timer Value register) + ret + + +ASM_PFX(ArmReadCntvCtl): + mrs x0, cntv_ctl_el0 // Read CNTV_CTL (Virtual Timer Control Register) + ret + + +ASM_PFX(ArmWriteCntvCtl): + msr cntv_ctl_el0, x0 // Write to CNTV_CTL (Virtual Timer Control Register) + ret + + +ASM_PFX(ArmReadCntvCt): + mrs x0, cntvct_el0 // Read CNTVCT (Virtual Count Register) + ret + + +ASM_PFX(ArmReadCntpCval): + mrs x0, cntp_cval_el0 // Read CNTP_CTVAL (Physical Timer Compare Value Register) + ret + + +ASM_PFX(ArmWriteCntpCval): + msr cntp_cval_el0, x0 // Write to CNTP_CTVAL (Physical Timer Compare Value Register) + ret + + +ASM_PFX(ArmReadCntvCval): + mrs x0, cntv_cval_el0 // Read CNTV_CTVAL (Virtual Timer Compare Value Register) + ret + + +ASM_PFX(ArmWriteCntvCval): + msr cntv_cval_el0, x0 // write to CNTV_CTVAL (Virtual Timer Compare Value Register) + ret + + +ASM_PFX(ArmReadCntvOff): + mrs x0, cntvoff_el2 // Read CNTVOFF (virtual Offset register) + ret + + +ASM_PFX(ArmWriteCntvOff): + msr cntvoff_el2, x0 // Write to CNTVOFF (Virtual Offset register) + ret + + +ASM_FUNCTION_REMOVE_IF_UNREFERENCED diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.c b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.c new file mode 100644 index 0000000000..fd7f14f9cf --- /dev/null +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.c @@ -0,0 +1,263 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include "AArch64Lib.h" +#include "ArmLibPrivate.h" + +ARM_CACHE_TYPE +EFIAPI +ArmCacheType ( + VOID + ) +{ + return ARM_CACHE_TYPE_WRITE_BACK; +} + +ARM_CACHE_ARCHITECTURE +EFIAPI +ArmCacheArchitecture ( + VOID + ) +{ + UINT32 CLIDR = ReadCLIDR (); + + return (ARM_CACHE_ARCHITECTURE)CLIDR; // BugBug Fix Me +} + +BOOLEAN +EFIAPI +ArmDataCachePresent ( + VOID + ) +{ + UINT32 CLIDR = ReadCLIDR (); + + if ((CLIDR & 0x2) == 0x2) { + // Instruction cache exists + return TRUE; + } + if ((CLIDR & 0x7) == 0x4) { + // Unified cache + return TRUE; + } + + return FALSE; +} + +UINTN +EFIAPI +ArmDataCacheSize ( + VOID + ) +{ + UINT32 NumSets; + UINT32 Associativity; + UINT32 LineSize; + UINT32 CCSIDR = ReadCCSIDR (0); + + LineSize = (1 << ((CCSIDR & 0x7) + 2)); + Associativity = ((CCSIDR >> 3) & 0x3ff) + 1; + NumSets = ((CCSIDR >> 13) & 0x7fff) + 1; + + // LineSize is in words (4 byte chunks) + return NumSets * Associativity * LineSize * 4; +} + +UINTN +EFIAPI +ArmDataCacheAssociativity ( + VOID + ) +{ + UINT32 CCSIDR = ReadCCSIDR (0); + + return ((CCSIDR >> 3) & 0x3ff) + 1; +} + +UINTN +ArmDataCacheSets ( + VOID + ) +{ + UINT32 CCSIDR = ReadCCSIDR (0); + + return ((CCSIDR >> 13) & 0x7fff) + 1; +} + +UINTN +EFIAPI +ArmDataCacheLineLength ( + VOID + ) +{ + UINT32 CCSIDR = ReadCCSIDR (0) & 7; + + // * 4 converts to bytes + return (1 << (CCSIDR + 2)) * 4; +} + +BOOLEAN +EFIAPI +ArmInstructionCachePresent ( + VOID + ) +{ + UINT32 CLIDR = ReadCLIDR (); + + if ((CLIDR & 1) == 1) { + // Instruction cache exists + return TRUE; + } + if ((CLIDR & 0x7) == 0x4) { + // Unified cache + return TRUE; + } + + return FALSE; +} + +UINTN +EFIAPI +ArmInstructionCacheSize ( + VOID + ) +{ + UINT32 NumSets; + UINT32 Associativity; + UINT32 LineSize; + UINT32 CCSIDR = ReadCCSIDR (1); + + LineSize = (1 << ((CCSIDR & 0x7) + 2)); + Associativity = ((CCSIDR >> 3) & 0x3ff) + 1; + NumSets = ((CCSIDR >> 13) & 0x7fff) + 1; + + // LineSize is in words (4 byte chunks) + return NumSets * Associativity * LineSize * 4; +} + +UINTN +EFIAPI +ArmInstructionCacheAssociativity ( + VOID + ) +{ + UINT32 CCSIDR = ReadCCSIDR (1); + + return ((CCSIDR >> 3) & 0x3ff) + 1; +} + +UINTN +EFIAPI +ArmInstructionCacheSets ( + VOID + ) +{ + UINT32 CCSIDR = ReadCCSIDR (1); + + return ((CCSIDR >> 13) & 0x7fff) + 1; +} + +UINTN +EFIAPI +ArmInstructionCacheLineLength ( + VOID + ) +{ + UINT32 CCSIDR = ReadCCSIDR (1) & 7; + + // * 4 converts to bytes + return (1 << (CCSIDR + 2)) * 4; +} + + +VOID +AArch64DataCacheOperation ( + IN AARCH64_CACHE_OPERATION DataCacheOperation + ) +{ + UINTN SavedInterruptState; + + SavedInterruptState = ArmGetInterruptState (); + ArmDisableInterrupts(); + + AArch64AllDataCachesOperation (DataCacheOperation); + + ArmDrainWriteBuffer (); + + if (SavedInterruptState) { + ArmEnableInterrupts (); + } +} + + +VOID +AArch64PoUDataCacheOperation ( + IN AARCH64_CACHE_OPERATION DataCacheOperation + ) +{ + UINTN SavedInterruptState; + + SavedInterruptState = ArmGetInterruptState (); + ArmDisableInterrupts (); + + AArch64PerformPoUDataCacheOperation (DataCacheOperation); + + ArmDrainWriteBuffer (); + + if (SavedInterruptState) { + ArmEnableInterrupts (); + } +} + +VOID +EFIAPI +ArmInvalidateDataCache ( + VOID + ) +{ + AArch64DataCacheOperation (ArmInvalidateDataCacheEntryBySetWay); +} + +VOID +EFIAPI +ArmCleanInvalidateDataCache ( + VOID + ) +{ + AArch64DataCacheOperation (ArmCleanInvalidateDataCacheEntryBySetWay); +} + +VOID +EFIAPI +ArmCleanDataCache ( + VOID + ) +{ + AArch64DataCacheOperation (ArmCleanDataCacheEntryBySetWay); +} + +VOID +EFIAPI +ArmCleanDataCacheToPoU ( + VOID + ) +{ + AArch64PoUDataCacheOperation (ArmCleanDataCacheEntryBySetWay); +} diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h new file mode 100644 index 0000000000..04e3be0426 --- /dev/null +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h @@ -0,0 +1,98 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __AARCH64_LIB_H__ +#define __AARCH64_LIB_H__ + +typedef VOID (*AARCH64_CACHE_OPERATION)(UINTN); + +VOID +EFIAPI +ArmDrainWriteBuffer ( + VOID + ); + +VOID +EFIAPI +ArmInvalidateDataCacheEntryBySetWay ( + IN UINTN SetWayFormat + ); + +VOID +EFIAPI +ArmCleanDataCacheEntryBySetWay ( + IN UINTN SetWayFormat + ); + +VOID +EFIAPI +ArmCleanDataCacheToPoUEntryBySetWay ( + IN UINTN SetWayFormat + ); + +VOID +EFIAPI +ArmCleanInvalidateDataCacheEntryBySetWay ( + IN UINTN SetWayFormat + ); + +VOID +EFIAPI +ArmEnableAsynchronousAbort ( + VOID + ); + +UINTN +EFIAPI +ArmDisableAsynchronousAbort ( + VOID + ); + +VOID +EFIAPI +ArmEnableIrq ( + VOID + ); + +UINTN +EFIAPI +ArmDisableIrq ( + VOID + ); + +VOID +EFIAPI +ArmEnableFiq ( + VOID + ); + +UINTN +EFIAPI +ArmDisableFiq ( + VOID + ); + +VOID +AArch64PerformPoUDataCacheOperation ( + IN AARCH64_CACHE_OPERATION DataCacheOperation + ); + +VOID +AArch64AllDataCachesOperation ( + IN AARCH64_CACHE_OPERATION DataCacheOperation + ); + +#endif // __AARCH64_LIB_H__ + diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf new file mode 100644 index 0000000000..dca0b22dde --- /dev/null +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf @@ -0,0 +1,44 @@ +#/** @file +# +# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+# Portions copyright (c) 2011-2013, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = AArch64Lib + FILE_GUID = ef20ddf5-b334-47b3-94cf-52ff44c29138 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = ArmLib + +[Sources.AARCH64] + AArch64Lib.c + AArch64Mmu.c + AArch64ArchTimer.c + ArmLibSupportV8.S | GCC + ../Common/AArch64/ArmLibSupport.S | GCC + AArch64Support.S | GCC + AArch64ArchTimerSupport.S | GCC + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + MemoryAllocationLib + +[Protocols] + gEfiCpuArchProtocolGuid + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmCacheOperationThreshold diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64LibPrePi.inf b/ArmPkg/Library/ArmLib/AArch64/AArch64LibPrePi.inf new file mode 100644 index 0000000000..42f7e56287 --- /dev/null +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64LibPrePi.inf @@ -0,0 +1,48 @@ +#/** @file +# +# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+# Portions copyright (c) 2011-2013, ARM Ltd. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = AArch64LibPrePi + FILE_GUID = fd72688d-dbd8-4cf2-91a3-15171dea7816 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ArmLib + +[Sources.common] + ArmLibSupportV8.S | GCC + AArch64Support.S | GCC + + ../Common/AArch64/ArmLibSupport.S | GCC + ../Common/ArmLib.c + + AArch64Lib.c + AArch64Mmu.c + + AArch64ArchTimer.c + AArch64ArchTimerSupport.S | GCC + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + PrePiLib + +[Protocols] + gEfiCpuArchProtocolGuid + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmCacheOperationThreshold diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64LibSec.inf b/ArmPkg/Library/ArmLib/AArch64/AArch64LibSec.inf new file mode 100644 index 0000000000..9bb0bd21d0 --- /dev/null +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64LibSec.inf @@ -0,0 +1,43 @@ +#/* @file +# +# Copyright (c) 2011-2013, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = AArch64Lib + FILE_GUID = eb7441e4-3ddf-48b8-a009-14f428b19e49 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ArmLib + +[Sources.common] + ArmLibSupportV8.S | GCC + AArch64Support.S | GCC + ArmLib.c + + ../Common/AArch64/ArmLibSupport.S | GCC + + AArch64Lib.c + + AArch64ArchTimer.c + AArch64ArchTimerSupport.S | GCC + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + +[Protocols] + gEfiCpuArchProtocolGuid + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmCacheOperationThreshold diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c b/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c new file mode 100644 index 0000000000..8abc73a254 --- /dev/null +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c @@ -0,0 +1,644 @@ +/** @file +* File managing the MMU for ARMv8 architecture +* +* Copyright (c) 2011-2013, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include +#include +#include +#include +#include +#include +#include +#include "AArch64Lib.h" +#include "ArmLibPrivate.h" + +// We use this index definition to define an invalid block entry +#define TT_ATTR_INDX_INVALID ((UINT32)~0) + +STATIC +UINT64 +ArmMemoryAttributeToPageAttribute ( + IN ARM_MEMORY_REGION_ATTRIBUTES Attributes + ) +{ + switch (Attributes) { + case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK: + return TT_ATTR_INDX_MEMORY_WRITE_BACK; + case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH: + return TT_ATTR_INDX_MEMORY_WRITE_THROUGH; + case ARM_MEMORY_REGION_ATTRIBUTE_DEVICE: + return TT_ATTR_INDX_DEVICE_MEMORY; + case ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED: + return TT_ATTR_INDX_MEMORY_NON_CACHEABLE; + case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK: + return TT_ATTR_INDX_MEMORY_WRITE_BACK; + case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH: + return TT_ATTR_INDX_MEMORY_WRITE_THROUGH; + case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_DEVICE: + return TT_ATTR_INDX_DEVICE_MEMORY; + case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_UNCACHED_UNBUFFERED: + return TT_ATTR_INDX_MEMORY_NON_CACHEABLE; + default: + ASSERT(0); + return TT_ATTR_INDX_DEVICE_MEMORY; + } +} + +UINT64 +PageAttributeToGcdAttribute ( + IN UINT64 PageAttributes + ) +{ + UINT64 GcdAttributes; + + switch (PageAttributes & TT_ATTR_INDX_MASK) { + case TT_ATTR_INDX_DEVICE_MEMORY: + GcdAttributes = EFI_MEMORY_UC; + break; + case TT_ATTR_INDX_MEMORY_NON_CACHEABLE: + GcdAttributes = EFI_MEMORY_WC; + break; + case TT_ATTR_INDX_MEMORY_WRITE_THROUGH: + GcdAttributes = EFI_MEMORY_WT; + break; + case TT_ATTR_INDX_MEMORY_WRITE_BACK: + GcdAttributes = EFI_MEMORY_WB; + break; + default: + DEBUG ((EFI_D_ERROR, "PageAttributeToGcdAttribute: PageAttributes:0x%lX not supported.\n", PageAttributes)); + ASSERT (0); + // The Global Coherency Domain (GCD) value is defined as a bit set. + // Returning 0 means no attribute has been set. + GcdAttributes = 0; + } + + // Determine protection attributes + if (((PageAttributes & TT_AP_MASK) == TT_AP_NO_RO) || ((PageAttributes & TT_AP_MASK) == TT_AP_RO_RO)) { + // Read only cases map to write-protect + GcdAttributes |= EFI_MEMORY_WP; + } + + // Process eXecute Never attribute + if ((PageAttributes & (TT_PXN_MASK | TT_UXN_MASK)) != 0 ) { + GcdAttributes |= EFI_MEMORY_XP; + } + + return GcdAttributes; +} + +UINT64 +GcdAttributeToPageAttribute ( + IN UINT64 GcdAttributes + ) +{ + UINT64 PageAttributes; + + switch (GcdAttributes & 0xFF) { + case EFI_MEMORY_UC: + PageAttributes = TT_ATTR_INDX_DEVICE_MEMORY; + break; + case EFI_MEMORY_WC: + PageAttributes = TT_ATTR_INDX_MEMORY_NON_CACHEABLE; + break; + case EFI_MEMORY_WT: + PageAttributes = TT_ATTR_INDX_MEMORY_WRITE_THROUGH; + break; + case EFI_MEMORY_WB: + PageAttributes = TT_ATTR_INDX_MEMORY_WRITE_BACK; + break; + default: + DEBUG ((EFI_D_ERROR, "GcdAttributeToPageAttribute: 0x%X attributes is not supported.\n", GcdAttributes)); + ASSERT (0); + // If no match has been found then we mark the memory as device memory. + // The only side effect of using device memory should be a slow down in the performance. + PageAttributes = TT_ATTR_INDX_DEVICE_MEMORY; + } + + // Determine protection attributes + if (GcdAttributes & EFI_MEMORY_WP) { + // Read only cases map to write-protect + PageAttributes |= TT_AP_RO_RO; + } + + // Process eXecute Never attribute + if (GcdAttributes & EFI_MEMORY_XP) { + PageAttributes |= (TT_PXN_MASK | TT_UXN_MASK); + } + + return PageAttributes; +} + +ARM_MEMORY_REGION_ATTRIBUTES +GcdAttributeToArmAttribute ( + IN UINT64 GcdAttributes + ) +{ + switch (GcdAttributes & 0xFF) { + case EFI_MEMORY_UC: + return ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; + case EFI_MEMORY_WC: + return ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED; + case EFI_MEMORY_WT: + return ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH; + case EFI_MEMORY_WB: + return ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; + default: + DEBUG ((EFI_D_ERROR, "GcdAttributeToArmAttribute: 0x%lX attributes is not supported.\n", GcdAttributes)); + ASSERT (0); + return ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; + } +} + +// Describe the T0SZ values for each translation table level +typedef struct { + UINTN MinT0SZ; + UINTN MaxT0SZ; + UINTN LargestT0SZ; // Generally (MaxT0SZ == LargestT0SZ) but at the Level3 Table + // the MaxT0SZ is not at the boundary of the table +} T0SZ_DESCRIPTION_PER_LEVEL; + +// Map table for the corresponding Level of Table +STATIC CONST T0SZ_DESCRIPTION_PER_LEVEL T0SZPerTableLevel[] = { + { 16, 24, 24 }, // Table Level 0 + { 25, 33, 33 }, // Table Level 1 + { 34, 39, 42 } // Table Level 2 +}; + +VOID +GetRootTranslationTableInfo ( + IN UINTN T0SZ, + OUT UINTN *TableLevel, + OUT UINTN *TableEntryCount + ) +{ + UINTN Index; + + // Identify the level of the root table from the given T0SZ + for (Index = 0; Index < sizeof (T0SZPerTableLevel) / sizeof (T0SZ_DESCRIPTION_PER_LEVEL); Index++) { + if (T0SZ <= T0SZPerTableLevel[Index].MaxT0SZ) { + break; + } + } + + // If we have not found the corresponding maximum T0SZ then we use the last one + if (Index == sizeof (T0SZPerTableLevel) / sizeof (T0SZ_DESCRIPTION_PER_LEVEL)) { + Index--; + } + + // Get the level of the root table + if (TableLevel) { + *TableLevel = Index; + } + + // The Size of the Table is 2^(T0SZ-LargestT0SZ) + if (TableEntryCount) { + *TableEntryCount = 1 << (T0SZPerTableLevel[Index].LargestT0SZ - T0SZ + 1); + } +} + +STATIC +VOID +LookupAddresstoRootTable ( + IN UINT64 MaxAddress, + OUT UINTN *T0SZ, + OUT UINTN *TableEntryCount + ) +{ + UINTN TopBit; + + // Check the parameters are not NULL + ASSERT ((T0SZ != NULL) && (TableEntryCount != NULL)); + + // Look for the highest bit set in MaxAddress + for (TopBit = 63; TopBit != 0; TopBit--) { + if ((1ULL << TopBit) & MaxAddress) { + // MaxAddress top bit is found + TopBit = TopBit + 1; + break; + } + } + ASSERT (TopBit != 0); + + // Calculate T0SZ from the top bit of the MaxAddress + *T0SZ = 64 - TopBit; + + // Get the Table info from T0SZ + GetRootTranslationTableInfo (*T0SZ, NULL, TableEntryCount); +} + +STATIC +UINT64* +GetBlockEntryListFromAddress ( + IN UINT64 *RootTable, + IN UINT64 RegionStart, + OUT UINTN *TableLevel, + IN OUT UINT64 *BlockEntrySize, + IN OUT UINT64 **LastBlockEntry + ) +{ + UINTN RootTableLevel; + UINTN RootTableEntryCount; + UINT64 *TranslationTable; + UINT64 *BlockEntry; + UINT64 BlockEntryAddress; + UINTN BaseAddressAlignment; + UINTN PageLevel; + UINTN Index; + UINTN IndexLevel; + UINTN T0SZ; + UINT64 Attributes; + UINT64 TableAttributes; + + // Initialize variable + BlockEntry = NULL; + + // Ensure the parameters are valid + ASSERT (TableLevel && BlockEntrySize && LastBlockEntry); + + // Ensure the Region is aligned on 4KB boundary + ASSERT ((RegionStart & (SIZE_4KB - 1)) == 0); + + // Ensure the required size is aligned on 4KB boundary + ASSERT ((*BlockEntrySize & (SIZE_4KB - 1)) == 0); + + // + // Calculate LastBlockEntry from T0SZ + // + T0SZ = ArmGetTCR () & TCR_T0SZ_MASK; + // Get the Table info from T0SZ + GetRootTranslationTableInfo (T0SZ, &RootTableLevel, &RootTableEntryCount); + // The last block of the root table depends on the number of entry in this table + *LastBlockEntry = (UINT64*)((UINTN)RootTable + (RootTableEntryCount * sizeof(UINT64))); + + // If the start address is 0x0 then we use the size of the region to identify the alignment + if (RegionStart == 0) { + // Identify the highest possible alignment for the Region Size + for (BaseAddressAlignment = 0; BaseAddressAlignment < 64; BaseAddressAlignment++) { + if ((1 << BaseAddressAlignment) & *BlockEntrySize) { + break; + } + } + } else { + // Identify the highest possible alignment for the Base Address + for (BaseAddressAlignment = 0; BaseAddressAlignment < 64; BaseAddressAlignment++) { + if ((1 << BaseAddressAlignment) & RegionStart) { + break; + } + } + } + + // Identify the Page Level the RegionStart must belongs to + PageLevel = 3 - ((BaseAddressAlignment - 12) / 9); + + // If the required size is smaller than the current block size then we need to go to the page bellow. + if (*BlockEntrySize < TT_ADDRESS_AT_LEVEL(PageLevel)) { + // It does not fit so we need to go a page level above + PageLevel++; + } + + // Expose the found PageLevel to the caller + *TableLevel = PageLevel; + + // Now, we have the Table Level we can get the Block Size associated to this table + *BlockEntrySize = TT_ADDRESS_AT_LEVEL(PageLevel); + + // + // Get the Table Descriptor for the corresponding PageLevel. We need to decompose RegionStart to get appropriate entries + // + + TranslationTable = RootTable; + for (IndexLevel = RootTableLevel; IndexLevel <= PageLevel; IndexLevel++) { + BlockEntry = (UINT64*)TT_GET_ENTRY_FOR_ADDRESS (TranslationTable, IndexLevel, RegionStart); + + if ((IndexLevel != 3) && ((*BlockEntry & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY)) { + // Go to the next table + TranslationTable = (UINT64*)(*BlockEntry & TT_ADDRESS_MASK_DESCRIPTION_TABLE); + + // If we are at the last level then update the output + if (IndexLevel == PageLevel) { + // And get the appropriate BlockEntry at the next level + BlockEntry = (UINT64*)TT_GET_ENTRY_FOR_ADDRESS (TranslationTable, IndexLevel + 1, RegionStart); + + // Set the last block for this new table + *LastBlockEntry = (UINT64*)((UINTN)TranslationTable + (TT_ENTRY_COUNT * sizeof(UINT64))); + } + } else if ((*BlockEntry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY) { + // If we are not at the last level then we need to split this BlockEntry + if (IndexLevel != PageLevel) { + // Retrieve the attributes from the block entry + Attributes = *BlockEntry & TT_ATTRIBUTES_MASK; + + // Convert the block entry attributes into Table descriptor attributes + TableAttributes = TT_TABLE_AP_NO_PERMISSION; + if (Attributes & TT_PXN_MASK) { + TableAttributes = TT_TABLE_PXN; + } + if (Attributes & TT_UXN_MASK) { + TableAttributes = TT_TABLE_XN; + } + if (Attributes & TT_NS) { + TableAttributes = TT_TABLE_NS; + } + + // Get the address corresponding at this entry + BlockEntryAddress = RegionStart; + BlockEntryAddress = BlockEntryAddress >> TT_ADDRESS_OFFSET_AT_LEVEL(IndexLevel); + // Shift back to right to set zero before the effective address + BlockEntryAddress = BlockEntryAddress << TT_ADDRESS_OFFSET_AT_LEVEL(IndexLevel); + + // Set the correct entry type + if (IndexLevel + 1 == 3) { + Attributes |= TT_TYPE_BLOCK_ENTRY_LEVEL3; + } else { + Attributes |= TT_TYPE_BLOCK_ENTRY; + } + + // Create a new translation table + TranslationTable = (UINT64*)AllocatePages (EFI_SIZE_TO_PAGES((TT_ENTRY_COUNT * sizeof(UINT64)) + TT_ALIGNMENT_DESCRIPTION_TABLE)); + if (TranslationTable == NULL) { + return NULL; + } + TranslationTable = (UINT64*)((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE); + + // Fill the new BlockEntry with the TranslationTable + *BlockEntry = ((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE) | TableAttributes | TT_TYPE_TABLE_ENTRY; + + // Populate the newly created lower level table + BlockEntry = TranslationTable; + for (Index = 0; Index < TT_ENTRY_COUNT; Index++) { + *BlockEntry = Attributes | (BlockEntryAddress + (Index << TT_ADDRESS_OFFSET_AT_LEVEL(IndexLevel + 1))); + BlockEntry++; + } + // Block Entry points at the beginning of the Translation Table + BlockEntry = TranslationTable; + } + } else { + // Case of Invalid Entry and we are at a page level above of the one targetted. + if (IndexLevel != PageLevel) { + // Create a new translation table + TranslationTable = (UINT64*)AllocatePages (EFI_SIZE_TO_PAGES((TT_ENTRY_COUNT * sizeof(UINT64)) + TT_ALIGNMENT_DESCRIPTION_TABLE)); + if (TranslationTable == NULL) { + return NULL; + } + TranslationTable = (UINT64*)((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE); + + ZeroMem (TranslationTable, TT_ENTRY_COUNT * sizeof(UINT64)); + + // Fill the new BlockEntry with the TranslationTable + *BlockEntry = ((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE) | TT_TYPE_TABLE_ENTRY; + } + } + } + + return BlockEntry; +} + +STATIC +RETURN_STATUS +FillTranslationTable ( + IN UINT64 *RootTable, + IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryRegion + ) +{ + UINT64 Attributes; + UINT32 Type; + UINT64 RegionStart; + UINT64 RemainingRegionLength; + UINT64 *BlockEntry; + UINT64 *LastBlockEntry; + UINT64 BlockEntrySize; + UINTN TableLevel; + + // Ensure the Length is aligned on 4KB boundary + ASSERT ((MemoryRegion->Length > 0) && ((MemoryRegion->Length & (SIZE_4KB - 1)) == 0)); + + // Variable initialization + Attributes = ArmMemoryAttributeToPageAttribute (MemoryRegion->Attributes) | TT_AF; + RemainingRegionLength = MemoryRegion->Length; + RegionStart = MemoryRegion->VirtualBase; + + do { + // Get the first Block Entry that matches the Virtual Address and also the information on the Table Descriptor + // such as the the size of the Block Entry and the address of the last BlockEntry of the Table Descriptor + BlockEntrySize = RemainingRegionLength; + BlockEntry = GetBlockEntryListFromAddress (RootTable, RegionStart, &TableLevel, &BlockEntrySize, &LastBlockEntry); + if (BlockEntry == NULL) { + // GetBlockEntryListFromAddress() return NULL when it fails to allocate new pages from the Translation Tables + return RETURN_OUT_OF_RESOURCES; + } + + if (TableLevel != 3) { + Type = TT_TYPE_BLOCK_ENTRY; + } else { + Type = TT_TYPE_BLOCK_ENTRY_LEVEL3; + } + + do { + // Fill the Block Entry with attribute and output block address + *BlockEntry = (RegionStart & TT_ADDRESS_MASK_BLOCK_ENTRY) | Attributes | Type; + + // Go to the next BlockEntry + RegionStart += BlockEntrySize; + RemainingRegionLength -= BlockEntrySize; + BlockEntry++; + } while ((RemainingRegionLength >= BlockEntrySize) && (BlockEntry <= LastBlockEntry)); + } while (RemainingRegionLength != 0); + + return RETURN_SUCCESS; +} + +RETURN_STATUS +SetMemoryAttributes ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes, + IN EFI_PHYSICAL_ADDRESS VirtualMask + ) +{ + RETURN_STATUS Status; + ARM_MEMORY_REGION_DESCRIPTOR MemoryRegion; + UINT64 *TranslationTable; + + MemoryRegion.PhysicalBase = BaseAddress; + MemoryRegion.VirtualBase = BaseAddress; + MemoryRegion.Length = Length; + MemoryRegion.Attributes = GcdAttributeToArmAttribute (Attributes); + + TranslationTable = ArmGetTTBR0BaseAddress (); + + Status = FillTranslationTable (TranslationTable, &MemoryRegion); + if (RETURN_ERROR (Status)) { + return Status; + } + + // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks + // flush and invalidate pages + ArmCleanInvalidateDataCache (); + + ArmInvalidateInstructionCache (); + + // Invalidate all TLB entries so changes are synced + ArmInvalidateTlb (); + + return RETURN_SUCCESS; +} + +RETURN_STATUS +EFIAPI +ArmConfigureMmu ( + IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryTable, + OUT VOID **TranslationTableBase OPTIONAL, + OUT UINTN *TranslationTableSize OPTIONAL + ) +{ + VOID* TranslationTable; + UINTN TranslationTablePageCount; + UINT32 TranslationTableAttribute; + ARM_MEMORY_REGION_DESCRIPTOR *MemoryTableEntry; + UINT64 MaxAddress; + UINT64 TopAddress; + UINTN T0SZ; + UINTN RootTableEntryCount; + UINT64 TCR; + RETURN_STATUS Status; + + ASSERT (MemoryTable != NULL); + + // Identify the highest address of the memory table + MaxAddress = MemoryTable->PhysicalBase + MemoryTable->Length - 1; + MemoryTableEntry = MemoryTable; + while (MemoryTableEntry->Length != 0) { + TopAddress = MemoryTableEntry->PhysicalBase + MemoryTableEntry->Length - 1; + if (TopAddress > MaxAddress) { + MaxAddress = TopAddress; + } + MemoryTableEntry++; + } + + // Lookup the Table Level to get the information + LookupAddresstoRootTable (MaxAddress, &T0SZ, &RootTableEntryCount); + + // + // Set TCR that allows us to retrieve T0SZ in the subsequent functions + // + if ((ArmReadCurrentEL () == AARCH64_EL2) || (ArmReadCurrentEL () == AARCH64_EL3)) { + //Note: Bits 23 and 31 are reserved bits in TCR_EL2 and TCR_EL3 + TCR = T0SZ | (1UL << 31) | (1UL << 23) | TCR_TG0_4KB; + + // Set the Physical Address Size using MaxAddress + if (MaxAddress < SIZE_4GB) { + TCR |= TCR_PS_4GB; + } else if (MaxAddress < SIZE_64GB) { + TCR |= TCR_PS_64GB; + } else if (MaxAddress < SIZE_1TB) { + TCR |= TCR_PS_1TB; + } else if (MaxAddress < SIZE_4TB) { + TCR |= TCR_PS_4TB; + } else if (MaxAddress < SIZE_16TB) { + TCR |= TCR_PS_16TB; + } else if (MaxAddress < SIZE_256TB) { + TCR |= TCR_PS_256TB; + } else { + DEBUG ((EFI_D_ERROR, "ArmConfigureMmu: The MaxAddress 0x%lX is not supported by this MMU support.\n", MaxAddress)); + ASSERT (0); // Bigger than 48-bit memory space are not supported + return RETURN_UNSUPPORTED; + } + } else { + ASSERT (0); // Bigger than 48-bit memory space are not supported + return RETURN_UNSUPPORTED; + } + + // Set TCR + ArmSetTCR (TCR); + + // Allocate pages for translation table + TranslationTablePageCount = EFI_SIZE_TO_PAGES((RootTableEntryCount * sizeof(UINT64)) + TT_ALIGNMENT_DESCRIPTION_TABLE); + TranslationTable = AllocatePages (TranslationTablePageCount); + if (TranslationTable == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + TranslationTable = (VOID*)((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE); + // We set TTBR0 just after allocating the table to retrieve its location from the subsequent + // functions without needing to pass this value across the functions. The MMU is only enabled + // after the translation tables are populated. + ArmSetTTBR0 (TranslationTable); + + if (TranslationTableBase != NULL) { + *TranslationTableBase = TranslationTable; + } + + if (TranslationTableSize != NULL) { + *TranslationTableSize = RootTableEntryCount * sizeof(UINT64); + } + + ZeroMem (TranslationTable, RootTableEntryCount * sizeof(UINT64)); + + // Disable MMU and caches. ArmDisableMmu() also invalidates the TLBs + ArmDisableMmu (); + ArmDisableDataCache (); + ArmDisableInstructionCache (); + + // Make sure nothing sneaked into the cache + ArmCleanInvalidateDataCache (); + ArmInvalidateInstructionCache (); + + TranslationTableAttribute = TT_ATTR_INDX_INVALID; + while (MemoryTable->Length != 0) { + // Find the memory attribute for the Translation Table + if (((UINTN)TranslationTable >= MemoryTable->PhysicalBase) && + ((UINTN)TranslationTable <= MemoryTable->PhysicalBase - 1 + MemoryTable->Length)) { + TranslationTableAttribute = MemoryTable->Attributes; + } + + Status = FillTranslationTable (TranslationTable, MemoryTable); + if (RETURN_ERROR (Status)) { + goto FREE_TRANSLATION_TABLE; + } + MemoryTable++; + } + + // Translate the Memory Attributes into Translation Table Register Attributes + if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED) || + (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_UNCACHED_UNBUFFERED)) { + TCR |= TCR_SH_NON_SHAREABLE | TCR_RGN_OUTER_NON_CACHEABLE | TCR_RGN_INNER_NON_CACHEABLE; + } else if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK) || + (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK)) { + TCR |= TCR_SH_INNER_SHAREABLE | TCR_RGN_OUTER_WRITE_BACK_ALLOC | TCR_RGN_INNER_WRITE_BACK_ALLOC; + } else if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH) || + (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH)) { + TCR |= TCR_SH_NON_SHAREABLE | TCR_RGN_OUTER_WRITE_THROUGH | TCR_RGN_INNER_WRITE_THROUGH; + } else { + // If we failed to find a mapping that contains the root translation table then it probably means the translation table + // is not mapped in the given memory map. + ASSERT (0); + Status = RETURN_UNSUPPORTED; + goto FREE_TRANSLATION_TABLE; + } + + ArmSetMAIR (MAIR_ATTR(TT_ATTR_INDX_DEVICE_MEMORY, MAIR_ATTR_DEVICE_MEMORY) | // mapped to EFI_MEMORY_UC + MAIR_ATTR(TT_ATTR_INDX_MEMORY_NON_CACHEABLE, MAIR_ATTR_NORMAL_MEMORY_NON_CACHEABLE) | // mapped to EFI_MEMORY_WC + MAIR_ATTR(TT_ATTR_INDX_MEMORY_WRITE_THROUGH, MAIR_ATTR_NORMAL_MEMORY_WRITE_THROUGH) | // mapped to EFI_MEMORY_WT + MAIR_ATTR(TT_ATTR_INDX_MEMORY_WRITE_BACK, MAIR_ATTR_NORMAL_MEMORY_WRITE_BACK)); // mapped to EFI_MEMORY_WB + + ArmDisableAlignmentCheck (); + ArmEnableInstructionCache (); + ArmEnableDataCache (); + + ArmEnableMmu (); + return RETURN_SUCCESS; + +FREE_TRANSLATION_TABLE: + FreePages (TranslationTable, TranslationTablePageCount); + return Status; +} diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S b/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S new file mode 100644 index 0000000000..c45e33d6b9 --- /dev/null +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S @@ -0,0 +1,503 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+# Copyright (c) 2011 - 2013, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#------------------------------------------------------------------------------ + +#include +#include + +.text +.align 3 + +GCC_ASM_EXPORT (ArmInvalidateInstructionCache) +GCC_ASM_EXPORT (ArmInvalidateDataCacheEntryByMVA) +GCC_ASM_EXPORT (ArmCleanDataCacheEntryByMVA) +GCC_ASM_EXPORT (ArmCleanInvalidateDataCacheEntryByMVA) +GCC_ASM_EXPORT (ArmInvalidateDataCacheEntryBySetWay) +GCC_ASM_EXPORT (ArmCleanDataCacheEntryBySetWay) +GCC_ASM_EXPORT (ArmCleanInvalidateDataCacheEntryBySetWay) +GCC_ASM_EXPORT (ArmDrainWriteBuffer) +GCC_ASM_EXPORT (ArmEnableMmu) +GCC_ASM_EXPORT (ArmDisableMmu) +GCC_ASM_EXPORT (ArmDisableCachesAndMmu) +GCC_ASM_EXPORT (ArmMmuEnabled) +GCC_ASM_EXPORT (ArmEnableDataCache) +GCC_ASM_EXPORT (ArmDisableDataCache) +GCC_ASM_EXPORT (ArmEnableInstructionCache) +GCC_ASM_EXPORT (ArmDisableInstructionCache) +GCC_ASM_EXPORT (ArmDisableAlignmentCheck) +GCC_ASM_EXPORT (ArmEnableAlignmentCheck) +GCC_ASM_EXPORT (ArmEnableBranchPrediction) +GCC_ASM_EXPORT (ArmDisableBranchPrediction) +GCC_ASM_EXPORT (AArch64AllDataCachesOperation) +GCC_ASM_EXPORT (AArch64PerformPoUDataCacheOperation) +GCC_ASM_EXPORT (ArmDataMemoryBarrier) +GCC_ASM_EXPORT (ArmDataSyncronizationBarrier) +GCC_ASM_EXPORT (ArmInstructionSynchronizationBarrier) +GCC_ASM_EXPORT (ArmWriteVBar) +GCC_ASM_EXPORT (ArmVFPImplemented) +GCC_ASM_EXPORT (ArmEnableVFP) +GCC_ASM_EXPORT (ArmCallWFI) +GCC_ASM_EXPORT (ArmInvalidateInstructionAndDataTlb) +GCC_ASM_EXPORT (ArmReadMpidr) +GCC_ASM_EXPORT (ArmReadTpidrurw) +GCC_ASM_EXPORT (ArmWriteTpidrurw) +GCC_ASM_EXPORT (ArmIsArchTimerImplemented) +GCC_ASM_EXPORT (ArmReadIdPfr0) +GCC_ASM_EXPORT (ArmReadIdPfr1) +GCC_ASM_EXPORT (ArmWriteHcr) +GCC_ASM_EXPORT (ArmReadCurrentEL) + +.set CTRL_M_BIT, (1 << 0) +.set CTRL_A_BIT, (1 << 1) +.set CTRL_C_BIT, (1 << 2) +.set CTRL_I_BIT, (1 << 12) +.set CTRL_V_BIT, (1 << 12) +.set CPACR_VFP_BITS, (3 << 20) + +ASM_PFX(ArmInvalidateDataCacheEntryByMVA): + dc ivac, x0 // Invalidate single data cache line + dsb sy + isb + ret + + +ASM_PFX(ArmCleanDataCacheEntryByMVA): + dc cvac, x0 // Clean single data cache line + dsb sy + isb + ret + + +ASM_PFX(ArmCleanInvalidateDataCacheEntryByMVA): + dc civac, x0 // Clean and invalidate single data cache line + dsb sy + isb + ret + + +ASM_PFX(ArmInvalidateDataCacheEntryBySetWay): + dc isw, x0 // Invalidate this line + dsb sy + isb + ret + + +ASM_PFX(ArmCleanInvalidateDataCacheEntryBySetWay): + dc cisw, x0 // Clean and Invalidate this line + dsb sy + isb + ret + + +ASM_PFX(ArmCleanDataCacheEntryBySetWay): + dc csw, x0 // Clean this line + dsb sy + isb + ret + + +ASM_PFX(ArmInvalidateInstructionCache): + ic iallu // Invalidate entire instruction cache + dsb sy + isb + ret + + +ASM_PFX(ArmEnableMmu): + EL1_OR_EL2_OR_EL3(x1) +1: mrs x0, sctlr_el1 // Read System control register EL1 + b 4f +2: mrs x0, sctlr_el2 // Read System control register EL2 + b 4f +3: mrs x0, sctlr_el3 // Read System control register EL3 +4: orr x0, x0, #CTRL_M_BIT // Set MMU enable bit + EL1_OR_EL2_OR_EL3(x1) +1: tlbi alle1 + isb + msr sctlr_el1, x0 // Write back + b 4f +2: tlbi alle2 + isb + msr sctlr_el2, x0 // Write back + b 4f +3: tlbi alle3 + isb + msr sctlr_el3, x0 // Write back +4: dsb sy + isb + ret + + +ASM_PFX(ArmDisableMmu): + EL1_OR_EL2_OR_EL3(x1) +1: mrs x0, sctlr_el1 // Read System Control Register EL1 + b 4f +2: mrs x0, sctlr_el2 // Read System Control Register EL2 + b 4f +3: mrs x0, sctlr_el3 // Read System Control Register EL3 +4: bic x0, x0, #CTRL_M_BIT // Clear MMU enable bit + EL1_OR_EL2_OR_EL3(x1) +1: msr sctlr_el1, x0 // Write back + tlbi alle1 + b 4f +2: msr sctlr_el2, x0 // Write back + tlbi alle2 + b 4f +3: msr sctlr_el3, x0 // Write back + tlbi alle3 +4: dsb sy + isb + ret + + +ASM_PFX(ArmDisableCachesAndMmu): + EL1_OR_EL2_OR_EL3(x1) +1: mrs x0, sctlr_el1 // Get control register EL1 + b 4f +2: mrs x0, sctlr_el2 // Get control register EL2 + b 4f +3: mrs x0, sctlr_el3 // Get control register EL3 +4: bic x0, x0, #CTRL_M_BIT // Disable MMU + bic x0, x0, #CTRL_C_BIT // Disable D Cache + bic x0, x0, #CTRL_I_BIT // Disable I Cache + EL1_OR_EL2_OR_EL3(x1) +1: msr sctlr_el1, x0 // Write back control register + b 4f +2: msr sctlr_el2, x0 // Write back control register + b 4f +3: msr sctlr_el3, x0 // Write back control register +4: dsb sy + isb + ret + + +ASM_PFX(ArmMmuEnabled): + EL1_OR_EL2_OR_EL3(x1) +1: mrs x0, sctlr_el1 // Get control register EL1 + b 4f +2: mrs x0, sctlr_el2 // Get control register EL2 + b 4f +3: mrs x0, sctlr_el3 // Get control register EL3 +4: and x0, x0, #CTRL_M_BIT + ret + + +ASM_PFX(ArmEnableDataCache): + EL1_OR_EL2_OR_EL3(x1) +1: mrs x0, sctlr_el1 // Get control register EL1 + b 4f +2: mrs x0, sctlr_el2 // Get control register EL2 + b 4f +3: mrs x0, sctlr_el3 // Get control register EL3 +4: orr x0, x0, #CTRL_C_BIT // Set C bit + EL1_OR_EL2_OR_EL3(x1) +1: msr sctlr_el1, x0 // Write back control register + b 4f +2: msr sctlr_el2, x0 // Write back control register + b 4f +3: msr sctlr_el3, x0 // Write back control register +4: dsb sy + isb + ret + + +ASM_PFX(ArmDisableDataCache): + EL1_OR_EL2_OR_EL3(x1) +1: mrs x0, sctlr_el1 // Get control register EL1 + b 4f +2: mrs x0, sctlr_el2 // Get control register EL2 + b 4f +3: mrs x0, sctlr_el3 // Get control register EL3 +4: bic x0, x0, #CTRL_C_BIT // Clear C bit + EL1_OR_EL2_OR_EL3(x1) +1: msr sctlr_el1, x0 // Write back control register + b 4f +2: msr sctlr_el2, x0 // Write back control register + b 4f +3: msr sctlr_el3, x0 // Write back control register +4: dsb sy + isb + ret + + +ASM_PFX(ArmEnableInstructionCache): + EL1_OR_EL2_OR_EL3(x1) +1: mrs x0, sctlr_el1 // Get control register EL1 + b 4f +2: mrs x0, sctlr_el2 // Get control register EL2 + b 4f +3: mrs x0, sctlr_el3 // Get control register EL3 +4: orr x0, x0, #CTRL_I_BIT // Set I bit + EL1_OR_EL2_OR_EL3(x1) +1: msr sctlr_el1, x0 // Write back control register + b 4f +2: msr sctlr_el2, x0 // Write back control register + b 4f +3: msr sctlr_el3, x0 // Write back control register +4: dsb sy + isb + ret + + +ASM_PFX(ArmDisableInstructionCache): + EL1_OR_EL2_OR_EL3(x1) +1: mrs x0, sctlr_el1 // Get control register EL1 + b 4f +2: mrs x0, sctlr_el2 // Get control register EL2 + b 4f +3: mrs x0, sctlr_el3 // Get control register EL3 +4: bic x0, x0, #CTRL_I_BIT // Clear I bit + EL1_OR_EL2_OR_EL3(x1) +1: msr sctlr_el1, x0 // Write back control register + b 4f +2: msr sctlr_el2, x0 // Write back control register + b 4f +3: msr sctlr_el3, x0 // Write back control register +4: dsb sy + isb + ret + + +ASM_PFX(ArmEnableAlignmentCheck): + EL1_OR_EL2(x1) +1: mrs x0, sctlr_el1 // Get control register EL1 + b 3f +2: mrs x0, sctlr_el2 // Get control register EL2 +3: orr x0, x0, #CTRL_A_BIT // Set A (alignment check) bit + EL1_OR_EL2(x1) +1: msr sctlr_el1, x0 // Write back control register + b 3f +2: msr sctlr_el2, x0 // Write back control register +3: dsb sy + isb + ret + + +ASM_PFX(ArmDisableAlignmentCheck): + EL1_OR_EL2_OR_EL3(x1) +1: mrs x0, sctlr_el1 // Get control register EL1 + b 4f +2: mrs x0, sctlr_el2 // Get control register EL2 + b 4f +3: mrs x0, sctlr_el3 // Get control register EL3 +4: bic x0, x0, #CTRL_A_BIT // Clear A (alignment check) bit + EL1_OR_EL2_OR_EL3(x1) +1: msr sctlr_el1, x0 // Write back control register + b 4f +2: msr sctlr_el2, x0 // Write back control register + b 4f +3: msr sctlr_el3, x0 // Write back control register +4: dsb sy + isb + ret + + +// Always turned on in AArch64. Else implementation specific. Leave in for C compatibility for now +ASM_PFX(ArmEnableBranchPrediction): + ret + + +// Always turned on in AArch64. Else implementation specific. Leave in for C compatibility for now. +ASM_PFX(ArmDisableBranchPrediction): + ret + + +ASM_PFX(AArch64AllDataCachesOperation): +// We can use regs 0-7 and 9-15 without having to save/restore. +// Save our link register on the stack. + str x30, [sp, #-0x10]! + mov x1, x0 // Save Function call in x1 + mrs x6, clidr_el1 // Read EL1 CLIDR + and x3, x6, #0x7000000 // Mask out all but Level of Coherency (LoC) + lsr x3, x3, #23 // Left align cache level value + cbz x3, L_Finished // No need to clean if LoC is 0 + mov x10, #0 // Start clean at cache level 0 + b Loop1 + +ASM_PFX(AArch64PerformPoUDataCacheOperation): +// We can use regs 0-7 and 9-15 without having to save/restore. +// Save our link register on the stack. + str x30, [sp, #-0x10]! + mov x1, x0 // Save Function call in x1 + mrs x6, clidr_el1 // Read EL1 CLIDR + and x3, x6, #0x38000000 // Mask out all but Point of Unification (PoU) + lsr x3, x3, #26 // Left align cache level value + cbz x3, L_Finished // No need to clean if LoC is 0 + mov x10, #0 // Start clean at cache level 0 + +Loop1: + add x2, x10, x10, lsr #1 // Work out 3x cachelevel for cache info + lsr x12, x6, x2 // bottom 3 bits are the Cache type for this level + and x12, x12, #7 // get those 3 bits alone + cmp x12, #2 // what cache at this level? + b.lt L_Skip // no cache or only instruction cache at this level + msr csselr_el1, x10 // write the Cache Size selection register with current level (CSSELR) + isb // isb to sync the change to the CacheSizeID reg + mrs x12, ccsidr_el1 // reads current Cache Size ID register (CCSIDR) + and x2, x12, #0x7 // extract the line length field + add x2, x2, #4 // add 4 for the line length offset (log2 16 bytes) + mov x4, #0x400 + sub x4, x4, #1 + and x4, x4, x12, lsr #3 // x4 is the max number on the way size (right aligned) + clz w5, w4 // w5 is the bit position of the way size increment + mov x7, #0x00008000 + sub x7, x7, #1 + and x7, x7, x12, lsr #13 // x7 is the max number of the index size (right aligned) + +Loop2: + mov x9, x4 // x9 working copy of the max way size (right aligned) + +Loop3: + lsl x11, x9, x5 + orr x0, x10, x11 // factor in the way number and cache number + lsl x11, x7, x2 + orr x0, x0, x11 // factor in the index number + + blr x1 // Goto requested cache operation + + subs x9, x9, #1 // decrement the way number + b.ge Loop3 + subs x7, x7, #1 // decrement the index + b.ge Loop2 +L_Skip: + add x10, x10, #2 // increment the cache number + cmp x3, x10 + b.gt Loop1 + +L_Finished: + dsb sy + isb + ldr x30, [sp], #0x10 + ret + + +ASM_PFX(ArmDataMemoryBarrier): + dmb sy + ret + + +ASM_PFX(ArmDataSyncronizationBarrier): +ASM_PFX(ArmDrainWriteBuffer): + dsb sy + ret + + +ASM_PFX(ArmInstructionSynchronizationBarrier): + isb + ret + + +ASM_PFX(ArmWriteVBar): + EL1_OR_EL2_OR_EL3(x1) +1: msr vbar_el1, x0 // Set the Address of the EL1 Vector Table in the VBAR register + b 4f +2: msr vbar_el2, x0 // Set the Address of the EL2 Vector Table in the VBAR register + b 4f +3: msr vbar_el3, x0 // Set the Address of the EL3 Vector Table in the VBAR register +4: isb + ret + +ASM_PFX(ArmEnableVFP): + // Check whether floating-point is implemented in the processor. + mov x1, x30 // Save LR + bl ArmReadIdPfr0 // Read EL1 Processor Feature Register (PFR0) + mov x30, x1 // Restore LR + ands x0, x0, #AARCH64_PFR0_FP// Extract bits indicating VFP implementation + cmp x0, #0 // VFP is implemented if '0'. + b.ne 4f // Exit if VFP not implemented. + // FVP is implemented. + // Make sure VFP exceptions are not trapped (to any exception level). + mrs x0, cpacr_el1 // Read EL1 Coprocessor Access Control Register (CPACR) + orr x0, x0, #CPACR_VFP_BITS // Disable FVP traps to EL1 + msr cpacr_el1, x0 // Write back EL1 Coprocessor Access Control Register (CPACR) + mov x1, #AARCH64_CPTR_TFP // TFP Bit for trapping VFP Exceptions + EL1_OR_EL2_OR_EL3(x2) +1:ret // Not configurable in EL1 +2:mrs x0, cptr_el2 // Disable VFP traps to EL2 + bic x0, x0, x1 + msr cptr_el2, x0 + ret +3:mrs x0, cptr_el3 // Disable VFP traps to EL3 + bic x0, x0, x1 + msr cptr_el3, x0 +4:ret + + +ASM_PFX(ArmCallWFI): + wfi + ret + + +ASM_PFX(ArmInvalidateInstructionAndDataTlb): + EL1_OR_EL2_OR_EL3(x0) +1: tlbi alle1 + b 4f +2: tlbi alle2 + b 4f +3: tlbi alle3 +4: dsb sy + isb + ret + + +ASM_PFX(ArmReadMpidr): + mrs x0, mpidr_el1 // read EL1 MPIDR + ret + + +// Keep old function names for C compatibilty for now. Change later? +ASM_PFX(ArmReadTpidrurw): + mrs x0, tpidr_el0 // read tpidr_el0 (v7 TPIDRURW) -> (v8 TPIDR_EL0) + ret + + +// Keep old function names for C compatibilty for now. Change later? +ASM_PFX(ArmWriteTpidrurw): + msr tpidr_el0, x0 // write tpidr_el0 (v7 TPIDRURW) -> (v8 TPIDR_EL0) + ret + + +// Arch timers are mandatory on AArch64 +ASM_PFX(ArmIsArchTimerImplemented): + mov x0, #1 + ret + + +ASM_PFX(ArmReadIdPfr0): + mrs x0, id_aa64pfr0_el1 // Read ID_AA64PFR0 Register + ret + + +// Q: id_aa64pfr1_el1 not defined yet. What does this funtion want to access? +// A: used to setup arch timer. Check if we have security extensions, permissions to set stuff. +// See: ArmPkg/Library/ArmArchTimerLib/AArch64/ArmArchTimerLib.c +// Not defined yet, but stick in here for now, should read all zeros. +ASM_PFX(ArmReadIdPfr1): + mrs x0, id_aa64pfr1_el1 // Read ID_PFR1 Register + ret + +// VOID ArmWriteHcr(UINTN Hcr) +ASM_PFX(ArmWriteHcr): + msr hcr_el2, x0 // Write the passed HCR value + ret + +// UINTN ArmReadCurrentEL(VOID) +ASM_PFX(ArmReadCurrentEL): + mrs x0, CurrentEL + ret + +dead: + b dead + +ASM_FUNCTION_REMOVE_IF_UNREFERENCED diff --git a/ArmPkg/Library/ArmLib/AArch64/ArmLib.c b/ArmPkg/Library/ArmLib/AArch64/ArmLib.c new file mode 100644 index 0000000000..fa95d352dc --- /dev/null +++ b/ArmPkg/Library/ArmLib/AArch64/ArmLib.c @@ -0,0 +1,53 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include + +#include "ArmLibPrivate.h" + +VOID +EFIAPI +ArmCacheInformation ( + OUT ARM_CACHE_INFO *CacheInfo + ) +{ + if (CacheInfo != NULL) { + CacheInfo->Type = ArmCacheType(); + CacheInfo->Architecture = ArmCacheArchitecture(); + CacheInfo->DataCachePresent = ArmDataCachePresent(); + CacheInfo->DataCacheSize = ArmDataCacheSize(); + CacheInfo->DataCacheAssociativity = ArmDataCacheAssociativity(); + CacheInfo->DataCacheLineLength = ArmDataCacheLineLength(); + CacheInfo->InstructionCachePresent = ArmInstructionCachePresent(); + CacheInfo->InstructionCacheSize = ArmInstructionCacheSize(); + CacheInfo->InstructionCacheAssociativity = ArmInstructionCacheAssociativity(); + CacheInfo->InstructionCacheLineLength = ArmInstructionCacheLineLength(); + } +} + +VOID +EFIAPI +ArmSetAuxCrBit ( + IN UINT32 Bits + ) +{ + UINT32 val = ArmReadAuxCr(); + val |= Bits; + ArmWriteAuxCr(val); +} diff --git a/ArmPkg/Library/ArmLib/AArch64/ArmLibPrivate.h b/ArmPkg/Library/ArmLib/AArch64/ArmLibPrivate.h new file mode 100644 index 0000000000..d2804fc102 --- /dev/null +++ b/ArmPkg/Library/ArmLib/AArch64/ArmLibPrivate.h @@ -0,0 +1,82 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __ARM_LIB_PRIVATE_H__ +#define __ARM_LIB_PRIVATE_H__ + +#define CACHE_SIZE_4_KB (3UL) +#define CACHE_SIZE_8_KB (4UL) +#define CACHE_SIZE_16_KB (5UL) +#define CACHE_SIZE_32_KB (6UL) +#define CACHE_SIZE_64_KB (7UL) +#define CACHE_SIZE_128_KB (8UL) + +#define CACHE_ASSOCIATIVITY_DIRECT (0UL) +#define CACHE_ASSOCIATIVITY_4_WAY (2UL) +#define CACHE_ASSOCIATIVITY_8_WAY (3UL) + +#define CACHE_PRESENT (0UL) +#define CACHE_NOT_PRESENT (1UL) + +#define CACHE_LINE_LENGTH_32_BYTES (2UL) + +#define SIZE_FIELD_TO_CACHE_SIZE(x) (((x) >> 6) & 0x0F) +#define SIZE_FIELD_TO_CACHE_ASSOCIATIVITY(x) (((x) >> 3) & 0x07) +#define SIZE_FIELD_TO_CACHE_PRESENCE(x) (((x) >> 2) & 0x01) +#define SIZE_FIELD_TO_CACHE_LINE_LENGTH(x) (((x) >> 0) & 0x03) + +#define DATA_CACHE_SIZE_FIELD(x) (((x) >> 12) & 0x0FFF) +#define INSTRUCTION_CACHE_SIZE_FIELD(x) (((x) >> 0) & 0x0FFF) + +#define DATA_CACHE_SIZE(x) (SIZE_FIELD_TO_CACHE_SIZE(DATA_CACHE_SIZE_FIELD(x))) +#define DATA_CACHE_ASSOCIATIVITY(x) (SIZE_FIELD_TO_CACHE_ASSOCIATIVITY(DATA_CACHE_SIZE_FIELD(x))) +#define DATA_CACHE_PRESENT(x) (SIZE_FIELD_TO_CACHE_PRESENCE(DATA_CACHE_SIZE_FIELD(x))) +#define DATA_CACHE_LINE_LENGTH(x) (SIZE_FIELD_TO_CACHE_LINE_LENGTH(DATA_CACHE_SIZE_FIELD(x))) + +#define INSTRUCTION_CACHE_SIZE(x) (SIZE_FIELD_TO_CACHE_SIZE(INSTRUCTION_CACHE_SIZE_FIELD(x))) +#define INSTRUCTION_CACHE_ASSOCIATIVITY(x) (SIZE_FIELD_TO_CACHE_ASSOCIATIVITY(INSTRUCTION_CACHE_SIZE_FIELD(x))) +#define INSTRUCTION_CACHE_PRESENT(x) (SIZE_FIELD_TO_CACHE_PRESENCE(INSTRUCTION_CACHE_SIZE_FIELD(x))) +#define INSTRUCTION_CACHE_LINE_LENGTH(x) (SIZE_FIELD_TO_CACHE_LINE_LENGTH(INSTRUCTION_CACHE_SIZE_FIELD(x))) + +#define CACHE_TYPE(x) (((x) >> 25) & 0x0F) +#define CACHE_TYPE_WRITE_BACK (0x0EUL) + +#define CACHE_ARCHITECTURE(x) (((x) >> 24) & 0x01) +#define CACHE_ARCHITECTURE_UNIFIED (0UL) +#define CACHE_ARCHITECTURE_SEPARATE (1UL) + + +VOID +CPSRMaskInsert ( + IN UINT32 Mask, + IN UINT32 Value + ); + +UINT32 +CPSRRead ( + VOID + ); + +UINT32 +ReadCCSIDR ( + IN UINT32 CSSELR + ); + +UINT32 +ReadCLIDR ( + VOID + ); + +#endif // __ARM_LIB_PRIVATE_H__ diff --git a/ArmPkg/Library/ArmLib/AArch64/ArmLibSupportV8.S b/ArmPkg/Library/ArmLib/AArch64/ArmLibSupportV8.S new file mode 100644 index 0000000000..aee3dc1183 --- /dev/null +++ b/ArmPkg/Library/ArmLib/AArch64/ArmLibSupportV8.S @@ -0,0 +1,127 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+# Copyright (c) 2011 - 2013, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#------------------------------------------------------------------------------ + +#include + +.text +.align 3 + +GCC_ASM_EXPORT (ArmIsMpCore) +GCC_ASM_EXPORT (ArmEnableAsynchronousAbort) +GCC_ASM_EXPORT (ArmDisableAsynchronousAbort) +GCC_ASM_EXPORT (ArmEnableIrq) +GCC_ASM_EXPORT (ArmDisableIrq) +GCC_ASM_EXPORT (ArmEnableFiq) +GCC_ASM_EXPORT (ArmDisableFiq) +GCC_ASM_EXPORT (ArmEnableInterrupts) +GCC_ASM_EXPORT (ArmDisableInterrupts) +GCC_ASM_EXPORT (ArmDisableAllExceptions) +GCC_ASM_EXPORT (ReadCCSIDR) +GCC_ASM_EXPORT (ReadCLIDR) + +#------------------------------------------------------------------------------ + +.set MPIDR_U_BIT, (30) +.set MPIDR_U_MASK, (1 << MPIDR_U_BIT) +.set DAIF_FIQ_BIT, (1 << 0) +.set DAIF_IRQ_BIT, (1 << 1) +.set DAIF_ABORT_BIT, (1 << 2) +.set DAIF_DEBUG_BIT, (1 << 3) +.set DAIF_INT_BITS, (DAIF_FIQ_BIT | DAIF_IRQ_BIT) +.set DAIF_ALL, (DAIF_DEBUG_BIT | DAIF_ABORT_BIT | DAIF_INT_BITS) + + +ASM_PFX(ArmIsMpCore): + mrs x0, mpidr_el1 // Read EL1 Mutliprocessor Affinty Reg (MPIDR) + and x0, x0, #MPIDR_U_MASK // U Bit clear, the processor is part of a multiprocessor system + lsr x0, x0, #MPIDR_U_BIT + eor x0, x0, #1 + ret + + +ASM_PFX(ArmEnableAsynchronousAbort): + msr daifclr, #DAIF_ABORT_BIT + isb + ret + + +ASM_PFX(ArmDisableAsynchronousAbort): + msr daifset, #DAIF_ABORT_BIT + isb + ret + + +ASM_PFX(ArmEnableIrq): + msr daifclr, #DAIF_IRQ_BIT + isb + ret + + +ASM_PFX(ArmDisableIrq): + msr daifset, #DAIF_IRQ_BIT + isb + ret + + +ASM_PFX(ArmEnableFiq): + msr daifclr, #DAIF_FIQ_BIT + isb + ret + + +ASM_PFX(ArmDisableFiq): + msr daifset, #DAIF_FIQ_BIT + isb + ret + + +ASM_PFX(ArmEnableInterrupts): + msr daifclr, #DAIF_INT_BITS + isb + ret + + +ASM_PFX(ArmDisableInterrupts): + msr daifset, #DAIF_INT_BITS + isb + ret + + +ASM_PFX(ArmDisableAllExceptions): + msr daifset, #DAIF_ALL + isb + ret + + +// UINT32 +// ReadCCSIDR ( +// IN UINT32 CSSELR +// ) +ASM_PFX(ReadCCSIDR): + msr csselr_el1, x0 // Write Cache Size Selection Register (CSSELR) + isb + mrs x0, ccsidr_el1 // Read current Cache Size ID Register (CCSIDR) + ret + + +// UINT32 +// ReadCLIDR ( +// IN UINT32 CSSELR +// ) +ASM_PFX(ReadCLIDR): + mrs x0, clidr_el1 // Read Cache Level ID Register + ret + +ASM_FUNCTION_REMOVE_IF_UNREFERENCED diff --git a/ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimer.c b/ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimer.c index 478a5da695..d04211b29d 100644 --- a/ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimer.c +++ b/ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimer.c @@ -21,7 +21,7 @@ #include #include "ArmV7Lib.h" #include "ArmLibPrivate.h" -#include +#include VOID EFIAPI diff --git a/ArmPkg/Library/ArmLib/Null/NullArmLib.inf b/ArmPkg/Library/ArmLib/Null/NullArmLib.inf index d437198109..f6d8b19429 100644 --- a/ArmPkg/Library/ArmLib/Null/NullArmLib.inf +++ b/ArmPkg/Library/ArmLib/Null/NullArmLib.inf @@ -31,6 +31,9 @@ ../Common/Arm/ArmLibSupport.S | GCC ../Common/Arm/ArmLibSupport.asm | RVCT +[Sources.AARCH64] + ../Common/AArch64/ArmLibSupport.S | GCC + [Packages] ArmPkg/ArmPkg.dec MdePkg/MdePkg.dec diff --git a/ArmPkg/Library/ArmSmcLib/AArch64/ArmSmc.S b/ArmPkg/Library/ArmSmcLib/AArch64/ArmSmc.S new file mode 100644 index 0000000000..579a73e96c --- /dev/null +++ b/ArmPkg/Library/ArmSmcLib/AArch64/ArmSmc.S @@ -0,0 +1,78 @@ +// +// Copyright (c) 2012-2013, ARM Limited. All rights reserved. +// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// + +.text +.align 3 + +GCC_ASM_EXPORT(ArmCallSmc) +GCC_ASM_EXPORT(ArmCallSmcArg1) +GCC_ASM_EXPORT(ArmCallSmcArg2) +GCC_ASM_EXPORT(ArmCallSmcArg3) + +ASM_PFX(ArmCallSmc): + str x1, [sp, #-0x10]! + mov x1, x0 + ldr x0,[x1] + smc #0 + str x0,[x1] + ldr x1, [sp], #0x10 + ret + +ASM_PFX(ArmCallSmcArg1): + stp x2, x3, [sp, #-0x10]! + mov x2, x0 + mov x3, x1 + ldr x0,[x2] + ldr x1,[x3] + smc #0 + str x0,[x2] + str x1,[x3] + ldp x2, x3, [sp], #0x10 + ret + +ASM_PFX(ArmCallSmcArg2): + stp x3, x4, [sp, #-0x10]! + str x5, [sp, #-8]! + mov x3, x0 + mov x4, x1 + mov x5, x2 + ldr x0,[x3] + ldr x1,[x4] + ldr x2,[x5] + smc #0 + str x0,[x3] + str x1,[x4] + str x2,[x5] + ldr x5, [sp], #8 + ldp x3, x4, [sp], #0x10 + ret + +ASM_PFX(ArmCallSmcArg3): + stp x4, x5, [sp, #-0x10]! + stp x6, x7, [sp, #-0x10]! + mov x4, x0 + mov x5, x1 + mov x6, x2 + mov x7, x3 + ldr x0,[x4] + ldr x1,[x5] + ldr x2,[x6] + ldr x3,[x7] + smc #0 + str x0,[x4] + str x1,[x5] + str x2,[x6] + str x3,[x7] + ldp x4, x5, [sp], #0x10 + ldp x6, x7, [sp], #0x10 + ret diff --git a/ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf b/ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf index a3e12d26d1..f07a569ddb 100644 --- a/ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf +++ b/ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf @@ -23,6 +23,9 @@ Arm/ArmSmc.asm | RVCT Arm/ArmSmc.S | GCC +[Sources.AARCH64] + AArch64/ArmSmc.S | GCC + [Packages] MdePkg/MdePkg.dec ArmPkg/ArmPkg.dec diff --git a/ArmPkg/Library/ArmSmcLibNull/AArch64/ArmSmcNull.S b/ArmPkg/Library/ArmSmcLibNull/AArch64/ArmSmcNull.S new file mode 100644 index 0000000000..ec6e067ac3 --- /dev/null +++ b/ArmPkg/Library/ArmSmcLibNull/AArch64/ArmSmcNull.S @@ -0,0 +1,32 @@ +// +// Copyright (c) 2012-2013, ARM Limited. All rights reserved. +// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// + +.text +.align 3 + +GCC_ASM_EXPORT(ArmCallSmc) +GCC_ASM_EXPORT(ArmCallSmcArg1) +GCC_ASM_EXPORT(ArmCallSmcArg2) +GCC_ASM_EXPORT(ArmCallSmcArg3) + +ASM_PFX(ArmCallSmc): + ret + +ASM_PFX(ArmCallSmcArg1): + ret + +ASM_PFX(ArmCallSmcArg2): + ret + +ASM_PFX(ArmCallSmcArg3): + ret diff --git a/ArmPkg/Library/ArmSmcLibNull/ArmSmcLibNull.inf b/ArmPkg/Library/ArmSmcLibNull/ArmSmcLibNull.inf index fed6e95ddf..51006e78bb 100644 --- a/ArmPkg/Library/ArmSmcLibNull/ArmSmcLibNull.inf +++ b/ArmPkg/Library/ArmSmcLibNull/ArmSmcLibNull.inf @@ -26,6 +26,9 @@ Arm/ArmSmcNull.asm | RVCT Arm/ArmSmcNull.S | GCC +[Sources.AARCH64] + AArch64/ArmSmcNull.S | GCC + [Packages] MdePkg/MdePkg.dec ArmPkg/ArmPkg.dec diff --git a/ArmPkg/Library/BaseMemoryLibStm/AArch64/CopyMem.c b/ArmPkg/Library/BaseMemoryLibStm/AArch64/CopyMem.c new file mode 100644 index 0000000000..71ae02a03e --- /dev/null +++ b/ArmPkg/Library/BaseMemoryLibStm/AArch64/CopyMem.c @@ -0,0 +1,146 @@ +/** @file + + Copyright (c) 2012-2013, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "MemLibInternals.h" + +/** + Copy Length bytes from Source to Destination. + + @param DestinationBuffer Target of copy + @param SourceBuffer Place to copy from + @param Length Number of bytes to copy + + @return Destination + +**/ +VOID * +EFIAPI +InternalMemCopyMem ( + OUT VOID *DestinationBuffer, + IN CONST VOID *SourceBuffer, + IN UINTN Length + ) +{ + // + // Declare the local variables that actually move the data elements as + // volatile to prevent the optimizer from replacing this function with + // the intrinsic memcpy() + // + volatile UINT8 *Destination8; + CONST UINT8 *Source8; + volatile UINT32 *Destination32; + CONST UINT32 *Source32; + volatile UINT64 *Destination64; + CONST UINT64 *Source64; + UINTN Alignment; + + if ((((UINTN)DestinationBuffer & 0x7) == 0) && (((UINTN)SourceBuffer & 0x7) == 0) && (Length >= 8)) { + if (SourceBuffer > DestinationBuffer) { + Destination64 = (UINT64*)DestinationBuffer; + Source64 = (CONST UINT64*)SourceBuffer; + while (Length >= 8) { + *(Destination64++) = *(Source64++); + Length -= 8; + } + + // Finish if there are still some bytes to copy + Destination8 = (UINT8*)Destination64; + Source8 = (CONST UINT8*)Source64; + while (Length-- != 0) { + *(Destination8++) = *(Source8++); + } + } else if (SourceBuffer < DestinationBuffer) { + Destination64 = (UINT64*)((UINTN)DestinationBuffer + Length); + Source64 = (CONST UINT64*)((UINTN)SourceBuffer + Length); + + // Destination64 and Source64 were aligned on a 64-bit boundary + // but if length is not a multiple of 8 bytes then they won't be + // anymore. + + Alignment = Length & 0x7; + if (Alignment != 0) { + Destination8 = (UINT8*)Destination64; + Source8 = (CONST UINT8*)Source64; + + while (Alignment-- != 0) { + *(--Destination8) = *(--Source8); + --Length; + } + Destination64 = (UINT64*)Destination8; + Source64 = (CONST UINT64*)Source8; + } + + while (Length > 0) { + *(--Destination64) = *(--Source64); + Length -= 8; + } + } + } else if ((((UINTN)DestinationBuffer & 0x3) == 0) && (((UINTN)SourceBuffer & 0x3) == 0) && (Length >= 4)) { + if (SourceBuffer > DestinationBuffer) { + Destination32 = (UINT32*)DestinationBuffer; + Source32 = (CONST UINT32*)SourceBuffer; + while (Length >= 4) { + *(Destination32++) = *(Source32++); + Length -= 4; + } + + // Finish if there are still some bytes to copy + Destination8 = (UINT8*)Destination32; + Source8 = (CONST UINT8*)Source32; + while (Length-- != 0) { + *(Destination8++) = *(Source8++); + } + } else if (SourceBuffer < DestinationBuffer) { + Destination32 = (UINT32*)((UINTN)DestinationBuffer + Length); + Source32 = (CONST UINT32*)((UINTN)SourceBuffer + Length); + + // Destination32 and Source32 were aligned on a 32-bit boundary + // but if length is not a multiple of 4 bytes then they won't be + // anymore. + + Alignment = Length & 0x3; + if (Alignment != 0) { + Destination8 = (UINT8*)Destination32; + Source8 = (CONST UINT8*)Source32; + + while (Alignment-- != 0) { + *(--Destination8) = *(--Source8); + --Length; + } + Destination32 = (UINT32*)Destination8; + Source32 = (CONST UINT32*)Source8; + } + + while (Length > 0) { + *(--Destination32) = *(--Source32); + Length -= 4; + } + } + } else { + if (SourceBuffer > DestinationBuffer) { + Destination8 = (UINT8*)DestinationBuffer; + Source8 = (CONST UINT8*)SourceBuffer; + while (Length-- != 0) { + *(Destination8++) = *(Source8++); + } + } else if (SourceBuffer < DestinationBuffer) { + Destination8 = (UINT8*)DestinationBuffer + Length; + Source8 = (CONST UINT8*)SourceBuffer + Length; + while (Length-- != 0) { + *(--Destination8) = *(--Source8); + } + } + } + return DestinationBuffer; +} diff --git a/ArmPkg/Library/BaseMemoryLibStm/AArch64/SetMem.c b/ArmPkg/Library/BaseMemoryLibStm/AArch64/SetMem.c new file mode 100644 index 0000000000..368a819e59 --- /dev/null +++ b/ArmPkg/Library/BaseMemoryLibStm/AArch64/SetMem.c @@ -0,0 +1,84 @@ +/** @file + + Copyright (c) 2012-2013, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "MemLibInternals.h" + +/** + Set Buffer to Value for Size bytes. + + @param Buffer Memory to set. + @param Length Number of bytes to set + @param Value Value of the set operation. + + @return Buffer + +**/ +VOID * +EFIAPI +InternalMemSetMem ( + OUT VOID *Buffer, + IN UINTN Length, + IN UINT8 Value + ) +{ + // + // Declare the local variables that actually move the data elements as + // volatile to prevent the optimizer from replacing this function with + // the intrinsic memset() + // + volatile UINT8 *Pointer8; + volatile UINT32 *Pointer32; + volatile UINT64 *Pointer64; + UINT32 Value32; + UINT64 Value64; + + if ((((UINTN)Buffer & 0x7) == 0) && (Length >= 8)) { + // Generate the 64bit value + Value32 = (Value << 24) | (Value << 16) | (Value << 8) | Value; + Value64 = (((UINT64)Value32) << 32) | Value32; + + Pointer64 = (UINT64*)Buffer; + while (Length >= 8) { + *(Pointer64++) = Value64; + Length -= 8; + } + + // Finish with bytes if needed + Pointer8 = (UINT8*)Pointer64; + while (Length-- > 0) { + *(Pointer8++) = Value; + } + } else if ((((UINTN)Buffer & 0x3) == 0) && (Length >= 4)) { + // Generate the 32bit value + Value32 = (Value << 24) | (Value << 16) | (Value << 8) | Value; + + Pointer32 = (UINT32*)Buffer; + while (Length >= 4) { + *(Pointer32++) = Value32; + Length -= 4; + } + + // Finish with bytes if needed + Pointer8 = (UINT8*)Pointer32; + while (Length-- > 0) { + *(Pointer8++) = Value; + } + } else { + Pointer8 = (UINT8*)Buffer; + while (Length-- > 0) { + *(Pointer8++) = Value; + } + } + return Buffer; +} diff --git a/ArmPkg/Library/BaseMemoryLibStm/BaseMemoryLibStm.inf b/ArmPkg/Library/BaseMemoryLibStm/BaseMemoryLibStm.inf index 7d82b12ab2..a4d28036b6 100755 --- a/ArmPkg/Library/BaseMemoryLibStm/BaseMemoryLibStm.inf +++ b/ArmPkg/Library/BaseMemoryLibStm/BaseMemoryLibStm.inf @@ -7,6 +7,7 @@ # # Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
# Portions copyright (c) 2010, Apple Inc. All rights reserved.
+# Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -28,7 +29,7 @@ # -# VALID_ARCHITECTURES = ARM +# VALID_ARCHITECTURES = ARM AARCH64 # @@ -54,6 +55,9 @@ Arm/SetMem.asm Arm/SetMem.S +[Sources.AARCH64] + AArch64/CopyMem.c + AArch64/SetMem.c [Packages] MdePkg/MdePkg.dec diff --git a/ArmPkg/Library/BasePeCoffLib/AArch64/PeCoffLoaderEx.c b/ArmPkg/Library/BasePeCoffLib/AArch64/PeCoffLoaderEx.c new file mode 100644 index 0000000000..8a1829a262 --- /dev/null +++ b/ArmPkg/Library/BasePeCoffLib/AArch64/PeCoffLoaderEx.c @@ -0,0 +1,129 @@ +/** @file + Specific relocation fixups for ARM architecture. + + Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
+ Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "BasePeCoffLibInternals.h" +#include + +// +// Note: Currently only large memory model is supported by UEFI relocation code. +// + +/** + Performs an AARCH64-based specific relocation fixup and is a no-op on other + instruction sets. + + @param Reloc The pointer to the relocation record. + @param Fixup The pointer to the address to fix up. + @param FixupData The pointer to a buffer to log the fixups. + @param Adjust The offset to adjust the fixup. + + @return Status code. + +**/ +RETURN_STATUS +PeCoffLoaderRelocateImageEx ( + IN UINT16 **Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +{ + UINT64 *F64; + + switch ((**Reloc) >> 12) { + + case EFI_IMAGE_REL_BASED_DIR64: + F64 = (UINT64 *) Fixup; + *F64 = *F64 + (UINT64) Adjust; + if (*FixupData != NULL) { + *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64)); + *(UINT64 *)(*FixupData) = *F64; + *FixupData = *FixupData + sizeof(UINT64); + } + break; + + default: + return RETURN_UNSUPPORTED; + } + + return RETURN_SUCCESS; +} + +/** + Returns TRUE if the machine type of PE/COFF image is supported. Supported + does not mean the image can be executed it means the PE/COFF loader supports + loading and relocating of the image type. It's up to the caller to support + the entry point. + + @param Machine Machine type from the PE Header. + + @return TRUE if this PE/COFF loader can load the image + +**/ +BOOLEAN +PeCoffLoaderImageFormatSupported ( + IN UINT16 Machine + ) +{ + if ((Machine == IMAGE_FILE_MACHINE_AARCH64) || (Machine == IMAGE_FILE_MACHINE_EBC)) { + return TRUE; + } + + return FALSE; +} + +/** + Performs an ARM-based specific re-relocation fixup and is a no-op on other + instruction sets. This is used to re-relocated the image into the EFI virtual + space for runtime calls. + + @param Reloc The pointer to the relocation record. + @param Fixup The pointer to the address to fix up. + @param FixupData The pointer to a buffer to log the fixups. + @param Adjust The offset to adjust the fixup. + + @return Status code. + +**/ +RETURN_STATUS +PeHotRelocateImageEx ( + IN UINT16 **Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +{ + UINT64 *Fixup64; + + switch ((**Reloc) >> 12) { + case EFI_IMAGE_REL_BASED_DIR64: + Fixup64 = (UINT64 *) Fixup; + *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT64)); + if (*(UINT64 *) (*FixupData) == *Fixup64) { + *Fixup64 = *Fixup64 + (UINT64) Adjust; + } + + *FixupData = *FixupData + sizeof (UINT64); + break; + + default: + DEBUG ((EFI_D_ERROR, "PeHotRelocateEx:unknown fixed type\n")); + return RETURN_UNSUPPORTED; + } + + return RETURN_SUCCESS; +} diff --git a/ArmPkg/Library/BasePeCoffLib/BasePeCoffLib.inf b/ArmPkg/Library/BasePeCoffLib/BasePeCoffLib.inf index 7236db7912..929d789cb7 100755 --- a/ArmPkg/Library/BasePeCoffLib/BasePeCoffLib.inf +++ b/ArmPkg/Library/BasePeCoffLib/BasePeCoffLib.inf @@ -6,6 +6,7 @@ # # Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
# Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+# Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -27,7 +28,7 @@ # -# VALID_ARCHITECTURES = IA32 X64 IPF EBC ARM +# VALID_ARCHITECTURES = IA32 X64 IPF EBC ARM AARCH64 # [Sources] @@ -43,6 +44,9 @@ [Sources.ARM] Arm/PeCoffLoaderEx.c +[Sources.AARCH64] + AArch64/PeCoffLoaderEx.c + [Packages] MdePkg/MdePkg.dec diff --git a/ArmPkg/Library/BdsLib/BdsLinuxFdt.c b/ArmPkg/Library/BdsLib/BdsLinuxFdt.c index 1927de7264..57d8dcc907 100644 --- a/ArmPkg/Library/BdsLib/BdsLinuxFdt.c +++ b/ArmPkg/Library/BdsLib/BdsLinuxFdt.c @@ -336,7 +336,7 @@ PrepareFdt ( INTN err; INTN node; INTN cpu_node; - INTN lenp; + INT32 lenp; CONST VOID* BootArg; CONST VOID* Method; EFI_PHYSICAL_ADDRESS InitrdImageStart; diff --git a/ArmPkg/Library/CompilerIntrinsicsLib/AArch64/memcpy.S b/ArmPkg/Library/CompilerIntrinsicsLib/AArch64/memcpy.S new file mode 100644 index 0000000000..18433b3d50 --- /dev/null +++ b/ArmPkg/Library/CompilerIntrinsicsLib/AArch64/memcpy.S @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2011 - 2013, ARM Ltd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +.text +.align 2 + + +ASM_GLOBAL ASM_PFX(memcpy) + + +// Taken from Newlib BSD implementation. +ASM_PFX(memcpy): + // Copy dst to x6, so we can preserve return value. + mov x6, x0 + + // NOTE: although size_t is unsigned, this code uses signed + // comparisons on x2 so relies on nb never having its top bit + // set. In practice this is not going to be a real problem. + + // Require at least 64 bytes to be worth aligning. + cmp x2, #64 + blt qwordcopy + + // Compute offset to align destination to 16 bytes. + neg x3, x0 + and x3, x3, 15 + + cbz x3, blockcopy // offset == 0 is likely + + // We know there is at least 64 bytes to be done, so we + // do a 16 byte misaligned copy at first and then later do + // all 16-byte aligned copies. Some bytes will be copied + // twice, but there's no harm in that since memcpy does not + // guarantee correctness on overlap. + + sub x2, x2, x3 // nb -= offset + ldp x4, x5, [x1] + add x1, x1, x3 + stp x4, x5, [x6] + add x6, x6, x3 + + // The destination pointer is now qword (16 byte) aligned. + // (The src pointer might be.) + +blockcopy: + // Copy 64 bytes at a time. + subs x2, x2, #64 + blt 3f +2: subs x2, x2, #64 + ldp x4, x5, [x1,#0] + ldp x8, x9, [x1,#16] + ldp x10,x11,[x1,#32] + ldp x12,x13,[x1,#48] + add x1, x1, #64 + stp x4, x5, [x6,#0] + stp x8, x9, [x6,#16] + stp x10,x11,[x6,#32] + stp x12,x13,[x6,#48] + add x6, x6, #64 + bge 2b + + // Unwind pre-decrement +3: add x2, x2, #64 + +qwordcopy: + // Copy 0-48 bytes, 16 bytes at a time. + subs x2, x2, #16 + blt tailcopy +2: ldp x4, x5, [x1],#16 + subs x2, x2, #16 + stp x4, x5, [x6],#16 + bge 2b + + // No need to unwind the pre-decrement, it would not change + // the low 4 bits of the count. But how likely is it for the + // byte count to be multiple of 16? Is it worth the overhead + // of testing for x2 == -16? + +tailcopy: + // Copy trailing 0-15 bytes. + tbz x2, #3, 1f + ldr x4, [x1],#8 // copy 8 bytes + str x4, [x6],#8 +1: + tbz x2, #2, 1f + ldr w4, [x1],#4 // copy 4 bytes + str w4, [x6],#4 +1: + tbz x2, #1, 1f + ldrh w4, [x1],#2 // copy 2 bytes + strh w4, [x6],#2 +1: + tbz x2, #0, return + ldrb w4, [x1] // copy 1 byte + strb w4, [x6] + +return: + // This is the only return point of memcpy. + ret diff --git a/ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf b/ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf index 53b1b15c77..3e95105cd5 100644 --- a/ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf +++ b/ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf @@ -22,9 +22,8 @@ VERSION_STRING = 1.0 LIBRARY_CLASS = CompilerIntrinsicsLib - -[Sources.common] - +[Sources.AARCH64] + AArch64/memcpy.S | GCC [Sources.ARM] Arm/mullu.asm | RVCT diff --git a/ArmPkg/Library/DebugAgentSymbolsBaseLib/AArch64/DebugAgentException.S b/ArmPkg/Library/DebugAgentSymbolsBaseLib/AArch64/DebugAgentException.S new file mode 100644 index 0000000000..022e2796c5 --- /dev/null +++ b/ArmPkg/Library/DebugAgentSymbolsBaseLib/AArch64/DebugAgentException.S @@ -0,0 +1,93 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#------------------------------------------------------------------------------ + +GCC_ASM_EXPORT(DebugAgentVectorTable) +GCC_ASM_IMPORT(DefaultExceptionHandler) + +.text +ASM_PFX(DebugAgentVectorTable): + +// +// Current EL with SP0 : 0x0 - 0x180 +// +.align 11 +ASM_PFX(SynchronousExceptionSP0): + b ASM_PFX(SynchronousExceptionSP0) + +.align 7 +ASM_PFX(IrqSP0): + b ASM_PFX(IrqSP0) + +.align 7 +ASM_PFX(FiqSP0): + b ASM_PFX(FiqSP0) + +.align 7 +ASM_PFX(SErrorSP0): + b ASM_PFX(SErrorSP0) + +// +// Current EL with SPx: 0x200 - 0x380 +// +.align 7 +ASM_PFX(SynchronousExceptionSPx): + b ASM_PFX(SynchronousExceptionSPx) + +.align 7 +ASM_PFX(IrqSPx): + b ASM_PFX(IrqSPx) + +.align 7 +ASM_PFX(FiqSPx): + b ASM_PFX(FiqSPx) + +.align 7 +ASM_PFX(SErrorSPx): + b ASM_PFX(SErrorSPx) + +/* Lower EL using AArch64 : 0x400 - 0x580 */ +.align 7 +ASM_PFX(SynchronousExceptionA64): + b ASM_PFX(SynchronousExceptionA64) + +.align 7 +ASM_PFX(IrqA64): + b ASM_PFX(IrqA64) + +.align 7 +ASM_PFX(FiqA64): + b ASM_PFX(FiqA64) + +.align 7 +ASM_PFX(SErrorA64): + b ASM_PFX(SErrorA64) + +// +// Lower EL using AArch32 : 0x0 - 0x180 +// +.align 7 +ASM_PFX(SynchronousExceptionA32): + b ASM_PFX(SynchronousExceptionA32) + +.align 7 +ASM_PFX(IrqA32): + b ASM_PFX(IrqA32) + +.align 7 +ASM_PFX(FiqA32): + b ASM_PFX(FiqA32) + +.align 7 +ASM_PFX(SErrorA32): + b ASM_PFX(SErrorA32) diff --git a/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.c b/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.c index 25a904e3f2..6da648d990 100644 --- a/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.c +++ b/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.c @@ -285,7 +285,7 @@ InitializeDebugAgent ( // Now we've got UART, make the check: // - The Vector table must be 32-byte aligned - ASSERT(((UINTN)DebugAgentVectorTable & ARM_VECTOR_TABLE_ALIGNMENT) == 0); + //Need to fix basetools ASSERT(((UINTN)DebugAgentVectorTable & ARM_VECTOR_TABLE_ALIGNMENT) == 0); ArmWriteVBar ((UINTN)DebugAgentVectorTable); // We use InitFlag to know if DebugAgent has been intialized from diff --git a/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf b/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf index f6a0ec2938..f7dfa01d51 100644 --- a/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf +++ b/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf @@ -26,6 +26,9 @@ Arm/DebugAgentException.asm | RVCT Arm/DebugAgentException.S | GCC +[Sources.AARCH64] + AArch64/DebugAgentException.S | GCC + [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec diff --git a/ArmPkg/Library/DefaultExceptionHandlerLib/AArch64/DefaultExceptionHandler.c b/ArmPkg/Library/DefaultExceptionHandlerLib/AArch64/DefaultExceptionHandler.c new file mode 100644 index 0000000000..27a09044b2 --- /dev/null +++ b/ArmPkg/Library/DefaultExceptionHandlerLib/AArch64/DefaultExceptionHandler.c @@ -0,0 +1,112 @@ +/** @file + Default exception handler + + Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *gDebugImageTableHeader = NULL; + +STATIC CHAR8 *gExceptionTypeString[] = { + "Synchronous", + "IRQ", + "FIQ", + "SError" +}; + +CHAR8 * +GetImageName ( + IN UINTN FaultAddress, + OUT UINTN *ImageBase, + OUT UINTN *PeCoffSizeOfHeaders + ); + +/** + This is the default action to take on an unexpected exception + + Since this is exception context don't do anything crazy like try to allcoate memory. + + @param ExceptionType Type of the exception + @param SystemContext Register state at the time of the Exception + +**/ +VOID +DefaultExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + CHAR8 Buffer[100]; + UINTN CharCount; + + CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"\n\n%a Exception: \n", gExceptionTypeString[ExceptionType]); + SerialPortWrite ((UINT8 *) Buffer, CharCount); + + DEBUG_CODE_BEGIN (); + CHAR8 *Pdb; + UINTN ImageBase; + UINTN PeCoffSizeOfHeader; + Pdb = GetImageName (SystemContext.SystemContextAArch64->ELR, &ImageBase, &PeCoffSizeOfHeader); + if (Pdb != NULL) { + DEBUG ((EFI_D_ERROR, "%a loaded at 0x%016lx \n", Pdb, ImageBase)); + } + DEBUG_CODE_END (); + + DEBUG ((EFI_D_ERROR, "\n X0 0x%016lx X1 0x%016lx X2 0x%016lx X3 0x%016lx\n", SystemContext.SystemContextAArch64->X0, SystemContext.SystemContextAArch64->X1, SystemContext.SystemContextAArch64->X2, SystemContext.SystemContextAArch64->X3)); + DEBUG ((EFI_D_ERROR, " X4 0x%016lx X5 0x%016lx X6 0x%016lx X7 0x%016lx\n", SystemContext.SystemContextAArch64->X4, SystemContext.SystemContextAArch64->X5, SystemContext.SystemContextAArch64->X6, SystemContext.SystemContextAArch64->X7)); + DEBUG ((EFI_D_ERROR, " X8 0x%016lx X9 0x%016lx X10 0x%016lx X11 0x%016lx\n", SystemContext.SystemContextAArch64->X8, SystemContext.SystemContextAArch64->X9, SystemContext.SystemContextAArch64->X10, SystemContext.SystemContextAArch64->X11)); + DEBUG ((EFI_D_ERROR, " X12 0x%016lx X13 0x%016lx X14 0x%016lx X15 0x%016lx\n", SystemContext.SystemContextAArch64->X12, SystemContext.SystemContextAArch64->X13, SystemContext.SystemContextAArch64->X14, SystemContext.SystemContextAArch64->X15)); + DEBUG ((EFI_D_ERROR, " X16 0x%016lx X17 0x%016lx X18 0x%016lx X19 0x%016lx\n", SystemContext.SystemContextAArch64->X16, SystemContext.SystemContextAArch64->X17, SystemContext.SystemContextAArch64->X18, SystemContext.SystemContextAArch64->X19)); + DEBUG ((EFI_D_ERROR, " X20 0x%016lx X21 0x%016lx X22 0x%016lx X23 0x%016lx\n", SystemContext.SystemContextAArch64->X20, SystemContext.SystemContextAArch64->X21, SystemContext.SystemContextAArch64->X22, SystemContext.SystemContextAArch64->X23)); + DEBUG ((EFI_D_ERROR, " X24 0x%016lx X25 0x%016lx X26 0x%016lx X27 0x%016lx\n", SystemContext.SystemContextAArch64->X24, SystemContext.SystemContextAArch64->X25, SystemContext.SystemContextAArch64->X26, SystemContext.SystemContextAArch64->X27)); + DEBUG ((EFI_D_ERROR, " X28 0x%016lx FP 0x%016lx LR 0x%016lx \n", SystemContext.SystemContextAArch64->X28, SystemContext.SystemContextAArch64->FP, SystemContext.SystemContextAArch64->LR)); + + /* We save these as 128bit numbers, but have to print them as two 64bit numbers, + so swap the 64bit words to correctly represent a 128bit number. */ + DEBUG ((EFI_D_ERROR, "\n V0 0x%016lx %016lx V1 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V0[1], SystemContext.SystemContextAArch64->V0[0], SystemContext.SystemContextAArch64->V1[1], SystemContext.SystemContextAArch64->V1[0])); + DEBUG ((EFI_D_ERROR, " V2 0x%016lx %016lx V3 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V2[1], SystemContext.SystemContextAArch64->V2[0], SystemContext.SystemContextAArch64->V3[1], SystemContext.SystemContextAArch64->V3[0])); + DEBUG ((EFI_D_ERROR, " V4 0x%016lx %016lx V5 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V4[1], SystemContext.SystemContextAArch64->V4[0], SystemContext.SystemContextAArch64->V5[1], SystemContext.SystemContextAArch64->V5[0])); + DEBUG ((EFI_D_ERROR, " V6 0x%016lx %016lx V7 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V6[1], SystemContext.SystemContextAArch64->V6[0], SystemContext.SystemContextAArch64->V7[1], SystemContext.SystemContextAArch64->V7[0])); + DEBUG ((EFI_D_ERROR, " V8 0x%016lx %016lx V9 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V8[1], SystemContext.SystemContextAArch64->V8[0], SystemContext.SystemContextAArch64->V9[1], SystemContext.SystemContextAArch64->V9[0])); + DEBUG ((EFI_D_ERROR, " V10 0x%016lx %016lx V11 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V10[1], SystemContext.SystemContextAArch64->V10[0], SystemContext.SystemContextAArch64->V11[1], SystemContext.SystemContextAArch64->V11[0])); + DEBUG ((EFI_D_ERROR, " V12 0x%016lx %016lx V13 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V12[1], SystemContext.SystemContextAArch64->V12[0], SystemContext.SystemContextAArch64->V13[1], SystemContext.SystemContextAArch64->V13[0])); + DEBUG ((EFI_D_ERROR, " V14 0x%016lx %016lx V15 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V14[1], SystemContext.SystemContextAArch64->V14[0], SystemContext.SystemContextAArch64->V15[1], SystemContext.SystemContextAArch64->V15[0])); + DEBUG ((EFI_D_ERROR, " V16 0x%016lx %016lx V17 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V16[1], SystemContext.SystemContextAArch64->V16[0], SystemContext.SystemContextAArch64->V17[1], SystemContext.SystemContextAArch64->V17[0])); + DEBUG ((EFI_D_ERROR, " V18 0x%016lx %016lx V19 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V18[1], SystemContext.SystemContextAArch64->V18[0], SystemContext.SystemContextAArch64->V19[1], SystemContext.SystemContextAArch64->V19[0])); + DEBUG ((EFI_D_ERROR, " V20 0x%016lx %016lx V21 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V20[1], SystemContext.SystemContextAArch64->V20[0], SystemContext.SystemContextAArch64->V21[1], SystemContext.SystemContextAArch64->V21[0])); + DEBUG ((EFI_D_ERROR, " V22 0x%016lx %016lx V23 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V22[1], SystemContext.SystemContextAArch64->V22[0], SystemContext.SystemContextAArch64->V23[1], SystemContext.SystemContextAArch64->V23[0])); + DEBUG ((EFI_D_ERROR, " V24 0x%016lx %016lx V25 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V24[1], SystemContext.SystemContextAArch64->V24[0], SystemContext.SystemContextAArch64->V25[1], SystemContext.SystemContextAArch64->V25[0])); + DEBUG ((EFI_D_ERROR, " V26 0x%016lx %016lx V27 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V26[1], SystemContext.SystemContextAArch64->V26[0], SystemContext.SystemContextAArch64->V27[1], SystemContext.SystemContextAArch64->V27[0])); + DEBUG ((EFI_D_ERROR, " V28 0x%016lx %016lx V29 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V28[1], SystemContext.SystemContextAArch64->V28[0], SystemContext.SystemContextAArch64->V29[1], SystemContext.SystemContextAArch64->V29[0])); + DEBUG ((EFI_D_ERROR, " V30 0x%016lx %016lx V31 0x%016lx %016lx\n", SystemContext.SystemContextAArch64->V30[1], SystemContext.SystemContextAArch64->V30[0], SystemContext.SystemContextAArch64->V31[1], SystemContext.SystemContextAArch64->V31[0])); + + DEBUG ((EFI_D_ERROR, "\n SP 0x%016lx ELR 0x%016lx SPSR 0x%08lx FPSR 0x%08lx\n ESR 0x%08lx FAR 0x%016lx\n", SystemContext.SystemContextAArch64->SP, SystemContext.SystemContextAArch64->ELR, SystemContext.SystemContextAArch64->SPSR, SystemContext.SystemContextAArch64->FPSR, SystemContext.SystemContextAArch64->ESR, SystemContext.SystemContextAArch64->FAR)); + + DEBUG ((EFI_D_ERROR, "\n ESR : EC 0x%02x IL 0x%x ISS 0x%08x\n", (SystemContext.SystemContextAArch64->ESR & 0xFC000000) >> 26, (SystemContext.SystemContextAArch64->ESR >> 25) & 0x1, SystemContext.SystemContextAArch64->ESR & 0x1FFFFFF )); + + DEBUG ((EFI_D_ERROR, "\n")); + ASSERT (FALSE); +} + diff --git a/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf b/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf index 61dabf484e..da8190bd3c 100644 --- a/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf +++ b/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf @@ -1,6 +1,7 @@ #/** @file # -# Copyright (c) 2008, Apple Inc. All rights reserved.
+# Copyright (c) 2008, Apple Inc. All rights reserved.
+# Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -27,6 +28,9 @@ [Sources.ARM] Arm/DefaultExceptionHandler.c +[Sources.AARCH64] + AArch64/DefaultExceptionHandler.c + [Packages] MdePkg/MdePkg.dec ArmPkg/ArmPkg.dec diff --git a/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLibBase.inf b/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLibBase.inf index 39b2775fce..8f5b3e1010 100644 --- a/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLibBase.inf +++ b/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLibBase.inf @@ -26,6 +26,9 @@ [Sources.ARM] Arm/DefaultExceptionHandler.c +[Sources.AARCH64] + AArch64/DefaultExceptionHandler.c + [Packages] MdePkg/MdePkg.dec ArmPkg/ArmPkg.dec diff --git a/ArmPkg/Library/SemihostLib/AArch64/GccSemihost.S b/ArmPkg/Library/SemihostLib/AArch64/GccSemihost.S new file mode 100644 index 0000000000..42211cf4ff --- /dev/null +++ b/ArmPkg/Library/SemihostLib/AArch64/GccSemihost.S @@ -0,0 +1,23 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+# Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#------------------------------------------------------------------------------ + +.text +.align 2 + +.globl ASM_PFX(GccSemihostCall) + +ASM_PFX(GccSemihostCall): + hlt #0xf000 + ret diff --git a/ArmPkg/Library/SemihostLib/SemihostLib.inf b/ArmPkg/Library/SemihostLib/SemihostLib.inf index a0a6871780..78727780a9 100644 --- a/ArmPkg/Library/SemihostLib/SemihostLib.inf +++ b/ArmPkg/Library/SemihostLib/SemihostLib.inf @@ -2,6 +2,7 @@ # Semihosting JTAG lib # # Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+# Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -25,7 +26,7 @@ # # The following information is for reference only and not required by the build tools. # -# VALID_ARCHITECTURES = ARM +# VALID_ARCHITECTURES = ARM AARCH64 # [Sources.common] SemihostLib.c @@ -33,10 +34,13 @@ [Sources.ARM] Arm/GccSemihost.S | GCC +[Sources.AARCH64] + AArch64/GccSemihost.S | GCC + [Packages] MdePkg/MdePkg.dec ArmPkg/ArmPkg.dec [LibraryClasses] BaseLib - +