]> git.proxmox.com Git - mirror_edk2.git/commitdiff
ArmPkg: ARM/AArch64 implementation of CpuExceptionHandlerLib
authorCohen, Eugene <eugene@hp.com>
Mon, 7 Mar 2016 15:16:35 +0000 (15:16 +0000)
committerArd Biesheuvel <ard.biesheuvel@linaro.org>
Wed, 16 Mar 2016 11:19:58 +0000 (12:19 +0100)
Introduce ARM and AArch64 instances of the CpuExceptionHandlerLib which
provides exception handling and registration of handlers regardless of
execution phase.

Two variants of the ArmExceptionLib are provided: one where exception
handlers reside within the module (meeting appropriate architectural
alignment requirements for the vector table) and another one that will
relocate a copy of thee xception handlers to an address specified by
PcdCpuVectorBaseAddress. The ArmRelocateExceptionLib is intended for use
in cases where ArmExceptionLib is too large for the application
(uncompressed XIP images) as driven by the vector table alignment padding.

The AArch64 build of this library supports execution at EL1, EL2, and EL3
exception levels.

Tested on ARM, and AArch64 with SEC, DXE Core, and CpuDxe modules.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Eugene Cohen <eugene@hp.com>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
ArmPkg/ArmPkg.dsc
ArmPkg/Library/ArmExceptionLib/AArch64/AArch64Exception.c [new file with mode: 0644]
ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S [new file with mode: 0644]
ArmPkg/Library/ArmExceptionLib/Arm/ArmException.c [new file with mode: 0644]
ArmPkg/Library/ArmExceptionLib/Arm/ExceptionSupport.S [new file with mode: 0644]
ArmPkg/Library/ArmExceptionLib/Arm/ExceptionSupport.asm [new file with mode: 0644]
ArmPkg/Library/ArmExceptionLib/ArmExceptionLib.c [new file with mode: 0644]
ArmPkg/Library/ArmExceptionLib/ArmExceptionLib.inf [new file with mode: 0644]
ArmPkg/Library/ArmExceptionLib/ArmRelocateExceptionLib.inf [new file with mode: 0644]

index 688244bd7c539891b877553b2c2ad1bd307f6ecf..df5be6e21f3313e2044a85e29ed3f2f435ec5379 100644 (file)
@@ -63,6 +63,7 @@
   UncachedMemoryAllocationLib|ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf\r
   DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf\r
   DefaultExceptionHandlerLib|ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf\r
+  CpuExceptionHandlerLib|ArmPkg/Library/ArmExceptionLib/ArmExceptionLib.inf\r
 \r
   CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf\r
   ArmGicLib|ArmPkg/Drivers/ArmGic/ArmGicLib.inf\r
   ArmPkg/Library/SemihostLib/SemihostLib.inf\r
   ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf\r
   ArmPkg/Library/ArmPsciResetSystemLib/ArmPsciResetSystemLib.inf\r
+  ArmPkg/Library/ArmExceptionLib/ArmExceptionLib.inf\r
+  ArmPkg/Library/ArmExceptionLib/ArmRelocateExceptionLib.inf\r
 \r
   ArmPkg/Drivers/CpuDxe/CpuDxe.inf\r
   ArmPkg/Drivers/CpuPei/CpuPei.inf\r
diff --git a/ArmPkg/Library/ArmExceptionLib/AArch64/AArch64Exception.c b/ArmPkg/Library/ArmExceptionLib/AArch64/AArch64Exception.c
new file mode 100644 (file)
index 0000000..3d6eb49
--- /dev/null
@@ -0,0 +1,44 @@
+/** @file\r
+*  Exception Handling support specific for AArch64\r
+*\r
+*  Copyright (c) 2016 HP Development Company, L.P.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Chipset/AArch64.h>\r
+\r
+#include <Protocol/DebugSupport.h> // for MAX_AARCH64_EXCEPTION\r
+\r
+UINTN                   gMaxExceptionNumber = MAX_AARCH64_EXCEPTION;\r
+EFI_EXCEPTION_CALLBACK  gExceptionHandlers[MAX_AARCH64_EXCEPTION + 1] = { 0 };\r
+EFI_EXCEPTION_CALLBACK  gDebuggerExceptionHandlers[MAX_AARCH64_EXCEPTION + 1] = { 0 };\r
+PHYSICAL_ADDRESS        gExceptionVectorAlignmentMask = ARM_VECTOR_TABLE_ALIGNMENT;\r
+UINTN                   gDebuggerNoHandlerValue = 0; // todo: define for AArch64\r
+\r
+RETURN_STATUS ArchVectorConfig(\r
+  IN  UINTN       VectorBaseAddress\r
+  )\r
+{\r
+  UINTN             HcrReg;\r
+\r
+  if (ArmReadCurrentEL() == AARCH64_EL2) {\r
+    HcrReg = ArmReadHcr();\r
+\r
+    // Trap General Exceptions. All exceptions that would be routed to EL1 are routed to EL2\r
+    HcrReg |= ARM_HCR_TGE;\r
+\r
+    ArmWriteHcr(HcrReg);\r
+  }\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
diff --git a/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S b/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S
new file mode 100644 (file)
index 0000000..790ce00
--- /dev/null
@@ -0,0 +1,425 @@
+//\r
+// Copyright (c) 2011 - 2014 ARM LTD. All rights reserved.<BR>\r
+// Portion of Copyright (c) 2014 NVIDIA Corporation. All rights reserved.<BR>\r
+// Copyright (c) 2016 HP Development Company, L.P.\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution.  The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+//------------------------------------------------------------------------------\r
+\r
+#include <Chipset/AArch64.h>\r
+#include <Library/PcdLib.h>\r
+#include <AsmMacroIoLibV8.h>\r
+#include <Protocol/DebugSupport.h> // for exception type definitions\r
+\r
+/*\r
+  This is the stack constructed by the exception handler (low address to high address).\r
+  X0 to FAR makes up the EFI_SYSTEM_CONTEXT for AArch64.\r
+\r
+  UINT64  X0;     0x000\r
+  UINT64  X1;     0x008\r
+  UINT64  X2;     0x010\r
+  UINT64  X3;     0x018\r
+  UINT64  X4;     0x020\r
+  UINT64  X5;     0x028\r
+  UINT64  X6;     0x030\r
+  UINT64  X7;     0x038\r
+  UINT64  X8;     0x040\r
+  UINT64  X9;     0x048\r
+  UINT64  X10;    0x050\r
+  UINT64  X11;    0x058\r
+  UINT64  X12;    0x060\r
+  UINT64  X13;    0x068\r
+  UINT64  X14;    0x070\r
+  UINT64  X15;    0x078\r
+  UINT64  X16;    0x080\r
+  UINT64  X17;    0x088\r
+  UINT64  X18;    0x090\r
+  UINT64  X19;    0x098\r
+  UINT64  X20;    0x0a0\r
+  UINT64  X21;    0x0a8\r
+  UINT64  X22;    0x0b0\r
+  UINT64  X23;    0x0b8\r
+  UINT64  X24;    0x0c0\r
+  UINT64  X25;    0x0c8\r
+  UINT64  X26;    0x0d0\r
+  UINT64  X27;    0x0d8\r
+  UINT64  X28;    0x0e0\r
+  UINT64  FP;     0x0e8   // x29 - Frame Pointer\r
+  UINT64  LR;     0x0f0   // x30 - Link Register\r
+  UINT64  SP;     0x0f8   // x31 - Stack Pointer\r
+\r
+  // FP/SIMD Registers. 128bit if used as Q-regs.\r
+  UINT64  V0[2];  0x100\r
+  UINT64  V1[2];  0x110\r
+  UINT64  V2[2];  0x120\r
+  UINT64  V3[2];  0x130\r
+  UINT64  V4[2];  0x140\r
+  UINT64  V5[2];  0x150\r
+  UINT64  V6[2];  0x160\r
+  UINT64  V7[2];  0x170\r
+  UINT64  V8[2];  0x180\r
+  UINT64  V9[2];  0x190\r
+  UINT64  V10[2]; 0x1a0\r
+  UINT64  V11[2]; 0x1b0\r
+  UINT64  V12[2]; 0x1c0\r
+  UINT64  V13[2]; 0x1d0\r
+  UINT64  V14[2]; 0x1e0\r
+  UINT64  V15[2]; 0x1f0\r
+  UINT64  V16[2]; 0x200\r
+  UINT64  V17[2]; 0x210\r
+  UINT64  V18[2]; 0x220\r
+  UINT64  V19[2]; 0x230\r
+  UINT64  V20[2]; 0x240\r
+  UINT64  V21[2]; 0x250\r
+  UINT64  V22[2]; 0x260\r
+  UINT64  V23[2]; 0x270\r
+  UINT64  V24[2]; 0x280\r
+  UINT64  V25[2]; 0x290\r
+  UINT64  V26[2]; 0x2a0\r
+  UINT64  V27[2]; 0x2b0\r
+  UINT64  V28[2]; 0x2c0\r
+  UINT64  V29[2]; 0x2d0\r
+  UINT64  V30[2]; 0x2e0\r
+  UINT64  V31[2]; 0x2f0\r
+\r
+  // System Context\r
+  UINT64  ELR;    0x300   // Exception Link Register\r
+  UINT64  SPSR;   0x308   // Saved Processor Status Register\r
+  UINT64  FPSR;   0x310   // Floating Point Status Register\r
+  UINT64  ESR;    0x318   // Exception syndrome register\r
+  UINT64  FAR;    0x320   // Fault Address Register\r
+  UINT64  Padding;0x328   // Required for stack alignment\r
+*/\r
+\r
+GCC_ASM_EXPORT(ExceptionHandlersEnd)\r
+GCC_ASM_EXPORT(CommonExceptionEntry)\r
+GCC_ASM_EXPORT(AsmCommonExceptionEntry)\r
+GCC_ASM_EXPORT(CommonCExceptionHandler)\r
+\r
+.text\r
+\r
+#define GP_CONTEXT_SIZE    (32 *  8)\r
+#define FP_CONTEXT_SIZE    (32 * 16)\r
+#define SYS_CONTEXT_SIZE   ( 6 *  8) // 5 SYS regs + Alignment requirement (ie: the stack must be aligned on 0x10)\r
+\r
+// Cannot str x31 directly\r
+#define ALL_GP_REGS                                     \\r
+        REG_PAIR (x0,  x1,  0x000, GP_CONTEXT_SIZE);    \\r
+        REG_PAIR (x2,  x3,  0x010, GP_CONTEXT_SIZE);    \\r
+        REG_PAIR (x4,  x5,  0x020, GP_CONTEXT_SIZE);    \\r
+        REG_PAIR (x6,  x7,  0x030, GP_CONTEXT_SIZE);    \\r
+        REG_PAIR (x8,  x9,  0x040, GP_CONTEXT_SIZE);    \\r
+        REG_PAIR (x10, x11, 0x050, GP_CONTEXT_SIZE);    \\r
+        REG_PAIR (x12, x13, 0x060, GP_CONTEXT_SIZE);    \\r
+        REG_PAIR (x14, x15, 0x070, GP_CONTEXT_SIZE);    \\r
+        REG_PAIR (x16, x17, 0x080, GP_CONTEXT_SIZE);    \\r
+        REG_PAIR (x18, x19, 0x090, GP_CONTEXT_SIZE);    \\r
+        REG_PAIR (x20, x21, 0x0a0, GP_CONTEXT_SIZE);    \\r
+        REG_PAIR (x22, x23, 0x0b0, GP_CONTEXT_SIZE);    \\r
+        REG_PAIR (x24, x25, 0x0c0, GP_CONTEXT_SIZE);    \\r
+        REG_PAIR (x26, x27, 0x0d0, GP_CONTEXT_SIZE);    \\r
+        REG_PAIR (x28, x29, 0x0e0, GP_CONTEXT_SIZE);    \\r
+        REG_ONE  (x30,      0x0f0, GP_CONTEXT_SIZE);\r
+\r
+// In order to save the SP we need to put it somewhere else first.\r
+// STR only works with XZR/WZR directly\r
+#define SAVE_SP \\r
+        add x1, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE); \\r
+        REG_ONE (x1,        0x0f8, GP_CONTEXT_SIZE);\r
+\r
+#define ALL_FP_REGS                                     \\r
+        REG_PAIR (q0,  q1,  0x000, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q2,  q3,  0x020, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q4,  q5,  0x040, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q6,  q7,  0x060, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q8,  q9,  0x080, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q10, q11, 0x0a0, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q12, q13, 0x0c0, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q14, q15, 0x0e0, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q16, q17, 0x100, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q18, q19, 0x120, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q20, q21, 0x140, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q22, q23, 0x160, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q24, q25, 0x180, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q26, q27, 0x1a0, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q28, q29, 0x1c0, FP_CONTEXT_SIZE);    \\r
+        REG_PAIR (q30, q31, 0x1e0, FP_CONTEXT_SIZE);\r
+\r
+#define ALL_SYS_REGS                                    \\r
+        REG_PAIR (x1,  x2,  0x000, SYS_CONTEXT_SIZE);   \\r
+        REG_PAIR (x3,  x4,  0x010, SYS_CONTEXT_SIZE);   \\r
+        REG_ONE  (x5,       0x020, SYS_CONTEXT_SIZE);\r
+\r
+//\r
+// There are two methods for installing AArch64 exception vectors:\r
+//  1. Install a copy of the vectors to a location specified by a PCD\r
+//  2. Write VBAR directly, requiring that vectors have proper alignment (2K)\r
+// The conditional below adjusts the alignment requirement based on which\r
+// exception vector initialization method is used.\r
+//\r
+\r
+#if defined(ARM_RELOCATE_VECTORS)\r
+GCC_ASM_EXPORT(ExceptionHandlersStart)\r
+ASM_PFX(ExceptionHandlersStart):\r
+#else\r
+VECTOR_BASE(ExceptionHandlersStart)\r
+#endif\r
+\r
+//\r
+// Current EL with SP0 : 0x0 - 0x180\r
+//\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SYNC)\r
+ASM_PFX(SynchronousExceptionSP0):\r
+  b   ASM_PFX(SynchronousExceptionEntry)\r
+\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_IRQ)\r
+ASM_PFX(IrqSP0):\r
+  b   ASM_PFX(IrqEntry)\r
+\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_FIQ)\r
+ASM_PFX(FiqSP0):\r
+  b   ASM_PFX(FiqEntry)\r
+\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SERR)\r
+ASM_PFX(SErrorSP0):\r
+  b   ASM_PFX(SErrorEntry)\r
+\r
+//\r
+// Current EL with SPx: 0x200 - 0x380\r
+//\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SYNC)\r
+ASM_PFX(SynchronousExceptionSPx):\r
+  b   ASM_PFX(SynchronousExceptionEntry)\r
+\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_IRQ)\r
+ASM_PFX(IrqSPx):\r
+  b   ASM_PFX(IrqEntry)\r
+\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_FIQ)\r
+ASM_PFX(FiqSPx):\r
+  b   ASM_PFX(FiqEntry)\r
+\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SERR)\r
+ASM_PFX(SErrorSPx):\r
+  b   ASM_PFX(SErrorEntry)\r
+\r
+//\r
+// Lower EL using AArch64 : 0x400 - 0x580\r
+//\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SYNC)\r
+ASM_PFX(SynchronousExceptionA64):\r
+  b   ASM_PFX(SynchronousExceptionEntry)\r
+\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_IRQ)\r
+ASM_PFX(IrqA64):\r
+  b   ASM_PFX(IrqEntry)\r
+\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_FIQ)\r
+ASM_PFX(FiqA64):\r
+  b   ASM_PFX(FiqEntry)\r
+\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SERR)\r
+ASM_PFX(SErrorA64):\r
+  b   ASM_PFX(SErrorEntry)\r
+\r
+//\r
+// Lower EL using AArch32 : 0x600 - 0x780\r
+//\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SYNC)\r
+ASM_PFX(SynchronousExceptionA32):\r
+  b   ASM_PFX(SynchronousExceptionEntry)\r
+\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_IRQ)\r
+ASM_PFX(IrqA32):\r
+  b   ASM_PFX(IrqEntry)\r
+\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_FIQ)\r
+ASM_PFX(FiqA32):\r
+  b   ASM_PFX(FiqEntry)\r
+\r
+VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SERR)\r
+ASM_PFX(SErrorA32):\r
+  b   ASM_PFX(SErrorEntry)\r
+\r
+VECTOR_END(ExceptionHandlersStart)\r
+\r
+#undef  REG_PAIR\r
+#undef  REG_ONE\r
+#define REG_PAIR(REG1, REG2, OFFSET, CONTEXT_SIZE)  stp  REG1, REG2, [sp, #(OFFSET-CONTEXT_SIZE)]\r
+#define REG_ONE(REG1, OFFSET, CONTEXT_SIZE)         stur REG1, [sp, #(OFFSET-CONTEXT_SIZE)]\r
+\r
+ASM_PFX(SynchronousExceptionEntry):\r
+  // Move the stackpointer so we can reach our structure with the str instruction.\r
+  sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)\r
+\r
+  // Save all the General regs before touching x0 and x1.\r
+  // This does not save r31(SP) as it is special. We do that later.\r
+  ALL_GP_REGS\r
+\r
+  // Record the type of exception that occurred.\r
+  mov       x0, #EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS\r
+\r
+  // Jump to our general handler to deal with all the common parts and process the exception.\r
+  ldr       x1, ASM_PFX(CommonExceptionEntry)\r
+  br        x1\r
+\r
+ASM_PFX(IrqEntry):\r
+  sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)\r
+  ALL_GP_REGS\r
+  mov       x0, #EXCEPT_AARCH64_IRQ\r
+  ldr       x1, ASM_PFX(CommonExceptionEntry)\r
+  br        x1\r
+\r
+ASM_PFX(FiqEntry):\r
+  sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)\r
+  ALL_GP_REGS\r
+  mov       x0, #EXCEPT_AARCH64_FIQ\r
+  ldr       x1, ASM_PFX(CommonExceptionEntry)\r
+  br        x1\r
+\r
+ASM_PFX(SErrorEntry):\r
+  sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)\r
+  ALL_GP_REGS\r
+  mov       x0, #EXCEPT_AARCH64_SERROR\r
+  ldr       x1, ASM_PFX(CommonExceptionEntry)\r
+  br        x1\r
+\r
+\r
+//\r
+// This gets patched by the C code that patches in the vector table\r
+//\r
+.align 3\r
+ASM_PFX(CommonExceptionEntry):\r
+  .8byte ASM_PFX(AsmCommonExceptionEntry)\r
+\r
+ASM_PFX(ExceptionHandlersEnd):\r
+\r
+\r
+\r
+//\r
+// This code runs from CpuDxe driver loaded address. It is patched into\r
+// CommonExceptionEntry.\r
+//\r
+ASM_PFX(AsmCommonExceptionEntry):\r
+  /* NOTE:\r
+     We have to break up the save code because the immediate value to be used\r
+     with the SP is too big to do it all in one step so we need to shuffle the SP\r
+     along as we go. (we only have 9bits of immediate to work with) */\r
+\r
+  // Save the current Stack pointer before we start modifying it.\r
+  SAVE_SP\r
+\r
+  // Preserve the stack pointer we came in with before we modify it\r
+  EL1_OR_EL2_OR_EL3(x1)\r
+1:mrs      x1, elr_el1   // Exception Link Register\r
+  mrs      x2, spsr_el1  // Saved Processor Status Register 32bit\r
+  mrs      x3, fpsr      // Floating point Status Register  32bit\r
+  mrs      x4, esr_el1   // EL1 Exception syndrome register 32bit\r
+  mrs      x5, far_el1   // EL1 Fault Address Register\r
+  b        4f\r
+\r
+2:mrs      x1, elr_el2   // Exception Link Register\r
+  mrs      x2, spsr_el2  // Saved Processor Status Register 32bit\r
+  mrs      x3, fpsr      // Floating point Status Register  32bit\r
+  mrs      x4, esr_el2   // EL2 Exception syndrome register 32bit\r
+  mrs      x5, far_el2   // EL2 Fault Address Register\r
+  b        4f\r
+\r
+3:mrs      x1, elr_el3   // Exception Link Register\r
+  mrs      x2, spsr_el3  // Saved Processor Status Register 32bit\r
+  mrs      x3, fpsr      // Floating point Status Register  32bit\r
+  mrs      x4, esr_el3   // EL3 Exception syndrome register 32bit\r
+  mrs      x5, far_el3   // EL3 Fault Address Register\r
+\r
+  // Adjust SP to save next set\r
+4:add      sp, sp, #FP_CONTEXT_SIZE\r
+\r
+  // Push FP regs to Stack.\r
+  ALL_FP_REGS\r
+\r
+  // Adjust SP to save next set\r
+  add      sp, sp, #SYS_CONTEXT_SIZE\r
+\r
+  // Save the SYS regs\r
+  ALL_SYS_REGS\r
+\r
+  // Point to top of struct after all regs saved\r
+  sub      sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)\r
+\r
+  // x0 still holds the exception type.\r
+  // Set x1 to point to the top of our struct on the Stack\r
+  mov      x1, sp\r
+\r
+// CommonCExceptionHandler (\r
+//   IN     EFI_EXCEPTION_TYPE           ExceptionType,   R0\r
+//   IN OUT EFI_SYSTEM_CONTEXT           SystemContext    R1\r
+//   )\r
+\r
+  // Call the handler as defined above\r
+\r
+  // For now we spin in the handler if we received an abort of some kind.\r
+  // We do not try to recover.\r
+  bl       ASM_PFX(CommonCExceptionHandler) // Call exception handler\r
+\r
+\r
+// Defines for popping from stack\r
+\r
+#undef REG_PAIR\r
+#undef REG_ONE\r
+#define REG_PAIR(REG1, REG2, OFFSET, CONTEXT_SIZE)    ldp  REG1, REG2, [sp, #(OFFSET-CONTEXT_SIZE)]\r
+#define REG_ONE(REG1, OFFSET, CONTEXT_SIZE)           ldur REG1, [sp, #(OFFSET-CONTEXT_SIZE)]\r
+\r
+  //\r
+  // Disable interrupt(IRQ and FIQ) before restoring context,\r
+  // or else the context will be corrupted by interrupt reentrance.\r
+  // Interrupt mask will be restored from spsr by hardware when we call eret\r
+  //\r
+  msr   daifset, #3\r
+  isb\r
+\r
+  // Adjust SP to pop system registers\r
+  add     sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)\r
+  ALL_SYS_REGS\r
+\r
+  EL1_OR_EL2_OR_EL3(x6)\r
+1:msr      elr_el1, x1   // Exception Link Register\r
+  msr      spsr_el1,x2   // Saved Processor Status Register 32bit\r
+  msr      fpsr, x3      // Floating point Status Register  32bit\r
+  msr      esr_el1, x4   // EL1 Exception syndrome register 32bit\r
+  msr      far_el1, x5   // EL1 Fault Address Register\r
+  b        4f\r
+2:msr      elr_el2, x1   // Exception Link Register\r
+  msr      spsr_el2,x2   // Saved Processor Status Register 32bit\r
+  msr      fpsr, x3      // Floating point Status Register  32bit\r
+  msr      esr_el2, x4   // EL2 Exception syndrome register 32bit\r
+  msr      far_el2, x5   // EL2 Fault Address Register\r
+  b        4f\r
+3:msr      elr_el3, x1   // Exception Link Register\r
+  msr      spsr_el3,x2   // Saved Processor Status Register 32bit\r
+  msr      fpsr, x3      // Floating point Status Register  32bit\r
+  msr      esr_el3, x4   // EL3 Exception syndrome register 32bit\r
+  msr      far_el3, x5   // EL3 Fault Address Register\r
+4:// pop all regs and return from exception.\r
+  sub     sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)\r
+  ALL_GP_REGS\r
+\r
+  // Adjust SP to pop next set\r
+  add      sp, sp, #FP_CONTEXT_SIZE\r
+  // Pop FP regs to Stack.\r
+  ALL_FP_REGS\r
+\r
+  // Adjust SP to be where we started from when we came into the handler.\r
+  // The handler can not change the SP.\r
+  add      sp, sp, #SYS_CONTEXT_SIZE\r
+\r
+  eret\r
+\r
+#undef REG_PAIR\r
+#undef REG_ONE\r
diff --git a/ArmPkg/Library/ArmExceptionLib/Arm/ArmException.c b/ArmPkg/Library/ArmExceptionLib/Arm/ArmException.c
new file mode 100644 (file)
index 0000000..0a0c2a2
--- /dev/null
@@ -0,0 +1,50 @@
+/** @file\r
+*  Exception handling support specific for ARM\r
+*\r
+* Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
+* Copyright (c) 2014, ARM Limited. All rights reserved.<BR>\r
+* Copyright (c) 2016 HP Development Company, L.P.<BR>\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Chipset/ArmV7.h>\r
+\r
+#include <Library/ArmLib.h>\r
+\r
+#include <Protocol/DebugSupport.h> // for MAX_ARM_EXCEPTION\r
+\r
+UINTN                   gMaxExceptionNumber = MAX_ARM_EXCEPTION;\r
+EFI_EXCEPTION_CALLBACK  gExceptionHandlers[MAX_ARM_EXCEPTION + 1] = { 0 };\r
+EFI_EXCEPTION_CALLBACK  gDebuggerExceptionHandlers[MAX_ARM_EXCEPTION + 1] = { 0 };\r
+PHYSICAL_ADDRESS        gExceptionVectorAlignmentMask = ARM_VECTOR_TABLE_ALIGNMENT;\r
+\r
+// Exception handler contains branch to vector location (jmp $) so no handler\r
+// NOTE: This code assumes vectors are ARM and not Thumb code\r
+UINTN                   gDebuggerNoHandlerValue = 0xEAFFFFFE;\r
+\r
+RETURN_STATUS ArchVectorConfig(\r
+  IN  UINTN       VectorBaseAddress\r
+  )\r
+{\r
+  // if the vector address corresponds to high vectors\r
+  if (VectorBaseAddress == 0xFFFF0000) {\r
+    // set SCTLR.V to enable high vectors\r
+    ArmSetHighVectors();\r
+  }\r
+  else {\r
+    // Set SCTLR.V to 0 to enable VBAR to be used\r
+    ArmSetLowVectors();\r
+  }\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
diff --git a/ArmPkg/Library/ArmExceptionLib/Arm/ExceptionSupport.S b/ArmPkg/Library/ArmExceptionLib/Arm/ExceptionSupport.S
new file mode 100644 (file)
index 0000000..fa4087c
--- /dev/null
@@ -0,0 +1,305 @@
+#------------------------------------------------------------------------------\r
+#\r
+# Use ARMv6 instruction to operate on a single stack\r
+#\r
+# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
+# Copyright (c) 2014, ARM Limited. All rights reserved.<BR>\r
+# Copyright (c) 2016 HP Development Company, L.P.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution.  The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#------------------------------------------------------------------------------\r
+\r
+#include <Library/PcdLib.h>\r
+\r
+/*\r
+\r
+This is the stack constructed by the exception handler (low address to high address)\r
+                # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM\r
+  Reg   Offset\r
+  ===   ======\r
+  R0    0x00    # stmfd     SP!,{R0-R12}\r
+  R1    0x04\r
+  R2    0x08\r
+  R3    0x0c\r
+  R4    0x10\r
+  R5    0x14\r
+  R6    0x18\r
+  R7    0x1c\r
+  R8    0x20\r
+  R9    0x24\r
+  R10   0x28\r
+  R11   0x2c\r
+  R12   0x30\r
+  SP    0x34    # reserved via subtraction 0x20 (32) from SP\r
+  LR    0x38\r
+  PC    0x3c\r
+  CPSR  0x40\r
+  DFSR  0x44\r
+  DFAR  0x48\r
+  IFSR  0x4c\r
+  IFAR  0x50\r
+\r
+  LR    0x54    # SVC Link register (we need to restore it)\r
+\r
+  LR    0x58    # pushed by srsfd\r
+  CPSR  0x5c\r
+\r
+ */\r
+\r
+\r
+GCC_ASM_EXPORT(ExceptionHandlersStart)\r
+GCC_ASM_EXPORT(ExceptionHandlersEnd)\r
+GCC_ASM_EXPORT(CommonExceptionEntry)\r
+GCC_ASM_EXPORT(AsmCommonExceptionEntry)\r
+GCC_ASM_EXPORT(CommonCExceptionHandler)\r
+\r
+.text\r
+.syntax unified\r
+#if !defined(__APPLE__)\r
+.fpu neon    @ makes vpush/vpop assemble\r
+#endif\r
+.align 5\r
+\r
+\r
+//\r
+// This code gets copied to the ARM vector table\r
+// ExceptionHandlersStart - ExceptionHandlersEnd gets copied\r
+//\r
+ASM_PFX(ExceptionHandlersStart):\r
+\r
+ASM_PFX(Reset):\r
+  b ASM_PFX(ResetEntry)\r
+\r
+ASM_PFX(UndefinedInstruction):\r
+  b ASM_PFX(UndefinedInstructionEntry)\r
+\r
+ASM_PFX(SoftwareInterrupt):\r
+  b ASM_PFX(SoftwareInterruptEntry)\r
+\r
+ASM_PFX(PrefetchAbort):\r
+  b ASM_PFX(PrefetchAbortEntry)\r
+\r
+ASM_PFX(DataAbort):\r
+  b ASM_PFX(DataAbortEntry)\r
+\r
+ASM_PFX(ReservedException):\r
+  b ASM_PFX(ReservedExceptionEntry)\r
+\r
+ASM_PFX(Irq):\r
+  b ASM_PFX(IrqEntry)\r
+\r
+ASM_PFX(Fiq):\r
+  b ASM_PFX(FiqEntry)\r
+\r
+ASM_PFX(ResetEntry):\r
+  srsdb     #0x13!                    @ Store return state on SVC stack\r
+                                      @ We are already in SVC mode\r
+\r
+  stmfd     SP!,{LR}                  @ Store the link register for the current mode\r
+  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              @ Store the register state\r
+\r
+  mov       R0,#0                     @ ExceptionType\r
+  ldr       R1,ASM_PFX(CommonExceptionEntry)\r
+  bx        R1\r
+\r
+ASM_PFX(UndefinedInstructionEntry):\r
+  sub       LR, LR, #4                @ Only -2 for Thumb, adjust in CommonExceptionEntry\r
+  srsdb     #0x13!                    @ Store return state on SVC stack\r
+  cps       #0x13                     @ Switch to SVC for common stack\r
+  stmfd     SP!,{LR}                  @ Store the link register for the current mode\r
+  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              @ Store the register state\r
+\r
+  mov       R0,#1                     @ ExceptionType\r
+  ldr       R1,ASM_PFX(CommonExceptionEntry)\r
+  bx        R1\r
+\r
+ASM_PFX(SoftwareInterruptEntry):\r
+  srsdb     #0x13!                    @ Store return state on SVC stack\r
+                                      @ We are already in SVC mode\r
+  stmfd     SP!,{LR}                  @ Store the link register for the current mode\r
+  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              @ Store the register state\r
+\r
+  mov       R0,#2                     @ ExceptionType\r
+  ldr       R1,ASM_PFX(CommonExceptionEntry)\r
+  bx        R1\r
+\r
+ASM_PFX(PrefetchAbortEntry):\r
+  sub       LR,LR,#4\r
+  srsdb     #0x13!                    @ Store return state on SVC stack\r
+  cps       #0x13                     @ Switch to SVC for common stack\r
+  stmfd     SP!,{LR}                  @ Store the link register for the current mode\r
+  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              @ Store the register state\r
+\r
+  mov       R0,#3                     @ ExceptionType\r
+  ldr       R1,ASM_PFX(CommonExceptionEntry)\r
+  bx        R1\r
+\r
+ASM_PFX(DataAbortEntry):\r
+  sub       LR,LR,#8\r
+  srsdb     #0x13!                    @ Store return state on SVC stack\r
+  cps       #0x13                     @ Switch to SVC for common stack\r
+  stmfd     SP!,{LR}                  @ Store the link register for the current mode\r
+  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              @ Store the register state\r
+\r
+  mov       R0,#4\r
+  ldr       R1,ASM_PFX(CommonExceptionEntry)\r
+  bx        R1\r
+\r
+ASM_PFX(ReservedExceptionEntry):\r
+  srsdb     #0x13!                    @ Store return state on SVC stack\r
+  cps       #0x13                     @ Switch to SVC for common stack\r
+  stmfd     SP!,{LR}                  @ Store the link register for the current mode\r
+  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              @ Store the register state\r
+\r
+  mov       R0,#5\r
+  ldr       R1,ASM_PFX(CommonExceptionEntry)\r
+  bx        R1\r
+\r
+ASM_PFX(IrqEntry):\r
+  sub       LR,LR,#4\r
+  srsdb     #0x13!                    @ Store return state on SVC stack\r
+  cps       #0x13                     @ Switch to SVC for common stack\r
+  stmfd     SP!,{LR}                  @ Store the link register for the current mode\r
+  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              @ Store the register state\r
+\r
+  mov       R0,#6                     @ ExceptionType\r
+  ldr       R1,ASM_PFX(CommonExceptionEntry)\r
+  bx        R1\r
+\r
+ASM_PFX(FiqEntry):\r
+  sub       LR,LR,#4\r
+  srsdb     #0x13!                    @ Store return state on SVC stack\r
+  cps       #0x13                     @ Switch to SVC for common stack\r
+  stmfd     SP!,{LR}                  @ Store the link register for the current mode\r
+  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              @ Store the register state\r
+                                      @ Since we have already switch to SVC R8_fiq - R12_fiq\r
+                                      @ never get used or saved\r
+  mov       R0,#7                     @ ExceptionType\r
+  ldr       R1,ASM_PFX(CommonExceptionEntry)\r
+  bx        R1\r
+\r
+//\r
+// This gets patched by the C code that patches in the vector table\r
+//\r
+ASM_PFX(CommonExceptionEntry):\r
+  .word       ASM_PFX(AsmCommonExceptionEntry)\r
+\r
+ASM_PFX(ExceptionHandlersEnd):\r
+\r
+//\r
+// This code runs from CpuDxe driver loaded address. It is patched into\r
+// CommonExceptionEntry.\r
+//\r
+ASM_PFX(AsmCommonExceptionEntry):\r
+  mrc       p15, 0, R1, c6, c0, 2   @ Read IFAR\r
+  str       R1, [SP, #0x50]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR\r
+\r
+  mrc       p15, 0, R1, c5, c0, 1   @ Read IFSR\r
+  str       R1, [SP, #0x4c]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR\r
+\r
+  mrc       p15, 0, R1, c6, c0, 0   @ Read DFAR\r
+  str       R1, [SP, #0x48]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR\r
+\r
+  mrc       p15, 0, R1, c5, c0, 0   @ Read DFSR\r
+  str       R1, [SP, #0x44]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR\r
+\r
+  ldr       R1, [SP, #0x5c]         @ srsdb saved pre-exception CPSR on the stack\r
+  str       R1, [SP, #0x40]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR\r
+\r
+  add       R2, SP, #0x38           @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR\r
+  and       R3, R1, #0x1f           @ Check CPSR to see if User or System Mode\r
+  cmp       R3, #0x1f               @ if ((CPSR == 0x10) || (CPSR == 0x1f))\r
+  cmpne     R3, #0x10               @\r
+  stmdaeq   R2, {lr}^               @   save unbanked lr\r
+                                    @ else\r
+  stmdane   R2, {lr}                @   save SVC lr\r
+\r
+\r
+  ldr       R5, [SP, #0x58]         @ PC is the LR pushed by srsfd\r
+                                    @ Check to see if we have to adjust for Thumb entry\r
+  sub       r4, r0, #1              @ if (ExceptionType == 1 || ExceptionType == 2)) {\r
+  cmp       r4, #1                  @   // UND & SVC have differnt LR adjust for Thumb\r
+  bhi       NoAdjustNeeded\r
+\r
+  tst       r1, #0x20               @   if ((CPSR & T)) == T) {  // Thumb Mode on entry\r
+  addne     R5, R5, #2              @     PC += 2;\r
+  strne     R5,[SP,#0x58]           @ Update LR value pushed by srsfd\r
+\r
+NoAdjustNeeded:\r
+\r
+  str       R5, [SP, #0x3c]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.PC\r
+\r
+  add       R1, SP, #0x60           @ We pushed 0x60 bytes on the stack\r
+  str       R1, [SP, #0x34]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.SP\r
+\r
+                                    @ R0 is ExceptionType\r
+  mov       R1,SP                   @ R1 is SystemContext\r
+\r
+#if (FixedPcdGet32(PcdVFPEnabled))\r
+  vpush     {d0-d15}                @ save vstm registers in case they are used in optimizations\r
+#endif\r
+\r
+  mov       R4, SP                  @ Save current SP\r
+  tst       R4, #4\r
+  subne     SP, SP, #4              @ Adjust SP if not 8-byte aligned\r
+\r
+/*\r
+VOID\r
+EFIAPI\r
+CommonCExceptionHandler (\r
+  IN     EFI_EXCEPTION_TYPE           ExceptionType,   R0\r
+  IN OUT EFI_SYSTEM_CONTEXT           SystemContext    R1\r
+  )\r
+\r
+*/\r
+  blx       ASM_PFX(CommonCExceptionHandler)  @ Call exception handler\r
+\r
+  mov       SP, R4                  @ Restore SP\r
+\r
+#if (FixedPcdGet32(PcdVFPEnabled))\r
+  vpop      {d0-d15}\r
+#endif\r
+\r
+  ldr       R1, [SP, #0x4c]         @ Restore EFI_SYSTEM_CONTEXT_ARM.IFSR\r
+  mcr       p15, 0, R1, c5, c0, 1   @ Write IFSR\r
+\r
+  ldr       R1, [SP, #0x44]         @ Restore EFI_SYSTEM_CONTEXT_ARM.DFSR\r
+  mcr       p15, 0, R1, c5, c0, 0   @ Write DFSR\r
+\r
+  ldr       R1,[SP,#0x3c]           @ EFI_SYSTEM_CONTEXT_ARM.PC\r
+  str       R1,[SP,#0x58]           @ Store it back to srsfd stack slot so it can be restored\r
+\r
+  ldr       R1,[SP,#0x40]           @ EFI_SYSTEM_CONTEXT_ARM.CPSR\r
+  str       R1,[SP,#0x5c]           @ Store it back to srsfd stack slot so it can be restored\r
+\r
+  add       R3, SP, #0x54           @ Make R3 point to SVC LR saved on entry\r
+  add       R2, SP, #0x38           @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR\r
+  and       R1, R1, #0x1f           @ Check to see if User or System Mode\r
+  cmp       R1, #0x1f               @ if ((CPSR == 0x10) || (CPSR == 0x1f))\r
+  cmpne     R1, #0x10               @\r
+  ldmibeq   R2, {lr}^               @   restore unbanked lr\r
+                                    @ else\r
+  ldmibne   R3, {lr}                @   restore SVC lr, via ldmfd SP!, {LR}\r
+\r
+  ldmfd     SP!,{R0-R12}            @ Restore general purpose registers\r
+                                    @ Exception handler can not change SP\r
+\r
+  add       SP,SP,#0x20             @ Clear out the remaining stack space\r
+  ldmfd     SP!,{LR}                @ restore the link register for this context\r
+  rfefd     SP!                     @ return from exception via srsfd stack slot\r
+\r
diff --git a/ArmPkg/Library/ArmExceptionLib/Arm/ExceptionSupport.asm b/ArmPkg/Library/ArmExceptionLib/Arm/ExceptionSupport.asm
new file mode 100644 (file)
index 0000000..848a54b
--- /dev/null
@@ -0,0 +1,302 @@
+//------------------------------------------------------------------------------\r
+//\r
+// Use ARMv6 instruction to operate on a single stack\r
+//\r
+// Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
+// Copyright (c) 2014, ARM Limited. All rights reserved.<BR>\r
+// Copyright (c) 2016 HP Development Company, L.P.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution.  The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+//------------------------------------------------------------------------------\r
+\r
+#include <Library/PcdLib.h>\r
+\r
+/*\r
+\r
+This is the stack constructed by the exception handler (low address to high address)\r
+                # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM\r
+  Reg   Offset\r
+  ===   ======\r
+  R0    0x00    # stmfd     SP!,{R0-R12}\r
+  R1    0x04\r
+  R2    0x08\r
+  R3    0x0c\r
+  R4    0x10\r
+  R5    0x14\r
+  R6    0x18\r
+  R7    0x1c\r
+  R8    0x20\r
+  R9    0x24\r
+  R10   0x28\r
+  R11   0x2c\r
+  R12   0x30\r
+  SP    0x34    # reserved via subtraction 0x20 (32) from SP\r
+  LR    0x38\r
+  PC    0x3c\r
+  CPSR  0x40\r
+  DFSR  0x44\r
+  DFAR  0x48\r
+  IFSR  0x4c\r
+  IFAR  0x50\r
+\r
+  LR    0x54    # SVC Link register (we need to restore it)\r
+\r
+  LR    0x58    # pushed by srsfd\r
+  CPSR  0x5c\r
+\r
+ */\r
+\r
+\r
+  EXPORT  ExceptionHandlersStart\r
+  EXPORT  ExceptionHandlersEnd\r
+  EXPORT  CommonExceptionEntry\r
+  EXPORT  AsmCommonExceptionEntry\r
+  IMPORT  CommonCExceptionHandler\r
+\r
+  PRESERVE8\r
+  AREA  DxeExceptionHandlers, CODE, READONLY, CODEALIGN, ALIGN=5\r
+\r
+//\r
+// This code gets copied to the ARM vector table\r
+// ExceptionHandlersStart - ExceptionHandlersEnd gets copied\r
+//\r
+ExceptionHandlersStart\r
+\r
+Reset\r
+  b   ResetEntry\r
+\r
+UndefinedInstruction\r
+  b   UndefinedInstructionEntry\r
+\r
+SoftwareInterrupt\r
+  b   SoftwareInterruptEntry\r
+\r
+PrefetchAbort\r
+  b   PrefetchAbortEntry\r
+\r
+DataAbort\r
+  b   DataAbortEntry\r
+\r
+ReservedException\r
+  b   ReservedExceptionEntry\r
+\r
+Irq\r
+  b   IrqEntry\r
+\r
+Fiq\r
+  b   FiqEntry\r
+\r
+ResetEntry\r
+  srsfd     #0x13!                    ; Store return state on SVC stack\r
+                                      ; We are already in SVC mode\r
+  stmfd     SP!,{LR}                  ; Store the link register for the current mode\r
+  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              ; Store the register state\r
+\r
+  mov       R0,#0                     ; ExceptionType\r
+  ldr       R1,CommonExceptionEntry\r
+  bx        R1\r
+\r
+UndefinedInstructionEntry\r
+  sub       LR, LR, #4                ; Only -2 for Thumb, adjust in CommonExceptionEntry\r
+  srsfd     #0x13!                    ; Store return state on SVC stack\r
+  cps       #0x13                     ; Switch to SVC for common stack\r
+  stmfd     SP!,{LR}                  ; Store the link register for the current mode\r
+  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              ; Store the register state\r
+\r
+  mov       R0,#1                     ; ExceptionType\r
+  ldr       R1,CommonExceptionEntry;\r
+  bx        R1\r
+\r
+SoftwareInterruptEntry\r
+  srsfd     #0x13!                    ; Store return state on SVC stack\r
+                                      ; We are already in SVC mode\r
+  stmfd     SP!,{LR}                  ; Store the link register for the current mode\r
+  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              ; Store the register state\r
+\r
+  mov       R0,#2                     ; ExceptionType\r
+  ldr       R1,CommonExceptionEntry\r
+  bx        R1\r
+\r
+PrefetchAbortEntry\r
+  sub       LR,LR,#4\r
+  srsfd     #0x13!                    ; Store return state on SVC stack\r
+  cps       #0x13                     ; Switch to SVC for common stack\r
+  stmfd     SP!,{LR}                  ; Store the link register for the current mode\r
+  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              ; Store the register state\r
+\r
+  mov       R0,#3                     ; ExceptionType\r
+  ldr       R1,CommonExceptionEntry\r
+  bx        R1\r
+\r
+DataAbortEntry\r
+  sub       LR,LR,#8\r
+  srsfd     #0x13!                    ; Store return state on SVC stack\r
+  cps       #0x13                     ; Switch to SVC for common stack\r
+  stmfd     SP!,{LR}                  ; Store the link register for the current mode\r
+  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              ; Store the register state\r
+\r
+  mov       R0,#4                     ; ExceptionType\r
+  ldr       R1,CommonExceptionEntry\r
+  bx        R1\r
+\r
+ReservedExceptionEntry\r
+  srsfd     #0x13!                    ; Store return state on SVC stack\r
+  cps       #0x13                     ; Switch to SVC for common stack\r
+  stmfd     SP!,{LR}                  ; Store the link register for the current mode\r
+  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              ; Store the register state\r
+\r
+  mov       R0,#5                     ; ExceptionType\r
+  ldr       R1,CommonExceptionEntry\r
+  bx        R1\r
+\r
+IrqEntry\r
+  sub       LR,LR,#4\r
+  srsfd     #0x13!                    ; Store return state on SVC stack\r
+  cps       #0x13                     ; Switch to SVC for common stack\r
+  stmfd     SP!,{LR}                  ; Store the link register for the current mode\r
+  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              ; Store the register state\r
+\r
+  mov       R0,#6                     ; ExceptionType\r
+  ldr       R1,CommonExceptionEntry\r
+  bx        R1\r
+\r
+FiqEntry\r
+  sub       LR,LR,#4\r
+  srsfd     #0x13!                    ; Store return state on SVC stack\r
+  cps       #0x13                     ; Switch to SVC for common stack\r
+  stmfd     SP!,{LR}                  ; Store the link register for the current mode\r
+  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR\r
+  stmfd     SP!,{R0-R12}              ; Store the register state\r
+                                      ; Since we have already switch to SVC R8_fiq - R12_fiq\r
+                                      ; never get used or saved\r
+  mov       R0,#7                     ; ExceptionType\r
+  ldr       R1,CommonExceptionEntry\r
+  bx        R1\r
+\r
+//\r
+// This gets patched by the C code that patches in the vector table\r
+//\r
+CommonExceptionEntry\r
+  dcd       AsmCommonExceptionEntry\r
+\r
+ExceptionHandlersEnd\r
+\r
+//\r
+// This code runs from CpuDxe driver loaded address. It is patched into\r
+// CommonExceptionEntry.\r
+//\r
+AsmCommonExceptionEntry\r
+  mrc       p15, 0, R1, c6, c0, 2   ; Read IFAR\r
+  str       R1, [SP, #0x50]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR\r
+\r
+  mrc       p15, 0, R1, c5, c0, 1   ; Read IFSR\r
+  str       R1, [SP, #0x4c]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR\r
+\r
+  mrc       p15, 0, R1, c6, c0, 0   ; Read DFAR\r
+  str       R1, [SP, #0x48]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR\r
+\r
+  mrc       p15, 0, R1, c5, c0, 0   ; Read DFSR\r
+  str       R1, [SP, #0x44]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR\r
+\r
+  ldr       R1, [SP, #0x5c]         ; srsfd saved pre-exception CPSR on the stack\r
+  str       R1, [SP, #0x40]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR\r
+\r
+  add       R2, SP, #0x38           ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR\r
+  and       R3, R1, #0x1f           ; Check CPSR to see if User or System Mode\r
+  cmp       R3, #0x1f               ; if ((CPSR == 0x10) || (CPSR == 0x1f))\r
+  cmpne     R3, #0x10               ;\r
+  stmeqed   R2, {lr}^               ;   save unbanked lr\r
+                                    ; else\r
+  stmneed   R2, {lr}                ;   save SVC lr\r
+\r
+\r
+  ldr       R5, [SP, #0x58]         ; PC is the LR pushed by srsfd\r
+                                    ; Check to see if we have to adjust for Thumb entry\r
+  sub       r4, r0, #1              ; if (ExceptionType == 1 || ExceptionType == 2)) {\r
+  cmp       r4, #1                  ;   // UND & SVC have differnt LR adjust for Thumb\r
+  bhi       NoAdjustNeeded\r
+\r
+  tst       r1, #0x20               ;   if ((CPSR & T)) == T) {  // Thumb Mode on entry\r
+  addne     R5, R5, #2              ;     PC += 2;\r
+  strne     R5,[SP,#0x58]           ; Update LR value pushed by srsfd\r
+\r
+NoAdjustNeeded\r
+\r
+  str       R5, [SP, #0x3c]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.PC\r
+\r
+  add       R1, SP, #0x60           ; We pushed 0x60 bytes on the stack\r
+  str       R1, [SP, #0x34]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.SP\r
+\r
+                                    ; R0 is ExceptionType\r
+  mov       R1,SP                   ; R1 is SystemContext\r
+\r
+#if (FixedPcdGet32(PcdVFPEnabled))\r
+  vpush    {d0-d15}                 ; save vstm registers in case they are used in optimizations\r
+#endif\r
+\r
+  mov       R4, SP                  ; Save current SP\r
+  tst       R4, #4\r
+  subne     SP, SP, #4              ; Adjust SP if not 8-byte aligned\r
+\r
+/*\r
+VOID\r
+EFIAPI\r
+CommonCExceptionHandler (\r
+  IN     EFI_EXCEPTION_TYPE           ExceptionType,   R0\r
+  IN OUT EFI_SYSTEM_CONTEXT           SystemContext    R1\r
+  )\r
+\r
+*/\r
+  blx       CommonCExceptionHandler ; Call exception handler\r
+\r
+  mov       SP, R4                  ; Restore SP\r
+\r
+#if (FixedPcdGet32(PcdVFPEnabled))\r
+  vpop      {d0-d15}\r
+#endif\r
+\r
+  ldr       R1, [SP, #0x4c]         ; Restore EFI_SYSTEM_CONTEXT_ARM.IFSR\r
+  mcr       p15, 0, R1, c5, c0, 1   ; Write IFSR\r
+\r
+  ldr       R1, [SP, #0x44]         ; Restore EFI_SYSTEM_CONTEXT_ARM.DFSR\r
+  mcr       p15, 0, R1, c5, c0, 0   ; Write DFSR\r
+\r
+  ldr       R1,[SP,#0x3c]           ; EFI_SYSTEM_CONTEXT_ARM.PC\r
+  str       R1,[SP,#0x58]           ; Store it back to srsfd stack slot so it can be restored\r
+\r
+  ldr       R1,[SP,#0x40]           ; EFI_SYSTEM_CONTEXT_ARM.CPSR\r
+  str       R1,[SP,#0x5c]           ; Store it back to srsfd stack slot so it can be restored\r
+\r
+  add       R3, SP, #0x54           ; Make R3 point to SVC LR saved on entry\r
+  add       R2, SP, #0x38           ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR\r
+  and       R1, R1, #0x1f           ; Check to see if User or System Mode\r
+  cmp       R1, #0x1f               ; if ((CPSR == 0x10) || (CPSR == 0x1f))\r
+  cmpne     R1, #0x10               ;\r
+  ldmeqed   R2, {lr}^               ;   restore unbanked lr\r
+                                    ; else\r
+  ldmneed   R3, {lr}                ;   restore SVC lr, via ldmfd SP!, {LR}\r
+\r
+  ldmfd     SP!,{R0-R12}            ; Restore general purpose registers\r
+                                    ; Exception handler can not change SP\r
+\r
+  add       SP,SP,#0x20             ; Clear out the remaining stack space\r
+  ldmfd     SP!,{LR}                ; restore the link register for this context\r
+  rfefd     SP!                     ; return from exception via srsfd stack slot\r
+\r
+  END\r
+\r
+\r
diff --git a/ArmPkg/Library/ArmExceptionLib/ArmExceptionLib.c b/ArmPkg/Library/ArmExceptionLib/ArmExceptionLib.c
new file mode 100644 (file)
index 0000000..5977a3e
--- /dev/null
@@ -0,0 +1,320 @@
+/* @file\r
+*  Main file supporting the SEC Phase for Versatile Express\r
+*\r
+*  Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
+*  Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
+*  Copyright (c) 2016 HP Development Company, L.P.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/CpuExceptionHandlerLib.h>\r
+\r
+#include <Library/ArmLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/CacheMaintenanceLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DefaultExceptionHandlerLib.h>\r
+\r
+RETURN_STATUS\r
+CopyExceptionHandlers(\r
+  IN  PHYSICAL_ADDRESS        BaseAddress\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterExceptionHandler(\r
+  IN EFI_EXCEPTION_TYPE            ExceptionType,\r
+  IN EFI_CPU_INTERRUPT_HANDLER     InterruptHandler\r
+  );\r
+\r
+VOID\r
+ExceptionHandlersStart(\r
+  VOID\r
+  );\r
+\r
+VOID\r
+ExceptionHandlersEnd(\r
+  VOID\r
+  );\r
+\r
+RETURN_STATUS ArchVectorConfig(\r
+  IN  UINTN       VectorBaseAddress\r
+  );\r
+\r
+// these globals are provided by the architecture specific source (Arm or AArch64)\r
+extern UINTN                    gMaxExceptionNumber;\r
+extern EFI_EXCEPTION_CALLBACK   gExceptionHandlers[];\r
+extern EFI_EXCEPTION_CALLBACK   gDebuggerExceptionHandlers[];\r
+extern PHYSICAL_ADDRESS         gExceptionVectorAlignmentMask;\r
+extern UINTN                    gDebuggerNoHandlerValue;\r
+\r
+// A compiler flag adjusts the compilation of this library to a variant where\r
+// the vectors are relocated (copied) to another location versus using the\r
+// vectors in-place.  Since this effects an assembly .align directive we must\r
+// address this at library build time.  Since this affects the build of the\r
+// library we cannot represent this in a PCD since PCDs are evaluated on\r
+// a per-module basis.\r
+#if defined(ARM_RELOCATE_VECTORS)\r
+BOOLEAN gArmRelocateVectorTable = TRUE;\r
+#else\r
+BOOLEAN gArmRelocateVectorTable = FALSE;\r
+#endif\r
+\r
+\r
+/**\r
+Initializes all CPU exceptions entries and provides the default exception handlers.\r
+\r
+Caller should try to get an array of interrupt and/or exception vectors that are in use and need to\r
+persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.\r
+If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.\r
+If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.\r
+\r
+@param[in]  VectorInfo    Pointer to reserved vector list.\r
+\r
+@retval EFI_SUCCESS           CPU Exception Entries have been successfully initialized\r
+with default exception handlers.\r
+@retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.\r
+@retval EFI_UNSUPPORTED       This function is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeCpuExceptionHandlers(\r
+  IN EFI_VECTOR_HANDOFF_INFO       *VectorInfo OPTIONAL\r
+  )\r
+{\r
+  RETURN_STATUS     Status;\r
+  UINTN             VectorBase;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  // if we are requested to copy exceptin handlers to another location\r
+  if (gArmRelocateVectorTable) {\r
+\r
+    VectorBase = PcdGet32(PcdCpuVectorBaseAddress);\r
+    Status = CopyExceptionHandlers(VectorBase);\r
+\r
+  }\r
+  else { // use VBAR to point to where our exception handlers are\r
+\r
+    // The vector table must be aligned for the architecture.  If this\r
+    // assertion fails ensure the appropriate FFS alignment is in effect,\r
+    // which can be accomplished by ensuring the proper Align=X statement\r
+    // in the platform packaging rules.  For ARM Align=32 is required and\r
+    // for AArch64 Align=4K is required.  Align=Auto can be used but this\r
+    // is known to cause an issue with populating the reset vector area\r
+    // for encapsulated FVs.\r
+    ASSERT(((UINTN)ExceptionHandlersStart & gExceptionVectorAlignmentMask) == 0);\r
+\r
+    // We do not copy the Exception Table at PcdGet32(PcdCpuVectorBaseAddress). We just set Vector\r
+    // Base Address to point into CpuDxe code.\r
+    VectorBase = (UINTN)ExceptionHandlersStart;\r
+\r
+    Status = RETURN_SUCCESS;\r
+  }\r
+\r
+  if (!RETURN_ERROR(Status)) {\r
+    // call the architecture-specific routine to prepare for the new vector\r
+    // configuration to take effect\r
+    ArchVectorConfig(VectorBase);\r
+\r
+    ArmWriteVBar(VectorBase);\r
+  }\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+Copies exception handlers to the speciifed address.\r
+\r
+Caller should try to get an array of interrupt and/or exception vectors that are in use and need to\r
+persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.\r
+If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.\r
+If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.\r
+\r
+@param[in]  VectorInfo    Pointer to reserved vector list.\r
+\r
+@retval EFI_SUCCESS           CPU Exception Entries have been successfully initialized\r
+with default exception handlers.\r
+@retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.\r
+@retval EFI_UNSUPPORTED       This function is not supported.\r
+\r
+**/\r
+RETURN_STATUS\r
+CopyExceptionHandlers(\r
+  IN  PHYSICAL_ADDRESS        BaseAddress\r
+  )\r
+{\r
+  RETURN_STATUS        Status;\r
+  UINTN                Length;\r
+  UINTN                Index;\r
+  UINT32               *VectorBase;\r
+\r
+  // ensure that the destination value specifies an address meeting the vector alignment requirements\r
+  ASSERT ((BaseAddress & gExceptionVectorAlignmentMask) == 0);\r
+\r
+  //\r
+  // Copy an implementation of the exception vectors to PcdCpuVectorBaseAddress.\r
+  //\r
+  Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;\r
+\r
+  VectorBase = (UINT32 *)(UINTN)BaseAddress;\r
+\r
+  if (FeaturePcdGet(PcdDebuggerExceptionSupport) == TRUE) {\r
+    // Save existing vector table, in case debugger is already hooked in\r
+    CopyMem((VOID *)gDebuggerExceptionHandlers, (VOID *)VectorBase, sizeof (EFI_EXCEPTION_CALLBACK)* (gMaxExceptionNumber+1));\r
+  }\r
+\r
+  // Copy our assembly code into the page that contains the exception vectors.\r
+  CopyMem((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length);\r
+\r
+  //\r
+  // Initialize the C entry points for interrupts\r
+  //\r
+  for (Index = 0; Index <= gMaxExceptionNumber; Index++) {\r
+    if (!FeaturePcdGet(PcdDebuggerExceptionSupport) ||\r
+      (gDebuggerExceptionHandlers[Index] == 0) || (gDebuggerExceptionHandlers[Index] == (VOID *)gDebuggerNoHandlerValue)) {\r
+\r
+      Status = RegisterExceptionHandler(Index, NULL);\r
+      ASSERT_EFI_ERROR(Status);\r
+    }\r
+    else {\r
+      // If the debugger has already hooked put its vector back\r
+      VectorBase[Index] = (UINT32)(UINTN)gDebuggerExceptionHandlers[Index];\r
+    }\r
+  }\r
+\r
+  // Flush Caches since we updated executable stuff\r
+  InvalidateInstructionCacheRange((VOID *)(UINTN)BaseAddress, Length);\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers.\r
+\r
+Caller should try to get an array of interrupt and/or exception vectors that are in use and need to\r
+persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.\r
+If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.\r
+If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.\r
+\r
+@param[in]  VectorInfo    Pointer to reserved vector list.\r
+\r
+@retval EFI_SUCCESS           All CPU interrupt/exception entries have been successfully initialized\r
+with default interrupt/exception handlers.\r
+@retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.\r
+@retval EFI_UNSUPPORTED       This function is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeCpuInterruptHandlers(\r
+IN EFI_VECTOR_HANDOFF_INFO       *VectorInfo OPTIONAL\r
+)\r
+{\r
+  // not needed, this is what the CPU driver is for\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+Registers a function to be called from the processor exception handler. (On ARM/AArch64 this only\r
+provides exception handlers, not interrupt handling which is provided through the Hardware Interrupt\r
+Protocol.)\r
+\r
+This function registers and enables the handler specified by ExceptionHandler for a processor\r
+interrupt or exception type specified by ExceptionType. If ExceptionHandler is NULL, then the\r
+handler for the processor interrupt or exception type specified by ExceptionType is uninstalled.\r
+The installed handler is called once for each processor interrupt or exception.\r
+NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or\r
+InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned.\r
+\r
+@param[in]  ExceptionType     Defines which interrupt or exception to hook.\r
+@param[in]  ExceptionHandler  A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called\r
+when a processor interrupt occurs. If this parameter is NULL, then the handler\r
+will be uninstalled.\r
+\r
+@retval EFI_SUCCESS           The handler for the processor interrupt was successfully installed or uninstalled.\r
+@retval EFI_ALREADY_STARTED   ExceptionHandler is not NULL, and a handler for ExceptionType was\r
+previously installed.\r
+@retval EFI_INVALID_PARAMETER ExceptionHandler is NULL, and a handler for ExceptionType was not\r
+previously installed.\r
+@retval EFI_UNSUPPORTED       The interrupt specified by ExceptionType is not supported,\r
+or this function is not supported.\r
+**/\r
+RETURN_STATUS\r
+RegisterCpuInterruptHandler(\r
+  IN EFI_EXCEPTION_TYPE             ExceptionType,\r
+  IN EFI_CPU_INTERRUPT_HANDLER      ExceptionHandler\r
+  ) {\r
+  if (ExceptionType > gMaxExceptionNumber) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  if ((ExceptionHandler != NULL) && (gExceptionHandlers[ExceptionType] != NULL)) {\r
+    return RETURN_ALREADY_STARTED;\r
+  }\r
+\r
+  gExceptionHandlers[ExceptionType] = ExceptionHandler;\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+Register exception handler.\r
+\r
+@param  This                  A pointer to the SMM_CPU_SERVICE_PROTOCOL instance.\r
+@param  ExceptionType         Defines which interrupt or exception to hook. Type EFI_EXCEPTION_TYPE and\r
+the valid values for this parameter are defined in EFI_DEBUG_SUPPORT_PROTOCOL\r
+of the UEFI 2.0 specification.\r
+@param  InterruptHandler      A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER\r
+that is called when a processor interrupt occurs.\r
+If this parameter is NULL, then the handler will be uninstalled.\r
+\r
+@retval EFI_SUCCESS           The handler for the processor interrupt was successfully installed or uninstalled.\r
+@retval EFI_ALREADY_STARTED   InterruptHandler is not NULL, and a handler for InterruptType was previously installed.\r
+@retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not previously installed.\r
+@retval EFI_UNSUPPORTED       The interrupt specified by InterruptType is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterExceptionHandler(\r
+  IN EFI_EXCEPTION_TYPE            ExceptionType,\r
+  IN EFI_CPU_INTERRUPT_HANDLER     InterruptHandler\r
+  )\r
+{\r
+  return RegisterCpuInterruptHandler(ExceptionType, InterruptHandler);\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+CommonCExceptionHandler(\r
+  IN     EFI_EXCEPTION_TYPE           ExceptionType,\r
+  IN OUT EFI_SYSTEM_CONTEXT           SystemContext\r
+  )\r
+{\r
+  if (ExceptionType <= gMaxExceptionNumber) {\r
+    if (gExceptionHandlers[ExceptionType]) {\r
+      gExceptionHandlers[ExceptionType](ExceptionType, SystemContext);\r
+      return;\r
+    }\r
+  }\r
+  else {\r
+    DEBUG((EFI_D_ERROR, "Unknown exception type %d\n", ExceptionType));\r
+    ASSERT(FALSE);\r
+  }\r
+\r
+  DefaultExceptionHandler(ExceptionType, SystemContext);\r
+}\r
diff --git a/ArmPkg/Library/ArmExceptionLib/ArmExceptionLib.inf b/ArmPkg/Library/ArmExceptionLib/ArmExceptionLib.inf
new file mode 100644 (file)
index 0000000..10d9ae0
--- /dev/null
@@ -0,0 +1,63 @@
+## @file\r
+# Instance of CpuExceptionHandlerLib Library for ARM/AArch64 architectures\r
+#\r
+# This library instance is used for modules that will implement exception\r
+# handlers in-place (by programming VBAR).  The exception handlers will be\r
+# generated with alignment as required by the processor architecture.  The\r
+# alignment must be propagated into the parent FFS/FV through FDF build rules\r
+# for the relevant module types (i.e. Align=Auto).\r
+#\r
+# Note that using this library instance can cause growth to the size of the FV\r
+# due to the padding added by the build tools to meet the vector alignment\r
+# requirements and may not be desirable for space-sensitive FVs (uncompressed /\r
+# XIP components).  The alternative library instance, ArmRelocateExceptionLib\r
+# should be considered for these applications.\r
+#\r
+#  Copyright (c) 2011-2012, ARM Limited. All rights reserved.\r
+#  Copyright (c) 2016 HP Development Company, L.P.\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution.  The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = ArmExceptionLib\r
+  FILE_GUID                      = A9796991-4E88-47F0-87C5-D96A1D270539\r
+  MODULE_TYPE                    = BASE\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = CpuExceptionHandlerLib\r
+\r
+[Sources.common]\r
+  ArmExceptionLib.c\r
+\r
+[Sources.Arm]\r
+  Arm/ArmException.c\r
+  Arm/ExceptionSupport.asm | RVCT\r
+  Arm/ExceptionSupport.S   | GCC\r
+\r
+[Sources.AARCH64]\r
+  AArch64/AArch64Exception.c\r
+  AArch64/ExceptionSupport.S\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  ArmPkg/ArmPkg.dec\r
+\r
+[LibraryClasses]\r
+  ArmLib\r
+  DebugLib\r
+  DefaultExceptionHandlerLib\r
+  BaseMemoryLib\r
+  CacheMaintenanceLib\r
+\r
+[Pcd]\r
+  gArmTokenSpaceGuid.PcdDebuggerExceptionSupport\r
+  gArmTokenSpaceGuid.PcdCpuVectorBaseAddress\r
diff --git a/ArmPkg/Library/ArmExceptionLib/ArmRelocateExceptionLib.inf b/ArmPkg/Library/ArmExceptionLib/ArmRelocateExceptionLib.inf
new file mode 100644 (file)
index 0000000..340812b
--- /dev/null
@@ -0,0 +1,65 @@
+## @file\r
+# Instance of CpuExceptionHandlerLib Library for ARM/AArch64 architectures\r
+#\r
+# This library instance is used when exception vectors must be relocated to\r
+# a specific address.  The address is specified by PcdCpuVectorBaseAddress.\r
+# Since the alignment requirement for in-place exception handlers causes\r
+# image size to increase, this instance is useful for modules that need to\r
+# minimize space used in their FV (like XIP modules).  See ArmExceptionLib.inf\r
+# for the in-place exception handler alternative.\r
+#\r
+#  Copyright (c) 2011-2012, ARM Limited. All rights reserved.\r
+#  Copyright (c) 2016 HP Development Company, L.P.\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution.  The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = ArmRelocateExceptionLib\r
+  FILE_GUID                      = 62AA447A-1FBA-429E-9E0D-CE0D2D8DCF58\r
+  MODULE_TYPE                    = BASE\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = CpuExceptionHandlerLib\r
+\r
+[Sources.common]\r
+  ArmExceptionLib.c\r
+\r
+[Sources.Arm]\r
+  Arm/ArmException.c\r
+  Arm/ExceptionSupport.asm | RVCT\r
+  Arm/ExceptionSupport.S   | GCC\r
+\r
+[Sources.AARCH64]\r
+  AArch64/AArch64Exception.c\r
+  AArch64/ExceptionSupport.S\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  ArmPkg/ArmPkg.dec\r
+\r
+[LibraryClasses]\r
+  ArmLib\r
+  DebugLib\r
+  DefaultExceptionHandlerLib\r
+  BaseMemoryLib\r
+  CacheMaintenanceLib\r
+\r
+[Pcd]\r
+  gArmTokenSpaceGuid.PcdDebuggerExceptionSupport\r
+  gArmTokenSpaceGuid.PcdCpuVectorBaseAddress\r
+\r
+[BuildOptions]\r
+  # We must pass a define to specify that we are relocating vectors so the\r
+  # vector alignment is relaxed (space savings); note that this must be done\r
+  # as a define and not a PCD since it affects assembly directives.\r
+  *_*_*_PP_FLAGS = -DARM_RELOCATE_VECTORS\r
+  *_*_*_CC_FLAGS = -DARM_RELOCATE_VECTORS\r