From c5d244956ea4c3304105556d0827bbea83264c50 Mon Sep 17 00:00:00 2001
From: Mikhail Krichanov <mikhailkrichanov@gmail.com>
Date: Thu, 23 May 2024 20:46:54 +0300
Subject: [PATCH] Ring3: Defined SysCallReturnToCore for AARCH64, forbade
 ExceptionHanlders to use EL0 stack.

---
 .../AArch64/ExceptionSupport.S                | 27 ++---------------
 .../Dxe/SysCall/AARCH64/CoreBootServices.S    | 30 +++++++++++++++----
 .../Core/Dxe/SysCall/AARCH64/InitializeMsr.c  |  8 +++--
 MdeModulePkg/Core/Dxe/SysCall/BootServices.c  | 13 ++++++++
 4 files changed, 47 insertions(+), 31 deletions(-)

diff --git a/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S b/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S
index aeb1475075..fbdccb921a 100644
--- a/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S
+++ b/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S
@@ -116,23 +116,7 @@ ASM_PFX(ExceptionHandlersStart):
 VECTOR_BASE(ExceptionHandlersStart)
 #endif
 
-  .macro  ExceptionEntry, val, sp=SPx
-  //
-  // Our backtrace and register dump code is written in C and so it requires
-  // a stack. This makes it difficult to produce meaningful diagnostics when
-  // the stack pointer has been corrupted. So in such cases (i.e., when taking
-  // synchronous exceptions), this macro is expanded with \sp set to SP0, in
-  // which case we switch to the SP_EL0 stack pointer, which has been
-  // initialized to point to a buffer that has been set aside for this purpose.
-  //
-  // Since 'sp' may no longer refer to the stack frame that was active when
-  // the exception was taken, we may have to switch back and forth between
-  // SP_EL0 and SP_ELx to record the correct value for SP in the context struct.
-  //
-  .ifnc   \sp, SPx
-  msr     SPsel, xzr
-  .endif
-
+  .macro  ExceptionEntry, val
   // Move the stackpointer so we can reach our structure with the str instruction.
   sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
 
@@ -154,13 +138,7 @@ VECTOR_BASE(ExceptionHandlersStart)
   stp      x28, x29, [sp, #0xe0]
   add      x28, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
 
-  .ifnc    \sp, SPx
-  msr      SPsel, #1
-  mov      x7, sp
-  msr      SPsel, xzr
-  .else
   mov      x7, x28
-  .endif
 
   stp      x30,  x7, [sp, #0xf0]
 
@@ -201,7 +179,7 @@ ASM_PFX(SErrorSP0):
 //
 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPX_SYNC)
 ASM_PFX(SynchronousExceptionSPx):
-  ExceptionEntry  EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS, SP0
+  ExceptionEntry  EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
 
 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPX_IRQ)
 ASM_PFX(IrqSPx):
@@ -343,6 +321,7 @@ ASM_PFX(CommonExceptionEntry):
   b        continue
 is_SVC:
   ldr      x1, [sp, #0x8]
+  add      sp, sp, #0xe0
 continue:
 
   // Pop FP regs from Stack.
diff --git a/MdeModulePkg/Core/Dxe/SysCall/AARCH64/CoreBootServices.S b/MdeModulePkg/Core/Dxe/SysCall/AARCH64/CoreBootServices.S
index b6eef51714..c6cc39d265 100644
--- a/MdeModulePkg/Core/Dxe/SysCall/AARCH64/CoreBootServices.S
+++ b/MdeModulePkg/Core/Dxe/SysCall/AARCH64/CoreBootServices.S
@@ -30,18 +30,22 @@ ASM_FUNC(CallInstallMultipleProtocolInterfaces)
 //   (x0) Data
 //   (x1) gRing3CallStackTop
 //   (x2) gRing3EntryPoint
+//   (x3) gCoreSysCallStackTop
+//   (x4) &CoreSp
 //------------------------------------------------------------------------------
 ASM_FUNC(ArmCallRing3)
+  // Save FP and LR on Core Stack.
+  stp	x29, x30, [sp, #-0x10]!
   // Disable interrupts
   msr  daifset, #0xf
   isb
-
-  // Use SP_ELx for Exception level ELx.
-  msr  SPsel, #1
-
+  // Prepare Ring3 SP and EntryPoint.
   msr  sp_el0, x1
-
   msr  elr_el1, x2
+  // Save Core SP and switch to Ring3Call Stack.
+  mov  x5, sp
+  str  x5, [x4]
+  mov  sp, x3
 
   // Copy PSTATE to SPSR.
   mrs  x1, nzcv
@@ -61,3 +65,19 @@ ASM_FUNC(ArmCallRing3)
   dsb sy
 
   eret
+
+//------------------------------------------------------------------------------
+// VOID
+// EFIAPI
+// ReturnToCore (
+//   IN EFI_STATUS Status,
+//   IN UINTN      CoreSp
+//   );
+//------------------------------------------------------------------------------
+ASM_FUNC(ReturnToCore)
+  // Switch to Core Stack.
+  mov  sp, x1
+  // Restore Stack.
+  ldp	 x29, x30, [sp]
+  add	 sp, sp, #0x10
+  ret
diff --git a/MdeModulePkg/Core/Dxe/SysCall/AARCH64/InitializeMsr.c b/MdeModulePkg/Core/Dxe/SysCall/AARCH64/InitializeMsr.c
index 0510fc5957..6db895d8de 100644
--- a/MdeModulePkg/Core/Dxe/SysCall/AARCH64/InitializeMsr.c
+++ b/MdeModulePkg/Core/Dxe/SysCall/AARCH64/InitializeMsr.c
@@ -10,12 +10,16 @@
 
 #include "DxeMain.h"
 
+extern UINTN  CoreSp;
+
 EFI_STATUS
 EFIAPI
 ArmCallRing3 (
   IN RING3_CALL_DATA *Data,
   IN VOID            *StackPointer,
-  IN VOID            *EntryPoint
+  IN VOID            *EntryPoint,
+  IN VOID            *SysCallStack,
+  IN VOID            *CoreStack
   );
 
 VOID
@@ -74,5 +78,5 @@ CallRing3 (
   IN RING3_CALL_DATA *Data
   )
 {
-  return ArmCallRing3 (Data, gRing3CallStackTop, gRing3EntryPoint);
+  return ArmCallRing3 (Data, gRing3CallStackTop, gRing3EntryPoint, gCoreSysCallStackTop, &CoreSp);
 }
diff --git a/MdeModulePkg/Core/Dxe/SysCall/BootServices.c b/MdeModulePkg/Core/Dxe/SysCall/BootServices.c
index 508fe4fba6..061ac97855 100644
--- a/MdeModulePkg/Core/Dxe/SysCall/BootServices.c
+++ b/MdeModulePkg/Core/Dxe/SysCall/BootServices.c
@@ -8,6 +8,8 @@
 #include "DxeMain.h"
 #include "SupportedProtocols.h"
 
+UINTN  CoreSp;
+
 LIST_ENTRY mProtocolsHead = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolsHead);
 
 typedef struct {
@@ -65,6 +67,13 @@ CallInstallMultipleProtocolInterfaces (
   IN VOID        *Function
   );
 
+VOID
+EFIAPI
+ReturnToCore (
+  IN EFI_STATUS Status,
+  IN UINTN      CoreSp
+  );
+
 VOID
 EFIAPI
 FreeProtocolsList (
@@ -1403,6 +1412,10 @@ SysCallBootService (
   EFI_STATUS              Status;
   EFI_PHYSICAL_ADDRESS    Physical;
 
+  if (Type == SysCallReturnToCore) {
+    ReturnToCore (*(EFI_STATUS *)CoreRbp, CoreSp);
+  }
+
   Status = CoreAllocatePages (
              AllocateAnyPages,
              EfiRing3MemoryType,