From 54d7a130ec482a93fc64e927862b79bb16dc31e5 Mon Sep 17 00:00:00 2001
From: Mikhail Krichanov <mikhailkrichanov@gmail.com>
Date: Thu, 4 Jul 2024 17:21:51 +0300
Subject: [PATCH] Ring3: Added PAN support for ARM.

---
 ArmPkg/Include/Chipset/ArmV7.h                |  3 ++
 ArmPkg/Include/Library/ArmLib.h               | 24 +++++------
 ArmPkg/Library/ArmLib/Arm/ArmLibSupportV7.S   |  4 ++
 ArmPkg/Library/ArmLib/Arm/ArmV7Lib.c          | 15 +++++++
 ArmPkg/Library/ArmLib/Arm/ArmV7Lib.h          | 10 +++++
 .../Arm/DefaultExceptionHandler.c             |  5 ++-
 .../Core/Dxe/SysCall/ARM/CoreBootServices.S   | 42 ++++++++++---------
 .../Core/Dxe/SysCall/ARM/InitializeMsr.c      | 42 ++++++++++++++++++-
 8 files changed, 112 insertions(+), 33 deletions(-)

diff --git a/ArmPkg/Include/Chipset/ArmV7.h b/ArmPkg/Include/Chipset/ArmV7.h
index 94620c087d..a8db422b93 100644
--- a/ArmPkg/Include/Chipset/ArmV7.h
+++ b/ArmPkg/Include/Chipset/ArmV7.h
@@ -20,6 +20,9 @@
 #define ARM_PFR1_TIMER  (0xFUL << 16)
 #define ARM_PFR1_GIC    (0xFUL << 28)
 
+// ID_MMFR3 - ARM Memory Model Feature Register 3 definitions
+#define ARM_MMFR3_PAN   (0xFUL << 16)
+
 // Domain Access Control Register
 #define DOMAIN_ACCESS_CONTROL_MASK(a)      (3UL << (2 * (a)))
 #define DOMAIN_ACCESS_CONTROL_NONE(a)      (0UL << (2 * (a)))
diff --git a/ArmPkg/Include/Library/ArmLib.h b/ArmPkg/Include/Library/ArmLib.h
index e13f36ce53..fb9a8646f7 100644
--- a/ArmPkg/Include/Library/ArmLib.h
+++ b/ArmPkg/Include/Library/ArmLib.h
@@ -764,6 +764,18 @@ ArmHasCcidx (
   VOID
   );
 
+/**
+  Checks whether the CPU implements the Privileged Access Never.
+
+  @retval TRUE  FEAT_PAN is implemented.
+  @retval FALSE FEAT_PAN is not mplemented.
+**/
+BOOLEAN
+EFIAPI
+ArmHasPan (
+  VOID
+  );
+
 #ifdef MDE_CPU_AARCH64
 ///
 /// AArch64-only ID Register Helper functions
@@ -781,18 +793,6 @@ ArmHasVhe (
   VOID
   );
 
-/**
-  Checks whether the CPU implements the Privileged Access Never.
-
-  @retval TRUE  FEAT_PAN is implemented.
-  @retval FALSE FEAT_PAN is not mplemented.
-**/
-BOOLEAN
-EFIAPI
-ArmHasPan (
-  VOID
-  );
-
 /**
   Checks whether the CPU implements the Trace Buffer Extension.
 
diff --git a/ArmPkg/Library/ArmLib/Arm/ArmLibSupportV7.S b/ArmPkg/Library/ArmLib/Arm/ArmLibSupportV7.S
index d843f91dfc..d1558c3cec 100644
--- a/ArmPkg/Library/ArmLib/Arm/ArmLibSupportV7.S
+++ b/ArmPkg/Library/ArmLib/Arm/ArmLibSupportV7.S
@@ -64,6 +64,10 @@ ASM_FUNC(ArmReadIdMmfr4)
   mrc    p15,0,r0,c0,c2,6     @ Read ID_MMFR4 Register
   bx     lr
 
+ASM_FUNC(ArmReadIdMmfr3)
+  mrc    p15,0,r0,c0,c1,7     @ Read ID_MMFR3 Register
+  bx     lr
+
 // UINTN
 // ReadCCSIDR (
 //   IN UINT32 CSSELR
diff --git a/ArmPkg/Library/ArmLib/Arm/ArmV7Lib.c b/ArmPkg/Library/ArmLib/Arm/ArmV7Lib.c
index 521d5be0de..2775f24fbd 100644
--- a/ArmPkg/Library/ArmLib/Arm/ArmV7Lib.c
+++ b/ArmPkg/Library/ArmLib/Arm/ArmV7Lib.c
@@ -119,3 +119,18 @@ ArmHasCcidx (
   Mmfr4 = ArmReadIdMmfr4 ();
   return (((Mmfr4 >> 24) & 0xF) == 1) ? TRUE : FALSE;
 }
+
+/**
+  Checks whether the CPU implements the Privileged Access Never.
+
+  @retval TRUE  FEAT_PAN is implemented.
+  @retval FALSE FEAT_PAN is not mplemented.
+**/
+BOOLEAN
+EFIAPI
+ArmHasPan (
+  VOID
+  )
+{
+  return ((ArmReadIdMmfr3 () & ARM_MMFR3_PAN) != 0);
+}
diff --git a/ArmPkg/Library/ArmLib/Arm/ArmV7Lib.h b/ArmPkg/Library/ArmLib/Arm/ArmV7Lib.h
index 404ff92c4e..9e033cfd3d 100644
--- a/ArmPkg/Library/ArmLib/Arm/ArmV7Lib.h
+++ b/ArmPkg/Library/ArmLib/Arm/ArmV7Lib.h
@@ -60,6 +60,16 @@ ArmReadIdMmfr4 (
   VOID
   );
 
+/** Reads the ID_MMFR3 register.
+
+   @return The contents of the ID_MMFR3 register.
+**/
+UINT32
+EFIAPI
+ArmReadIdMmfr3 (
+  VOID
+  );
+
 UINTN
 EFIAPI
 ArmReadIdPfr1 (
diff --git a/ArmPkg/Library/DefaultExceptionHandlerLib/Arm/DefaultExceptionHandler.c b/ArmPkg/Library/DefaultExceptionHandlerLib/Arm/DefaultExceptionHandler.c
index 653035daa8..006db6d517 100644
--- a/ArmPkg/Library/DefaultExceptionHandlerLib/Arm/DefaultExceptionHandler.c
+++ b/ArmPkg/Library/DefaultExceptionHandlerLib/Arm/DefaultExceptionHandler.c
@@ -197,7 +197,8 @@ STATIC CHAR8  *gExceptionTypeString[] = {
 
 
 **/
-VOID
+EFI_STATUS
+EFIAPI
 DefaultExceptionHandler (
   IN     EFI_EXCEPTION_TYPE  ExceptionType,
   IN OUT EFI_SYSTEM_CONTEXT  SystemContext
@@ -316,4 +317,6 @@ DefaultExceptionHandler (
 
   // If some one is stepping past the exception handler adjust the PC to point to the next instruction
   SystemContext.SystemContextArm->PC += PcAdjust;
+
+  return EFI_SUCCESS;
 }
diff --git a/MdeModulePkg/Core/Dxe/SysCall/ARM/CoreBootServices.S b/MdeModulePkg/Core/Dxe/SysCall/ARM/CoreBootServices.S
index 406a7f66cf..90b000fc0d 100644
--- a/MdeModulePkg/Core/Dxe/SysCall/ARM/CoreBootServices.S
+++ b/MdeModulePkg/Core/Dxe/SysCall/ARM/CoreBootServices.S
@@ -7,25 +7,7 @@
 
 #include <AsmMacroIoLib.h>
 
-//------------------------------------------------------------------------------
-// VOID
-// EFIAPI
-// DisableSMAP (
-//   VOID
-//   );
-//------------------------------------------------------------------------------
-ASM_FUNC(DisableSMAP)
-    bx    LR
-
-//------------------------------------------------------------------------------
-// VOID
-// EFIAPI
-// EnableSMAP (
-//   VOID
-//   );
-//------------------------------------------------------------------------------
-ASM_FUNC(EnableSMAP)
-    bx    LR
+.arch armv8.1a
 
 //------------------------------------------------------------------------------
 // EFI_STATUS
@@ -71,3 +53,25 @@ ASM_FUNC(CoreBootServices)
 //------------------------------------------------------------------------------
 ASM_FUNC(CallRing3)
     bx    LR
+
+//------------------------------------------------------------------------------
+// VOID
+// EFIAPI
+// ArmSetPan (
+//   VOID
+//   );
+//------------------------------------------------------------------------------
+ASM_FUNC(ArmSetPan)
+  setpan #1
+  bx     LR
+
+//------------------------------------------------------------------------------
+// VOID
+// EFIAPI
+// ArmClearPan (
+//  VOID
+//  );
+//------------------------------------------------------------------------------
+ASM_FUNC(ArmClearPan)
+  setpan #0
+  bx     LR
diff --git a/MdeModulePkg/Core/Dxe/SysCall/ARM/InitializeMsr.c b/MdeModulePkg/Core/Dxe/SysCall/ARM/InitializeMsr.c
index fb7c2c35b6..02845996d9 100644
--- a/MdeModulePkg/Core/Dxe/SysCall/ARM/InitializeMsr.c
+++ b/MdeModulePkg/Core/Dxe/SysCall/ARM/InitializeMsr.c
@@ -5,8 +5,22 @@
 
 **/
 
+#include <Library/ArmLib.h>
+
 #include "DxeMain.h"
 
+VOID
+EFIAPI
+ArmSetPan (
+  VOID
+  );
+
+VOID
+EFIAPI
+ArmClearPan (
+  VOID
+  );
+
 VOID
 EFIAPI
 InitializeMsr (
@@ -14,5 +28,31 @@ InitializeMsr (
   IN     UINTN                   NumberOfEntries
   )
 {
-
+  if (ArmHasPan ()) {
+    //
+    // Enable Privileged Access Never feature.
+    //
+    ArmSetPan ();
+  } else {
+    DEBUG ((DEBUG_ERROR, "Core: Failed to initialize MSRs for Ring3.\n"));
+    ASSERT (FALSE);
+  }
+}
+
+VOID
+EFIAPI
+DisableSMAP (
+  VOID
+  )
+{
+  ArmClearPan ();
+}
+
+VOID
+EFIAPI
+EnableSMAP (
+  VOID
+  )
+{
+  ArmSetPan ();
 }