diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/common/atomic_helpers.h | 1 | ||||
-rw-r--r-- | src/common/cache_management.cpp | 60 | ||||
-rw-r--r-- | src/common/cache_management.h | 27 | ||||
-rw-r--r-- | src/common/common_funcs.h | 4 | ||||
-rw-r--r-- | src/common/host_memory.cpp | 6 | ||||
-rw-r--r-- | src/common/settings.cpp | 1 | ||||
-rw-r--r-- | src/common/x64/cpu_detect.cpp | 59 | ||||
-rw-r--r-- | src/common/x64/cpu_detect.h | 4 |
9 files changed, 160 insertions, 4 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index c0555f840..b7c15c191 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -34,6 +34,8 @@ add_library(common STATIC bit_util.h cityhash.cpp cityhash.h + cache_management.cpp + cache_management.h common_funcs.h common_types.h concepts.h diff --git a/src/common/atomic_helpers.h b/src/common/atomic_helpers.h index bef5015c1..aef3b66a4 100644 --- a/src/common/atomic_helpers.h +++ b/src/common/atomic_helpers.h @@ -156,6 +156,7 @@ AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN { break; default: assert(false); + break; } } diff --git a/src/common/cache_management.cpp b/src/common/cache_management.cpp new file mode 100644 index 000000000..57810b76a --- /dev/null +++ b/src/common/cache_management.cpp @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <cstring> + +#include "alignment.h" +#include "cache_management.h" +#include "common_types.h" + +namespace Common { + +#if defined(ARCHITECTURE_x86_64) + +// Most cache operations are no-ops on x86 + +void DataCacheLineCleanByVAToPoU(void* start, size_t size) {} +void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size) {} +void DataCacheLineCleanByVAToPoC(void* start, size_t size) {} +void DataCacheZeroByVA(void* start, size_t size) { + std::memset(start, 0, size); +} + +#elif defined(ARCHITECTURE_arm64) + +// BS/DminLine is log2(cache size in words), we want size in bytes +#define EXTRACT_DMINLINE(ctr_el0) (1 << ((((ctr_el0) >> 16) & 0xf) + 2)) +#define EXTRACT_BS(dczid_el0) (1 << (((dczid_el0)&0xf) + 2)) + +#define DEFINE_DC_OP(op_name, function_name) \ + void function_name(void* start, size_t size) { \ + size_t ctr_el0; \ + asm volatile("mrs %[ctr_el0], ctr_el0\n\t" : [ctr_el0] "=r"(ctr_el0)); \ + size_t cacheline_size = EXTRACT_DMINLINE(ctr_el0); \ + uintptr_t va_start = reinterpret_cast<uintptr_t>(start); \ + uintptr_t va_end = va_start + size; \ + for (uintptr_t va = va_start; va < va_end; va += cacheline_size) { \ + asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory"); \ + } \ + } + +#define DEFINE_DC_OP_DCZID(op_name, function_name) \ + void function_name(void* start, size_t size) { \ + size_t dczid_el0; \ + asm volatile("mrs %[dczid_el0], dczid_el0\n\t" : [dczid_el0] "=r"(dczid_el0)); \ + size_t cacheline_size = EXTRACT_BS(dczid_el0); \ + uintptr_t va_start = reinterpret_cast<uintptr_t>(start); \ + uintptr_t va_end = va_start + size; \ + for (uintptr_t va = va_start; va < va_end; va += cacheline_size) { \ + asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory"); \ + } \ + } + +DEFINE_DC_OP(cvau, DataCacheLineCleanByVAToPoU); +DEFINE_DC_OP(civac, DataCacheLineCleanAndInvalidateByVAToPoC); +DEFINE_DC_OP(cvac, DataCacheLineCleanByVAToPoC); +DEFINE_DC_OP_DCZID(zva, DataCacheZeroByVA); + +#endif + +} // namespace Common diff --git a/src/common/cache_management.h b/src/common/cache_management.h new file mode 100644 index 000000000..e467b87e4 --- /dev/null +++ b/src/common/cache_management.h @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "stdlib.h" + +namespace Common { + +// Data cache instructions enabled at EL0 by SCTLR_EL1.UCI. +// VA = virtual address +// PoC = point of coherency +// PoU = point of unification + +// dc cvau +void DataCacheLineCleanByVAToPoU(void* start, size_t size); + +// dc civac +void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size); + +// dc cvac +void DataCacheLineCleanByVAToPoC(void* start, size_t size); + +// dc zva +void DataCacheZeroByVA(void* start, size_t size); + +} // namespace Common diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index e1e2a90fc..0dad9338a 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -31,8 +31,10 @@ #ifndef _MSC_VER -#ifdef ARCHITECTURE_x86_64 +#if defined(ARCHITECTURE_x86_64) #define Crash() __asm__ __volatile__("int $3") +#elif defined(ARCHITECTURE_arm64) +#define Crash() __asm__ __volatile__("brk #0") #else #define Crash() exit(1) #endif diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 7f9659612..909f6cf3f 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -359,6 +359,12 @@ public: } }); + long page_size = sysconf(_SC_PAGESIZE); + if (page_size != 0x1000) { + LOG_CRITICAL(HW_Memory, "page size {:#x} is incompatible with 4K paging", page_size); + throw std::bad_alloc{}; + } + // Backing memory initialization #if defined(__FreeBSD__) && __FreeBSD__ < 13 // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 0a560ebb7..8173462cb 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -151,6 +151,7 @@ void UpdateRescalingInfo() { ASSERT(false); info.up_scale = 1; info.down_shift = 0; + break; } info.up_factor = static_cast<f32>(info.up_scale) / (1U << info.down_shift); info.down_factor = static_cast<f32>(1U << info.down_shift) / info.up_scale; diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp index 1a27532d4..e54383a4a 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp @@ -4,14 +4,27 @@ #include <array> #include <cstring> +#include <fstream> #include <iterator> +#include <optional> #include <string_view> +#include <thread> +#include <vector> #include "common/bit_util.h" #include "common/common_types.h" +#include "common/logging/log.h" #include "common/x64/cpu_detect.h" +#ifdef _WIN32 +#include <windows.h> +#endif + #ifdef _MSC_VER #include <intrin.h> + +static inline u64 xgetbv(u32 index) { + return _xgetbv(index); +} #else #if defined(__DragonFly__) || defined(__FreeBSD__) @@ -39,12 +52,11 @@ static inline void __cpuid(int info[4], u32 function_id) { } #define _XCR_XFEATURE_ENABLED_MASK 0 -static inline u64 _xgetbv(u32 index) { +static inline u64 xgetbv(u32 index) { u32 eax, edx; __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); return ((u64)edx << 32) | eax; } - #endif // _MSC_VER namespace Common { @@ -107,7 +119,7 @@ static CPUCaps Detect() { // - Is the XSAVE bit set in CPUID? // - XGETBV result has the XCR bit set. if (Common::Bit<28>(cpu_id[2]) && Common::Bit<27>(cpu_id[2])) { - if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) { + if ((xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) { caps.avx = true; if (Common::Bit<12>(cpu_id[2])) caps.fma = true; @@ -192,4 +204,45 @@ const CPUCaps& GetCPUCaps() { return caps; } +std::optional<int> GetProcessorCount() { +#if defined(_WIN32) + // Get the buffer length. + DWORD length = 0; + GetLogicalProcessorInformation(nullptr, &length); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + LOG_ERROR(Frontend, "Failed to query core count."); + return std::nullopt; + } + std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer( + length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)); + // Now query the core count. + if (!GetLogicalProcessorInformation(buffer.data(), &length)) { + LOG_ERROR(Frontend, "Failed to query core count."); + return std::nullopt; + } + return static_cast<int>( + std::count_if(buffer.cbegin(), buffer.cend(), [](const auto& proc_info) { + return proc_info.Relationship == RelationProcessorCore; + })); +#elif defined(__unix__) + const int thread_count = std::thread::hardware_concurrency(); + std::ifstream smt("/sys/devices/system/cpu/smt/active"); + char state = '0'; + if (smt) { + smt.read(&state, sizeof(state)); + } + switch (state) { + case '0': + return thread_count; + case '1': + return thread_count / 2; + default: + return std::nullopt; + } +#else + // Shame on you + return std::nullopt; +#endif +} + } // namespace Common diff --git a/src/common/x64/cpu_detect.h b/src/common/x64/cpu_detect.h index 6830f3795..ca8db19d6 100644 --- a/src/common/x64/cpu_detect.h +++ b/src/common/x64/cpu_detect.h @@ -4,6 +4,7 @@ #pragma once +#include <optional> #include <string_view> #include "common/common_types.h" @@ -74,4 +75,7 @@ struct CPUCaps { */ const CPUCaps& GetCPUCaps(); +/// Detects CPU core count +std::optional<int> GetProcessorCount(); + } // namespace Common |