public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Nate DeSimone" <nathaniel.l.desimone@intel.com>
To: devel@edk2.groups.io
Cc: Andrew Fish <afish@apple.com>, Ray Ni <ray.ni@intel.com>,
	Michael D Kinney <michael.d.kinney@intel.com>,
	Chasel Chiu <chasel.chiu@intel.com>
Subject: [PATCH v1 6/6] EmulatorPkg: Add EmuCacheMaintenanceLib
Date: Sun,  5 Mar 2023 16:22:05 -0800	[thread overview]
Message-ID: <20230306002205.1640-7-nathaniel.l.desimone@intel.com> (raw)
In-Reply-To: <20230306002205.1640-1-nathaniel.l.desimone@intel.com>

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


  parent reply	other threads:[~2023-03-06  0:22 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 ` Nate DeSimone [this message]
2023-03-10 16:45 ` [edk2-devel] [PATCH v1 0/6] Add Raspberry Pi Support to EmulatorPkg Ard Biesheuvel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230306002205.1640-7-nathaniel.l.desimone@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox