ArmPkg: Added Aarch64 support

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Harry Liebel <Harry.Liebel@arm.com>
Signed-off-by: Olivier Martin <olivier.martin@arm.com>



git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14486 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Harry Liebel 2013-07-18 18:07:46 +00:00 committed by oliviermartin
parent 8477cb6e15
commit 25402f5d06
58 changed files with 4786 additions and 43 deletions

View File

@ -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

View File

@ -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

View File

@ -15,7 +15,7 @@
#include <Base.h>
#include <Library/ArmLib.h>
#include <Library/ArmCpuLib.h>
#include <Library/ArmV7ArchTimerLib.h>
#include <Library/ArmArchTimerLib.h>
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include <Library/PcdLib.h>

View File

@ -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 <Base.h>
#include <Library/ArmLib.h>
#include <Library/ArmCpuLib.h>
#include <Library/ArmArchTimerLib.h>
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include <Library/PcdLib.h>
#include <Chipset/ArmCortexA5x.h>
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
)
{
}

View File

@ -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

View File

@ -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 <Base.h>
#include <Library/ArmLib.h>
#include <Library/ArmCpuLib.h>
#include <Library/ArmGicLib.h>
#include <Library/ArmArchTimerLib.h>
#include <Library/IoLib.h>
#include <Library/PcdLib.h>
#include <Chipset/ArmAemV8.h>
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
}

View File

@ -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

View File

@ -0,0 +1,153 @@
/** @file
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
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 <Chipset/AArch64.h>
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;
}

View File

@ -0,0 +1,381 @@
//
// Copyright (c) 2011 - 2013 ARM LTD. All rights reserved.<BR>
//
// 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 <Library/PcdLib.h>
#include <AsmMacroIoLibV8.h>
/*
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

View File

@ -0,0 +1,189 @@
/*++
Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>
Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
Portions copyright (c) 2011-2013, ARM Ltd. All rights reserved.<BR>
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;
}

View File

@ -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,

View File

@ -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

View File

@ -24,7 +24,7 @@
#include <Library/UefiLib.h>
#include <Library/PcdLib.h>
#include <Library/IoLib.h>
#include <Library/ArmV7ArchTimerLib.h>
#include <Library/ArmArchTimerLib.h>
#include <Protocol/Timer.h>
#include <Protocol/HardwareInterrupt.h>

View File

@ -2,6 +2,8 @@
# Support a Semi Host file system over a debuggers JTAG
#
# Copyright (c) 2009, Apple Inc. All rights reserved.<BR>
# 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]

View File

@ -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.<BR>
Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
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__

View File

@ -0,0 +1,179 @@
/** @file
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
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 <Chipset/AArch64Mmu.h>
#include <Chipset/ArmArchTimer.h>
// 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__

View File

@ -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_

View File

@ -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 <Chipset/AArch64.h>
#endif //__ARM_AEM_V8_H__

View File

@ -1,6 +1,6 @@
/** @file
*
* Copyright (c) 2011, ARM Limited. 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
@ -12,8 +12,8 @@
*
**/
#ifndef __ARMV7_ARCH_TIMER_H_
#define __ARMV7_ARCH_TIMER_H_
#ifndef __ARM_ARCH_TIMER_H_
#define __ARM_ARCH_TIMER_H_
UINTN
EFIAPI
@ -135,4 +135,5 @@ ArmWriteCntvOff (
UINT64 Val
);
#endif
#endif // __ARM_ARCH_TIMER_H_

View File

@ -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

View File

@ -17,7 +17,7 @@
#define __ARM_V7_H__
#include <Chipset/ArmV7Mmu.h>
#include <Chipset/ArmV7ArchTimer.h>
#include <Chipset/ArmArchTimer.h>
// ARM Interrupt ID in Exception Table
#define ARM_ARCH_EXCEPTION_IRQ EXCEPT_ARM_IRQ

View File

@ -1,6 +1,6 @@
/** @file
Copyright (c) 2011, ARM Ltd. All rights reserved.<BR>
Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
@ -12,8 +12,8 @@
**/
#ifndef __ARM_V7_ARCH_TIMER_LIB_H__
#define __ARM_V7_ARCH_TIMER_LIB_H__
#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)
@ -36,7 +36,7 @@ typedef enum {
CnthpCtl,
CnthpCval,
RegMaximum
}ARM_ARCH_TIMER_REGS;
} ARM_ARCH_TIMER_REGS;
VOID
EFIAPI
@ -112,4 +112,4 @@ ArmArchTimerSetCompareVal (
IN UINT64 Val
);
#endif // __ARM_V7_ARCH_TIMER_LIB_H__
#endif // __ARM_ARCH_TIMER_LIB_H__

View File

@ -18,10 +18,16 @@
#include <Uefi/UefiBaseType.h>
#ifdef ARM_CPU_ARMv6
#include <Chipset/ARM1176JZ-S.h>
#ifdef MDE_CPU_ARM
#ifdef ARM_CPU_ARMv6
#include <Chipset/ARM1176JZ-S.h>
#else
#include <Chipset/ArmV7.h>
#endif
#elif defined(MDE_CPU_AARCH64)
#include <Chipset/AArch64.h>
#else
#include <Chipset/ArmV7.h>
#error "Unknown chipset."
#endif
typedef enum {
@ -501,6 +507,7 @@ ArmCallWFE (
VOID
EFIAPI
ArmCallWFI (
VOID
);

View File

@ -19,7 +19,7 @@
#include <Library/TimerLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/ArmV7ArchTimerLib.h>
#include <Library/ArmArchTimerLib.h>
#include <Chipset/ArmV7.h>
#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"));

View File

@ -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 <Uefi.h>
#include <Chipset/AArch64.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/ArmLib.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include "AArch64Lib.h"
#include "ArmLibPrivate.h"
#include <Library/ArmArchTimerLib.h>
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);
}

View File

@ -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

View File

@ -0,0 +1,263 @@
/** @file
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
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 <Uefi.h>
#include <Chipset/AArch64.h>
#include <Library/ArmLib.h>
#include <Library/BaseLib.h>
#include <Library/IoLib.h>
#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);
}

View File

@ -0,0 +1,98 @@
/** @file
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
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__

View File

@ -0,0 +1,44 @@
#/** @file
#
# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
# 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

View File

@ -0,0 +1,48 @@
#/** @file
#
# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
# Portions copyright (c) 2011-2013, ARM Ltd. All rights reserved.<BR>
#
# 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

View File

@ -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

View File

@ -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 <Uefi.h>
#include <Chipset/AArch64.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/ArmLib.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#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;
}

View File

@ -0,0 +1,503 @@
#------------------------------------------------------------------------------
#
# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
# 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 <Chipset/AArch64.h>
#include <AsmMacroIoLibV8.h>
.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

View File

@ -0,0 +1,53 @@
/** @file
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
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 <Base.h>
#include <Library/ArmLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#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);
}

View File

@ -0,0 +1,82 @@
/** @file
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
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__

View File

@ -0,0 +1,127 @@
#------------------------------------------------------------------------------
#
# Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
# 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 <AsmMacroIoLib.h>
.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

View File

@ -21,7 +21,7 @@
#include <Library/DebugLib.h>
#include "ArmV7Lib.h"
#include "ArmLibPrivate.h"
#include <Library/ArmV7ArchTimerLib.h>
#include <Library/ArmArchTimerLib.h>
VOID
EFIAPI

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,146 @@
/** @file
Copyright (c) 2012-2013, ARM Ltd. All rights reserved.<BR>
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;
}

View File

@ -0,0 +1,84 @@
/** @file
Copyright (c) 2012-2013, ARM Ltd. All rights reserved.<BR>
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;
}

View File

@ -7,6 +7,7 @@
#
# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
# Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
# Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
#
# 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

View File

@ -0,0 +1,129 @@
/** @file
Specific relocation fixups for ARM architecture.
Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
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 <Library/BaseLib.h>
//
// 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;
}

View File

@ -6,6 +6,7 @@
#
# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
# Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
# Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
#
# 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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,93 @@
#------------------------------------------------------------------------------
#
# Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
#
# 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)

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,112 @@
/** @file
Default exception handler
Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
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 <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/PeCoffGetEntryPointLib.h>
#include <Library/PrintLib.h>
#include <Library/ArmDisassemblerLib.h>
#include <Library/SerialPortLib.h>
#include <Guid/DebugImageInfoTable.h>
#include <Protocol/DebugSupport.h>
#include <Protocol/LoadedImage.h>
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);
}

View File

@ -1,6 +1,7 @@
#/** @file
#
# Copyright (c) 2008, Apple Inc. All rights reserved.<BR>
# Copyright (c) 2008, Apple Inc. All rights reserved.<BR>
# Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
#
# 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

View File

@ -26,6 +26,9 @@
[Sources.ARM]
Arm/DefaultExceptionHandler.c
[Sources.AARCH64]
AArch64/DefaultExceptionHandler.c
[Packages]
MdePkg/MdePkg.dec
ArmPkg/ArmPkg.dec

View File

@ -0,0 +1,23 @@
#------------------------------------------------------------------------------
#
# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
# Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
#
# 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

View File

@ -2,6 +2,7 @@
# Semihosting JTAG lib
#
# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
# Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
#
# 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