public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH v1 0/6] Add Raspberry Pi Support to EmulatorPkg
@ 2023-03-06  0:21 Nate DeSimone
  2023-03-06  0:22 ` [PATCH v1 1/6] ArmPkg: Add ArmMmuNullLib Nate DeSimone
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Nate DeSimone @ 2023-03-06  0:21 UTC (permalink / raw)
  To: devel
  Cc: Andrew Fish, Ray Ni, Leif Lindholm, Ard Biesheuvel, Sami Mujawar,
	Michael D Kinney, Chasel Chiu

This patch series is the result of a fun weekend project that I
did in my spare time. It implements the changes nessesary for
EmulatorPkg to run on the Raspberry Pi. It should also work on
other 32-bit ARM systems, but I only specifically tested on
Raspberry Pi OS (formerly Raspbian.)

I ran into several interesting issues during the development of
this patch series and it ended up being a good learning
experience for me. Some things of note are:

 1 - Assembly Code
 
There are several pieces of assembly code in EmulatorPkg that need
to be rewritten when porting to a new machine architecture. This
code fell into two categories, stack manipulation and "gaskets."

 2 - ABI Differences

The most significant amount of assembly code is the "gasket"
functions. The gasket functions are responsible for converting from
the UNIX ABI to the EFI ABI. They enable EmulatorPkg to
support executing arbitary UEFI binaries without needing
recompilation specifically for EmulatorPkg. X86 has many ABI
specifications that vary based on target OS and compiler toolchain.
There have been several attempts to unify things on the x86 side,
but they usually just result in the addition of yet another ABI.
Things are much more uniform on ARM due to wide acceptance of the
AAPCS. Due to this, the ABI differences between UNIX and EFI boil
down to passing of variadic arguments and enum values. Neither of
these cases apply to the function signatures for the gaskets.
Therefore, on ARM these gaskets can be simple wrapper functions
written in C since the UNIX and EFI ABIs are identical... at least
for the set of functions that need gaskets.

 3 - Instruction Cache Maintenance

Because EmulatorPkg and edk2 in general contains a PE/COFF loader,
it counts as "self-modifying code". The way self modifying code is
handled on ARM is considerably more complex than x86. While on x86
there is no requirement for self-modifying code to flush the
instruction cache, on ARM failure to do so will result in incorrect
behavior. Additionally, flushing the cache is considerably more
difficult on ARM. On x86, one can simply add a CLFLUSH or WBINVD
instruction; they are perfectly valid to execute while in Ring 3.
On ARM, flushing the cache requires one to write to system control
registers, which can only be done in EL1 (kernel mode) or higher.
Therefore, while flushing the cache can be done on in the x86
version of EmulatorPkg without any interaction with the OS, on ARM
we need to invoke OS syscalls.

To accomodate this, I have added a new EMU_IO_THUNK_PROTOCOL that
implements the CacheMaintenanceLib LibraryClass. This new
implementation uses the GCC intrinsic function
__builtin_clear_cache(), which on x86 gets converted into a CLFLUSH
instruction by the compiler. On ARM, it gets converted into a call
to the __clear_cache() API in libgcc. The ARM implementation of
libgcc invokes the ARM_cacheflush syscall (0xF0002), which only
exists in kernels built for the ARM architecture.

I have added wrapper implementations of the CacheMaintenanceLib
LibraryClass for PEI and DXE that use the EMU_THUNK infrastructure
to acquire the EMU_CACHE_THUNK_PROTOCOL and invoke the equivilent
functions, which in turn will use the GCC intrinsic mentioned
above.

I have only enable this version of CacheMaintenanceLib on the ARM
architecture, because it will take several thousand CPU
instructions to execute, as opposed to about ten on the current x86
implementation.

 Testing Done:

Boots to shell on Raspberry Pi OS "bullseye."

Cc: Andrew Fish <afish@apple.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Chasel Chiu <chasel.chiu@intel.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>

Nate DeSimone (6):
  ArmPkg: Add ArmMmuNullLib
  EmulatorPkg: Add ARM Build Target
  EmulatorPkg: Fix PosixFileSystem function misspellings
  EmulatorPkg: Add ARM support to UNIX Host App
  EmulatorPkg: Add ARM support to EmuSec
  EmulatorPkg: Add EmuCacheMaintenanceLib

 ArmPkg/ArmPkg.dsc                             |    2 +
 ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.c  |   84 ++
 .../Library/ArmMmuNullLib/ArmMmuNullLib.inf   |   36 +
 EmulatorPkg/EmulatorPkg.dec                   |    4 +-
 EmulatorPkg/EmulatorPkg.dsc                   |   29 +-
 EmulatorPkg/EmulatorPkg.fdf                   |    6 +-
 EmulatorPkg/Include/Protocol/EmuCache.h       |  217 ++++
 .../DxeEmuCacheMaintenanceLib.c               |  337 +++++
 .../DxeEmuCacheMaintenanceLib.inf             |   37 +
 .../PeiEmuCacheMaintenanceLib.c               |  344 ++++++
 .../PeiEmuCacheMaintenanceLib.inf             |   39 +
 EmulatorPkg/Sec/Arm/SwitchRam.S               |   32 +
 EmulatorPkg/Sec/Arm/TempRam.c                 |   58 +
 EmulatorPkg/Sec/Sec.inf                       |    9 +-
 EmulatorPkg/Unix/Host/Arm/Gasket.c            |  895 ++++++++++++++
 .../Unix/Host/Arm/GasketFunctionDefinitions.h | 1092 +++++++++++++++++
 EmulatorPkg/Unix/Host/Arm/SwitchStack.S       |   39 +
 EmulatorPkg/Unix/Host/CacheMaintenance.c      |  284 +++++
 EmulatorPkg/Unix/Host/Gasket.h                |   12 +-
 EmulatorPkg/Unix/Host/Host.c                  |    5 +-
 EmulatorPkg/Unix/Host/Host.h                  |    2 +
 EmulatorPkg/Unix/Host/Host.inf                |   14 +-
 EmulatorPkg/Unix/Host/Ia32/Gasket.S           |   31 +-
 EmulatorPkg/Unix/Host/PosixFileSystem.c       |   22 +-
 EmulatorPkg/Unix/Host/X64/Gasket.S            |   31 +-
 EmulatorPkg/build.sh                          |   13 +-
 26 files changed, 3617 insertions(+), 57 deletions(-)
 create mode 100644 ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.c
 create mode 100644 ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.inf
 create mode 100644 EmulatorPkg/Include/Protocol/EmuCache.h
 create mode 100644 EmulatorPkg/Library/DxeEmuCacheMaintenanceLib/DxeEmuCacheMaintenanceLib.c
 create mode 100644 EmulatorPkg/Library/DxeEmuCacheMaintenanceLib/DxeEmuCacheMaintenanceLib.inf
 create mode 100644 EmulatorPkg/Library/PeiEmuCacheMaintenanceLib/PeiEmuCacheMaintenanceLib.c
 create mode 100644 EmulatorPkg/Library/PeiEmuCacheMaintenanceLib/PeiEmuCacheMaintenanceLib.inf
 create mode 100644 EmulatorPkg/Sec/Arm/SwitchRam.S
 create mode 100644 EmulatorPkg/Sec/Arm/TempRam.c
 create mode 100644 EmulatorPkg/Unix/Host/Arm/Gasket.c
 create mode 100644 EmulatorPkg/Unix/Host/Arm/GasketFunctionDefinitions.h
 create mode 100644 EmulatorPkg/Unix/Host/Arm/SwitchStack.S
 create mode 100644 EmulatorPkg/Unix/Host/CacheMaintenance.c

-- 
2.30.2


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v1 1/6] ArmPkg: Add ArmMmuNullLib
  2023-03-06  0:21 [PATCH v1 0/6] Add Raspberry Pi Support to EmulatorPkg Nate DeSimone
@ 2023-03-06  0:22 ` Nate DeSimone
  2023-03-06  0:22 ` [PATCH v1 2/6] EmulatorPkg: Add ARM Build Target Nate DeSimone
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Nate DeSimone @ 2023-03-06  0:22 UTC (permalink / raw)
  To: devel
  Cc: Leif Lindholm, Ard Biesheuvel, Sami Mujawar, Michael D Kinney,
	Chasel Chiu

Adds a NULL implementation of the ArmMmuLib. This is nessesary for
ARM support in EmulatorPkg due to DxeIplPeim requiring an
implementation of ArmMmuLib.

Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Chasel Chiu <chasel.chiu@intel.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
---
 ArmPkg/ArmPkg.dsc                             |  2 +
 ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.c  | 84 +++++++++++++++++++
 .../Library/ArmMmuNullLib/ArmMmuNullLib.inf   | 36 ++++++++
 3 files changed, 122 insertions(+)
 create mode 100644 ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.c
 create mode 100644 ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.inf

diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
index 3fb95d1951..3dc2c21e9d 100644
--- a/ArmPkg/ArmPkg.dsc
+++ b/ArmPkg/ArmPkg.dsc
@@ -6,6 +6,7 @@
 # Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
 # Copyright (c) Microsoft Corporation.<BR>
 # Copyright (c) 2021, Ampere Computing LLC. All rights reserved.
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
 #
 #    SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -142,6 +143,7 @@
   ArmPkg/Filesystem/SemihostFs/SemihostFs.inf
 
   ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf
+  ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.inf
 
   ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
   ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
diff --git a/ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.c b/ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.c
new file mode 100644
index 0000000000..f91582f86a
--- /dev/null
+++ b/ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.c
@@ -0,0 +1,84 @@
+/** @file
+  ARM MMU NULL Library
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2015 - 2016, Linaro Ltd. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+#include <Library/ArmMmuLib.h>
+
+EFI_STATUS
+EFIAPI
+ArmConfigureMmu (
+  IN  ARM_MEMORY_REGION_DESCRIPTOR  *MemoryTable,
+  OUT VOID                          **TranslationTableBase OPTIONAL,
+  OUT UINTN                         *TranslationTableSize  OPTIONAL
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+ArmSetMemoryRegionNoExec (
+  IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN  UINT64                Length
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+ArmClearMemoryRegionNoExec (
+  IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN  UINT64                Length
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+ArmSetMemoryRegionReadOnly (
+  IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN  UINT64                Length
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+ArmClearMemoryRegionReadOnly (
+  IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN  UINT64                Length
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+VOID
+EFIAPI
+ArmReplaceLiveTranslationEntry (
+  IN  UINT64   *Entry,
+  IN  UINT64   Value,
+  IN  UINT64   RegionStart,
+  IN  BOOLEAN  DisableMmu
+  )
+{
+  return;
+}
+
+EFI_STATUS
+ArmSetMemoryAttributes (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length,
+  IN UINT64                Attributes
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.inf b/ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.inf
new file mode 100644
index 0000000000..fa6791f3d9
--- /dev/null
+++ b/ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.inf
@@ -0,0 +1,36 @@
+## @file
+#  Module Information description file for ARM MMU NULL Library
+#
+#  For user space environments like EmulatorPkg
+#
+#  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010017
+  BASE_NAME                      = ArmMmuNullLib
+  FILE_GUID                      = E61735C8-DD00-4C4A-B07B-FD71A67C239D
+  VERSION_STRING                 = 1.0
+  MODULE_TYPE                    = BASE
+  LIBRARY_CLASS                  = ArmMmuLib
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES ARM AARCH64
+#
+
+[LibraryClasses]
+
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  MdePkg/MdePkg.dec
+
+[Pcd]
+
+[Sources]
+  ArmMmuNullLib.c
+
+[Guids]
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v1 2/6] EmulatorPkg: Add ARM Build Target
  2023-03-06  0:21 [PATCH v1 0/6] Add Raspberry Pi Support to EmulatorPkg Nate DeSimone
  2023-03-06  0:22 ` [PATCH v1 1/6] ArmPkg: Add ArmMmuNullLib Nate DeSimone
@ 2023-03-06  0:22 ` Nate DeSimone
  2023-03-06  0:22 ` [PATCH v1 3/6] EmulatorPkg: Fix PosixFileSystem function misspellings Nate DeSimone
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Nate DeSimone @ 2023-03-06  0:22 UTC (permalink / raw)
  To: devel; +Cc: Andrew Fish, Ray Ni, Michael D Kinney, Chasel Chiu

Adds the ARM build target to EmulatorPkg.

Moves PcdDxeIplSwitchToLongMode and PcdDxeIplBuildPageTables to
only apply for the IA32 and X64 build targets since they are
not used on ARM.

Adds ARM compiler instrinsics libraries.

Adds NULL implementation of ArmMmuLib.

Disables EbcDxe on ARM builds since EbcDxe does not support the
ARM architecture.

Cc: Andrew Fish <afish@apple.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Chasel Chiu <chasel.chiu@intel.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
---
 EmulatorPkg/EmulatorPkg.dsc | 17 ++++++++++++++---
 EmulatorPkg/EmulatorPkg.fdf |  6 ++++--
 EmulatorPkg/build.sh        | 13 ++++++++++++-
 3 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/EmulatorPkg/EmulatorPkg.dsc b/EmulatorPkg/EmulatorPkg.dsc
index b44435d7e6..19ba60aa23 100644
--- a/EmulatorPkg/EmulatorPkg.dsc
+++ b/EmulatorPkg/EmulatorPkg.dsc
@@ -4,7 +4,7 @@
 # The Emulation Platform can be used to debug individual modules, prior to creating
 # a real platform. This also provides an example for how an DSC is created.
 #
-# Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2006 - 2023, Intel Corporation. All rights reserved.<BR>
 # Portions copyright (c) 2010 - 2011, Apple Inc. All rights reserved.<BR>
 # Copyright (c) Microsoft Corporation.
 #
@@ -19,7 +19,7 @@
   DSC_SPECIFICATION              = 0x00010005
   OUTPUT_DIRECTORY               = Build/Emulator$(ARCH)
 
-  SUPPORTED_ARCHITECTURES        = X64|IA32
+  SUPPORTED_ARCHITECTURES        = X64|IA32|ARM
   BUILD_TARGETS                  = DEBUG|RELEASE|NOOPT
   SKUID_IDENTIFIER               = DEFAULT
   FLASH_DEFINITION               = EmulatorPkg/EmulatorPkg.fdf
@@ -140,6 +140,13 @@
   AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
 !endif
 
+[LibraryClasses.ARM]
+  ArmMmuLib|ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.inf
+  NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
+
+  # Add support for GCC stack protector
+  NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
+
 [LibraryClasses.common.SEC]
   PeiServicesLib|EmulatorPkg/Library/SecPeiServicesLib/SecPeiServicesLib.inf
   PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
@@ -211,8 +218,10 @@
   TimerLib|EmulatorPkg/Library/DxeTimerLib/DxeTimerLib.inf
 
 [PcdsFeatureFlag]
-  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreImageLoaderSearchTeSectionFirst|FALSE
+
+[PcdsFeatureFlag.IA32, PcdsFeatureFlag.X64]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplBuildPageTables|FALSE
 
 [PcdsFixedAtBuild]
@@ -368,7 +377,9 @@
 !endif
   }
 
+!if "ARM" not in $(ARCH)
   MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
+!endif
   MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
   EmulatorPkg/EmuThunkDxe/EmuThunk.inf
   EmulatorPkg/CpuRuntimeDxe/Cpu.inf
diff --git a/EmulatorPkg/EmulatorPkg.fdf b/EmulatorPkg/EmulatorPkg.fdf
index 5420756eaa..06f002a624 100644
--- a/EmulatorPkg/EmulatorPkg.fdf
+++ b/EmulatorPkg/EmulatorPkg.fdf
@@ -1,7 +1,7 @@
 ## @file
 # This is Emulator FDF file with UEFI HII features enabled
 #
-# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2008 - 2023, Intel Corporation. All rights reserved.<BR>
 # Portions copyright (c) 2009 - 2011, Apple Inc. All rights reserved.<BR>
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -148,7 +148,9 @@ INF  EmulatorPkg/ResetRuntimeDxe/Reset.inf
 INF  MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
 INF  EmulatorPkg/FvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
 INF  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
-INF  MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
+!if "ARM" not in $(ARCH)
+  INF  MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
+!endif
 INF  MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
 INF  EmulatorPkg/EmuThunkDxe/EmuThunk.inf
 INF  EmulatorPkg/CpuRuntimeDxe/Cpu.inf
diff --git a/EmulatorPkg/build.sh b/EmulatorPkg/build.sh
index 76c22dfaf8..55f9cbaa1b 100755
--- a/EmulatorPkg/build.sh
+++ b/EmulatorPkg/build.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 #
 # Copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
-# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2010 - 2023, Intel Corporation. All rights reserved.<BR>
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -83,6 +83,15 @@ case `uname` in
       x86_64)
         HOST_PROCESSOR=X64
         ;;
+      armv6l)
+        HOST_PROCESSOR=ARM
+        ;;
+      armv7l)
+        HOST_PROCESSOR=ARM
+        ;;
+      armv8l)
+        HOST_PROCESSOR=ARM
+        ;;
     esac
 
     gcc_version=$(gcc -v 2>&1 | tail -1 | awk '{print $3}')
@@ -174,6 +183,8 @@ case $PROCESSOR in
     LIB_NAMES="ld-linux-x86-64.so.2 libdl.so.2 crt1.o crti.o crtn.o"
     LIB_SEARCH_PATHS="/usr/lib/x86_64-linux-gnu /usr/lib64 /lib64 /usr/lib /lib"
     ;;
+  ARM)
+    ARCH_SIZE=32
 esac
 
 for libname in $LIB_NAMES
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v1 3/6] EmulatorPkg: Fix PosixFileSystem function misspellings
  2023-03-06  0:21 [PATCH v1 0/6] Add Raspberry Pi Support to EmulatorPkg Nate DeSimone
  2023-03-06  0:22 ` [PATCH v1 1/6] ArmPkg: Add ArmMmuNullLib Nate DeSimone
  2023-03-06  0:22 ` [PATCH v1 2/6] EmulatorPkg: Add ARM Build Target Nate DeSimone
@ 2023-03-06  0:22 ` Nate DeSimone
  2023-03-06  0:22 ` [PATCH v1 4/6] EmulatorPkg: Add ARM support to UNIX Host App Nate DeSimone
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Nate DeSimone @ 2023-03-06  0:22 UTC (permalink / raw)
  To: devel; +Cc: Andrew Fish, Ray Ni, Michael D Kinney, Chasel Chiu

Fixes spelling errors in the following function names:

GasketPosixFileCLose --> GasketPosixFileClose
PosixFileCLose --> PosixFileClose
GasketPosixFileSetPossition --> GasketPosixFileSetPosition
PosixFileSetPossition --> PosixFileSetPosition
GasketPosixFileGetPossition --> GasketPosixFileGetPosition
PosixFileGetPossition --> PosixFileGetPosition
GasketPosixFileSystmeThunkOpen --> GasketPosixFileSystemThunkOpen
PosixFileSystmeThunkOpen --> PosixFileSystemThunkOpen
GasketPosixFileSystmeThunkClose --> GasketPosixFileSystemThunkClose
PosixFileSystmeThunkClose --> PosixFileSystemThunkClose

Cc: Andrew Fish <afish@apple.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Chasel Chiu <chasel.chiu@intel.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
---
 EmulatorPkg/Unix/Host/Gasket.h          | 12 +++++-----
 EmulatorPkg/Unix/Host/Ia32/Gasket.S     | 31 +++++++++++++------------
 EmulatorPkg/Unix/Host/PosixFileSystem.c | 22 +++++++++---------
 EmulatorPkg/Unix/Host/X64/Gasket.S      | 31 +++++++++++++------------
 4 files changed, 49 insertions(+), 47 deletions(-)

diff --git a/EmulatorPkg/Unix/Host/Gasket.h b/EmulatorPkg/Unix/Host/Gasket.h
index 6dafc903cf..90c591e024 100644
--- a/EmulatorPkg/Unix/Host/Gasket.h
+++ b/EmulatorPkg/Unix/Host/Gasket.h
@@ -1,7 +1,7 @@
 /** @file
 
   Copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
-  Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2011 - 2023, Intel Corporation. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -360,7 +360,7 @@ GasketPosixFileOpen (
 
 EFI_STATUS
 EFIAPI
-GasketPosixFileCLose (
+GasketPosixFileClose (
   IN EFI_FILE_PROTOCOL  *This
   );
 
@@ -388,14 +388,14 @@ GasketPosixFileWrite (
 
 EFI_STATUS
 EFIAPI
-GasketPosixFileSetPossition (
+GasketPosixFileSetPosition (
   IN EFI_FILE_PROTOCOL  *This,
   IN UINT64             Position
   );
 
 EFI_STATUS
 EFIAPI
-GasketPosixFileGetPossition (
+GasketPosixFileGetPosition (
   IN EFI_FILE_PROTOCOL  *This,
   OUT UINT64            *Position
   );
@@ -426,13 +426,13 @@ GasketPosixFileFlush (
 
 EFI_STATUS
 EFIAPI
-GasketPosixFileSystmeThunkOpen (
+GasketPosixFileSystemThunkOpen (
   IN  EMU_IO_THUNK_PROTOCOL  *This
   );
 
 EFI_STATUS
 EFIAPI
-GasketPosixFileSystmeThunkClose (
+GasketPosixFileSystemThunkClose (
   IN  EMU_IO_THUNK_PROTOCOL  *This
   );
 
diff --git a/EmulatorPkg/Unix/Host/Ia32/Gasket.S b/EmulatorPkg/Unix/Host/Ia32/Gasket.S
index 36197ff260..f4c2b456d8 100644
--- a/EmulatorPkg/Unix/Host/Ia32/Gasket.S
+++ b/EmulatorPkg/Unix/Host/Ia32/Gasket.S
@@ -7,6 +7,7 @@
 # the code common.
 #
 # Copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 #------------------------------------------------------------------------------
@@ -847,8 +848,8 @@ ASM_PFX(GasketPosixFileOpen):
   ret
 
 
-ASM_GLOBAL ASM_PFX(GasketPosixFileCLose)
-ASM_PFX(GasketPosixFileCLose):
+ASM_GLOBAL ASM_PFX(GasketPosixFileClose)
+ASM_PFX(GasketPosixFileClose):
   pushl %ebp
   movl  %esp, %ebp
   subl  $24, %esp      // sub extra 16 from the stack for alignment
@@ -856,7 +857,7 @@ ASM_PFX(GasketPosixFileCLose):
   movl  8(%ebp), %eax
   movl  %eax, (%esp)
 
-  call    ASM_PFX(PosixFileCLose)
+  call    ASM_PFX(PosixFileClose)
 
   leave
   ret
@@ -915,8 +916,8 @@ ASM_PFX(GasketPosixFileWrite):
   ret
 
 
-ASM_GLOBAL ASM_PFX(GasketPosixFileSetPossition)
-ASM_PFX(GasketPosixFileSetPossition):
+ASM_GLOBAL ASM_PFX(GasketPosixFileSetPosition)
+ASM_PFX(GasketPosixFileSetPosition):
   pushl %ebp
   movl  %esp, %ebp
   subl  $40, %esp      // sub extra 16 from the stack for alignment
@@ -928,14 +929,14 @@ ASM_PFX(GasketPosixFileSetPossition):
   movl  8(%ebp), %eax
   movl  %eax, (%esp)
 
-  call    ASM_PFX(PosixFileSetPossition)
+  call    ASM_PFX(PosixFileSetPosition)
 
   leave
   ret
 
 
-ASM_GLOBAL ASM_PFX(GasketPosixFileGetPossition)
-ASM_PFX(GasketPosixFileGetPossition):
+ASM_GLOBAL ASM_PFX(GasketPosixFileGetPosition)
+ASM_PFX(GasketPosixFileGetPosition):
   pushl %ebp
   movl  %esp, %ebp
   subl  $24, %esp      // sub extra 16 from the stack for alignment
@@ -945,7 +946,7 @@ ASM_PFX(GasketPosixFileGetPossition):
   movl  8(%ebp), %eax
   movl  %eax, (%esp)
 
-  call    ASM_PFX(PosixFileGetPossition)
+  call    ASM_PFX(PosixFileGetPosition)
 
   leave
   ret
@@ -1008,8 +1009,8 @@ ASM_PFX(GasketPosixFileFlush):
   ret
 
 
-ASM_GLOBAL ASM_PFX(GasketPosixFileSystmeThunkOpen)
-ASM_PFX(GasketPosixFileSystmeThunkOpen):
+ASM_GLOBAL ASM_PFX(GasketPosixFileSystemThunkOpen)
+ASM_PFX(GasketPosixFileSystemThunkOpen):
   pushl %ebp
   movl  %esp, %ebp
   subl  $24, %esp      // sub extra 16 from the stack for alignment
@@ -1017,14 +1018,14 @@ ASM_PFX(GasketPosixFileSystmeThunkOpen):
   movl  8(%ebp), %eax
   movl  %eax, (%esp)
 
-  call    ASM_PFX(PosixFileSystmeThunkOpen)
+  call    ASM_PFX(PosixFileSystemThunkOpen)
 
   leave
   ret
 
 
-ASM_GLOBAL ASM_PFX(GasketPosixFileSystmeThunkClose)
-ASM_PFX(GasketPosixFileSystmeThunkClose):
+ASM_GLOBAL ASM_PFX(GasketPosixFileSystemThunkClose)
+ASM_PFX(GasketPosixFileSystemThunkClose):
   pushl %ebp
   movl  %esp, %ebp
   subl  $24, %esp      // sub extra 16 from the stack for alignment
@@ -1032,7 +1033,7 @@ ASM_PFX(GasketPosixFileSystmeThunkClose):
   movl  8(%ebp), %eax
   movl  %eax, (%esp)
 
-  call    ASM_PFX(PosixFileSystmeThunkClose)
+  call    ASM_PFX(PosixFileSystemThunkClose)
 
   leave
   ret
diff --git a/EmulatorPkg/Unix/Host/PosixFileSystem.c b/EmulatorPkg/Unix/Host/PosixFileSystem.c
index b69d3d5520..3a86d6675c 100644
--- a/EmulatorPkg/Unix/Host/PosixFileSystem.c
+++ b/EmulatorPkg/Unix/Host/PosixFileSystem.c
@@ -2,7 +2,7 @@
  POSIX Pthreads to emulate APs and implement threads
 
 Copyright (c) 2011, Apple Inc. All rights reserved.
-Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2019 - 2023, Intel Corporation. All rights reserved.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 
@@ -70,12 +70,12 @@ PosixFileSetInfo (
 EFI_FILE_PROTOCOL  gPosixFileProtocol = {
   EFI_FILE_REVISION,
   GasketPosixFileOpen,
-  GasketPosixFileCLose,
+  GasketPosixFileClose,
   GasketPosixFileDelete,
   GasketPosixFileRead,
   GasketPosixFileWrite,
-  GasketPosixFileGetPossition,
-  GasketPosixFileSetPossition,
+  GasketPosixFileGetPosition,
+  GasketPosixFileSetPosition,
   GasketPosixFileGetInfo,
   GasketPosixFileSetInfo,
   GasketPosixFileFlush
@@ -643,7 +643,7 @@ Done:;
 
 **/
 EFI_STATUS
-PosixFileCLose (
+PosixFileClose (
   IN EFI_FILE_PROTOCOL  *This
   )
 {
@@ -883,7 +883,7 @@ PosixFileWrite (
 
 **/
 EFI_STATUS
-PosixFileSetPossition (
+PosixFileSetPosition (
   IN EFI_FILE_PROTOCOL  *This,
   IN UINT64             Position
   )
@@ -930,7 +930,7 @@ PosixFileSetPossition (
 
 **/
 EFI_STATUS
-PosixFileGetPossition (
+PosixFileGetPosition (
   IN EFI_FILE_PROTOCOL  *This,
   OUT UINT64            *Position
   )
@@ -1473,7 +1473,7 @@ PosixFileFlush (
 }
 
 EFI_STATUS
-PosixFileSystmeThunkOpen (
+PosixFileSystemThunkOpen (
   IN  EMU_IO_THUNK_PROTOCOL  *This
   )
 {
@@ -1530,7 +1530,7 @@ PosixFileSystmeThunkOpen (
 }
 
 EFI_STATUS
-PosixFileSystmeThunkClose (
+PosixFileSystemThunkClose (
   IN  EMU_IO_THUNK_PROTOCOL  *This
   )
 {
@@ -1566,7 +1566,7 @@ EMU_IO_THUNK_PROTOCOL  gPosixFileSystemThunkIo = {
   NULL,
   NULL,
   0,
-  GasketPosixFileSystmeThunkOpen,
-  GasketPosixFileSystmeThunkClose,
+  GasketPosixFileSystemThunkOpen,
+  GasketPosixFileSystemThunkClose,
   NULL
 };
diff --git a/EmulatorPkg/Unix/Host/X64/Gasket.S b/EmulatorPkg/Unix/Host/X64/Gasket.S
index 030faa8e4c..e82c9d4ad6 100644
--- a/EmulatorPkg/Unix/Host/X64/Gasket.S
+++ b/EmulatorPkg/Unix/Host/X64/Gasket.S
@@ -8,6 +8,7 @@
 # RSI, RDI calle-save on EFI, scatch on UNIX callign
 #
 # Copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 #------------------------------------------------------------------------------
@@ -941,8 +942,8 @@ ASM_PFX(GasketPosixFileOpen):
   ret
 
 
-ASM_GLOBAL ASM_PFX(GasketPosixFileCLose)
-ASM_PFX(GasketPosixFileCLose):
+ASM_GLOBAL ASM_PFX(GasketPosixFileClose)
+ASM_PFX(GasketPosixFileClose):
   pushq   %rbp            // stack frame is for the debugger
   movq    %rsp, %rbp
 
@@ -951,7 +952,7 @@ ASM_PFX(GasketPosixFileCLose):
 
   movq    %rcx, %rdi    // Swizzle args
 
-  call    ASM_PFX(PosixFileCLose)
+  call    ASM_PFX(PosixFileClose)
 
   popq    %rdi          // restore state
   popq    %rsi
@@ -1017,8 +1018,8 @@ ASM_PFX(GasketPosixFileWrite):
   ret
 
 
-ASM_GLOBAL ASM_PFX(GasketPosixFileSetPossition)
-ASM_PFX(GasketPosixFileSetPossition):
+ASM_GLOBAL ASM_PFX(GasketPosixFileSetPosition)
+ASM_PFX(GasketPosixFileSetPosition):
   pushq   %rbp            // stack frame is for the debugger
   movq    %rsp, %rbp
 
@@ -1028,7 +1029,7 @@ ASM_PFX(GasketPosixFileSetPossition):
   movq    %rcx, %rdi    // Swizzle args
   movq    %rdx, %rsi
 
-  call    ASM_PFX(PosixFileSetPossition)
+  call    ASM_PFX(PosixFileSetPosition)
 
   popq    %rdi          // restore state
   popq    %rsi
@@ -1036,8 +1037,8 @@ ASM_PFX(GasketPosixFileSetPossition):
   ret
 
 
-ASM_GLOBAL ASM_PFX(GasketPosixFileGetPossition)
-ASM_PFX(GasketPosixFileGetPossition):
+ASM_GLOBAL ASM_PFX(GasketPosixFileGetPosition)
+ASM_PFX(GasketPosixFileGetPosition):
   pushq   %rbp            // stack frame is for the debugger
   movq    %rsp, %rbp
 
@@ -1047,7 +1048,7 @@ ASM_PFX(GasketPosixFileGetPossition):
   movq    %rcx, %rdi    // Swizzle args
   movq    %rdx, %rsi
 
-  call    ASM_PFX(PosixFileGetPossition)
+  call    ASM_PFX(PosixFileGetPosition)
 
   popq    %rdi          // restore state
   popq    %rsi
@@ -1115,8 +1116,8 @@ ASM_PFX(GasketPosixFileFlush):
   ret
 
 
-ASM_GLOBAL ASM_PFX(GasketPosixFileSystmeThunkOpen)
-ASM_PFX(GasketPosixFileSystmeThunkOpen):
+ASM_GLOBAL ASM_PFX(GasketPosixFileSystemThunkOpen)
+ASM_PFX(GasketPosixFileSystemThunkOpen):
   pushq   %rbp            // stack frame is for the debugger
   movq    %rsp, %rbp
 
@@ -1125,7 +1126,7 @@ ASM_PFX(GasketPosixFileSystmeThunkOpen):
 
   movq    %rcx, %rdi    // Swizzle args
 
-  call    ASM_PFX(PosixFileSystmeThunkOpen)
+  call    ASM_PFX(PosixFileSystemThunkOpen)
 
   popq    %rdi          // restore state
   popq    %rsi
@@ -1133,8 +1134,8 @@ ASM_PFX(GasketPosixFileSystmeThunkOpen):
   ret
 
 
-ASM_GLOBAL ASM_PFX(GasketPosixFileSystmeThunkClose)
-ASM_PFX(GasketPosixFileSystmeThunkClose):
+ASM_GLOBAL ASM_PFX(GasketPosixFileSystemThunkClose)
+ASM_PFX(GasketPosixFileSystemThunkClose):
   pushq   %rbp            // stack frame is for the debugger
   movq    %rsp, %rbp
 
@@ -1143,7 +1144,7 @@ ASM_PFX(GasketPosixFileSystmeThunkClose):
 
   movq    %rcx, %rdi    // Swizzle args
 
-  call    ASM_PFX(PosixFileSystmeThunkClose)
+  call    ASM_PFX(PosixFileSystemThunkClose)
 
   popq    %rdi          // restore state
   popq    %rsi
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v1 4/6] EmulatorPkg: Add ARM support to UNIX Host App
  2023-03-06  0:21 [PATCH v1 0/6] Add Raspberry Pi Support to EmulatorPkg Nate DeSimone
                   ` (2 preceding siblings ...)
  2023-03-06  0:22 ` [PATCH v1 3/6] EmulatorPkg: Fix PosixFileSystem function misspellings Nate DeSimone
@ 2023-03-06  0:22 ` Nate DeSimone
  2023-03-06  0:22 ` [PATCH v1 5/6] EmulatorPkg: Add ARM support to EmuSec Nate DeSimone
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Nate DeSimone @ 2023-03-06  0:22 UTC (permalink / raw)
  To: devel; +Cc: Andrew Fish, Ray Ni, Michael D Kinney, Chasel Chiu

Adds ARM implementation of the EFIAPI to UNIX ABI gasket.
Adds ARM implementation of SecCore stack switch and invocation.
Adds ARM compiler flags.

Cc: Andrew Fish <afish@apple.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Chasel Chiu <chasel.chiu@intel.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
---
 EmulatorPkg/EmulatorPkg.dsc                   |    5 +
 EmulatorPkg/Unix/Host/Arm/Gasket.c            |  895 ++++++++++++++
 .../Unix/Host/Arm/GasketFunctionDefinitions.h | 1092 +++++++++++++++++
 EmulatorPkg/Unix/Host/Arm/SwitchStack.S       |   39 +
 EmulatorPkg/Unix/Host/Host.inf                |   12 +-
 5 files changed, 2042 insertions(+), 1 deletion(-)
 create mode 100644 EmulatorPkg/Unix/Host/Arm/Gasket.c
 create mode 100644 EmulatorPkg/Unix/Host/Arm/GasketFunctionDefinitions.h
 create mode 100644 EmulatorPkg/Unix/Host/Arm/SwitchStack.S

diff --git a/EmulatorPkg/EmulatorPkg.dsc b/EmulatorPkg/EmulatorPkg.dsc
index 19ba60aa23..62d853e470 100644
--- a/EmulatorPkg/EmulatorPkg.dsc
+++ b/EmulatorPkg/EmulatorPkg.dsc
@@ -313,6 +313,11 @@
     ##
     EmulatorPkg/Unix/Host/Host.inf
   !endif
+!elseif "ARM" in $(ARCH) && "MSFT" not in $(FAMILY) && $(WIN_HOST_BUILD) == FALSE
+  ##
+  #  Emulator, OS POSIX application
+  ##
+  EmulatorPkg/Unix/Host/Host.inf
 !endif
 
 !ifndef $(SKIP_MAIN_BUILD)
diff --git a/EmulatorPkg/Unix/Host/Arm/Gasket.c b/EmulatorPkg/Unix/Host/Arm/Gasket.c
new file mode 100644
index 0000000000..818025df58
--- /dev/null
+++ b/EmulatorPkg/Unix/Host/Arm/Gasket.c
@@ -0,0 +1,895 @@
+/**@file Gasket.c
+
+  Manages any differences between the UNIX ABI and the EFI/Windows ABI
+  For ARM systems the AAPCS
+  (https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst)
+  has mostly standardized the ABI across different operating systems. There are
+  some differences in argument passing for variadic functions and passing of
+  enum values as arguments. Neither of these cases apply for
+  the EMU_THUNK_PROTOCOL so we can use a simple wrapper functions.
+
+Copyright (c) 2004 - 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "GasketFunctionDefinitions.h"
+
+//
+// Gasket functions for the top-level EMU_THUNK_PROTOCOL
+//
+
+UINTN
+EFIAPI
+GasketSecWriteStdErr (
+  IN UINT8  *Buffer,
+  IN UINTN  NumberOfBytes
+  )
+{
+  return SecWriteStdErr (Buffer, NumberOfBytes);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSecConfigStdIn (
+  VOID
+  )
+{
+  return SecConfigStdIn ();
+}
+
+UINTN
+EFIAPI
+GasketSecWriteStdOut (
+  IN UINT8  *Buffer,
+  IN UINTN  NumberOfBytes
+  )
+{
+  return SecWriteStdOut (Buffer, NumberOfBytes);
+}
+
+UINTN
+EFIAPI
+GasketSecReadStdIn (
+  IN UINT8  *Buffer,
+  IN UINTN  NumberOfBytes
+  )
+{
+  return SecReadStdIn (Buffer, NumberOfBytes);
+}
+
+BOOLEAN
+EFIAPI
+GasketSecPollStdIn (
+  VOID
+  )
+{
+  return SecPollStdIn ();
+}
+
+VOID *
+EFIAPI
+GasketSecMalloc (
+  IN  UINTN  Size
+  )
+{
+  return SecMalloc (Size);
+}
+
+VOID *
+EFIAPI
+GasketSecValloc (
+  IN  UINTN  Size
+  )
+{
+  return SecValloc (Size);
+}
+
+BOOLEAN
+EFIAPI
+GasketSecFree (
+  IN  VOID  *Ptr
+  )
+{
+  return SecFree (Ptr);
+}
+
+RETURN_STATUS
+EFIAPI
+GasketSecPeCoffGetEntryPoint (
+  IN     VOID  *Pe32Data,
+  IN OUT VOID  **EntryPoint
+  )
+{
+  return SecPeCoffGetEntryPoint (Pe32Data, EntryPoint);
+}
+
+VOID
+EFIAPI
+GasketSecPeCoffRelocateImageExtraAction (
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
+  )
+{
+  SecPeCoffRelocateImageExtraAction (ImageContext);
+}
+
+VOID
+EFIAPI
+GasketSecPeCoffUnloadImageExtraAction (
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
+  )
+{
+  SecPeCoffUnloadImageExtraAction (ImageContext);
+}
+
+VOID
+EFIAPI
+GasketSecEnableInterrupt (
+  VOID
+  )
+{
+  SecEnableInterrupt ();
+}
+
+VOID
+EFIAPI
+GasketSecDisableInterrupt (
+  VOID
+  )
+{
+  SecDisableInterrupt ();
+}
+
+UINT64
+EFIAPI
+GasketQueryPerformanceFrequency (
+  VOID
+  )
+{
+  return QueryPerformanceFrequency ();
+}
+
+UINT64
+EFIAPI
+GasketQueryPerformanceCounter (
+  VOID
+  )
+{
+  return QueryPerformanceCounter ();
+}
+
+VOID
+EFIAPI
+GasketSecSleep (
+  IN  UINT64  Nanoseconds
+  )
+{
+  SecSleep (Nanoseconds);
+}
+
+VOID
+EFIAPI
+GasketSecCpuSleep (
+  VOID
+  )
+{
+  SecCpuSleep ();
+}
+
+VOID
+EFIAPI
+GasketSecExit (
+  UINTN  Status
+  )
+{
+  SecExit (Status);
+}
+
+VOID
+EFIAPI
+GasketSecGetTime (
+  OUT  EFI_TIME              *Time,
+  OUT EFI_TIME_CAPABILITIES  *Capabilities OPTIONAL
+  )
+{
+  SecGetTime (Time, Capabilities);
+}
+
+VOID
+EFIAPI
+GasketSecSetTime (
+  IN  EFI_TIME  *Time
+  )
+{
+  SecSetTime (Time);
+}
+
+VOID
+EFIAPI
+GasketSecSetTimer (
+  IN  UINT64                  PeriodMs,
+  IN  EMU_SET_TIMER_CALLBACK  CallBack
+  )
+{
+  SecSetTimer (PeriodMs, CallBack);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSecGetNextProtocol (
+  IN  BOOLEAN                EmuBusDriver,
+  OUT EMU_IO_THUNK_PROTOCOL  **Instance  OPTIONAL
+  )
+{
+  return SecGetNextProtocol (EmuBusDriver, Instance);
+}
+
+//
+// Gasket functions for PPIs produced by SEC
+//
+
+EFI_STATUS
+EFIAPI
+GasketSecUnixPeiAutoScan (
+  IN  UINTN                 Index,
+  OUT EFI_PHYSICAL_ADDRESS  *MemoryBase,
+  OUT UINT64                *MemorySize
+  )
+{
+  return SecUnixPeiAutoScan (Index, MemoryBase, MemorySize);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSecUnixFdAddress (
+  IN     UINTN                 Index,
+  IN OUT EFI_PHYSICAL_ADDRESS  *FdBase,
+  IN OUT UINT64                *FdSize,
+  IN OUT EFI_PHYSICAL_ADDRESS  *FixUp
+  )
+{
+  return SecUnixFdAddress (Index, FdBase, FdSize, FixUp);
+}
+
+VOID *
+EFIAPI
+GasketSecEmuThunkAddress (
+  VOID
+  )
+{
+  return SecEmuThunkAddress ();
+}
+
+//
+// Reverse (UNIX to EFIAPI) gaskets
+//
+
+UINTN
+ReverseGasketUint64 (
+  UINTN   CallBack,
+  UINT64  a
+  )
+{
+  CALL_BACK   Function;
+
+  Function = (CALL_BACK)(VOID *) CallBack;
+  Function (a);
+  return CallBack;
+}
+
+UINTN
+ReverseGasketUint64Uint64 (
+  VOID  *CallBack,
+  VOID  *Context,
+  VOID  *Key
+  )
+{
+  CALL_BACK_2ARG  Function;
+
+  Function = (CALL_BACK_2ARG) CallBack;
+  Function (Context, Key);
+  return (UINTN) CallBack;
+}
+
+//
+// Gasket functions for EMU_GRAPHICS_WINDOW_PROTOCOL
+//
+
+EFI_STATUS
+EFIAPI
+GasketX11Size (
+  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsWindowsIo,
+  UINT32                        Width,
+  UINT32                        Height
+  )
+{
+  return X11Size (GraphicsWindowsIo, Width, Height);
+}
+
+EFI_STATUS
+EFIAPI
+GasketX11CheckKey (
+  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsWindowsIo
+  )
+{
+  return X11CheckKey (GraphicsWindowsIo);
+}
+
+EFI_STATUS
+EFIAPI
+GasketX11GetKey (
+  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsWindowsIo,
+  EFI_KEY_DATA                  *key
+  )
+{
+  return X11GetKey (GraphicsWindowsIo, key);
+}
+
+EFI_STATUS
+EFIAPI
+GasketX11KeySetState (
+  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsWindowsIo,
+  EFI_KEY_TOGGLE_STATE          *KeyToggleState
+  )
+{
+  return X11KeySetState (GraphicsWindowsIo, KeyToggleState);
+}
+
+EFI_STATUS
+EFIAPI
+GasketX11RegisterKeyNotify (
+  IN EMU_GRAPHICS_WINDOW_PROTOCOL                      *GraphicsWindowsIo,
+  IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK  MakeCallBack,
+  IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK  BreakCallBack,
+  IN VOID                                              *Context
+  )
+{
+  return X11RegisterKeyNotify (GraphicsWindowsIo, MakeCallBack, BreakCallBack, Context);
+}
+
+EFI_STATUS
+EFIAPI
+GasketX11Blt (
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL    *GraphicsWindows,
+  IN  EFI_UGA_PIXEL                   *BltBuffer OPTIONAL,
+  IN  EFI_UGA_BLT_OPERATION           BltOperation,
+  IN  EMU_GRAPHICS_WINDOWS__BLT_ARGS  *Args
+  )
+{
+  return X11Blt (GraphicsWindows, BltBuffer, BltOperation, Args);
+}
+
+EFI_STATUS
+EFIAPI
+GasketX11CheckPointer (
+  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsWindowsIo
+  )
+{
+  return X11CheckPointer (GraphicsWindowsIo);
+}
+
+EFI_STATUS
+EFIAPI
+GasketX11GetPointerState (
+  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsWindowsIo,
+  EFI_SIMPLE_POINTER_STATE      *state
+  )
+{
+  return X11GetPointerState (GraphicsWindowsIo, state);
+}
+
+EFI_STATUS
+EFIAPI
+GasketX11GraphicsWindowOpen (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  )
+{
+  return X11GraphicsWindowOpen (This);
+}
+
+EFI_STATUS
+EFIAPI
+GasketX11GraphicsWindowClose (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  )
+{
+  return X11GraphicsWindowClose (This);
+}
+
+//
+// Gasket functions for accessing Pthreads
+//
+
+UINTN
+EFIAPI
+GasketPthreadMutexLock (
+  IN VOID  *Mutex
+  )
+{
+  return PthreadMutexLock (Mutex);
+}
+
+UINTN
+EFIAPI
+GasketPthreadMutexUnLock (
+  IN VOID  *Mutex
+  )
+{
+  return PthreadMutexUnLock (Mutex);
+}
+
+UINTN
+EFIAPI
+GasketPthreadMutexTryLock (
+  IN VOID  *Mutex
+  )
+{
+  return PthreadMutexTryLock (Mutex);
+}
+
+VOID *
+EFIAPI
+GasketPthreadMutexInit (
+  IN VOID
+  )
+{
+  return PthreadMutexInit ();
+}
+
+UINTN
+EFIAPI
+GasketPthreadMutexDestroy (
+  IN VOID  *Mutex
+  )
+{
+  return PthreadMutexDestroy (Mutex);
+}
+
+UINTN
+EFIAPI
+GasketPthreadCreate (
+  IN  VOID                       *Thread,
+  IN  VOID                       *Attribute,
+  IN  THREAD_THUNK_THREAD_ENTRY  Start,
+  IN  VOID                       *Context
+  )
+{
+  return PthreadCreate (Thread, Attribute, Start, Context);
+}
+
+VOID
+EFIAPI
+GasketPthreadExit (
+  IN VOID  *ValuePtr
+  )
+{
+  PthreadExit (ValuePtr);
+}
+
+UINTN
+EFIAPI
+GasketPthreadSelf (
+  VOID
+  )
+{
+  return PthreadSelf ();
+}
+
+EFI_STATUS
+EFIAPI
+GasketPthreadOpen (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  )
+{
+  return PthreadOpen (This);
+}
+
+EFI_STATUS
+EFIAPI
+GasketPthreadClose (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  )
+{
+  return PthreadClose (This);
+}
+
+//
+// Gasket functions for accessing the host filesystem
+//
+
+EFI_STATUS
+EFIAPI
+GasketPosixOpenVolume (
+  IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *This,
+  OUT EFI_FILE_PROTOCOL               **Root
+  )
+{
+  return PosixOpenVolume (This, Root);
+}
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileOpen (
+  IN EFI_FILE_PROTOCOL   *This,
+  OUT EFI_FILE_PROTOCOL  **NewHandle,
+  IN CHAR16              *FileName,
+  IN UINT64              OpenMode,
+  IN UINT64              Attributes
+  )
+{
+  return PosixFileOpen (This, NewHandle, FileName, OpenMode, Attributes);
+}
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileClose (
+  IN EFI_FILE_PROTOCOL  *This
+  )
+{
+  return PosixFileClose (This);
+}
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileDelete (
+  IN EFI_FILE_PROTOCOL  *This
+  )
+{
+  return PosixFileDelete (This);
+}
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileRead (
+  IN EFI_FILE_PROTOCOL  *This,
+  IN OUT UINTN          *BufferSize,
+  OUT VOID              *Buffer
+  )
+{
+  return PosixFileRead (This, BufferSize, Buffer);
+}
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileWrite (
+  IN EFI_FILE_PROTOCOL  *This,
+  IN OUT UINTN          *BufferSize,
+  IN VOID               *Buffer
+  )
+{
+  return PosixFileWrite (This, BufferSize, Buffer);
+}
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileSetPosition (
+  IN EFI_FILE_PROTOCOL  *This,
+  IN UINT64             Position
+  )
+{
+  return PosixFileSetPosition (This, Position);
+}
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileGetPosition (
+  IN EFI_FILE_PROTOCOL  *This,
+  OUT UINT64            *Position
+  )
+{
+  return PosixFileGetPosition (This, Position);
+}
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileGetInfo (
+  IN EFI_FILE_PROTOCOL  *This,
+  IN EFI_GUID           *InformationType,
+  IN OUT UINTN          *BufferSize,
+  OUT VOID              *Buffer
+  )
+{
+  return PosixFileGetInfo (This, InformationType, BufferSize, Buffer);
+}
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileSetInfo (
+  IN EFI_FILE_PROTOCOL  *This,
+  IN EFI_GUID           *InformationType,
+  IN UINTN              BufferSize,
+  IN VOID               *Buffer
+  )
+{
+  return PosixFileSetInfo (This, InformationType, BufferSize, Buffer);
+}
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileFlush (
+  IN EFI_FILE_PROTOCOL  *This
+  )
+{
+  return PosixFileFlush (This);
+}
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileSystemThunkOpen (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  )
+{
+  return PosixFileSystemThunkOpen (This);
+}
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileSystemThunkClose (//@todo
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  )
+{
+  return PosixFileSystemThunkClose (This);
+}
+
+//
+// Gasket functions for reading/writing to disk images
+//
+
+EFI_STATUS
+EFIAPI
+GasketEmuBlockIoReset (
+  IN EMU_BLOCK_IO_PROTOCOL  *This,
+  IN BOOLEAN                ExtendedVerification
+  )
+{
+  return EmuBlockIoReset (This, ExtendedVerification);
+}
+
+EFI_STATUS
+EFIAPI
+GasketEmuBlockIoReadBlocks (
+  IN     EMU_BLOCK_IO_PROTOCOL  *This,
+  IN     UINT32                 MediaId,
+  IN     EFI_LBA                LBA,
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
+  IN     UINTN                  BufferSize,
+  OUT VOID                      *Buffer
+  )
+{
+  return EmuBlockIoReadBlocks (This, MediaId, LBA, Token, BufferSize, Buffer);
+}
+
+EFI_STATUS
+EFIAPI
+GasketEmuBlockIoWriteBlocks (
+  IN     EMU_BLOCK_IO_PROTOCOL  *This,
+  IN     UINT32                 MediaId,
+  IN     EFI_LBA                LBA,
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
+  IN     UINTN                  BufferSize,
+  IN     VOID                   *Buffer
+  )
+{
+  return EmuBlockIoWriteBlocks (This, MediaId, LBA, Token, BufferSize, Buffer);
+}
+
+EFI_STATUS
+EFIAPI
+GasketEmuBlockIoFlushBlocks (
+  IN     EMU_BLOCK_IO_PROTOCOL  *This,
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token
+  )
+{
+  return EmuBlockIoFlushBlocks (This, Token);
+}
+
+EFI_STATUS
+EFIAPI
+GasketEmuBlockIoCreateMapping (
+  IN     EMU_BLOCK_IO_PROTOCOL  *This,
+  IN     EFI_BLOCK_IO_MEDIA     *Media
+  )
+{
+  return EmuBlockIoCreateMapping (This, Media);
+}
+
+EFI_STATUS
+EFIAPI
+GasketBlockIoThunkOpen (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  )
+{
+  return EmuBlockIoThunkOpen (This);
+}
+
+EFI_STATUS
+EFIAPI
+GasketBlockIoThunkClose (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  )
+{
+  return EmuBlockIoThunkClose (This);
+}
+
+//
+// Gasket functions for accessing BSD Sockets (TCP-IP Networks)
+//
+
+EFI_STATUS
+EFIAPI
+GasketSnpCreateMapping (
+  IN     EMU_SNP_PROTOCOL         *This,
+  IN     EFI_SIMPLE_NETWORK_MODE  *Media
+  )
+{
+  return EmuSnpCreateMapping (This, Media);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpStart (
+  IN EMU_SNP_PROTOCOL  *This
+  )
+{
+  return EmuSnpStart (This);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpStop (
+  IN EMU_SNP_PROTOCOL  *This
+  )
+{
+  return EmuSnpStop (This);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpInitialize (
+  IN EMU_SNP_PROTOCOL  *This,
+  IN UINTN             ExtraRxBufferSize  OPTIONAL,
+  IN UINTN             ExtraTxBufferSize  OPTIONAL
+  )
+{
+  return EmuSnpInitialize (This, ExtraRxBufferSize, ExtraTxBufferSize);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpReset (
+  IN EMU_SNP_PROTOCOL  *This,
+  IN BOOLEAN           ExtendedVerification
+  )
+{
+  return EmuSnpReset (This, ExtendedVerification);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpShutdown (
+  IN EMU_SNP_PROTOCOL  *This
+  )
+{
+  return EmuSnpShutdown (This);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpReceiveFilters (
+  IN EMU_SNP_PROTOCOL  *This,
+  IN UINT32            Enable,
+  IN UINT32            Disable,
+  IN BOOLEAN           ResetMCastFilter,
+  IN UINTN             MCastFilterCnt     OPTIONAL,
+  IN EFI_MAC_ADDRESS   *MCastFilter OPTIONAL
+  )
+{
+  return EmuSnpReceiveFilters (This, Enable, Disable, ResetMCastFilter, MCastFilterCnt, MCastFilter);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpStationAddress (
+  IN EMU_SNP_PROTOCOL  *This,
+  IN BOOLEAN           Reset,
+  IN EFI_MAC_ADDRESS   *New OPTIONAL
+  )
+{
+  return EmuSnpStationAddress (This, Reset, New);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpStatistics (
+  IN EMU_SNP_PROTOCOL         *This,
+  IN BOOLEAN                  Reset,
+  IN OUT UINTN                *StatisticsSize   OPTIONAL,
+  OUT EFI_NETWORK_STATISTICS  *StatisticsTable  OPTIONAL
+  )
+{
+  return EmuSnpStatistics (This, Reset, StatisticsSize, StatisticsTable);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpMCastIpToMac (
+  IN EMU_SNP_PROTOCOL  *This,
+  IN BOOLEAN           IPv6,
+  IN EFI_IP_ADDRESS    *IP,
+  OUT EFI_MAC_ADDRESS  *MAC
+  )
+{
+  return EmuSnpMCastIpToMac (This, IPv6, IP, MAC);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpNvData (
+  IN EMU_SNP_PROTOCOL  *This,
+  IN BOOLEAN           ReadWrite,
+  IN UINTN             Offset,
+  IN UINTN             BufferSize,
+  IN OUT VOID          *Buffer
+  )
+{
+  return EmuSnpNvData (This, ReadWrite, Offset, BufferSize, Buffer);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpGetStatus (
+  IN EMU_SNP_PROTOCOL  *This,
+  OUT UINT32           *InterruptStatus OPTIONAL,
+  OUT VOID             **TxBuf OPTIONAL
+  )
+{
+  return EmuSnpGetStatus (This, InterruptStatus, TxBuf);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpTransmit (
+  IN EMU_SNP_PROTOCOL  *This,
+  IN UINTN             HeaderSize,
+  IN UINTN             BufferSize,
+  IN VOID              *Buffer,
+  IN EFI_MAC_ADDRESS   *SrcAddr  OPTIONAL,
+  IN EFI_MAC_ADDRESS   *DestAddr OPTIONAL,
+  IN UINT16            *Protocol OPTIONAL
+  )
+{
+  return EmuSnpTransmit (This, HeaderSize, BufferSize, Buffer, SrcAddr, DestAddr, Protocol);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpReceive (
+  IN EMU_SNP_PROTOCOL  *This,
+  OUT UINTN            *HeaderSize OPTIONAL,
+  IN OUT UINTN         *BufferSize,
+  OUT VOID             *Buffer,
+  OUT EFI_MAC_ADDRESS  *SrcAddr    OPTIONAL,
+  OUT EFI_MAC_ADDRESS  *DestAddr   OPTIONAL,
+  OUT UINT16           *Protocol   OPTIONAL
+  )
+{
+  return EmuSnpReceive (This, HeaderSize, BufferSize, Buffer, SrcAddr, DestAddr, Protocol);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpThunkOpen (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  )
+{
+  return EmuSnpThunkOpen (This);
+}
+
+EFI_STATUS
+EFIAPI
+GasketSnpThunkClose (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  )
+{
+  return EmuSnpThunkClose (This);
+}
diff --git a/EmulatorPkg/Unix/Host/Arm/GasketFunctionDefinitions.h b/EmulatorPkg/Unix/Host/Arm/GasketFunctionDefinitions.h
new file mode 100644
index 0000000000..ab71dac9ec
--- /dev/null
+++ b/EmulatorPkg/Unix/Host/Arm/GasketFunctionDefinitions.h
@@ -0,0 +1,1092 @@
+/**@file GasketFunctionDefitions.h
+
+  This header file contains function definitions for the UNIX side of the ABI.
+  The Gaskets call these functions to allow UNIX APIs to be accessed from
+  within the PEI and DXE environments.
+
+Copyright (c) 2004 - 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// Functions for the top-level EMU_THUNK_PROTOCOL
+//
+
+#ifndef _GASKET_FUNCTION_DEFINITIONS_H_
+#define _GASKET_FUNCTION_DEFINITIONS_H_
+
+#include <Uefi/UefiBaseType.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/EmuThunk.h>
+#include <Protocol/EmuThread.h>
+#include <Protocol/EmuBlockIo.h>
+#include <Protocol/EmuGraphicsWindow.h>
+#include <Protocol/EmuSnp.h>
+#include "Gasket.h"
+
+UINTN
+SecWriteStdErr (
+  IN UINT8  *Buffer,
+  IN UINTN  NumberOfBytes
+  );
+
+EFI_STATUS
+SecConfigStdIn (
+  VOID
+  );
+
+UINTN
+SecWriteStdOut (
+  IN UINT8  *Buffer,
+  IN UINTN  NumberOfBytes
+  );
+
+UINTN
+SecReadStdIn (
+  IN UINT8  *Buffer,
+  IN UINTN  NumberOfBytes
+  );
+
+BOOLEAN
+SecPollStdIn (
+  VOID
+  );
+
+VOID *
+SecMalloc (
+  IN  UINTN  Size
+  );
+
+VOID *
+SecValloc (
+  IN  UINTN  Size
+  );
+
+BOOLEAN
+SecFree (
+  IN  VOID  *Ptr
+  );
+
+RETURN_STATUS
+EFIAPI
+SecPeCoffGetEntryPoint (
+  IN     VOID  *Pe32Data,
+  IN OUT VOID  **EntryPoint
+  );
+
+VOID
+EFIAPI
+SecPeCoffRelocateImageExtraAction (
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
+  );
+
+VOID
+SecEnableInterrupt (
+  VOID
+  );
+
+VOID
+SecDisableInterrupt (
+  VOID
+  );
+
+UINT64
+QueryPerformanceFrequency (
+  VOID
+  );
+
+UINT64
+QueryPerformanceCounter (
+  VOID
+  );
+
+VOID
+SecSleep (
+  IN  UINT64  Nanoseconds
+  );
+
+VOID
+SecCpuSleep (
+  VOID
+  );
+
+VOID
+SecExit (
+  UINTN  Status
+  );
+
+VOID
+SecGetTime (
+  OUT  EFI_TIME              *Time,
+  OUT EFI_TIME_CAPABILITIES  *Capabilities OPTIONAL
+  );
+
+VOID
+SecSetTime (
+  IN  EFI_TIME  *Time
+  );
+
+VOID
+SecSetTimer (
+  IN  UINT64                  PeriodMs,
+  IN  EMU_SET_TIMER_CALLBACK  CallBack
+  );
+
+EFI_STATUS
+SecGetNextProtocol (
+  IN  BOOLEAN                EmuBusDriver,
+  OUT EMU_IO_THUNK_PROTOCOL  **Instance   OPTIONAL
+  );
+
+VOID
+EFIAPI
+SecPeCoffUnloadImageExtraAction (
+  IN PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
+  );
+
+//
+// Functions for PPIs produced by SEC
+//
+
+EFI_STATUS
+SecUnixPeiAutoScan (
+  IN  UINTN                 Index,
+  OUT EFI_PHYSICAL_ADDRESS  *MemoryBase,
+  OUT UINT64                *MemorySize
+  );
+
+EFI_STATUS
+SecUnixFdAddress (
+  IN     UINTN                 Index,
+  IN OUT EFI_PHYSICAL_ADDRESS  *FdBase,
+  IN OUT UINT64                *FdSize,
+  IN OUT EFI_PHYSICAL_ADDRESS  *FixUp
+  );
+
+/**
+  Since the SEC is the only Unix program in stack it must export
+  an interface to do POSIX calls. gEmuThunkProtocol is initialized in EmuThunk.c
+
+  @retval Address of the gEmuThunkProtocol global
+
+**/
+VOID *
+SecEmuThunkAddress (
+  VOID
+  );
+
+//
+// Reverse (UNIX to EFIAPI) gaskets
+//
+
+typedef
+VOID
+(EFIAPI *CALL_BACK_2ARG) (
+  IN VOID  *Context,
+  IN VOID  *Key
+  );
+
+//
+// Functions for accessing libX11
+//
+
+EFI_STATUS
+X11Size (
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsIo,
+  IN  UINT32                        Width,
+  IN  UINT32                        Height
+  );
+
+EFI_STATUS
+X11CheckKey (
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsIo
+  );
+
+EFI_STATUS
+X11GetKey (
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsIo,
+  IN  EFI_KEY_DATA                  *KeyData
+  );
+
+EFI_STATUS
+X11KeySetState (
+  IN EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsIo,
+  IN EFI_KEY_TOGGLE_STATE          *KeyToggleState
+  );
+
+EFI_STATUS
+X11RegisterKeyNotify (
+  IN EMU_GRAPHICS_WINDOW_PROTOCOL                      *GraphicsIo,
+  IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK  MakeCallBack,
+  IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK  BreakCallBack,
+  IN VOID                                              *Context
+  );
+
+EFI_STATUS
+X11Blt (
+  IN EMU_GRAPHICS_WINDOW_PROTOCOL     *GraphicsIo,
+  IN  EFI_UGA_PIXEL                   *BltBuffer OPTIONAL,
+  IN  EFI_UGA_BLT_OPERATION           BltOperation,
+  IN  EMU_GRAPHICS_WINDOWS__BLT_ARGS  *Args
+  );
+
+EFI_STATUS
+X11CheckPointer (
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsIo
+  );
+
+EFI_STATUS
+X11GetPointerState (
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsIo,
+  IN  EFI_SIMPLE_POINTER_STATE      *State
+  );
+
+EFI_STATUS
+X11GraphicsWindowOpen (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  );
+
+EFI_STATUS
+X11GraphicsWindowClose (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  );
+
+//
+// Functions for accessing Pthreads
+//
+
+UINTN
+EFIAPI
+PthreadMutexLock (
+  IN VOID  *Mutex
+  );
+
+UINTN
+EFIAPI
+PthreadMutexUnLock (
+  IN VOID  *Mutex
+  );
+
+UINTN
+EFIAPI
+PthreadMutexTryLock (
+  IN VOID  *Mutex
+  );
+
+VOID *
+PthreadMutexInit (
+  IN VOID
+  );
+
+UINTN
+PthreadMutexDestroy (
+  IN VOID  *Mutex
+  );
+
+UINTN
+PthreadCreate (
+  IN  VOID                       *Thread,
+  IN  VOID                       *Attribute,
+  IN  THREAD_THUNK_THREAD_ENTRY  Start,
+  IN  VOID                       *Context
+  );
+
+VOID
+PthreadExit (
+  IN VOID  *ValuePtr
+  );
+
+UINTN
+PthreadSelf (
+  VOID
+  );
+
+EFI_STATUS
+PthreadOpen (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  );
+
+EFI_STATUS
+PthreadClose (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  );
+
+//
+// Functions for accessing the host filesystem
+//
+
+/**
+  Open the root directory on a volume.
+
+  @param  This Protocol instance pointer.
+  @param  Root Returns an Open file handle for the root directory
+
+  @retval EFI_SUCCESS          The device was opened.
+  @retval EFI_UNSUPPORTED      This volume does not support the file system.
+  @retval EFI_NO_MEDIA         The device has no media.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_ACCESS_DENIED    The service denied access to the file.
+  @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
+
+**/
+EFI_STATUS
+PosixOpenVolume (
+  IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *This,
+  OUT EFI_FILE_PROTOCOL               **Root
+  );
+
+/**
+  Opens a new file relative to the source file's location.
+
+  @param  This       The protocol instance pointer.
+  @param  NewHandle  Returns File Handle for FileName.
+  @param  FileName   Null terminated string. "\", ".", and ".." are supported.
+  @param  OpenMode   Open mode for file.
+  @param  Attributes Only used for EFI_FILE_MODE_CREATE.
+
+  @retval EFI_SUCCESS          The device was opened.
+  @retval EFI_NOT_FOUND        The specified file could not be found on the device.
+  @retval EFI_NO_MEDIA         The device has no media.
+  @retval EFI_MEDIA_CHANGED    The media has changed.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_ACCESS_DENIED    The service denied access to the file.
+  @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
+  @retval EFI_VOLUME_FULL      The volume is full.
+
+**/
+EFI_STATUS
+PosixFileOpen (
+  IN EFI_FILE_PROTOCOL   *This,
+  OUT EFI_FILE_PROTOCOL  **NewHandle,
+  IN CHAR16              *FileName,
+  IN UINT64              OpenMode,
+  IN UINT64              Attributes
+  );
+
+/**
+  Close the file handle
+
+  @param  This          Protocol instance pointer.
+
+  @retval EFI_SUCCESS   The device was opened.
+
+**/
+EFI_STATUS
+PosixFileClose (
+  IN EFI_FILE_PROTOCOL  *This
+  );
+
+/**
+  Close and delete the file handle.
+
+  @param  This                     Protocol instance pointer.
+
+  @retval EFI_SUCCESS              The device was opened.
+  @retval EFI_WARN_DELETE_FAILURE  The handle was closed but the file was not deleted.
+
+**/
+EFI_STATUS
+PosixFileDelete (
+  IN EFI_FILE_PROTOCOL  *This
+  );
+
+/**
+  Read data from the file.
+
+  @param  This       Protocol instance pointer.
+  @param  BufferSize On input size of buffer, on output amount of data in buffer.
+  @param  Buffer     The buffer in which data is read.
+
+  @retval EFI_SUCCESS          Data was read.
+  @retval EFI_NO_MEDIA         The device has no media.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_BUFFER_TO_SMALL  BufferSize is too small. BufferSize contains required size.
+
+**/
+EFI_STATUS
+PosixFileRead (
+  IN EFI_FILE_PROTOCOL  *This,
+  IN OUT UINTN          *BufferSize,
+  OUT VOID              *Buffer
+  );
+
+/**
+  Write data to a file.
+
+  @param  This       Protocol instance pointer.
+  @param  BufferSize On input size of buffer, on output amount of data in buffer.
+  @param  Buffer     The buffer in which data to write.
+
+  @retval EFI_SUCCESS          Data was written.
+  @retval EFI_UNSUPPORTED      Writes to Open directory are not supported.
+  @retval EFI_NO_MEDIA         The device has no media.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_DEVICE_ERROR     An attempt was made to write to a deleted file.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_WRITE_PROTECTED  The device is write protected.
+  @retval EFI_ACCESS_DENIED    The file was open for read only.
+  @retval EFI_VOLUME_FULL      The volume is full.
+
+**/
+EFI_STATUS
+PosixFileWrite (
+  IN EFI_FILE_PROTOCOL  *This,
+  IN OUT UINTN          *BufferSize,
+  IN VOID               *Buffer
+  );
+
+/**
+  Set a files current position
+
+  @param  This            Protocol instance pointer.
+  @param  Position        Byte position from the start of the file.
+
+  @retval EFI_SUCCESS     Data was written.
+  @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
+
+**/
+EFI_STATUS
+PosixFileSetPosition (
+  IN EFI_FILE_PROTOCOL  *This,
+  IN UINT64             Position
+  );
+
+/**
+  Get a file's current position
+
+  @param  This            Protocol instance pointer.
+  @param  Position        Byte position from the start of the file.
+
+  @retval EFI_SUCCESS     Data was written.
+  @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
+
+**/
+EFI_STATUS
+PosixFileGetPosition (
+  IN EFI_FILE_PROTOCOL  *This,
+  OUT UINT64            *Position
+  );
+
+/**
+  Get information about a file.
+
+  @param  This            Protocol instance pointer.
+  @param  InformationType Type of information to return in Buffer.
+  @param  BufferSize      On input size of buffer, on output amount of data in buffer.
+  @param  Buffer          The buffer to return data.
+
+  @retval EFI_SUCCESS          Data was returned.
+  @retval EFI_UNSUPPORTED      InformationType is not supported.
+  @retval EFI_NO_MEDIA         The device has no media.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_WRITE_PROTECTED  The device is write protected.
+  @retval EFI_ACCESS_DENIED    The file was open for read only.
+  @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
+
+**/
+EFI_STATUS
+PosixFileGetInfo (
+  IN EFI_FILE_PROTOCOL  *This,
+  IN EFI_GUID           *InformationType,
+  IN OUT UINTN          *BufferSize,
+  OUT VOID              *Buffer
+  );
+
+/**
+  Set information about a file
+
+  @param  File            Protocol instance pointer.
+  @param  InformationType Type of information in Buffer.
+  @param  BufferSize      Size of buffer.
+  @param  Buffer          The data to write.
+
+  @retval EFI_SUCCESS          Data was returned.
+  @retval EFI_UNSUPPORTED      InformationType is not supported.
+  @retval EFI_NO_MEDIA         The device has no media.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_WRITE_PROTECTED  The device is write protected.
+  @retval EFI_ACCESS_DENIED    The file was open for read only.
+
+**/
+EFI_STATUS
+PosixFileSetInfo (
+  IN EFI_FILE_PROTOCOL  *This,
+  IN EFI_GUID           *InformationType,
+  IN UINTN              BufferSize,
+  IN VOID               *Buffer
+  );
+
+/**
+  Flush data back for the file handle.
+
+  @param  This Protocol instance pointer.
+
+  @retval EFI_SUCCESS          Data was written.
+  @retval EFI_UNSUPPORTED      Writes to Open directory are not supported.
+  @retval EFI_NO_MEDIA         The device has no media.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_WRITE_PROTECTED  The device is write protected.
+  @retval EFI_ACCESS_DENIED    The file was open for read only.
+  @retval EFI_VOLUME_FULL      The volume is full.
+
+**/
+EFI_STATUS
+PosixFileFlush (
+  IN EFI_FILE_PROTOCOL  *This
+  );
+
+EFI_STATUS
+PosixFileSystemThunkOpen (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  );
+
+EFI_STATUS
+PosixFileSystemThunkClose (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  );
+
+//
+// Functions for reading/writing to disk images
+//
+
+EFI_STATUS
+EmuBlockIoReset (
+  IN EMU_BLOCK_IO_PROTOCOL  *This,
+  IN BOOLEAN                ExtendedVerification
+  );
+
+/**
+  Read BufferSize bytes from Lba into Buffer.
+
+  This function reads the requested number of blocks from the device. All the
+  blocks are read, or an error is returned.
+  If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
+  non-blocking I/O is being used, the Event associated with this request will
+  not be signaled.
+
+  @param[in]       This       Indicates a pointer to the calling context.
+  @param[in]       MediaId    Id of the media, changes every time the media is
+                              replaced.
+  @param[in]       Lba        The starting Logical Block Address to read from.
+  @param[in, out]  Token      A pointer to the token associated with the transaction.
+  @param[in]       BufferSize Size of Buffer, must be a multiple of device block size.
+  @param[out]      Buffer     A pointer to the destination buffer for the data. The
+                              caller is responsible for either having implicit or
+                              explicit ownership of the buffer.
+
+  @retval EFI_SUCCESS           The read request was queued if Token->Event is
+                                not NULL.The data was read correctly from the
+                                device if the Token->Event is NULL.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing
+                                the read.
+  @retval EFI_NO_MEDIA          There is no media in the device.
+  @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
+  @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the
+                                intrinsic block size of the device.
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+                                or the buffer is not on proper alignment.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack
+                                of resources.
+**/
+EFI_STATUS
+EmuBlockIoReadBlocks (
+  IN     EMU_BLOCK_IO_PROTOCOL  *This,
+  IN     UINT32                 MediaId,
+  IN     EFI_LBA                LBA,
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
+  IN     UINTN                  BufferSize,
+  OUT VOID                      *Buffer
+  );
+
+/**
+  Write BufferSize bytes from Lba into Buffer.
+
+  This function writes the requested number of blocks to the device. All blocks
+  are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
+  EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
+  being used, the Event associated with this request will not be signaled.
+
+  @param[in]       This       Indicates a pointer to the calling context.
+  @param[in]       MediaId    The media ID that the write request is for.
+  @param[in]       Lba        The starting logical block address to be written. The
+                              caller is responsible for writing to only legitimate
+                              locations.
+  @param[in, out]  Token      A pointer to the token associated with the transaction.
+  @param[in]       BufferSize Size of Buffer, must be a multiple of device block size.
+  @param[in]       Buffer     A pointer to the source buffer for the data.
+
+  @retval EFI_SUCCESS           The write request was queued if Event is not NULL.
+                                The data was written correctly to the device if
+                                the Event is NULL.
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.
+  @retval EFI_NO_MEDIA          There is no media in the device.
+  @retval EFI_MEDIA_CHANGED     The MediaId does not match the current device.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+                                or the buffer is not on proper alignment.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack
+                                of resources.
+
+**/
+EFI_STATUS
+EmuBlockIoWriteBlocks (
+  IN     EMU_BLOCK_IO_PROTOCOL  *This,
+  IN     UINT32                 MediaId,
+  IN     EFI_LBA                LBA,
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
+  IN     UINTN                  BufferSize,
+  IN     VOID                   *Buffer
+  );
+
+/**
+  Flush the Block Device.
+
+  If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
+  is returned and non-blocking I/O is being used, the Event associated with
+  this request will not be signaled.
+
+  @param[in]      This     Indicates a pointer to the calling context.
+  @param[in,out]  Token    A pointer to the token associated with the transaction
+
+  @retval EFI_SUCCESS          The flush request was queued if Event is not NULL.
+                               All outstanding data was written correctly to the
+                               device if the Event is NULL.
+  @retval EFI_DEVICE_ERROR     The device reported an error while writing back
+                               the data.
+  @retval EFI_WRITE_PROTECTED  The device cannot be written to.
+  @retval EFI_NO_MEDIA         There is no media in the device.
+  @retval EFI_MEDIA_CHANGED    The MediaId is not for the current media.
+  @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+                               of resources.
+
+**/
+EFI_STATUS
+EmuBlockIoFlushBlocks (
+  IN     EMU_BLOCK_IO_PROTOCOL  *This,
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token
+  );
+
+EFI_STATUS
+EmuBlockIoCreateMapping (
+  IN     EMU_BLOCK_IO_PROTOCOL  *This,
+  IN     EFI_BLOCK_IO_MEDIA     *Media
+  );
+
+EFI_STATUS
+EmuBlockIoThunkOpen (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  );
+
+EFI_STATUS
+EmuBlockIoThunkClose (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  );
+
+//
+// Functions for accessing BSD Sockets (TCP-IP Networks)
+//
+
+/**
+  Register storage for SNP Mode.
+
+  @param  This Protocol instance pointer.
+  @param  Mode SimpleNetworkProtocol Mode structure passed into driver.
+
+  @retval EFI_SUCCESS           The network interface was started.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+
+**/
+EFI_STATUS
+EmuSnpCreateMapping (
+  IN     EMU_SNP_PROTOCOL         *This,
+  IN     EFI_SIMPLE_NETWORK_MODE  *Mode
+  );
+
+/**
+  Changes the state of a network interface from "stopped" to "started".
+
+  @param  This Protocol instance pointer.
+
+  @retval EFI_SUCCESS           The network interface was started.
+  @retval EFI_ALREADY_STARTED   The network interface is already in the started state.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EmuSnpStart (
+  IN EMU_SNP_PROTOCOL  *This
+  );
+
+/**
+  Changes the state of a network interface from "started" to "stopped".
+
+  @param  This Protocol instance pointer.
+
+  @retval EFI_SUCCESS           The network interface was stopped.
+  @retval EFI_ALREADY_STARTED   The network interface is already in the stopped state.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EmuSnpStop (
+  IN EMU_SNP_PROTOCOL  *This
+  );
+
+/**
+  Resets a network adapter and allocates the transmit and receive buffers
+  required by the network interface; optionally, also requests allocation
+  of additional transmit and receive buffers.
+
+  @param  This              The protocol instance pointer.
+  @param  ExtraRxBufferSize The size, in bytes, of the extra receive buffer space
+                            that the driver should allocate for the network interface.
+                            Some network interfaces will not be able to use the extra
+                            buffer, and the caller will not know if it is actually
+                            being used.
+  @param  ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space
+                            that the driver should allocate for the network interface.
+                            Some network interfaces will not be able to use the extra
+                            buffer, and the caller will not know if it is actually
+                            being used.
+
+  @retval EFI_SUCCESS           The network interface was initialized.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_OUT_OF_RESOURCES  There was not enough memory for the transmit and
+                                receive buffers.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EmuSnpInitialize (
+  IN EMU_SNP_PROTOCOL  *This,
+  IN UINTN             ExtraRxBufferSize  OPTIONAL,
+  IN UINTN             ExtraTxBufferSize  OPTIONAL
+  );
+
+/**
+  Resets a network adapter and re-initializes it with the parameters that were
+  provided in the previous call to Initialize().
+
+  @param  This                 The protocol instance pointer.
+  @param  ExtendedVerification Indicates that the driver may perform a more
+                               exhaustive verification operation of the device
+                               during reset.
+
+  @retval EFI_SUCCESS           The network interface was reset.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EmuSnpReset (
+  IN EMU_SNP_PROTOCOL  *This,
+  IN BOOLEAN           ExtendedVerification
+  );
+
+/**
+  Resets a network adapter and leaves it in a state that is safe for
+  another driver to initialize.
+
+  @param  This Protocol instance pointer.
+
+  @retval EFI_SUCCESS           The network interface was shutdown.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EmuSnpShutdown (
+  IN EMU_SNP_PROTOCOL  *This
+  );
+
+/**
+  Manages the multicast receive filters of a network interface.
+
+  @param  This             The protocol instance pointer.
+  @param  Enable           A bit mask of receive filters to enable on the network interface.
+  @param  Disable          A bit mask of receive filters to disable on the network interface.
+  @param  ResetMCastFilter Set to TRUE to reset the contents of the multicast receive
+                           filters on the network interface to their default values.
+  @param  McastFilterCnt   Number of multicast HW MAC addresses in the new
+                           MCastFilter list. This value must be less than or equal to
+                           the MCastFilterCnt field of EMU_SNP_MODE. This
+                           field is optional if ResetMCastFilter is TRUE.
+  @param  MCastFilter      A pointer to a list of new multicast receive filter HW MAC
+                           addresses. This list will replace any existing multicast
+                           HW MAC address list. This field is optional if
+                           ResetMCastFilter is TRUE.
+
+  @retval EFI_SUCCESS           The multicast receive filter list was updated.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EmuSnpReceiveFilters (
+  IN EMU_SNP_PROTOCOL  *This,
+  IN UINT32            Enable,
+  IN UINT32            Disable,
+  IN BOOLEAN           ResetMCastFilter,
+  IN UINTN             MCastFilterCnt     OPTIONAL,
+  IN EFI_MAC_ADDRESS   *MCastFilter OPTIONAL
+  );
+
+/**
+  Modifies or resets the current station address, if supported.
+
+  @param  This  The protocol instance pointer.
+  @param  Reset Flag used to reset the station address to the network interfaces
+                permanent address.
+  @param  New   The new station address to be used for the network interface.
+
+  @retval EFI_SUCCESS           The network interfaces station address was updated.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EmuSnpStationAddress (
+  IN EMU_SNP_PROTOCOL  *This,
+  IN BOOLEAN           Reset,
+  IN EFI_MAC_ADDRESS   *New OPTIONAL
+  );
+
+/**
+  Resets or collects the statistics on a network interface.
+
+  @param  This            Protocol instance pointer.
+  @param  Reset           Set to TRUE to reset the statistics for the network interface.
+  @param  StatisticsSize  On input the size, in bytes, of StatisticsTable. On
+                          output the size, in bytes, of the resulting table of
+                          statistics.
+  @param  StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
+                          contains the statistics.
+
+  @retval EFI_SUCCESS           The statistics were collected from the network interface.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_BUFFER_TOO_SMALL  The Statistics buffer was too small. The current buffer
+                                size needed to hold the statistics is returned in
+                                StatisticsSize.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EmuSnpStatistics (
+  IN EMU_SNP_PROTOCOL         *This,
+  IN BOOLEAN                  Reset,
+  IN OUT UINTN                *StatisticsSize   OPTIONAL,
+  OUT EFI_NETWORK_STATISTICS  *StatisticsTable  OPTIONAL
+  );
+
+/**
+  Converts a multicast IP address to a multicast HW MAC address.
+
+  @param  This The protocol instance pointer.
+  @param  IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460]. Set
+               to FALSE if the multicast IP address is IPv4 [RFC 791].
+  @param  IP   The multicast IP address that is to be converted to a multicast
+               HW MAC address.
+  @param  MAC  The multicast HW MAC address that is to be generated from IP.
+
+  @retval EFI_SUCCESS           The multicast IP address was mapped to the multicast
+                                HW MAC address.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_BUFFER_TOO_SMALL  The Statistics buffer was too small. The current buffer
+                                size needed to hold the statistics is returned in
+                                StatisticsSize.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EmuSnpMCastIpToMac (
+  IN EMU_SNP_PROTOCOL  *This,
+  IN BOOLEAN           IPv6,
+  IN EFI_IP_ADDRESS    *IP,
+  OUT EFI_MAC_ADDRESS  *MAC
+  );
+
+/**
+  Performs read and write operations on the NVRAM device attached to a
+  network interface.
+
+  @param  This       The protocol instance pointer.
+  @param  ReadWrite  TRUE for read operations, FALSE for write operations.
+  @param  Offset     Byte offset in the NVRAM device at which to start the read or
+                     write operation. This must be a multiple of NvRamAccessSize and
+                     less than NvRamSize.
+  @param  BufferSize The number of bytes to read or write from the NVRAM device.
+                     This must also be a multiple of NvramAccessSize.
+  @param  Buffer     A pointer to the data buffer.
+
+  @retval EFI_SUCCESS           The NVRAM access was performed.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EmuSnpNvData (
+  IN EMU_SNP_PROTOCOL  *This,
+  IN BOOLEAN           ReadWrite,
+  IN UINTN             Offset,
+  IN UINTN             BufferSize,
+  IN OUT VOID          *Buffer
+  );
+
+/**
+  Reads the current interrupt status and recycled transmit buffer status from
+  a network interface.
+
+  @param  This            The protocol instance pointer.
+  @param  InterruptStatus A pointer to the bit mask of the currently active interrupts
+                          If this is NULL, the interrupt status will not be read from
+                          the device. If this is not NULL, the interrupt status will
+                          be read from the device. When the  interrupt status is read,
+                          it will also be cleared. Clearing the transmit  interrupt
+                          does not empty the recycled transmit buffer array.
+  @param  TxBuf           Recycled transmit buffer address. The network interface will
+                          not transmit if its internal recycled transmit buffer array
+                          is full. Reading the transmit buffer does not clear the
+                          transmit interrupt. If this is NULL, then the transmit buffer
+                          status will not be read. If there are no transmit buffers to
+                          recycle and TxBuf is not NULL, * TxBuf will be set to NULL.
+
+  @retval EFI_SUCCESS           The status of the network interface was retrieved.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EmuSnpGetStatus (
+  IN EMU_SNP_PROTOCOL  *This,
+  OUT UINT32           *InterruptStatus OPTIONAL,
+  OUT VOID             **TxBuf OPTIONAL
+  );
+
+/**
+  Places a packet in the transmit queue of a network interface.
+
+  @param  This       The protocol instance pointer.
+  @param  HeaderSize The size, in bytes, of the media header to be filled in by
+                     the Transmit() function. If HeaderSize is non-zero, then it
+                     must be equal to This->Mode->MediaHeaderSize and the DestAddr
+                     and Protocol parameters must not be NULL.
+  @param  BufferSize The size, in bytes, of the entire packet (media header and
+                     data) to be transmitted through the network interface.
+  @param  Buffer     A pointer to the packet (media header followed by data) to be
+                     transmitted. This parameter cannot be NULL. If HeaderSize is zero,
+                     then the media header in Buffer must already be filled in by the
+                     caller. If HeaderSize is non-zero, then the media header will be
+                     filled in by the Transmit() function.
+  @param  SrcAddr    The source HW MAC address. If HeaderSize is zero, then this parameter
+                     is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then
+                     This->Mode->CurrentAddress is used for the source HW MAC address.
+  @param  DestAddr   The destination HW MAC address. If HeaderSize is zero, then this
+                     parameter is ignored.
+  @param  Protocol   The type of header to build. If HeaderSize is zero, then this
+                     parameter is ignored. See RFC 1700, section "Ether Types", for
+                     examples.
+
+  @retval EFI_SUCCESS           The packet was placed on the transmit queue.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_NOT_READY         The network interface is too busy to accept this transmit request.
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EmuSnpTransmit (
+  IN EMU_SNP_PROTOCOL  *This,
+  IN UINTN             HeaderSize,
+  IN UINTN             BufferSize,
+  IN VOID              *Buffer,
+  IN EFI_MAC_ADDRESS   *SrcAddr  OPTIONAL,
+  IN EFI_MAC_ADDRESS   *DestAddr OPTIONAL,
+  IN UINT16            *Protocol OPTIONAL
+  );
+
+/**
+  Receives a packet from a network interface.
+
+  @param  This       The protocol instance pointer.
+  @param  HeaderSize The size, in bytes, of the media header received on the network
+                     interface. If this parameter is NULL, then the media header size
+                     will not be returned.
+  @param  BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
+                     bytes, of the packet that was received on the network interface.
+  @param  Buffer     A pointer to the data buffer to receive both the media header and
+                     the data.
+  @param  SrcAddr    The source HW MAC address. If this parameter is NULL, the
+                     HW MAC source address will not be extracted from the media
+                     header.
+  @param  DestAddr   The destination HW MAC address. If this parameter is NULL,
+                     the HW MAC destination address will not be extracted from the
+                     media header.
+  @param  Protocol   The media header type. If this parameter is NULL, then the
+                     protocol will not be extracted from the media header. See
+                     RFC 1700 section "Ether Types" for examples.
+
+  @retval  EFI_SUCCESS           The received data was stored in Buffer, and BufferSize has
+                                 been updated to the number of bytes received.
+  @retval  EFI_NOT_STARTED       The network interface has not been started.
+  @retval  EFI_NOT_READY         The network interface is too busy to accept this transmit
+                                 request.
+  @retval  EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.
+  @retval  EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval  EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval  EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EmuSnpReceive (
+  IN EMU_SNP_PROTOCOL  *This,
+  OUT UINTN            *HeaderSize OPTIONAL,
+  IN OUT UINTN         *BufferSize,
+  OUT VOID             *Buffer,
+  OUT EFI_MAC_ADDRESS  *SrcAddr    OPTIONAL,
+  OUT EFI_MAC_ADDRESS  *DestAddr   OPTIONAL,
+  OUT UINT16           *Protocol   OPTIONAL
+  );
+
+EFI_STATUS
+EmuSnpThunkOpen (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  );
+
+EFI_STATUS
+EmuSnpThunkClose (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  );
+
+#endif
diff --git a/EmulatorPkg/Unix/Host/Arm/SwitchStack.S b/EmulatorPkg/Unix/Host/Arm/SwitchStack.S
new file mode 100644
index 0000000000..cb3dfcf5c0
--- /dev/null
+++ b/EmulatorPkg/Unix/Host/Arm/SwitchStack.S
@@ -0,0 +1,39 @@
+#------------------------------------------------------------------------------
+#
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+
+#include <AsmMacroIoLib.h>
+
+#/**
+#   Routine for switching stacks with 2 parameters
+#
+# @param      EntryPoint     Entry point to be invoked after switching stack
+# @param      Context1       Parameter1 for entry point.
+# @param      Context2       Parameter2 for entry point.
+# @param      NewStack       The pointer to the new stack.
+#
+# @return     None
+#
+#**/
+#VOID
+#EFIAPI
+#PeiSwitchStacks (
+#  IN      SWITCH_STACK_ENTRY_POINT  EntryPoint,
+#  IN      VOID                      *Context1   OPTIONAL,
+#  IN      VOID                      *Context2   OPTIONAL,
+#  IN      VOID                      *NewStack
+#  )
+#
+ASM_FUNC(PeiSwitchStacks)
+    mov   sp, r3
+    push {r1}
+    push {r2}
+    push {r0}
+    pop  {r3}
+    pop  {r1}
+    pop  {r0}
+    bx   r3
diff --git a/EmulatorPkg/Unix/Host/Host.inf b/EmulatorPkg/Unix/Host/Host.inf
index f5ebbed683..effd0a3217 100644
--- a/EmulatorPkg/Unix/Host/Host.inf
+++ b/EmulatorPkg/Unix/Host/Host.inf
@@ -2,7 +2,7 @@
 # Entry Point of Emu Emulator
 #
 # Main executable file of Unix Emulator that loads PEI core after initialization finished.
-# Copyright (c) 2008 - 2022, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2008 - 2023, Intel Corporation. All rights reserved.<BR>
 # Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -42,6 +42,10 @@
   Ia32/Gasket.S       # enforce 16-byte stack alignment for Mac OS X
   Ia32/SwitchStack.c
 
+[Sources.ARM]
+  Arm/Gasket.c
+  Arm/SwitchStack.S
+  CacheMaintenance.c
 
 [Packages]
   MdePkg/MdePkg.dec
@@ -49,6 +53,9 @@
   NetworkPkg/NetworkPkg.dec
   EmulatorPkg/EmulatorPkg.dec
 
+[Packages.ARM]
+  ArmPkg/ArmPkg.dec
+
 [LibraryClasses]
   DebugLib
   PcdLib
@@ -127,6 +134,9 @@
    GCC:*_*_X64_PP_FLAGS == -m64 -E -x assembler-with-cpp -include $(DEST_DIR_DEBUG)/AutoGen.h
    GCC:*_*_X64_ASM_FLAGS == -m64 -c -x assembler -imacros $(DEST_DIR_DEBUG)/AutoGen.h
 
+   GCC:*_*_ARM_DLINK_FLAGS == -o $(BIN_DIR)/Host -mthumb -march=armv7-a -mlittle-endian -mabi=aapcs -L/usr/X11R6/lib
+   GCC:*_*_ARM_CC_FLAGS == -g -Os -fshort-wchar -fno-builtin -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -fno-common -march=armv7-a -mlittle-endian -mabi=aapcs -fno-short-enums -funsigned-char -fstack-protector -Wno-unused-but-set-variable -Wno-unused-const-variable -mword-relocations -flto -ffunction-sections -fdata-sections -fomit-frame-pointer -Wno-address -mthumb -mfloat-abi=hard -fno-pic -fno-pie -c -include $(DEST_DIR_DEBUG)/AutoGen.h
+
    GCC:*_*_*_DLINK2_FLAGS == -lpthread -ldl -lXext -lX11
 
 #
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v1 5/6] EmulatorPkg: Add ARM support to EmuSec
  2023-03-06  0:21 [PATCH v1 0/6] Add Raspberry Pi Support to EmulatorPkg Nate DeSimone
                   ` (3 preceding siblings ...)
  2023-03-06  0:22 ` [PATCH v1 4/6] EmulatorPkg: Add ARM support to UNIX Host App Nate DeSimone
@ 2023-03-06  0:22 ` Nate DeSimone
  2023-03-06  0:22 ` [PATCH v1 6/6] EmulatorPkg: Add EmuCacheMaintenanceLib Nate DeSimone
  2023-03-10 16:45 ` [edk2-devel] [PATCH v1 0/6] Add Raspberry Pi Support to EmulatorPkg Ard Biesheuvel
  6 siblings, 0 replies; 8+ messages in thread
From: Nate DeSimone @ 2023-03-06  0:22 UTC (permalink / raw)
  To: devel; +Cc: Andrew Fish, Ray Ni, Michael D Kinney, Chasel Chiu

Adds ARM implementation of EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI.

Cc: Andrew Fish <afish@apple.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Chasel Chiu <chasel.chiu@intel.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
---
 EmulatorPkg/Sec/Arm/SwitchRam.S | 32 ++++++++++++++++++
 EmulatorPkg/Sec/Arm/TempRam.c   | 58 +++++++++++++++++++++++++++++++++
 EmulatorPkg/Sec/Sec.inf         |  9 ++++-
 3 files changed, 98 insertions(+), 1 deletion(-)
 create mode 100644 EmulatorPkg/Sec/Arm/SwitchRam.S
 create mode 100644 EmulatorPkg/Sec/Arm/TempRam.c

diff --git a/EmulatorPkg/Sec/Arm/SwitchRam.S b/EmulatorPkg/Sec/Arm/SwitchRam.S
new file mode 100644
index 0000000000..d64772b8ed
--- /dev/null
+++ b/EmulatorPkg/Sec/Arm/SwitchRam.S
@@ -0,0 +1,32 @@
+#------------------------------------------------------------------------------
+#
+# Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+# Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+
+#include <AsmMacroIoLib.h>
+
+#/**
+#  This allows the caller to switch the stack and return
+#
+# @param      StackDelta     Signed amount by which to modify the stack pointer
+#
+# @return     Nothing. Goes to the Entry Point passing in the new parameters
+#
+#**/
+#VOID
+#EFIAPI
+#SecSwitchStack (
+#  VOID  *StackDelta
+#  )#
+#
+ASM_FUNC(SecSwitchStack)
+    mov   R1, R13
+    add   R1, R0, R1
+    mov   R13, R1
+    bx    LR
+
+
+
diff --git a/EmulatorPkg/Sec/Arm/TempRam.c b/EmulatorPkg/Sec/Arm/TempRam.c
new file mode 100644
index 0000000000..0a6b215591
--- /dev/null
+++ b/EmulatorPkg/Sec/Arm/TempRam.c
@@ -0,0 +1,58 @@
+/*++ @file
+  Temp RAM PPI
+
+  Copyright (c) 2011, Apple Inc. All rights reserved.<BR>
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#include <Ppi/TemporaryRamSupport.h>
+
+VOID
+SecSwitchStack (
+  INTN  StackDelta
+  );
+
+EFI_STATUS
+EFIAPI
+SecTemporaryRamSupport (
+  IN CONST EFI_PEI_SERVICES  **PeiServices,
+  IN EFI_PHYSICAL_ADDRESS    TemporaryMemoryBase,
+  IN EFI_PHYSICAL_ADDRESS    PermanentMemoryBase,
+  IN UINTN                   CopySize
+  )
+{
+  //
+  // Migrate the whole temporary memory to permanent memory.
+  //
+  CopyMem (
+    (VOID *)(UINTN)PermanentMemoryBase,
+    (VOID *)(UINTN)TemporaryMemoryBase,
+    CopySize
+    );
+
+  //
+  // SecSwitchStack function must be invoked after the memory migration
+  // immediately, also we need fixup the stack change caused by new call into
+  // permanent memory.
+  //
+  SecSwitchStack ((UINTN)(PermanentMemoryBase - TemporaryMemoryBase));
+
+  //
+  // We need *not* fix the return address because currently,
+  // The PeiCore is executed in flash.
+  //
+
+  //
+  // Simulate to invalid temporary memory, terminate temporary memory
+  //
+  // ZeroMem ((VOID*)(UINTN)TemporaryMemoryBase, CopySize);
+
+  return EFI_SUCCESS;
+}
diff --git a/EmulatorPkg/Sec/Sec.inf b/EmulatorPkg/Sec/Sec.inf
index 2f9e3d4780..264666f544 100644
--- a/EmulatorPkg/Sec/Sec.inf
+++ b/EmulatorPkg/Sec/Sec.inf
@@ -3,7 +3,7 @@
 #
 # Main executable file of Unix Emulator that loads PEI core after initialization finished.
 # Portions copyright (c) 2011, Apple Inc. All rights reserved.<BR>
-# Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2012 - 2023, Intel Corporation. All rights reserved.<BR>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -30,10 +30,17 @@
   Ia32/SwitchRam.asm
   Ia32/SwitchRam.S
 
+[Sources.ARM]
+  Arm/TempRam.c
+  Arm/SwitchRam.S
+
 [Packages]
   MdePkg/MdePkg.dec
   EmulatorPkg/EmulatorPkg.dec
 
+[Packages.ARM]
+  ArmPkg/ArmPkg.dec
+
 [LibraryClasses]
   DebugLib
   PeCoffGetEntryPointLib
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v1 6/6] EmulatorPkg: Add EmuCacheMaintenanceLib
  2023-03-06  0:21 [PATCH v1 0/6] Add Raspberry Pi Support to EmulatorPkg Nate DeSimone
                   ` (4 preceding siblings ...)
  2023-03-06  0:22 ` [PATCH v1 5/6] EmulatorPkg: Add ARM support to EmuSec Nate DeSimone
@ 2023-03-06  0:22 ` Nate DeSimone
  2023-03-10 16:45 ` [edk2-devel] [PATCH v1 0/6] Add Raspberry Pi Support to EmulatorPkg Ard Biesheuvel
  6 siblings, 0 replies; 8+ messages in thread
From: Nate DeSimone @ 2023-03-06  0:22 UTC (permalink / raw)
  To: devel; +Cc: Andrew Fish, Ray Ni, Michael D Kinney, Chasel Chiu

Adds new implementation of CacheMaintenanceLib that uses the GCC
intrinsic __builtin__clear_cache() to clear processor caches. This
is required on machine types that use a syscall to access the
cache controller.

Cc: Andrew Fish <afish@apple.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Chasel Chiu <chasel.chiu@intel.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
---
 EmulatorPkg/EmulatorPkg.dec                   |   4 +-
 EmulatorPkg/EmulatorPkg.dsc                   |   7 +
 EmulatorPkg/Include/Protocol/EmuCache.h       | 217 +++++++++++
 .../DxeEmuCacheMaintenanceLib.c               | 337 +++++++++++++++++
 .../DxeEmuCacheMaintenanceLib.inf             |  37 ++
 .../PeiEmuCacheMaintenanceLib.c               | 344 ++++++++++++++++++
 .../PeiEmuCacheMaintenanceLib.inf             |  39 ++
 EmulatorPkg/Unix/Host/CacheMaintenance.c      | 284 +++++++++++++++
 EmulatorPkg/Unix/Host/Host.c                  |   5 +-
 EmulatorPkg/Unix/Host/Host.h                  |   2 +
 EmulatorPkg/Unix/Host/Host.inf                |   2 +
 11 files changed, 1276 insertions(+), 2 deletions(-)
 create mode 100644 EmulatorPkg/Include/Protocol/EmuCache.h
 create mode 100644 EmulatorPkg/Library/DxeEmuCacheMaintenanceLib/DxeEmuCacheMaintenanceLib.c
 create mode 100644 EmulatorPkg/Library/DxeEmuCacheMaintenanceLib/DxeEmuCacheMaintenanceLib.inf
 create mode 100644 EmulatorPkg/Library/PeiEmuCacheMaintenanceLib/PeiEmuCacheMaintenanceLib.c
 create mode 100644 EmulatorPkg/Library/PeiEmuCacheMaintenanceLib/PeiEmuCacheMaintenanceLib.inf
 create mode 100644 EmulatorPkg/Unix/Host/CacheMaintenance.c

diff --git a/EmulatorPkg/EmulatorPkg.dec b/EmulatorPkg/EmulatorPkg.dec
index fe81652b04..adf615f796 100644
--- a/EmulatorPkg/EmulatorPkg.dec
+++ b/EmulatorPkg/EmulatorPkg.dec
@@ -2,7 +2,7 @@
 #
 # This is the Emu Emulation Environment Platform
 #
-# Copyright (c) 2008 - 2022, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2008 - 2023, Intel Corporation. All rights reserved.<BR>
 # Portions copyright (c) 2011, Apple Inc. All rights reserved.
 # (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
 #
@@ -37,6 +37,7 @@
   gEmuThreadThunkProtocolGuid    = { 0x3B1E4B7C, 0x09D8, 0x944F, { 0xA4, 0x08, 0x13, 0x09, 0xEB, 0x8B, 0x44, 0x27 } }
   gEmuBlockIoProtocolGuid        = { 0x6888A4AE, 0xAFCE, 0xE84B, { 0x91, 0x02, 0xF7, 0xB9, 0xDA, 0xE6, 0xA0, 0x30 } }
   gEmuSnpProtocolGuid            = { 0xFD5FBE54, 0x8C35, 0xB345, { 0x8A, 0x0F, 0x7A, 0xC8, 0xA5, 0xFD, 0x05, 0x21 } }
+  gEmuCacheThunkProtocolGuid     = { 0x8816732A, 0xF6DE, 0x466A, { 0x8E, 0x47, 0x1C, 0xE0, 0xEE, 0x1F, 0xB3, 0x3A } }
 
 [Ppis]
   gEmuThunkPpiGuid               = { 0xE113F896, 0x75CF, 0xF640, { 0x81, 0x7F, 0xC8, 0x5A, 0x79, 0xE8, 0xAE, 0x67 } }
@@ -109,6 +110,7 @@
   gEmulatorPkgTokenSpaceGuid.PcdEmuGop|L"GOP Window"|VOID*|0x00001018
   gEmulatorPkgTokenSpaceGuid.PcdEmuFileSystem|L"."|VOID*|0x00001004
   gEmulatorPkgTokenSpaceGuid.PcdEmuSerialPort|L"/dev/ttyS0"|VOID*|0x00001002
+  gEmulatorPkgTokenSpaceGuid.PcdEmuCache|L"CacheCtl"|VOID*|0x0000101d
 
   #
   # On Unix host, this is the network interface name on host system that will
diff --git a/EmulatorPkg/EmulatorPkg.dsc b/EmulatorPkg/EmulatorPkg.dsc
index 62d853e470..601c2d7988 100644
--- a/EmulatorPkg/EmulatorPkg.dsc
+++ b/EmulatorPkg/EmulatorPkg.dsc
@@ -187,6 +187,9 @@
 [LibraryClasses.common.PEIM]
   PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
 
+[LibraryClasses.ARM.PEIM, LibraryClasses.ARM.PEI_CORE]
+  CacheMaintenanceLib|EmulatorPkg/Library/PeiEmuCacheMaintenanceLib/PeiEmuCacheMaintenanceLib.inf
+
 [LibraryClasses.common.DXE_CORE]
   HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
   MemoryAllocationLib|MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf
@@ -217,6 +220,9 @@
   ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
   TimerLib|EmulatorPkg/Library/DxeTimerLib/DxeTimerLib.inf
 
+[LibraryClasses.ARM.DXE_CORE, LibraryClasses.ARM.DXE_RUNTIME_DRIVER, LibraryClasses.ARM.UEFI_DRIVER, LibraryClasses.ARM.DXE_DRIVER, LibraryClasses.ARM.UEFI_APPLICATION]
+  CacheMaintenanceLib|EmulatorPkg/Library/DxeEmuCacheMaintenanceLib/DxeEmuCacheMaintenanceLib.inf
+
 [PcdsFeatureFlag]
   gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreImageLoaderSearchTeSectionFirst|FALSE
 
@@ -269,6 +275,7 @@
   gEmulatorPkgTokenSpaceGuid.PcdEmuFileSystem|L"."
   gEmulatorPkgTokenSpaceGuid.PcdEmuSerialPort|L"/dev/ttyS0"
   gEmulatorPkgTokenSpaceGuid.PcdEmuNetworkInterface|L"en0"
+  gEmulatorPkgTokenSpaceGuid.PcdEmuCache|L"CacheCtl"
 
   gEmulatorPkgTokenSpaceGuid.PcdEmuCpuModel|L"Intel(R) Processor Model"
   gEmulatorPkgTokenSpaceGuid.PcdEmuCpuSpeed|L"3000"
diff --git a/EmulatorPkg/Include/Protocol/EmuCache.h b/EmulatorPkg/Include/Protocol/EmuCache.h
new file mode 100644
index 0000000000..3c05e7807c
--- /dev/null
+++ b/EmulatorPkg/Include/Protocol/EmuCache.h
@@ -0,0 +1,217 @@
+/** @file
+  Invoke syscalls for cache maintenance on platforms that require kernel
+  mode to manage the cache. ARM and RISC-V for example.
+
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EMU_CACHE__
+#define __EMU_CACHE__
+
+typedef struct _EMU_CACHE_THUNK_PROTOCOL EMU_CACHE_THUNK_PROTOCOL;
+
+/**
+  Invalidates the entire instruction cache in cache coherency domain of the
+  calling CPU.
+
+**/
+typedef
+VOID
+(EFIAPI *EMU_CACHE_PROTOCOL_INVALIDATE_INSTRUCTION_CACHE) (
+  VOID
+  );
+
+/**
+  Invalidates a range of instruction cache lines in the cache coherency domain
+  of the calling CPU.
+
+  Invalidates the instruction cache lines specified by Address and Length. If
+  Address is not aligned on a cache line boundary, then entire instruction
+  cache line containing Address is invalidated. If Address + Length is not
+  aligned on a cache line boundary, then the entire instruction cache line
+  containing Address + Length -1 is invalidated. This function may choose to
+  invalidate the entire instruction cache if that is more efficient than
+  invalidating the specified range. If Length is 0, then no instruction cache
+  lines are invalidated. Address is returned.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the instruction cache lines to
+                  invalidate. If the CPU is in a physical addressing mode, then
+                  Address is a physical address. If the CPU is in a virtual
+                  addressing mode, then Address is a virtual address.
+
+  @param  Length  The number of bytes to invalidate from the instruction cache.
+
+  @return Address.
+
+**/
+typedef
+VOID *
+(EFIAPI *EMU_CACHE_PROTOCOL_INVALIDATE_INSTRUCTION_CACHE_RANGE)(
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  );
+
+/**
+  Writes Back and Invalidates the entire data cache in cache coherency domain
+  of the calling CPU.
+
+  Writes Back and Invalidates the entire data cache in cache coherency domain
+  of the calling CPU. This function guarantees that all dirty cache lines are
+  written back to system memory, and also invalidates all the data cache lines
+  in the cache coherency domain of the calling CPU.
+
+**/
+typedef
+VOID
+(EFIAPI *EMU_CACHE_PROTOCOL_WRITE_BACK_INVALIDATE_DATA_CACHE)(
+  VOID
+  );
+
+/**
+  Writes Back and Invalidates a range of data cache lines in the cache
+  coherency domain of the calling CPU.
+
+  Writes Back and Invalidate the data cache lines specified by Address and
+  Length. If Address is not aligned on a cache line boundary, then entire data
+  cache line containing Address is written back and invalidated. If Address +
+  Length is not aligned on a cache line boundary, then the entire data cache
+  line containing Address + Length -1 is written back and invalidated. This
+  function may choose to write back and invalidate the entire data cache if
+  that is more efficient than writing back and invalidating the specified
+  range. If Length is 0, then no data cache lines are written back and
+  invalidated. Address is returned.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the data cache lines to write back and
+                  invalidate. If the CPU is in a physical addressing mode, then
+                  Address is a physical address. If the CPU is in a virtual
+                  addressing mode, then Address is a virtual address.
+  @param  Length  The number of bytes to write back and invalidate from the
+                  data cache.
+
+  @return Address of cache invalidation.
+
+**/
+typedef
+VOID *
+(EFIAPI *EMU_CACHE_PROTOCOL_WRITE_BACK_INVALIDATE_DATA_CACHE_RANGE)(
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  );
+
+/**
+  Writes Back the entire data cache in cache coherency domain of the calling
+  CPU.
+
+  Writes Back the entire data cache in cache coherency domain of the calling
+  CPU. This function guarantees that all dirty cache lines are written back to
+  system memory. This function may also invalidate all the data cache lines in
+  the cache coherency domain of the calling CPU.
+
+**/
+typedef
+VOID
+(EFIAPI *EMU_CACHE_PROTOCOL_WRITE_BACK_DATA_CACHE)(
+  VOID
+  );
+
+/**
+  Writes Back a range of data cache lines in the cache coherency domain of the
+  calling CPU.
+
+  Writes Back the data cache lines specified by Address and Length. If Address
+  is not aligned on a cache line boundary, then entire data cache line
+  containing Address is written back. If Address + Length is not aligned on a
+  cache line boundary, then the entire data cache line containing Address +
+  Length -1 is written back. This function may choose to write back the entire
+  data cache if that is more efficient than writing back the specified range.
+  If Length is 0, then no data cache lines are written back. This function may
+  also invalidate all the data cache lines in the specified range of the cache
+  coherency domain of the calling CPU. Address is returned.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the data cache lines to write back. If
+                  the CPU is in a physical addressing mode, then Address is a
+                  physical address. If the CPU is in a virtual addressing
+                  mode, then Address is a virtual address.
+  @param  Length  The number of bytes to write back from the data cache.
+
+  @return Address of cache written in main memory.
+
+**/
+typedef
+VOID *
+(EFIAPI *EMU_CACHE_PROTOCOL_WRITE_BACK_DATA_CACHE_RANGE)(
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  );
+
+/**
+  Invalidates the entire data cache in cache coherency domain of the calling
+  CPU.
+
+  Invalidates the entire data cache in cache coherency domain of the calling
+  CPU. This function must be used with care because dirty cache lines are not
+  written back to system memory. It is typically used for cache diagnostics. If
+  the CPU does not support invalidation of the entire data cache, then a write
+  back and invalidate operation should be performed on the entire data cache.
+
+**/
+typedef
+VOID
+(EFIAPI *EMU_CACHE_PROTOCOL_INVALIDATE_DATA_CACHE)(
+  VOID
+  );
+
+/**
+  Invalidates a range of data cache lines in the cache coherency domain of the
+  calling CPU.
+
+  Invalidates the data cache lines specified by Address and Length. If Address
+  is not aligned on a cache line boundary, then entire data cache line
+  containing Address is invalidated. If Address + Length is not aligned on a
+  cache line boundary, then the entire data cache line containing Address +
+  Length -1 is invalidated. This function must never invalidate any cache lines
+  outside the specified range. If Length is 0, the no data cache lines are
+  invalidated. Address is returned. This function must be used with care
+  because dirty cache lines are not written back to system memory. It is
+  typically used for cache diagnostics. If the CPU does not support
+  invalidation of a data cache range, then a write back and invalidate
+  operation should be performed on the data cache range.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the data cache lines to invalidate. If
+                  the CPU is in a physical addressing mode, then Address is a
+                  physical address. If the CPU is in a virtual addressing mode,
+                  then Address is a virtual address.
+  @param  Length  The number of bytes to invalidate from the data cache.
+
+  @return Address.
+
+**/
+typedef
+VOID *
+(EFIAPI *EMU_CACHE_INVALIDATE_DATA_CACHE_RANGE)(
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  );
+
+struct _EMU_CACHE_THUNK_PROTOCOL {
+  EMU_CACHE_PROTOCOL_INVALIDATE_INSTRUCTION_CACHE             InvalidateInstructionCache;
+  EMU_CACHE_PROTOCOL_INVALIDATE_INSTRUCTION_CACHE_RANGE       InvalidateInstructionCacheRange;
+  EMU_CACHE_PROTOCOL_WRITE_BACK_INVALIDATE_DATA_CACHE         WriteBackInvalidateDataCache;
+  EMU_CACHE_PROTOCOL_WRITE_BACK_INVALIDATE_DATA_CACHE_RANGE   WriteBackInvalidateDataCacheRange;
+  EMU_CACHE_PROTOCOL_WRITE_BACK_DATA_CACHE                    WriteBackDataCache;
+  EMU_CACHE_PROTOCOL_WRITE_BACK_DATA_CACHE_RANGE              WriteBackDataCacheRange;
+  EMU_CACHE_PROTOCOL_INVALIDATE_DATA_CACHE                    InvalidateDataCache;
+  EMU_CACHE_INVALIDATE_DATA_CACHE_RANGE                       InvalidateDataCacheRange;
+};
+
+#endif
diff --git a/EmulatorPkg/Library/DxeEmuCacheMaintenanceLib/DxeEmuCacheMaintenanceLib.c b/EmulatorPkg/Library/DxeEmuCacheMaintenanceLib/DxeEmuCacheMaintenanceLib.c
new file mode 100644
index 0000000000..2db07b5bd0
--- /dev/null
+++ b/EmulatorPkg/Library/DxeEmuCacheMaintenanceLib/DxeEmuCacheMaintenanceLib.c
@@ -0,0 +1,337 @@
+/** @file
+  Instance of Cache Maintenance Library using emulator thunks to OS syscalls
+
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+#include <Pi/PiHob.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/HobLib.h>
+
+#include <Protocol/EmuThunk.h>
+#include <Protocol/EmuIoThunk.h>
+#include <Protocol/EmuCache.h>
+
+EFI_STATUS
+EFIAPI
+DxeGetCacheThunkProtocol (
+  OUT      EMU_CACHE_THUNK_PROTOCOL   **EmuCache
+  )
+{
+  EFI_HOB_GUID_TYPE       *GuidHob;
+  EMU_THUNK_PROTOCOL      *Thunk;
+  EMU_IO_THUNK_PROTOCOL   *EmuIoThunk;
+  EFI_STATUS              Status;
+
+  //
+  // Get Unix Thunk Protocol so we can retrieve I/O Thunk Protocols
+  //
+  GuidHob = GetFirstGuidHob (&gEmuThunkProtocolGuid);
+  if (GuidHob == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  Thunk = (EMU_THUNK_PROTOCOL *)(*(UINTN *)(GET_GUID_HOB_DATA (GuidHob)));
+  if (Thunk == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Locate the I/O Thunk Protocol representing the Cache Thunk Protocol
+  //
+  for (Status = EFI_SUCCESS, EmuIoThunk = NULL; !EFI_ERROR (Status); ) {
+    Status = Thunk->GetNextProtocol (FALSE, &EmuIoThunk);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    if (EmuIoThunk->Instance == 0) {
+      if (CompareGuid (EmuIoThunk->Protocol, &gEmuCacheThunkProtocolGuid)) {
+        //
+        // Open the I/O Thunk Protocol to retrieve the Cache Thunk Protocol
+        //
+        Status = EmuIoThunk->Open (EmuIoThunk);
+        if (EFI_ERROR (Status)) {
+            return Status;
+        }
+        *EmuCache = (EMU_CACHE_THUNK_PROTOCOL *) EmuIoThunk->Interface;
+        return EFI_SUCCESS;
+      }
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Invalidates the entire instruction cache in cache coherency domain of the
+  calling CPU.
+
+**/
+VOID
+EFIAPI
+InvalidateInstructionCache (
+  VOID
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = DxeGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    EmuCache->InvalidateInstructionCache ();
+  }
+}
+
+/**
+  Invalidates a range of instruction cache lines in the cache coherency domain
+  of the calling CPU.
+
+  Invalidates the instruction cache lines specified by Address and Length. If
+  Address is not aligned on a cache line boundary, then entire instruction
+  cache line containing Address is invalidated. If Address + Length is not
+  aligned on a cache line boundary, then the entire instruction cache line
+  containing Address + Length -1 is invalidated. This function may choose to
+  invalidate the entire instruction cache if that is more efficient than
+  invalidating the specified range. If Length is 0, then no instruction cache
+  lines are invalidated. Address is returned.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the instruction cache lines to
+                  invalidate. If the CPU is in a physical addressing mode, then
+                  Address is a physical address. If the CPU is in a virtual
+                  addressing mode, then Address is a virtual address.
+
+  @param  Length  The number of bytes to invalidate from the instruction cache.
+
+  @return Address.
+
+**/
+VOID *
+EFIAPI
+InvalidateInstructionCacheRange (
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = DxeGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    return EmuCache->InvalidateInstructionCacheRange (Address, Length);
+  }
+  return NULL;
+}
+
+/**
+  Writes Back and Invalidates the entire data cache in cache coherency domain
+  of the calling CPU.
+
+  Writes Back and Invalidates the entire data cache in cache coherency domain
+  of the calling CPU. This function guarantees that all dirty cache lines are
+  written back to system memory, and also invalidates all the data cache lines
+  in the cache coherency domain of the calling CPU.
+
+**/
+VOID
+EFIAPI
+WriteBackInvalidateDataCache (
+  VOID
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = DxeGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    EmuCache->WriteBackInvalidateDataCache ();
+  }
+}
+
+/**
+  Writes Back and Invalidates a range of data cache lines in the cache
+  coherency domain of the calling CPU.
+
+  Writes Back and Invalidate the data cache lines specified by Address and
+  Length. If Address is not aligned on a cache line boundary, then entire data
+  cache line containing Address is written back and invalidated. If Address +
+  Length is not aligned on a cache line boundary, then the entire data cache
+  line containing Address + Length -1 is written back and invalidated. This
+  function may choose to write back and invalidate the entire data cache if
+  that is more efficient than writing back and invalidating the specified
+  range. If Length is 0, then no data cache lines are written back and
+  invalidated. Address is returned.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the data cache lines to write back and
+                  invalidate. If the CPU is in a physical addressing mode, then
+                  Address is a physical address. If the CPU is in a virtual
+                  addressing mode, then Address is a virtual address.
+  @param  Length  The number of bytes to write back and invalidate from the
+                  data cache.
+
+  @return Address of cache invalidation.
+
+**/
+VOID *
+EFIAPI
+WriteBackInvalidateDataCacheRange (
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = DxeGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    return EmuCache->WriteBackInvalidateDataCacheRange (Address, Length);
+  }
+  return NULL;
+}
+
+/**
+  Writes Back the entire data cache in cache coherency domain of the calling
+  CPU.
+
+  Writes Back the entire data cache in cache coherency domain of the calling
+  CPU. This function guarantees that all dirty cache lines are written back to
+  system memory. This function may also invalidate all the data cache lines in
+  the cache coherency domain of the calling CPU.
+
+**/
+VOID
+EFIAPI
+WriteBackDataCache (
+  VOID
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = DxeGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    EmuCache->WriteBackDataCache ();
+  }
+}
+
+/**
+  Writes Back a range of data cache lines in the cache coherency domain of the
+  calling CPU.
+
+  Writes Back the data cache lines specified by Address and Length. If Address
+  is not aligned on a cache line boundary, then entire data cache line
+  containing Address is written back. If Address + Length is not aligned on a
+  cache line boundary, then the entire data cache line containing Address +
+  Length -1 is written back. This function may choose to write back the entire
+  data cache if that is more efficient than writing back the specified range.
+  If Length is 0, then no data cache lines are written back. This function may
+  also invalidate all the data cache lines in the specified range of the cache
+  coherency domain of the calling CPU. Address is returned.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the data cache lines to write back. If
+                  the CPU is in a physical addressing mode, then Address is a
+                  physical address. If the CPU is in a virtual addressing
+                  mode, then Address is a virtual address.
+  @param  Length  The number of bytes to write back from the data cache.
+
+  @return Address of cache written in main memory.
+
+**/
+VOID *
+EFIAPI
+WriteBackDataCacheRange (
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = DxeGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    return EmuCache->WriteBackDataCacheRange (Address, Length);
+  }
+  return NULL;
+}
+
+/**
+  Invalidates the entire data cache in cache coherency domain of the calling
+  CPU.
+
+  Invalidates the entire data cache in cache coherency domain of the calling
+  CPU. This function must be used with care because dirty cache lines are not
+  written back to system memory. It is typically used for cache diagnostics. If
+  the CPU does not support invalidation of the entire data cache, then a write
+  back and invalidate operation should be performed on the entire data cache.
+
+**/
+VOID
+EFIAPI
+InvalidateDataCache (
+  VOID
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = DxeGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    EmuCache->InvalidateDataCache ();
+  }
+}
+
+/**
+  Invalidates a range of data cache lines in the cache coherency domain of the
+  calling CPU.
+
+  Invalidates the data cache lines specified by Address and Length. If Address
+  is not aligned on a cache line boundary, then entire data cache line
+  containing Address is invalidated. If Address + Length is not aligned on a
+  cache line boundary, then the entire data cache line containing Address +
+  Length -1 is invalidated. This function must never invalidate any cache lines
+  outside the specified range. If Length is 0, the no data cache lines are
+  invalidated. Address is returned. This function must be used with care
+  because dirty cache lines are not written back to system memory. It is
+  typically used for cache diagnostics. If the CPU does not support
+  invalidation of a data cache range, then a write back and invalidate
+  operation should be performed on the data cache range.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the data cache lines to invalidate. If
+                  the CPU is in a physical addressing mode, then Address is a
+                  physical address. If the CPU is in a virtual addressing mode,
+                  then Address is a virtual address.
+  @param  Length  The number of bytes to invalidate from the data cache.
+
+  @return Address.
+
+**/
+VOID *
+EFIAPI
+InvalidateDataCacheRange (
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = DxeGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    return EmuCache->InvalidateDataCacheRange (Address, Length);
+  }
+  return NULL;
+}
diff --git a/EmulatorPkg/Library/DxeEmuCacheMaintenanceLib/DxeEmuCacheMaintenanceLib.inf b/EmulatorPkg/Library/DxeEmuCacheMaintenanceLib/DxeEmuCacheMaintenanceLib.inf
new file mode 100644
index 0000000000..e71fa218d5
--- /dev/null
+++ b/EmulatorPkg/Library/DxeEmuCacheMaintenanceLib/DxeEmuCacheMaintenanceLib.inf
@@ -0,0 +1,37 @@
+## @file
+#  Instance of Cache Maintenance Library using emulator thunks to OS syscalls
+#
+#  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = DxeEmuCacheMaintenanceLib
+  FILE_GUID                      = 4ee4f13e-3aab-4654-9af9-36e0fa53107f
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.1
+  LIBRARY_CLASS                  = CacheMaintenanceLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER UEFI_APPLICATION
+
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM
+#
+
+[Sources]
+  DxeEmuCacheMaintenanceLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  EmulatorPkg/EmulatorPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  BaseMemoryLib
+  HobLib
+
+[Protocols]
+  gEmuThunkProtocolGuid
+  gEmuCacheThunkProtocolGuid
diff --git a/EmulatorPkg/Library/PeiEmuCacheMaintenanceLib/PeiEmuCacheMaintenanceLib.c b/EmulatorPkg/Library/PeiEmuCacheMaintenanceLib/PeiEmuCacheMaintenanceLib.c
new file mode 100644
index 0000000000..0abf63cd21
--- /dev/null
+++ b/EmulatorPkg/Library/PeiEmuCacheMaintenanceLib/PeiEmuCacheMaintenanceLib.c
@@ -0,0 +1,344 @@
+/** @file
+  Instance of Cache Maintenance Library using emulator thunks to OS syscalls
+
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesLib.h>
+
+#include <Ppi/EmuThunk.h>
+#include <Protocol/EmuThunk.h>
+#include <Protocol/EmuIoThunk.h>
+#include <Protocol/EmuCache.h>
+
+EFI_STATUS
+EFIAPI
+PeiGetCacheThunkProtocol (
+  OUT      EMU_CACHE_THUNK_PROTOCOL   **EmuCache
+  )
+{
+  EMU_THUNK_PPI           *ThunkPpi;
+  EMU_THUNK_PROTOCOL      *Thunk;
+  EMU_IO_THUNK_PROTOCOL   *EmuIoThunk;
+  EFI_STATUS              Status;
+
+  //
+  // Locate Unix Thunk Ppi
+  //
+  Status = PeiServicesLocatePpi (
+             &gEmuThunkPpiGuid,
+             0,
+             NULL,
+             (VOID **)&ThunkPpi
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Get the Unix Thunk Protocol so we can retrieve I/O Thunk Protocols
+  //
+  Thunk = (EMU_THUNK_PROTOCOL *)ThunkPpi->Thunk ();
+  if (Thunk == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Locate the I/O Thunk Protocol representing the Cache Thunk Protocol
+  //
+  for (Status = EFI_SUCCESS, EmuIoThunk = NULL; !EFI_ERROR (Status); ) {
+    Status = Thunk->GetNextProtocol (FALSE, &EmuIoThunk);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    if (EmuIoThunk->Instance == 0) {
+      if (CompareGuid (EmuIoThunk->Protocol, &gEmuCacheThunkProtocolGuid)) {
+        //
+        // Open the I/O Thunk Protocol to retrieve the Cache Thunk Protocol
+        //
+        Status = EmuIoThunk->Open (EmuIoThunk);
+        if (EFI_ERROR (Status)) {
+            return Status;
+        }
+        *EmuCache = (EMU_CACHE_THUNK_PROTOCOL *) EmuIoThunk->Interface;
+        return EFI_SUCCESS;
+      }
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Invalidates the entire instruction cache in cache coherency domain of the
+  calling CPU.
+
+**/
+VOID
+EFIAPI
+InvalidateInstructionCache (
+  VOID
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = PeiGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    EmuCache->InvalidateInstructionCache ();
+  }
+}
+
+/**
+  Invalidates a range of instruction cache lines in the cache coherency domain
+  of the calling CPU.
+
+  Invalidates the instruction cache lines specified by Address and Length. If
+  Address is not aligned on a cache line boundary, then entire instruction
+  cache line containing Address is invalidated. If Address + Length is not
+  aligned on a cache line boundary, then the entire instruction cache line
+  containing Address + Length -1 is invalidated. This function may choose to
+  invalidate the entire instruction cache if that is more efficient than
+  invalidating the specified range. If Length is 0, then no instruction cache
+  lines are invalidated. Address is returned.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the instruction cache lines to
+                  invalidate. If the CPU is in a physical addressing mode, then
+                  Address is a physical address. If the CPU is in a virtual
+                  addressing mode, then Address is a virtual address.
+
+  @param  Length  The number of bytes to invalidate from the instruction cache.
+
+  @return Address.
+
+**/
+VOID *
+EFIAPI
+InvalidateInstructionCacheRange (
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = PeiGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    return EmuCache->InvalidateInstructionCacheRange (Address, Length);
+  }
+  return NULL;
+}
+
+/**
+  Writes Back and Invalidates the entire data cache in cache coherency domain
+  of the calling CPU.
+
+  Writes Back and Invalidates the entire data cache in cache coherency domain
+  of the calling CPU. This function guarantees that all dirty cache lines are
+  written back to system memory, and also invalidates all the data cache lines
+  in the cache coherency domain of the calling CPU.
+
+**/
+VOID
+EFIAPI
+WriteBackInvalidateDataCache (
+  VOID
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = PeiGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    EmuCache->WriteBackInvalidateDataCache ();
+  }
+}
+
+/**
+  Writes Back and Invalidates a range of data cache lines in the cache
+  coherency domain of the calling CPU.
+
+  Writes Back and Invalidate the data cache lines specified by Address and
+  Length. If Address is not aligned on a cache line boundary, then entire data
+  cache line containing Address is written back and invalidated. If Address +
+  Length is not aligned on a cache line boundary, then the entire data cache
+  line containing Address + Length -1 is written back and invalidated. This
+  function may choose to write back and invalidate the entire data cache if
+  that is more efficient than writing back and invalidating the specified
+  range. If Length is 0, then no data cache lines are written back and
+  invalidated. Address is returned.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the data cache lines to write back and
+                  invalidate. If the CPU is in a physical addressing mode, then
+                  Address is a physical address. If the CPU is in a virtual
+                  addressing mode, then Address is a virtual address.
+  @param  Length  The number of bytes to write back and invalidate from the
+                  data cache.
+
+  @return Address of cache invalidation.
+
+**/
+VOID *
+EFIAPI
+WriteBackInvalidateDataCacheRange (
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = PeiGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    return EmuCache->WriteBackInvalidateDataCacheRange (Address, Length);
+  }
+  return NULL;
+}
+
+/**
+  Writes Back the entire data cache in cache coherency domain of the calling
+  CPU.
+
+  Writes Back the entire data cache in cache coherency domain of the calling
+  CPU. This function guarantees that all dirty cache lines are written back to
+  system memory. This function may also invalidate all the data cache lines in
+  the cache coherency domain of the calling CPU.
+
+**/
+VOID
+EFIAPI
+WriteBackDataCache (
+  VOID
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = PeiGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    EmuCache->WriteBackDataCache ();
+  }
+}
+
+/**
+  Writes Back a range of data cache lines in the cache coherency domain of the
+  calling CPU.
+
+  Writes Back the data cache lines specified by Address and Length. If Address
+  is not aligned on a cache line boundary, then entire data cache line
+  containing Address is written back. If Address + Length is not aligned on a
+  cache line boundary, then the entire data cache line containing Address +
+  Length -1 is written back. This function may choose to write back the entire
+  data cache if that is more efficient than writing back the specified range.
+  If Length is 0, then no data cache lines are written back. This function may
+  also invalidate all the data cache lines in the specified range of the cache
+  coherency domain of the calling CPU. Address is returned.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the data cache lines to write back. If
+                  the CPU is in a physical addressing mode, then Address is a
+                  physical address. If the CPU is in a virtual addressing
+                  mode, then Address is a virtual address.
+  @param  Length  The number of bytes to write back from the data cache.
+
+  @return Address of cache written in main memory.
+
+**/
+VOID *
+EFIAPI
+WriteBackDataCacheRange (
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = PeiGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    return EmuCache->WriteBackDataCacheRange (Address, Length);
+  }
+  return NULL;
+}
+
+/**
+  Invalidates the entire data cache in cache coherency domain of the calling
+  CPU.
+
+  Invalidates the entire data cache in cache coherency domain of the calling
+  CPU. This function must be used with care because dirty cache lines are not
+  written back to system memory. It is typically used for cache diagnostics. If
+  the CPU does not support invalidation of the entire data cache, then a write
+  back and invalidate operation should be performed on the entire data cache.
+
+**/
+VOID
+EFIAPI
+InvalidateDataCache (
+  VOID
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = PeiGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    EmuCache->InvalidateDataCache ();
+  }
+}
+
+/**
+  Invalidates a range of data cache lines in the cache coherency domain of the
+  calling CPU.
+
+  Invalidates the data cache lines specified by Address and Length. If Address
+  is not aligned on a cache line boundary, then entire data cache line
+  containing Address is invalidated. If Address + Length is not aligned on a
+  cache line boundary, then the entire data cache line containing Address +
+  Length -1 is invalidated. This function must never invalidate any cache lines
+  outside the specified range. If Length is 0, the no data cache lines are
+  invalidated. Address is returned. This function must be used with care
+  because dirty cache lines are not written back to system memory. It is
+  typically used for cache diagnostics. If the CPU does not support
+  invalidation of a data cache range, then a write back and invalidate
+  operation should be performed on the data cache range.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the data cache lines to invalidate. If
+                  the CPU is in a physical addressing mode, then Address is a
+                  physical address. If the CPU is in a virtual addressing mode,
+                  then Address is a virtual address.
+  @param  Length  The number of bytes to invalidate from the data cache.
+
+  @return Address.
+
+**/
+VOID *
+EFIAPI
+InvalidateDataCacheRange (
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  )
+{
+  EMU_CACHE_THUNK_PROTOCOL   *EmuCache;
+  EFI_STATUS                 Status;
+
+  Status = PeiGetCacheThunkProtocol (&EmuCache);
+  if (!EFI_ERROR (Status) && EmuCache != NULL) {
+    return EmuCache->InvalidateDataCacheRange (Address, Length);
+  }
+  return NULL;
+}
diff --git a/EmulatorPkg/Library/PeiEmuCacheMaintenanceLib/PeiEmuCacheMaintenanceLib.inf b/EmulatorPkg/Library/PeiEmuCacheMaintenanceLib/PeiEmuCacheMaintenanceLib.inf
new file mode 100644
index 0000000000..4e8b05e8a7
--- /dev/null
+++ b/EmulatorPkg/Library/PeiEmuCacheMaintenanceLib/PeiEmuCacheMaintenanceLib.inf
@@ -0,0 +1,39 @@
+## @file
+#  Instance of Cache Maintenance Library using emulator thunks to OS syscalls
+#
+#  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PeiEmuCacheMaintenanceLib
+  FILE_GUID                      = 00b3e408-f999-4cf4-ba95-166678fc867c
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.1
+  LIBRARY_CLASS                  = CacheMaintenanceLib|PEI_CORE PEIM
+
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM
+#
+
+[Sources]
+  PeiEmuCacheMaintenanceLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  EmulatorPkg/EmulatorPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  BaseMemoryLib
+  PeiServicesLib
+
+[Ppis]
+  gEmuThunkPpiGuid                          # PPI ALWAYS_CONSUMED
+
+[Protocols]
+  gEmuCacheThunkProtocolGuid
diff --git a/EmulatorPkg/Unix/Host/CacheMaintenance.c b/EmulatorPkg/Unix/Host/CacheMaintenance.c
new file mode 100644
index 0000000000..13dccda9bb
--- /dev/null
+++ b/EmulatorPkg/Unix/Host/CacheMaintenance.c
@@ -0,0 +1,284 @@
+/** @file
+  Invoke syscalls for cache maintenance on platforms that require kernel
+  mode to manage the instruction cache. ARM and RISC-V for example.
+
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Host.h"
+
+extern UINTN              gSystemMemoryCount;
+extern EMU_SYSTEM_MEMORY  *gSystemMemory;
+
+/**
+  Invalidates a range of instruction cache lines in the cache coherency domain
+  of the calling CPU.
+
+  Invalidates the instruction cache lines specified by Address and Length. If
+  Address is not aligned on a cache line boundary, then entire instruction
+  cache line containing Address is invalidated. If Address + Length is not
+  aligned on a cache line boundary, then the entire instruction cache line
+  containing Address + Length -1 is invalidated. This function may choose to
+  invalidate the entire instruction cache if that is more efficient than
+  invalidating the specified range. If Length is 0, then no instruction cache
+  lines are invalidated. Address is returned.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the instruction cache lines to
+                  invalidate. If the CPU is in a physical addressing mode, then
+                  Address is a physical address. If the CPU is in a virtual
+                  addressing mode, then Address is a virtual address.
+
+  @param  Length  The number of bytes to invalidate from the instruction cache.
+
+  @return Address.
+
+**/
+VOID *
+EFIAPI
+EmuInvalidateInstructionCacheRange (
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  )
+{
+  __builtin___clear_cache ((char*)Address, ((char*)Address) + Length);
+
+  return Address;
+}
+
+/**
+  Invalidates the entire instruction cache in cache coherency domain of the
+  calling CPU.
+
+**/
+VOID
+EFIAPI
+EmuInvalidateInstructionCache (
+  VOID
+  )
+{
+  UINTN   Index;
+
+  if (gSystemMemory != NULL) {
+    for (Index = 0; Index < gSystemMemoryCount; Index++) {
+      if (gSystemMemory[Index].Memory != 0) {
+        EmuInvalidateInstructionCacheRange ((VOID *)(UINTN)gSystemMemory[Index].Memory, gSystemMemory[Index].Size);
+      }
+    }
+  }
+}
+
+/**
+  Writes Back and Invalidates the entire data cache in cache coherency domain
+  of the calling CPU.
+
+  Writes Back and Invalidates the entire data cache in cache coherency domain
+  of the calling CPU. This function guarantees that all dirty cache lines are
+  written back to system memory, and also invalidates all the data cache lines
+  in the cache coherency domain of the calling CPU.
+
+**/
+VOID
+EFIAPI
+EmuWriteBackInvalidateDataCache (
+  VOID
+  )
+{
+  EmuInvalidateInstructionCache ();
+}
+
+/**
+  Writes Back and Invalidates a range of data cache lines in the cache
+  coherency domain of the calling CPU.
+
+  Writes Back and Invalidate the data cache lines specified by Address and
+  Length. If Address is not aligned on a cache line boundary, then entire data
+  cache line containing Address is written back and invalidated. If Address +
+  Length is not aligned on a cache line boundary, then the entire data cache
+  line containing Address + Length -1 is written back and invalidated. This
+  function may choose to write back and invalidate the entire data cache if
+  that is more efficient than writing back and invalidating the specified
+  range. If Length is 0, then no data cache lines are written back and
+  invalidated. Address is returned.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the data cache lines to write back and
+                  invalidate. If the CPU is in a physical addressing mode, then
+                  Address is a physical address. If the CPU is in a virtual
+                  addressing mode, then Address is a virtual address.
+  @param  Length  The number of bytes to write back and invalidate from the
+                  data cache.
+
+  @return Address of cache invalidation.
+
+**/
+VOID *
+EFIAPI
+EmuWriteBackInvalidateDataCacheRange (
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  )
+{
+  return EmuInvalidateInstructionCacheRange (Address, Length);
+}
+
+/**
+  Writes Back the entire data cache in cache coherency domain of the calling
+  CPU.
+
+  Writes Back the entire data cache in cache coherency domain of the calling
+  CPU. This function guarantees that all dirty cache lines are written back to
+  system memory. This function may also invalidate all the data cache lines in
+  the cache coherency domain of the calling CPU.
+
+**/
+VOID
+EFIAPI
+EmuWriteBackDataCache (
+  VOID
+  )
+{
+  EmuWriteBackInvalidateDataCache ();
+}
+
+/**
+  Writes Back a range of data cache lines in the cache coherency domain of the
+  calling CPU.
+
+  Writes Back the data cache lines specified by Address and Length. If Address
+  is not aligned on a cache line boundary, then entire data cache line
+  containing Address is written back. If Address + Length is not aligned on a
+  cache line boundary, then the entire data cache line containing Address +
+  Length -1 is written back. This function may choose to write back the entire
+  data cache if that is more efficient than writing back the specified range.
+  If Length is 0, then no data cache lines are written back. This function may
+  also invalidate all the data cache lines in the specified range of the cache
+  coherency domain of the calling CPU. Address is returned.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the data cache lines to write back. If
+                  the CPU is in a physical addressing mode, then Address is a
+                  physical address. If the CPU is in a virtual addressing
+                  mode, then Address is a virtual address.
+  @param  Length  The number of bytes to write back from the data cache.
+
+  @return Address of cache written in main memory.
+
+**/
+VOID *
+EFIAPI
+EmuWriteBackDataCacheRange (
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  )
+{
+  return EmuWriteBackInvalidateDataCacheRange (Address, Length);
+}
+
+/**
+  Invalidates the entire data cache in cache coherency domain of the calling
+  CPU.
+
+  Invalidates the entire data cache in cache coherency domain of the calling
+  CPU. This function must be used with care because dirty cache lines are not
+  written back to system memory. It is typically used for cache diagnostics. If
+  the CPU does not support invalidation of the entire data cache, then a write
+  back and invalidate operation should be performed on the entire data cache.
+
+**/
+VOID
+EFIAPI
+EmuInvalidateDataCache (
+  VOID
+  )
+{
+  EmuWriteBackInvalidateDataCache ();
+}
+
+/**
+  Invalidates a range of data cache lines in the cache coherency domain of the
+  calling CPU.
+
+  Invalidates the data cache lines specified by Address and Length. If Address
+  is not aligned on a cache line boundary, then entire data cache line
+  containing Address is invalidated. If Address + Length is not aligned on a
+  cache line boundary, then the entire data cache line containing Address +
+  Length -1 is invalidated. This function must never invalidate any cache lines
+  outside the specified range. If Length is 0, the no data cache lines are
+  invalidated. Address is returned. This function must be used with care
+  because dirty cache lines are not written back to system memory. It is
+  typically used for cache diagnostics. If the CPU does not support
+  invalidation of a data cache range, then a write back and invalidate
+  operation should be performed on the data cache range.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the data cache lines to invalidate. If
+                  the CPU is in a physical addressing mode, then Address is a
+                  physical address. If the CPU is in a virtual addressing mode,
+                  then Address is a virtual address.
+  @param  Length  The number of bytes to invalidate from the data cache.
+
+  @return Address.
+
+**/
+VOID *
+EFIAPI
+EmuInvalidateDataCacheRange (
+  IN      VOID   *Address,
+  IN      UINTN  Length
+  )
+{
+  return EmuWriteBackInvalidateDataCacheRange (Address, Length);
+}
+
+EMU_CACHE_THUNK_PROTOCOL  gEmuCacheThunk = {
+  EmuInvalidateInstructionCache,
+  EmuInvalidateInstructionCacheRange,
+  EmuWriteBackInvalidateDataCache,
+  EmuWriteBackInvalidateDataCacheRange,
+  EmuWriteBackDataCache,
+  EmuWriteBackDataCacheRange,
+  EmuInvalidateDataCache,
+  EmuInvalidateDataCacheRange
+};
+
+EFI_STATUS
+EFIAPI
+CacheOpen (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  )
+{
+  if (This->Instance != 0) {
+    // Only single instance is supported
+    return EFI_NOT_FOUND;
+  }
+
+  This->Interface = &gEmuCacheThunk;
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+CacheClose (
+  IN  EMU_IO_THUNK_PROTOCOL  *This
+  )
+{
+  return EFI_SUCCESS;
+}
+
+EMU_IO_THUNK_PROTOCOL  gCacheThunkIo = {
+  &gEmuCacheThunkProtocolGuid,
+  NULL,
+  NULL,
+  0,
+  CacheOpen,
+  CacheClose,
+  NULL
+};
diff --git a/EmulatorPkg/Unix/Host/Host.c b/EmulatorPkg/Unix/Host/Host.c
index 1f29dd00a3..06241c7127 100644
--- a/EmulatorPkg/Unix/Host/Host.c
+++ b/EmulatorPkg/Unix/Host/Host.c
@@ -1,6 +1,6 @@
 /*++ @file
 
-Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2023, Intel Corporation. All rights reserved.<BR>
 Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -165,6 +165,9 @@ main (
   // Emulator other Thunks
   //
   AddThunkProtocol (&gPthreadThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuApCount), FALSE);
+#if defined (MDE_CPU_ARM)
+  AddThunkProtocol (&gCacheThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuCache), FALSE);
+#endif
 
   // EmuSecLibConstructor ();
 
diff --git a/EmulatorPkg/Unix/Host/Host.h b/EmulatorPkg/Unix/Host/Host.h
index 0c81cdfc01..95d482d8d2 100644
--- a/EmulatorPkg/Unix/Host/Host.h
+++ b/EmulatorPkg/Unix/Host/Host.h
@@ -115,6 +115,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include <Protocol/EmuThread.h>
 #include <Protocol/EmuBlockIo.h>
 #include <Protocol/EmuSnp.h>
+#include <Protocol/EmuCache.h>
 
 #include <Guid/FileInfo.h>
 #include <Guid/FileSystemInfo.h>
@@ -356,5 +357,6 @@ extern EMU_IO_THUNK_PROTOCOL  gPosixFileSystemThunkIo;
 extern EMU_IO_THUNK_PROTOCOL  gPthreadThunkIo;
 extern EMU_IO_THUNK_PROTOCOL  gBlockIoThunkIo;
 extern EMU_IO_THUNK_PROTOCOL  gSnpThunkIo;
+extern EMU_IO_THUNK_PROTOCOL  gCacheThunkIo;
 
 #endif
diff --git a/EmulatorPkg/Unix/Host/Host.inf b/EmulatorPkg/Unix/Host/Host.inf
index effd0a3217..6cb6e12b00 100644
--- a/EmulatorPkg/Unix/Host/Host.inf
+++ b/EmulatorPkg/Unix/Host/Host.inf
@@ -80,6 +80,7 @@
   gEmuThreadThunkProtocolGuid
   gEmuBlockIoProtocolGuid
   gEmuSnpProtocolGuid
+  gEmuCacheThunkProtocolGuid
   gEfiSimpleFileSystemProtocolGuid
 
 [Guids]
@@ -99,6 +100,7 @@
   gEmulatorPkgTokenSpaceGuid.PcdEmuGop|L"GOP Window"
   gEmulatorPkgTokenSpaceGuid.PcdEmuFileSystem
   gEmulatorPkgTokenSpaceGuid.PcdEmuSerialPort
+  gEmulatorPkgTokenSpaceGuid.PcdEmuCache
   gEmulatorPkgTokenSpaceGuid.PcdEmuNetworkInterface
   gEmulatorPkgTokenSpaceGuid.PcdNetworkPacketFilterSize
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [edk2-devel] [PATCH v1 0/6] Add Raspberry Pi Support to EmulatorPkg
  2023-03-06  0:21 [PATCH v1 0/6] Add Raspberry Pi Support to EmulatorPkg Nate DeSimone
                   ` (5 preceding siblings ...)
  2023-03-06  0:22 ` [PATCH v1 6/6] EmulatorPkg: Add EmuCacheMaintenanceLib Nate DeSimone
@ 2023-03-10 16:45 ` Ard Biesheuvel
  6 siblings, 0 replies; 8+ messages in thread
From: Ard Biesheuvel @ 2023-03-10 16:45 UTC (permalink / raw)
  To: devel, nathaniel.l.desimone
  Cc: Andrew Fish, Ray Ni, Leif Lindholm, Ard Biesheuvel, Sami Mujawar,
	Michael D Kinney, Chasel Chiu

Hello Nate,

On Mon, 6 Mar 2023 at 01:22, Nate DeSimone
<nathaniel.l.desimone@intel.com> wrote:
>
> This patch series is the result of a fun weekend project that I
> did in my spare time. It implements the changes nessesary for
> EmulatorPkg to run on the Raspberry Pi. It should also work on
> other 32-bit ARM systems, but I only specifically tested on
> Raspberry Pi OS (formerly Raspbian.)
>

It works fine on 64-bit ARM systems that support 32-bit user space as
well. I managed to build and run this on my Qualcomm Snapdragon based
Lenovo Yoga C630 laptop running Debian Linux.

So

Tested-by: Ard Biesheuvel <ardb@kernel.org>

Also, good job!! This is really nice.

One nit: I had to add -mfpu=vfpv3 to the compiler command line in
Host.inf to work around a build error.


> I ran into several interesting issues during the development of
> this patch series and it ended up being a good learning
> experience for me. Some things of note are:
>
>  1 - Assembly Code
>
> There are several pieces of assembly code in EmulatorPkg that need
> to be rewritten when porting to a new machine architecture. This
> code fell into two categories, stack manipulation and "gaskets."
>
>  2 - ABI Differences
>
> The most significant amount of assembly code is the "gasket"
> functions. The gasket functions are responsible for converting from
> the UNIX ABI to the EFI ABI. They enable EmulatorPkg to
> support executing arbitary UEFI binaries without needing
> recompilation specifically for EmulatorPkg. X86 has many ABI
> specifications that vary based on target OS and compiler toolchain.
> There have been several attempts to unify things on the x86 side,
> but they usually just result in the addition of yet another ABI.
> Things are much more uniform on ARM due to wide acceptance of the
> AAPCS. Due to this, the ABI differences between UNIX and EFI boil
> down to passing of variadic arguments and enum values. Neither of
> these cases apply to the function signatures for the gaskets.
> Therefore, on ARM these gaskets can be simple wrapper functions
> written in C since the UNIX and EFI ABIs are identical... at least
> for the set of functions that need gaskets.
>

Glad to hear that. I assume this would apply to AArch64 as well.

>  3 - Instruction Cache Maintenance
>
> Because EmulatorPkg and edk2 in general contains a PE/COFF loader,
> it counts as "self-modifying code". The way self modifying code is
> handled on ARM is considerably more complex than x86. While on x86
> there is no requirement for self-modifying code to flush the
> instruction cache, on ARM failure to do so will result in incorrect
> behavior. Additionally, flushing the cache is considerably more
> difficult on ARM. On x86, one can simply add a CLFLUSH or WBINVD
> instruction; they are perfectly valid to execute while in Ring 3.
> On ARM, flushing the cache requires one to write to system control
> registers, which can only be done in EL1 (kernel mode) or higher.
> Therefore, while flushing the cache can be done on in the x86
> version of EmulatorPkg without any interaction with the OS, on ARM
> we need to invoke OS syscalls.
>
> To accomodate this, I have added a new EMU_IO_THUNK_PROTOCOL that
> implements the CacheMaintenanceLib LibraryClass. This new
> implementation uses the GCC intrinsic function
> __builtin_clear_cache(), which on x86 gets converted into a CLFLUSH
> instruction by the compiler. On ARM, it gets converted into a call
> to the __clear_cache() API in libgcc. The ARM implementation of
> libgcc invokes the ARM_cacheflush syscall (0xF0002), which only
> exists in kernels built for the ARM architecture.
>
> I have added wrapper implementations of the CacheMaintenanceLib
> LibraryClass for PEI and DXE that use the EMU_THUNK infrastructure
> to acquire the EMU_CACHE_THUNK_PROTOCOL and invoke the equivilent
> functions, which in turn will use the GCC intrinsic mentioned
> above.
>
> I have only enable this version of CacheMaintenanceLib on the ARM
> architecture, because it will take several thousand CPU
> instructions to execute, as opposed to about ten on the current x86
> implementation.
>

I think this is reasonable, but I am not a EmulatorPkg maintainer so I
will defer to them to comment on this approach.

>  Testing Done:
>
> Boots to shell on Raspberry Pi OS "bullseye."
>
> Cc: Andrew Fish <afish@apple.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Sami Mujawar <sami.mujawar@arm.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Chasel Chiu <chasel.chiu@intel.com>
> Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
>
> Nate DeSimone (6):
>   ArmPkg: Add ArmMmuNullLib

Given the recent focus on memory protections - could we turn this into
a EmuPkg specific one that calls the OS's mprotect() under the hood?


>   EmulatorPkg: Add ARM Build Target
>   EmulatorPkg: Fix PosixFileSystem function misspellings
>   EmulatorPkg: Add ARM support to UNIX Host App
>   EmulatorPkg: Add ARM support to EmuSec
>   EmulatorPkg: Add EmuCacheMaintenanceLib
>
>  ArmPkg/ArmPkg.dsc                             |    2 +
>  ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.c  |   84 ++
>  .../Library/ArmMmuNullLib/ArmMmuNullLib.inf   |   36 +
>  EmulatorPkg/EmulatorPkg.dec                   |    4 +-
>  EmulatorPkg/EmulatorPkg.dsc                   |   29 +-
>  EmulatorPkg/EmulatorPkg.fdf                   |    6 +-
>  EmulatorPkg/Include/Protocol/EmuCache.h       |  217 ++++
>  .../DxeEmuCacheMaintenanceLib.c               |  337 +++++
>  .../DxeEmuCacheMaintenanceLib.inf             |   37 +
>  .../PeiEmuCacheMaintenanceLib.c               |  344 ++++++
>  .../PeiEmuCacheMaintenanceLib.inf             |   39 +
>  EmulatorPkg/Sec/Arm/SwitchRam.S               |   32 +
>  EmulatorPkg/Sec/Arm/TempRam.c                 |   58 +
>  EmulatorPkg/Sec/Sec.inf                       |    9 +-
>  EmulatorPkg/Unix/Host/Arm/Gasket.c            |  895 ++++++++++++++
>  .../Unix/Host/Arm/GasketFunctionDefinitions.h | 1092 +++++++++++++++++
>  EmulatorPkg/Unix/Host/Arm/SwitchStack.S       |   39 +
>  EmulatorPkg/Unix/Host/CacheMaintenance.c      |  284 +++++
>  EmulatorPkg/Unix/Host/Gasket.h                |   12 +-
>  EmulatorPkg/Unix/Host/Host.c                  |    5 +-
>  EmulatorPkg/Unix/Host/Host.h                  |    2 +
>  EmulatorPkg/Unix/Host/Host.inf                |   14 +-
>  EmulatorPkg/Unix/Host/Ia32/Gasket.S           |   31 +-
>  EmulatorPkg/Unix/Host/PosixFileSystem.c       |   22 +-
>  EmulatorPkg/Unix/Host/X64/Gasket.S            |   31 +-
>  EmulatorPkg/build.sh                          |   13 +-
>  26 files changed, 3617 insertions(+), 57 deletions(-)
>  create mode 100644 ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.c
>  create mode 100644 ArmPkg/Library/ArmMmuNullLib/ArmMmuNullLib.inf
>  create mode 100644 EmulatorPkg/Include/Protocol/EmuCache.h
>  create mode 100644 EmulatorPkg/Library/DxeEmuCacheMaintenanceLib/DxeEmuCacheMaintenanceLib.c
>  create mode 100644 EmulatorPkg/Library/DxeEmuCacheMaintenanceLib/DxeEmuCacheMaintenanceLib.inf
>  create mode 100644 EmulatorPkg/Library/PeiEmuCacheMaintenanceLib/PeiEmuCacheMaintenanceLib.c
>  create mode 100644 EmulatorPkg/Library/PeiEmuCacheMaintenanceLib/PeiEmuCacheMaintenanceLib.inf
>  create mode 100644 EmulatorPkg/Sec/Arm/SwitchRam.S
>  create mode 100644 EmulatorPkg/Sec/Arm/TempRam.c
>  create mode 100644 EmulatorPkg/Unix/Host/Arm/Gasket.c
>  create mode 100644 EmulatorPkg/Unix/Host/Arm/GasketFunctionDefinitions.h
>  create mode 100644 EmulatorPkg/Unix/Host/Arm/SwitchStack.S
>  create mode 100644 EmulatorPkg/Unix/Host/CacheMaintenance.c
>
> --
> 2.30.2
>
>
>
> 
>
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2023-03-10 16:45 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-03-06  0:21 [PATCH v1 0/6] Add Raspberry Pi Support to EmulatorPkg Nate DeSimone
2023-03-06  0:22 ` [PATCH v1 1/6] ArmPkg: Add ArmMmuNullLib Nate DeSimone
2023-03-06  0:22 ` [PATCH v1 2/6] EmulatorPkg: Add ARM Build Target Nate DeSimone
2023-03-06  0:22 ` [PATCH v1 3/6] EmulatorPkg: Fix PosixFileSystem function misspellings Nate DeSimone
2023-03-06  0:22 ` [PATCH v1 4/6] EmulatorPkg: Add ARM support to UNIX Host App Nate DeSimone
2023-03-06  0:22 ` [PATCH v1 5/6] EmulatorPkg: Add ARM support to EmuSec Nate DeSimone
2023-03-06  0:22 ` [PATCH v1 6/6] EmulatorPkg: Add EmuCacheMaintenanceLib Nate DeSimone
2023-03-10 16:45 ` [edk2-devel] [PATCH v1 0/6] Add Raspberry Pi Support to EmulatorPkg Ard Biesheuvel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox