From aa4cf2ef963fe7eb0ba7a70bb7230bdde4edb6e8 Mon Sep 17 00:00:00 2001
From: oliviermartin <oliviermartin>
Date: Wed, 23 Apr 2014 16:47:13 +0000
Subject: [PATCH] ArmPkg/CpuDxe: Restore AArch64 system registers before
 returning from exception

Current EDK2 source code does actually trigger nested interrupted (even if
the PI spec says interrupt should not be nested).
This issue has highlighted the lack of restoring ELR_EL2/ELR_EL1 register.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off: Vijayakumar Subbu <vsubbu@nvidia.com>
Signed-off: Olivier Martin <olivier.martin@arm.com>


git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15481 6f19259b-4bc3-4df7-8a09-765794883524
---
 .../Drivers/CpuDxe/AArch64/ExceptionSupport.S | 21 +++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/ArmPkg/Drivers/CpuDxe/AArch64/ExceptionSupport.S b/ArmPkg/Drivers/CpuDxe/AArch64/ExceptionSupport.S
index a67477df83..8e2b37640f 100644
--- a/ArmPkg/Drivers/CpuDxe/AArch64/ExceptionSupport.S
+++ b/ArmPkg/Drivers/CpuDxe/AArch64/ExceptionSupport.S
@@ -1,5 +1,6 @@
 //
 // Copyright (c) 2011 - 2013 ARM LTD. All rights reserved.<BR>
+// Portion of Copyright (c) 2014 NVIDIA Corporation. All rights reserved.<BR>
 //
 // This program and the accompanying materials
 // are licensed and made available under the terms and conditions of the BSD License
@@ -358,9 +359,25 @@ ASM_PFX(AsmCommonExceptionEntry):
 
 #define REG_ONE(REG1, OFFSET, CONTEXT_SIZE)           ldr REG1, [sp, #(OFFSET-CONTEXT_SIZE)]
 
+  // Adjust SP to pop system registers
+  add     sp, sp, GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE
+  ALL_SYS_REGS
 
-  // pop all regs and return from exception.
-  add      sp, sp, GP_CONTEXT_SIZE
+  EL1_OR_EL2(x6)
+1:msr      elr_el1, x1   // Exception Link Register
+  msr      spsr_el1,x2   // Saved Processor Status Register 32bit
+  msr      fpsr, x3      // Floating point Status Register  32bit
+  msr      esr_el1, x4   // EL1 Exception syndrome register 32bit
+  msr      far_el1, x5   // EL1 Fault Address Register
+  b        3f
+2:msr      elr_el2, x1   // Exception Link Register
+  msr      spsr_el2,x2   // Saved Processor Status Register 32bit
+  msr      fpsr, x3      // Floating point Status Register  32bit
+  msr      esr_el2, x4   // EL1 Exception syndrome register 32bit
+  msr      far_el2, x5   // EL1 Fault Address Register
+
+3:// pop all regs and return from exception.
+  sub     sp, sp, FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE
   ALL_GP_REGS
 
   // Adjust SP to pop next set