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
next prev 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