From 93625d54892de631c87b8d59e59eeb986c8bb034 Mon Sep 17 00:00:00 2001
From: Mikhail Krichanov <mikhailkrichanov@gmail.com>
Date: Mon, 20 Jan 2025 12:57:14 +0300
Subject: [PATCH] Ring3: Placed UnicodeCollation driver into User space.

---
 .../AArch64/ExceptionSupport.S                |  31 ++--
 .../ArmExceptionLib/Arm/ExceptionSupport.S    |  51 +++---
 ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc          |   2 +-
 .../Dxe/SysCall/AARCH64/CoreBootServices.S    |   6 +-
 .../Dxe/SysCall/AARCH64/InitializeAARCH64.c   |   5 +-
 .../Core/Dxe/SysCall/ARM/CoreBootServices.S   |   7 +
 .../Core/Dxe/SysCall/ARM/InitializeARM.c      |   5 +-
 .../Dxe/SysCall/IA32/CoreBootServices.nasm    |  26 ++-
 .../Core/Dxe/SysCall/SupportedProtocols.c     | 153 +++++++++++++-----
 .../Dxe/SysCall/X64/CoreBootServices.nasm     |   2 +
 OvmfPkg/OvmfPkgIa32.fdf                       |   2 +-
 OvmfPkg/OvmfPkgIa32X64.fdf                    |   2 +-
 OvmfPkg/OvmfPkgX64.fdf                        |   2 +-
 13 files changed, 190 insertions(+), 104 deletions(-)

diff --git a/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S b/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S
index 653c50109e..78dc83f39f 100644
--- a/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S
+++ b/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S
@@ -90,6 +90,8 @@
   UINT64  ESR;    0x318   // Exception syndrome register
   UINT64  FAR;    0x320   // Fault Address Register
   UINT64  Type;   0x328   // Exception Type
+  UINT64  TTBR0;  0x330   // User Page Table
+  UINT64  Padding;0x338   // Alignment requirement
 */
 
 GCC_ASM_EXPORT(ExceptionHandlersEnd)
@@ -99,7 +101,7 @@ GCC_ASM_EXPORT(CommonCExceptionHandler)
 
 #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)
+#define SYS_CONTEXT_SIZE   ( 8 *  8) // 7 SYS regs + Alignment requirement (ie: the stack must be aligned on 0x10)
 
 ASM_FUNC_ALIGN(ExceptionHandlerBase, 4096)
 
@@ -264,6 +266,11 @@ ASM_PFX(CommonExceptionEntry):
   stp      x2,  x3,  [x28, #-SYS_CONTEXT_SIZE]!
   stp      x4,  x5,  [x28, #0x10]
   stp      x6,  x0,  [x28, #0x20]
+  EL1_OR_EL2(x1)
+1:mrs      x2, ttbr0_el1
+  b        3f
+2:mrs      x2, ttbr0_el2
+3:stp      x2, xzr,  [x28, #0x30]
 
   // Push FP regs to Stack.
   stp      q0,  q1,  [x28, #-FP_CONTEXT_SIZE]!
@@ -288,17 +295,12 @@ ASM_PFX(CommonExceptionEntry):
   cmp      x2, 0           // Check whether EL0 process was interrupted
   b.ne     NoTTBR0Switch
   adrp     x1, ASM_PFX(CorePageTable)
+  ldr      x4, [x1]
   EL1_OR_EL2(x3)
-1:mrs      x4, ttbr0_el1
-  str      x4, [x1, #0x8]  // UserPageTable
-  ldr      x4, [x1]        // CorePageTable
-  msr      ttbr0_el1, x4
+1:msr      ttbr0_el1, x4
   tlbi     vmalle1
   b        3f
-2:mrs      x4, ttbr0_el2
-  str      x4, [x1, #0x8]  // UserPageTable
-  ldr      x4, [x1]        // CorePageTable
-  msr      ttbr0_el2, x4
+2:msr      ttbr0_el2, x4
   tlbi     alle2
 3:dsb      sy
   isb
@@ -324,14 +326,12 @@ NoTTBR0Switch:
   and      x2, x2, #0xF
   cmp      x2, 0           // Check whether EL0 process was interrupted
   b.ne     NoTTBR0Switch2
-  adrp     x1, ASM_PFX(CorePageTable)
+  ldr      x4, [x28, #(FP_CONTEXT_SIZE + 0x30)] // UserPageTable
   EL1_OR_EL2(x3)
-1:ldr      x4, [x1, #0x8]  // UserPageTable
-  msr      ttbr0_el1, x4
+1:msr      ttbr0_el1, x4
   tlbi     vmalle1
   b        3f
-2:ldr      x4, [x1, #0x8]  // UserPageTable
-  msr      ttbr0_el2, x4
+2:msr      ttbr0_el2, x4
   tlbi     alle2
 3:dsb      sy
   isb
@@ -428,9 +428,6 @@ ASM_FUNC(RegisterEl0Stack)
 ASM_PFX(CorePageTable):
 .ds.d 1
 
-UserPageTable:
-.ds.d 1
-
 .balign 4096
 Padding:
 .ds.b 1
diff --git a/ArmPkg/Library/ArmExceptionLib/Arm/ExceptionSupport.S b/ArmPkg/Library/ArmExceptionLib/Arm/ExceptionSupport.S
index c36679308a..9c5c6398c1 100644
--- a/ArmPkg/Library/ArmExceptionLib/Arm/ExceptionSupport.S
+++ b/ArmPkg/Library/ArmExceptionLib/Arm/ExceptionSupport.S
@@ -43,8 +43,11 @@ This is the stack constructed by the exception handler (low address to high addr
 
   LR    0x54    # SVC Link register (we need to restore it)
 
-  LR    0x58    # pushed by srsfd
-  CPSR  0x5c
+  TTBR0 0x58
+Padding 0x5c
+
+  LR    0x60    # pushed by srsfd
+  CPSR  0x64
 
  */
 
@@ -98,7 +101,7 @@ ASM_PFX(Fiq):
 ASM_PFX(ResetEntry):
   srsdb     #0x13!                    @ Store return state on SVC stack
                                       @ We are already in SVC mode
-
+  sub       SP, SP, #0x8              @ Save space for TTBR0
   stmfd     SP!,{LR}                  @ Store the link register for the current mode
   sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
   stmfd     SP!,{R0-R12}              @ Store the register state
@@ -111,6 +114,7 @@ ASM_PFX(UndefinedInstructionEntry):
   sub       LR, LR, #4                @ Only -2 for Thumb, adjust in CommonExceptionEntry
   srsdb     #0x13!                    @ Store return state on SVC stack
   cps       #0x13                     @ Switch to SVC for common stack
+  sub       SP, SP, #0x8              @ Save space for TTBR0
   stmfd     SP!,{LR}                  @ Store the link register for the current mode
   sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
   stmfd     SP!,{R0-R12}              @ Store the register state
@@ -124,6 +128,7 @@ ASM_PFX(SoftwareInterruptEntry):
   isb
   srsdb     #0x13!                    @ Store return state on SVC stack
                                       @ We are already in SVC mode
+  sub       SP, SP, #0x8              @ Save space for TTBR0
   stmfd     SP!,{LR}                  @ Store the link register for the current mode
   sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
   stmfd     SP!,{R0-R12}              @ Store the register state
@@ -136,6 +141,7 @@ ASM_PFX(PrefetchAbortEntry):
   sub       LR,LR,#4
   srsdb     #0x13!                    @ Store return state on SVC stack
   cps       #0x13                     @ Switch to SVC for common stack
+  sub       SP, SP, #0x8              @ Save space for TTBR0
   stmfd     SP!,{LR}                  @ Store the link register for the current mode
   sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
   stmfd     SP!,{R0-R12}              @ Store the register state
@@ -148,6 +154,7 @@ ASM_PFX(DataAbortEntry):
   sub       LR,LR,#8
   srsdb     #0x13!                    @ Store return state on SVC stack
   cps       #0x13                     @ Switch to SVC for common stack
+  sub       SP, SP, #0x8              @ Save space for TTBR0
   stmfd     SP!,{LR}                  @ Store the link register for the current mode
   sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
   stmfd     SP!,{R0-R12}              @ Store the register state
@@ -159,6 +166,7 @@ ASM_PFX(DataAbortEntry):
 ASM_PFX(ReservedExceptionEntry):
   srsdb     #0x13!                    @ Store return state on SVC stack
   cps       #0x13                     @ Switch to SVC for common stack
+  sub       SP, SP, #0x8              @ Save space for TTBR0
   stmfd     SP!,{LR}                  @ Store the link register for the current mode
   sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
   stmfd     SP!,{R0-R12}              @ Store the register state
@@ -171,6 +179,7 @@ ASM_PFX(IrqEntry):
   sub       LR,LR,#4
   srsdb     #0x13!                    @ Store return state on SVC stack
   cps       #0x13                     @ Switch to SVC for common stack
+  sub       SP, SP, #0x8              @ Save space for TTBR0
   stmfd     SP!,{LR}                  @ Store the link register for the current mode
   sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
   stmfd     SP!,{R0-R12}              @ Store the register state
@@ -183,6 +192,7 @@ ASM_PFX(FiqEntry):
   sub       LR,LR,#4
   srsdb     #0x13!                    @ Store return state on SVC stack
   cps       #0x13                     @ Switch to SVC for common stack
+  sub       SP, SP, #0x8              @ Save space for TTBR0
   stmfd     SP!,{LR}                  @ Store the link register for the current mode
   sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
   stmfd     SP!,{R0-R12}              @ Store the register state
@@ -217,7 +227,7 @@ ASM_PFX(AsmCommonExceptionEntry):
   mrc       p15, 0, R1, c5, c0, 0   @ Read DFSR
   str       R1, [SP, #0x44]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR
 
-  ldr       R1, [SP, #0x5c]         @ srsdb saved pre-exception CPSR on the stack
+  ldr       R1, [SP, #0x64]         @ srsdb saved pre-exception CPSR on the stack
   str       R1, [SP, #0x40]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR
 
   add       R2, SP, #0x38           @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
@@ -229,20 +239,20 @@ ASM_PFX(AsmCommonExceptionEntry):
   stmdaeq   R2, {sp}^               @   save unbanked sp
                                     @ else
   stmdane   R2, {lr}                @   save SVC lr
-  addne     R1, SP, #0x60           @   We pushed 0x60 bytes on the stack
+  addne     R1, SP, #0x68           @   We pushed 0x68 bytes on the stack
   strne     R1, [SP, #0x34]         @   Store it in EFI_SYSTEM_CONTEXT_ARM.SP
 
 
-  ldr       R5, [SP, #0x58]         @ PC is the LR pushed by srsfd
+  ldr       R5, [SP, #0x60]         @ PC is the LR pushed by srsfd
                                     @ Check to see if we have to adjust for Thumb entry
   sub       r4, r0, #1              @ if (ExceptionType == 1 || ExceptionType == 2)) {
   cmp       r4, #1                  @   // UND & SVC have different LR adjust for Thumb
   bhi       NoAdjustNeeded
 
-  ldr       R1, [SP, #0x5c]         @ srsdb saved pre-exception CPSR on the stack
+  ldr       R1, [SP, #0x64]         @ srsdb saved pre-exception CPSR on the stack
   tst       r1, #0x20               @   if ((CPSR & T)) == T) {  // Thumb Mode on entry
   addne     R5, R5, #2              @     PC += 2;
-  strne     R5,[SP,#0x58]           @ Update LR value pushed by srsfd
+  strne     R5,[SP,#0x60]           @ Update LR value pushed by srsfd
 
 NoAdjustNeeded:
 
@@ -251,17 +261,12 @@ NoAdjustNeeded:
                                     @ R0 is ExceptionType
   mov       R1,SP                   @ R1 is SystemContext
 
-#if (FixedPcdGet32(PcdVFPEnabled))
-  vpush     {d0-d15}                @ save vstm registers in case they are used in optimizations
-#endif
-
   ldr       R5, [SP, #0x40]         @ Saved Processor Status Register
   and       R5, R5, #0xF
   cmp       R5, 0                   @ Check whether EL0 process was interrupted
   bne       NoTTBR0Switch
   mrc       p15,0,R5,c2,c0,0        @ R5 == TTBR0
-  ADRL      (R6, UserPageTable)
-  str       R5, [R6]
+  str       R5, [SP, #0x58]
   and       R5, R5, #0x7F           @ Preserve TTBR0 attributes
   LDRL      (R6, ASM_PFX(CorePageTable))
   orr       R6, R6, R5              @ Assign TTBR0 attributes
@@ -273,6 +278,10 @@ NoAdjustNeeded:
 
 NoTTBR0Switch:
 
+#if (FixedPcdGet32(PcdVFPEnabled))
+  vpush     {d0-d15}                @ save vstm registers in case they are used in optimizations
+#endif
+
   mov       R4, SP                  @ Save current SP
   tst       R4, #4
   subne     SP, SP, #4              @ Adjust SP if not 8-byte aligned
@@ -292,11 +301,15 @@ CommonCExceptionHandler (
 
   mov       SP, R4                  @ Restore SP
 
+#if (FixedPcdGet32(PcdVFPEnabled))
+  vpop      {d0-d15}
+#endif
+
   ldr       R4, [SP, #0x40]         @ Saved Processor Status Register
   and       R4, R4, #0xF
   cmp       R4, 0                   @ Check whether EL0 process was interrupted
   bne       NoTTBR0Switch2
-  LDRL      (R4, UserPageTable)
+  ldr       R4, [SP, #0x58]         @ User Page Table
   mcr       p15,0,R4,c2,c0,0        @ TTBR0 == R4
   mcr       p15,0,r0,c8,c7,0        @ TLBIALL, TLB Invalidate All.
   mcr       p15,0,r0,c7,c5,6        @ BPIALL, Branch Predictor Invalidate All.
@@ -305,10 +318,6 @@ CommonCExceptionHandler (
 
 NoTTBR0Switch2:
 
-#if (FixedPcdGet32(PcdVFPEnabled))
-  vpop      {d0-d15}
-#endif
-
   ldr       R1, [SP, #0x4c]         @ Restore EFI_SYSTEM_CONTEXT_ARM.IFSR
   mcr       p15, 0, R1, c5, c0, 1   @ Write IFSR
 
@@ -325,6 +334,7 @@ NoTTBR0Switch2:
 
   add       SP,SP,#0x20             @ Clear out the remaining stack space
   ldmfd     SP!,{LR}                @ restore the link register for this context
+  add       SP, SP, #0x8            @ Clear out TTBR0 and Padding
   rfefd     SP!                     @ return from exception via srsfd stack slot
 
 ASM_FUNC_ALIGN(ExceptionHandlerFinal, 4096)
@@ -336,9 +346,6 @@ ASM_FUNC_ALIGN(ExceptionHandlerFinal, 4096)
 ASM_PFX(CorePageTable):
 .ds.l 1
 
-UserPageTable:
-.ds.l 1
-
 .balign 4096
 Padding:
 .ds.b 1
diff --git a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc
index 0fe9186916..7b1492070b 100644
--- a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc
+++ b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc
@@ -90,7 +90,7 @@ APRIORI DXE {
   INF MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
   INF USER FatPkg/EnhancedFatDxe/Fat.inf
   INF USER MdeModulePkg/Core/Dxe/DxeRing3/DxeRing3.inf
-  INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
+  INF USER MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
   INF MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf
   INF OvmfPkg/VirtioFsDxe/VirtioFsDxe.inf
 
diff --git a/MdeModulePkg/Core/Dxe/SysCall/AARCH64/CoreBootServices.S b/MdeModulePkg/Core/Dxe/SysCall/AARCH64/CoreBootServices.S
index 41b31b1b28..e6161dff8b 100644
--- a/MdeModulePkg/Core/Dxe/SysCall/AARCH64/CoreBootServices.S
+++ b/MdeModulePkg/Core/Dxe/SysCall/AARCH64/CoreBootServices.S
@@ -82,7 +82,8 @@ ASM_FUNC(ArmCallRing3)
   stp  q12, q13, [sp, #0xa0]
   stp  q14, q15, [sp, #0x80]
 
-  stp  xzr, x16, [sp, #0x70]
+  mrs  x6, sp_el0
+  stp  x6,  x16, [sp, #0x70]
   stp  x17, x18, [sp, #0x60]
   stp  x19, x20, [sp, #0x50]
   stp  x21, x22, [sp, #0x40]
@@ -138,7 +139,7 @@ ASM_FUNC(ReturnToCore)
   ldp  q12, q13, [sp, #0xa0]
   ldp  q14, q15, [sp, #0x80]
 
-  ldr  x16, [sp, #0x78]
+  ldp  x6,  x16, [sp, #0x70]
   ldp  x17, x18, [sp, #0x60]
   ldp  x19, x20, [sp, #0x50]
   ldp  x21, x22, [sp, #0x40]
@@ -147,6 +148,7 @@ ASM_FUNC(ReturnToCore)
   ldp  x27, x28, [sp, #0x10]
   ldp  x29, x30, [sp]
   add	 sp, sp, #0x100
+  msr  sp_el0, x6
   // Enable interrupts.
   msr  daifclr, #0xf
   isb
diff --git a/MdeModulePkg/Core/Dxe/SysCall/AARCH64/InitializeAARCH64.c b/MdeModulePkg/Core/Dxe/SysCall/AARCH64/InitializeAARCH64.c
index 8bf1b91529..acbe3af845 100644
--- a/MdeModulePkg/Core/Dxe/SysCall/AARCH64/InitializeAARCH64.c
+++ b/MdeModulePkg/Core/Dxe/SysCall/AARCH64/InitializeAARCH64.c
@@ -12,8 +12,7 @@
 
 #include "DxeMain.h"
 
-STATIC UINTN  mSysCallStackTop;
-UINTN         gUserPageTable;
+UINTN  gUserPageTable;
 
 EFI_STATUS
 EFIAPI
@@ -156,8 +155,6 @@ CallRing3 (
   IN UINTN            *ReturnSP
   )
 {
-  mSysCallStackTop = SysCallStackTop;
-
   return ArmCallRing3 (
             Data,
             UserStackTop,
diff --git a/MdeModulePkg/Core/Dxe/SysCall/ARM/CoreBootServices.S b/MdeModulePkg/Core/Dxe/SysCall/ARM/CoreBootServices.S
index 2beb0b22ad..0fa82094ac 100644
--- a/MdeModulePkg/Core/Dxe/SysCall/ARM/CoreBootServices.S
+++ b/MdeModulePkg/Core/Dxe/SysCall/ARM/CoreBootServices.S
@@ -76,6 +76,9 @@ ASM_FUNC(ArmCallRing3)
   ldr   R6, [SP, #0x28]
   // R7 is gUserPageTable
   ldr   R7, [SP, #0x2C]
+  // Save old SP_usr and LR_usr on Core Stack.
+  sub   SP, SP, #0x8
+  stmia SP, {SP, LR}^
 
 #if (FixedPcdGet32(PcdVFPEnabled))
   // Save vstm registers in case they are used in optimizations.
@@ -135,6 +138,10 @@ ASM_FUNC(ReturnToCore)
   vpop  {d0-d15}
 #endif
 
+  // Restore old SP_usr and LR_usr.
+  ldmia SP, {SP, LR}^
+  add   SP, SP, #0x8
+
   pop   {R4-R12, LR}
 
   // Enable interrupts.
diff --git a/MdeModulePkg/Core/Dxe/SysCall/ARM/InitializeARM.c b/MdeModulePkg/Core/Dxe/SysCall/ARM/InitializeARM.c
index 9238c2ea91..34d5c43e2c 100644
--- a/MdeModulePkg/Core/Dxe/SysCall/ARM/InitializeARM.c
+++ b/MdeModulePkg/Core/Dxe/SysCall/ARM/InitializeARM.c
@@ -11,8 +11,7 @@
 
 #include "DxeMain.h"
 
-STATIC UINTN  mSysCallStackTop;
-UINTN         gUserPageTable;
+UINTN  gUserPageTable;
 
 EFI_STATUS
 EFIAPI
@@ -151,8 +150,6 @@ CallRing3 (
   IN UINTN            *ReturnSP
   )
 {
-  mSysCallStackTop = SysCallStackTop;
-
   return ArmCallRing3 (
             Data,
             UserStackTop,
diff --git a/MdeModulePkg/Core/Dxe/SysCall/IA32/CoreBootServices.nasm b/MdeModulePkg/Core/Dxe/SysCall/IA32/CoreBootServices.nasm
index bac5bc1e21..72f8e66a22 100644
--- a/MdeModulePkg/Core/Dxe/SysCall/IA32/CoreBootServices.nasm
+++ b/MdeModulePkg/Core/Dxe/SysCall/IA32/CoreBootServices.nasm
@@ -180,24 +180,27 @@ ASM_PFX(CallRing3):
     push    ebp
     push    edi
     push    esi
+    ; Save old SysCallStackTop.
+    push dword MSR_IA32_SYSENTER_ESP
+    call ASM_PFX(AsmReadMsr64)
+    pop     ebx
+    push    eax
 
     ; Save Core Stack pointer.
-    mov     ebx, [esp + 4 * 8] ; ReturnSP
+    mov     ebx, [esp + 4 * 9] ; ReturnSP
     mov     [ebx], esp
 
-    mov     ebx, [esp + 4 * 7]
-    mov     [ASM_PFX(SysCallStackTop)], ebx
     mov     edx, 0
-    mov     eax, ebx
+    mov     eax, [esp + 4 * 8] ; SysCallStackTop
     mov     ecx, MSR_IA32_SYSENTER_ESP
     wrmsr
 
     SetRing3DataSegmentSelectors
 
     ; Prepare SYSEXIT arguments.
-    mov     ecx, [esp + 4 * 6] ; UserStackTop
+    mov     ecx, [esp + 4 * 7] ; UserStackTop
     mov     edx, [ASM_PFX(gRing3EntryPoint)]
-    mov     eax, [esp + 4 * 5] ; Data
+    mov     eax, [esp + 4 * 6] ; Data
 
     ; Switch to User Stack.
     mov     ebp, ecx
@@ -223,8 +226,15 @@ ASM_PFX(SysCallEnd):
 ;------------------------------------------------------------------------------
 global ASM_PFX(ReturnToCore)
 ASM_PFX(ReturnToCore):
-    mov     eax, [esp + 4]   ; Status
+    mov     ebx, [esp + 4]   ; Status
     mov     esp, [esp + 4*2] ; ReturnSP
+    ; Restore old SysCallStackTop.
+    mov     edx, 0
+    pop     eax
+    mov     ecx, MSR_IA32_SYSENTER_ESP
+    wrmsr
+
+    mov     eax, ebx
     pop     esi
     pop     edi
     pop     ebp
@@ -245,5 +255,5 @@ ASM_PFX(gUserPageTable):
   resd 1
 
 ALIGN   4096
-ASM_PFX(SysCallStackTop):
+Padding:
   resd 1
diff --git a/MdeModulePkg/Core/Dxe/SysCall/SupportedProtocols.c b/MdeModulePkg/Core/Dxe/SysCall/SupportedProtocols.c
index 39c644fc63..eb4889c4ae 100644
--- a/MdeModulePkg/Core/Dxe/SysCall/SupportedProtocols.c
+++ b/MdeModulePkg/Core/Dxe/SysCall/SupportedProtocols.c
@@ -60,9 +60,6 @@ GoToRing3 (
   VA_END (Marker);
   ForbidSupervisorAccessToUserMemory ();
   //
-  // TODO: Get(),Set() for old SysCallStackTop.
-  //
-  //
   // TODO: Allocate new stacks (only for EFI_FILE_PROTOCOL instances?),
   // because UserDriver can be interrupted and interrupt handler may call the same UserDriver again.
   //
@@ -83,16 +80,20 @@ STATIC
 USER_SPACE_DRIVER *
 EFIAPI
 FindUserSpaceDriver (
-  IN VOID  *CoreWrapper
+  IN  VOID  *CoreWrapper,
+  OUT UINTN  *OldPageTable
   )
 {
   LIST_ENTRY         *Link;
   USER_SPACE_DRIVER  *UserDriver;
 
+  ASSERT (OldPageTable != NULL);
+
   for (Link = gUserSpaceDriversHead.ForwardLink; Link != &gUserSpaceDriversHead; Link = Link->ForwardLink) {
     UserDriver = BASE_CR (Link, USER_SPACE_DRIVER, Link);
 
     if (UserDriver->CoreWrapper == CoreWrapper) {
+      *OldPageTable  = gUserPageTable;
       gUserPageTable = UserDriver->UserPageTable;
       return UserDriver;
     }
@@ -112,8 +113,9 @@ CoreDriverBindingSupported (
   EFI_STATUS         Status;
   USER_SPACE_DRIVER  *UserDriver;
   VOID               *EntryPoint;
+  UINTN              OldPageTable;
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -131,6 +133,8 @@ CoreDriverBindingSupported (
              RemainingDevicePath
              );
 
+  gUserPageTable = OldPageTable;
+
   return Status;
 }
 
@@ -145,8 +149,9 @@ CoreDriverBindingStart (
   EFI_STATUS         Status;
   USER_SPACE_DRIVER  *UserDriver;
   VOID               *EntryPoint;
+  UINTN              OldPageTable;
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -164,6 +169,8 @@ CoreDriverBindingStart (
              RemainingDevicePath
              );
 
+  gUserPageTable = OldPageTable;
+
   return Status;
 }
 
@@ -179,8 +186,9 @@ CoreDriverBindingStop (
   EFI_STATUS         Status;
   USER_SPACE_DRIVER  *UserDriver;
   VOID               *EntryPoint;
+  UINTN              OldPageTable;
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -199,6 +207,8 @@ CoreDriverBindingStop (
              ChildHandleBuffer
              );
 
+  gUserPageTable = OldPageTable;
+
   return Status;
 }
 
@@ -212,8 +222,9 @@ CoreFileClose (
   EFI_STATUS         Status;
   USER_SPACE_DRIVER  *UserDriver;
   VOID               *EntryPoint;
+  UINTN              OldPageTable;
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -232,6 +243,8 @@ CoreFileClose (
   FreePool (UserDriver->CoreWrapper);
   RemoveEntryList (&UserDriver->Link);
 
+  gUserPageTable = OldPageTable;
+
   return Status;
 }
 
@@ -261,6 +274,7 @@ CoreFileRead (
   UINT32                PagesNumber;
   USER_SPACE_DRIVER     *UserDriver;
   VOID                  *EntryPoint;
+  UINTN                 OldPageTable;
 
   if ((This == NULL) || (BufferSize == NULL)) {
     return EFI_INVALID_PARAMETER;
@@ -268,7 +282,7 @@ CoreFileRead (
   //
   // gUserPageTable must be set before alloctation of EfiRing3MemoryType pages.
   //
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -284,6 +298,7 @@ CoreFileRead (
              &Ring3Pages
              );
   if (EFI_ERROR (Status)) {
+    gUserPageTable = OldPageTable;
     return Status;
   }
 
@@ -317,6 +332,8 @@ CoreFileRead (
 
   CoreFreePages (Ring3Pages, PagesNumber);
 
+  gUserPageTable = OldPageTable;
+
   return Status;
 }
 
@@ -340,10 +357,12 @@ CoreFileSetPosition (
   IN UINT64                   Position
   )
 {
+  EFI_STATUS         Status;
   USER_SPACE_DRIVER  *UserDriver;
   VOID               *EntryPoint;
+  UINTN              OldPageTable;
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -353,40 +372,43 @@ CoreFileSetPosition (
   ForbidSupervisorAccessToUserMemory ();
 
 #if defined (MDE_CPU_X64) || defined (MDE_CPU_AARCH64)
-  return GoToRing3 (
-           2,
-           EntryPoint,
-           UserDriver,
-           This,
-           Position
-           );
+  Status = GoToRing3 (
+             2,
+             EntryPoint,
+             UserDriver,
+             This,
+             Position
+             );
 #elif defined (MDE_CPU_IA32)
   //
   // UINT64 Position is passed as 2 double words on stack.
   //
-  return GoToRing3 (
-           3,
-           EntryPoint,
-           UserDriver,
-           This,
-           Position
-           );
+  Status = GoToRing3 (
+             3,
+             EntryPoint,
+             UserDriver,
+             This,
+             Position
+             );
 #elif defined (MDE_CPU_ARM)
   //
   // UINT64 Position is passed as 2 words in 2 registers and is aligned on 8 bytes.
   // R0 == This, R1 == NULL, R2 == Position_Low, R3 == Position_High.
   //
-  return GoToRing3 (
-           4,
-           EntryPoint,
-           UserDriver,
-           This,
-           NULL,
-           (UINT32)Position,
-           (UINT32)(Position >> 32)
-           );
+  Status = GoToRing3 (
+             4,
+             EntryPoint,
+             UserDriver,
+             This,
+             NULL,
+             (UINT32)Position,
+             (UINT32)(Position >> 32)
+             );
 #endif
 
+  gUserPageTable = OldPageTable;
+
+  return Status;
 }
 
 STATIC
@@ -401,12 +423,13 @@ CoreFileGetPosition (
   EFI_PHYSICAL_ADDRESS  Ring3Position;
   USER_SPACE_DRIVER     *UserDriver;
   VOID                  *EntryPoint;
+  UINTN                 OldPageTable;
 
   if ((This == NULL) || (Position == NULL)) {
     return EFI_INVALID_PARAMETER;
   }
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -418,6 +441,7 @@ CoreFileGetPosition (
              &Ring3Position
              );
   if (EFI_ERROR (Status)) {
+    gUserPageTable = OldPageTable;
     return Status;
   }
 
@@ -440,6 +464,8 @@ CoreFileGetPosition (
 
   CoreFreePages (Ring3Position, 1);
 
+  gUserPageTable = OldPageTable;
+
   return Status;
 }
 
@@ -461,12 +487,13 @@ CoreFileGetInfo (
   UINT32                PagesNumber;
   USER_SPACE_DRIVER     *UserDriver;
   VOID                  *EntryPoint;
+  UINTN                 OldPageTable;
 
   if ((This == NULL) || (BufferSize == NULL)) {
     return EFI_INVALID_PARAMETER;
   }
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -484,6 +511,7 @@ CoreFileGetInfo (
              &Ring3Pages
              );
   if (EFI_ERROR (Status)) {
+    gUserPageTable = OldPageTable;
     return Status;
   }
 
@@ -526,6 +554,8 @@ CoreFileGetInfo (
 
   CoreFreePages (Ring3Pages, PagesNumber);
 
+  gUserPageTable = OldPageTable;
+
   return Status;
 }
 
@@ -620,12 +650,13 @@ CoreFileOpen (
   USER_SPACE_DRIVER     *UserDriver;
   USER_SPACE_DRIVER     *NewDriver;
   VOID                  *EntryPoint;
+  UINTN                 OldPageTable;
 
   if ((This == NULL) || (NewHandle == NULL) || (FileName == NULL)) {
     return EFI_INVALID_PARAMETER;
   }
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -644,6 +675,7 @@ CoreFileOpen (
              );
   if (EFI_ERROR (Status)) {
     *NewHandle = NULL;
+    gUserPageTable = OldPageTable;
     return Status;
   }
 
@@ -657,6 +689,7 @@ CoreFileOpen (
   if (EFI_ERROR (Status)) {
     *NewHandle = NULL;
     CoreFreePages (Ring3Pages, PagesNumber);
+    gUserPageTable = OldPageTable;
     return Status;
   }
 
@@ -709,6 +742,7 @@ CoreFileOpen (
   if (EFI_ERROR (Status)) {
     *NewHandle = NULL;
     CoreFreePages (Ring3Pages, PagesNumber);
+    gUserPageTable = OldPageTable;
     return Status;
   }
 
@@ -716,6 +750,7 @@ CoreFileOpen (
   if (NewFile == NULL) {
     *NewHandle = NULL;
     CoreFreePages (Ring3Pages, PagesNumber);
+    gUserPageTable = OldPageTable;
     return EFI_OUT_OF_RESOURCES;
   }
 
@@ -751,6 +786,8 @@ CoreFileOpen (
 
   CoreFreePages (Ring3Pages, PagesNumber);
 
+  gUserPageTable = OldPageTable;
+
   return Status;
 }
 
@@ -768,12 +805,13 @@ CoreOpenVolume (
   USER_SPACE_DRIVER     *UserDriver;
   USER_SPACE_DRIVER     *NewDriver;
   VOID                  *EntryPoint;
+  UINTN                 OldPageTable;
 
   if (Root == NULL) {
     return EFI_INVALID_PARAMETER;
   }
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -790,6 +828,7 @@ CoreOpenVolume (
              );
   if (EFI_ERROR (Status)) {
     *Root = NULL;
+    gUserPageTable = OldPageTable;
     return Status;
   }
 
@@ -805,6 +844,7 @@ CoreOpenVolume (
   if (EFI_ERROR (Status)) {
     *Root = NULL;
     CoreFreePages (Physical, 1);
+    gUserPageTable = OldPageTable;
     return Status;
   }
 
@@ -812,6 +852,7 @@ CoreOpenVolume (
   if (File == NULL) {
     *Root = NULL;
     CoreFreePages (Physical, 1);
+    gUserPageTable = OldPageTable;
     return EFI_OUT_OF_RESOURCES;
   }
 
@@ -847,6 +888,8 @@ CoreOpenVolume (
 
   CoreFreePages (Physical, 1);
 
+  gUserPageTable = OldPageTable;
+
   return Status;
 }
 
@@ -864,8 +907,9 @@ CoreUnicodeCollationStriColl (
   VOID                  *EntryPoint;
   UINTN                 Size1;
   UINTN                 Size2;
+  UINTN                 OldPageTable;
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -880,6 +924,7 @@ CoreUnicodeCollationStriColl (
              &UserMem
              );
   if (EFI_ERROR (Status)) {
+    gUserPageTable = OldPageTable;
     return 0;
   }
 
@@ -900,6 +945,8 @@ CoreUnicodeCollationStriColl (
 
   CoreFreePages (UserMem, EFI_SIZE_TO_PAGES (Size1 + Size2));
 
+  gUserPageTable = OldPageTable;
+
   return (INTN)Status;
 }
 
@@ -917,8 +964,9 @@ CoreUnicodeCollationMetaiMatch (
   VOID                  *EntryPoint;
   UINTN                 Size1;
   UINTN                 Size2;
+  UINTN                 OldPageTable;
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -933,6 +981,7 @@ CoreUnicodeCollationMetaiMatch (
              &UserMem
              );
   if (EFI_ERROR (Status)) {
+    gUserPageTable = OldPageTable;
     return FALSE;
   }
 
@@ -953,6 +1002,8 @@ CoreUnicodeCollationMetaiMatch (
 
   CoreFreePages (UserMem, EFI_SIZE_TO_PAGES (Size1 + Size2));
 
+  gUserPageTable = OldPageTable;
+
   return (BOOLEAN)Status;
 }
 
@@ -968,8 +1019,9 @@ CoreUnicodeCollationStrLwr (
   USER_SPACE_DRIVER     *UserDriver;
   VOID                  *EntryPoint;
   UINTN                 Size1;
+  UINTN                 OldPageTable;
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -983,6 +1035,7 @@ CoreUnicodeCollationStrLwr (
              &UserMem
              );
   if (EFI_ERROR (Status)) {
+    gUserPageTable = OldPageTable;
     return;
   }
 
@@ -1004,6 +1057,8 @@ CoreUnicodeCollationStrLwr (
   ForbidSupervisorAccessToUserMemory ();
 
   CoreFreePages (UserMem, EFI_SIZE_TO_PAGES (Size1));
+
+  gUserPageTable = OldPageTable;
 }
 
 VOID
@@ -1018,8 +1073,9 @@ CoreUnicodeCollationStrUpr (
   USER_SPACE_DRIVER     *UserDriver;
   VOID                  *EntryPoint;
   UINTN                 Size1;
+  UINTN                 OldPageTable;
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -1033,6 +1089,7 @@ CoreUnicodeCollationStrUpr (
              &UserMem
              );
   if (EFI_ERROR (Status)) {
+    gUserPageTable = OldPageTable;
     return;
   }
 
@@ -1054,6 +1111,8 @@ CoreUnicodeCollationStrUpr (
   ForbidSupervisorAccessToUserMemory ();
 
   CoreFreePages (UserMem, EFI_SIZE_TO_PAGES (Size1));
+
+  gUserPageTable = OldPageTable;
 }
 
 VOID
@@ -1069,8 +1128,9 @@ CoreUnicodeCollationFatToStr (
   EFI_PHYSICAL_ADDRESS  UserMem;
   USER_SPACE_DRIVER     *UserDriver;
   VOID                  *EntryPoint;
+  UINTN                 OldPageTable;
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -1082,6 +1142,7 @@ CoreUnicodeCollationFatToStr (
              &UserMem
              );
   if (EFI_ERROR (Status)) {
+    gUserPageTable = OldPageTable;
     return;
   }
 
@@ -1105,6 +1166,8 @@ CoreUnicodeCollationFatToStr (
   ForbidSupervisorAccessToUserMemory ();
 
   CoreFreePages (UserMem, EFI_SIZE_TO_PAGES (FatSize * 3));
+
+  gUserPageTable = OldPageTable;
 }
 
 BOOLEAN
@@ -1121,8 +1184,9 @@ CoreUnicodeCollationStrToFat (
   USER_SPACE_DRIVER     *UserDriver;
   VOID                  *EntryPoint;
   UINTN                 Size1;
+  UINTN                 OldPageTable;
 
-  UserDriver = FindUserSpaceDriver (This);
+  UserDriver = FindUserSpaceDriver (This, &OldPageTable);
   ASSERT (UserDriver != NULL);
 
   This = UserDriver->UserSpaceDriver;
@@ -1136,6 +1200,7 @@ CoreUnicodeCollationStrToFat (
              &UserMem
              );
   if (EFI_ERROR (Status)) {
+    gUserPageTable = OldPageTable;
     return FALSE;
   }
 
@@ -1160,5 +1225,7 @@ CoreUnicodeCollationStrToFat (
 
   CoreFreePages (UserMem, EFI_SIZE_TO_PAGES (FatSize + Size1));
 
+  gUserPageTable = OldPageTable;
+
   return (BOOLEAN)Status;
 }
diff --git a/MdeModulePkg/Core/Dxe/SysCall/X64/CoreBootServices.nasm b/MdeModulePkg/Core/Dxe/SysCall/X64/CoreBootServices.nasm
index fd294cb7ae..baa3326a7c 100644
--- a/MdeModulePkg/Core/Dxe/SysCall/X64/CoreBootServices.nasm
+++ b/MdeModulePkg/Core/Dxe/SysCall/X64/CoreBootServices.nasm
@@ -218,6 +218,7 @@ ASM_PFX(CallRing3):
     push    r13
     push    r14
     push    r15
+    push qword [ASM_PFX(SysCallStackTop)]
 
     ; Save Core Stack pointer.
     mov     [r9], rsp
@@ -260,6 +261,7 @@ ASM_PFX(SysCallEnd):
 global ASM_PFX(ReturnToCore)
 ASM_PFX(ReturnToCore):
     mov     rsp, rdx
+    pop qword [ASM_PFX(SysCallStackTop)]
     pop     r15
     pop     r14
     pop     r13
diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
index 768a7dd1a8..a5894582ca 100644
--- a/OvmfPkg/OvmfPkgIa32.fdf
+++ b/OvmfPkg/OvmfPkgIa32.fdf
@@ -265,7 +265,7 @@ INF  MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
 INF  MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
 INF  MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
 INF  MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf
-INF  MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
+INF USER MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
 INF  MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
 INF  MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
 INF  MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
index 42b7b1a45e..7da62a294a 100644
--- a/OvmfPkg/OvmfPkgIa32X64.fdf
+++ b/OvmfPkg/OvmfPkgIa32X64.fdf
@@ -266,7 +266,7 @@ INF  MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
 INF  MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
 INF  MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
 INF  MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf
-INF  MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
+INF USER MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
 INF  MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
 INF  MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
 INF  MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 1c243ee618..9e1e66e68f 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -295,7 +295,7 @@ INF  MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
 INF  MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
 INF  MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
 INF  MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf
-INF  MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
+INF USER MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
 INF  MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
 INF  MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
 INF  MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf