From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by mx.groups.io with SMTP id smtpd.web10.22191.1678062132259075315 for ; Sun, 05 Mar 2023 16:22:13 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=k1KWn20T; spf=pass (domain: intel.com, ip: 134.134.136.65, mailfrom: nathaniel.l.desimone@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1678062133; x=1709598133; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=3QX8vM33wRzvBm1xowwQxC6FAM4IvVxGNnttwYoVH4Y=; b=k1KWn20T+ty7TRb2QrJjWRqnNbx2O3NC9iuPKLt1Ma0IapXm1nNl1gkI EpmlWVEskPH5aQfjjxDukP4AEc/6lYUy/hSAHPDZjWk1CKY87swc5KsFg 00IbxrQrzsWx9JnLfoKn9KmHT9mS/fU80KmHJBTSzTpxdLWtJgVKw7Pi3 TSJ+XM4xrujtBxueAgvUJTdKleOrLtwpi8YMrSw4x/ZmZRV1iFD/fQsCA JfaDUavD0pgfHmBw2gBO6wedjiKeTgajyFCUZBic2f7CuwShbTCze/W2x sQ8dvLHgJMmcR9o/+zIAj1vEzth7BRyGUuztXxgqSo0DLjna9I2c78AgJ Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10640"; a="337758121" X-IronPort-AV: E=Sophos;i="5.98,236,1673942400"; d="scan'208";a="337758121" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Mar 2023 16:22:11 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10640"; a="669263326" X-IronPort-AV: E=Sophos;i="5.98,236,1673942400"; d="scan'208";a="669263326" Received: from nldesimo-desk.amr.corp.intel.com ([10.24.12.177]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Mar 2023 16:22:11 -0800 From: "Nate DeSimone" To: devel@edk2.groups.io Cc: Andrew Fish , Ray Ni , Michael D Kinney , Chasel Chiu Subject: [PATCH v1 6/6] EmulatorPkg: Add EmuCacheMaintenanceLib Date: Sun, 5 Mar 2023 16:22:05 -0800 Message-Id: <20230306002205.1640-7-nathaniel.l.desimone@intel.com> X-Mailer: git-send-email 2.39.2.windows.1 In-Reply-To: <20230306002205.1640-1-nathaniel.l.desimone@intel.com> References: <20230306002205.1640-1-nathaniel.l.desimone@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 Cc: Ray Ni Cc: Michael D Kinney Cc: Chasel Chiu Signed-off-by: Nate DeSimone --- 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.
+# Copyright (c) 2008 - 2023, Intel Corporation. All rights reserved.
# Portions copyright (c) 2011, Apple Inc. All rights reserved. # (C) Copyright 2020 Hewlett Packard Enterprise Development LP
# @@ -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.
+ 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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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.
+# +# 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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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.
+# +# 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.
+ 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.
+Copyright (c) 2006 - 2023, Intel Corporation. All rights reserved.
Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.
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 #include #include +#include #include #include @@ -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