diff options
| author | 2022-12-10 12:24:33 -0500 | |
|---|---|---|
| committer | 2022-12-11 12:46:34 -0500 | |
| commit | ed3719244111af380fbba9e13286192c00708dea (patch) | |
| tree | 717f9598dd33fef8783005c9015486bc88a8a6c2 | |
| parent | Merge pull request #9412 from Saalvage/fix/trace-log-compilation (diff) | |
| download | yuzu-ed3719244111af380fbba9e13286192c00708dea.tar.gz yuzu-ed3719244111af380fbba9e13286192c00708dea.tar.xz yuzu-ed3719244111af380fbba9e13286192c00708dea.zip | |
memory: correct semantics of data cache management operations
Diffstat (limited to '')
| -rw-r--r-- | src/common/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/common/cache_management.cpp | 59 | ||||
| -rw-r--r-- | src/common/cache_management.h | 27 | ||||
| -rw-r--r-- | src/core/memory.cpp | 29 |
4 files changed, 15 insertions, 102 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 6bdffcb7a..25b22a281 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -34,8 +34,6 @@ add_library(common STATIC | |||
| 34 | bit_util.h | 34 | bit_util.h |
| 35 | cityhash.cpp | 35 | cityhash.cpp |
| 36 | cityhash.h | 36 | cityhash.h |
| 37 | cache_management.cpp | ||
| 38 | cache_management.h | ||
| 39 | common_funcs.h | 37 | common_funcs.h |
| 40 | common_precompiled_headers.h | 38 | common_precompiled_headers.h |
| 41 | common_types.h | 39 | common_types.h |
diff --git a/src/common/cache_management.cpp b/src/common/cache_management.cpp deleted file mode 100644 index ed353828a..000000000 --- a/src/common/cache_management.cpp +++ /dev/null | |||
| @@ -1,59 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <cstdint> | ||
| 5 | #include <cstring> | ||
| 6 | |||
| 7 | #include "common/cache_management.h" | ||
| 8 | |||
| 9 | namespace Common { | ||
| 10 | |||
| 11 | #if defined(ARCHITECTURE_x86_64) | ||
| 12 | |||
| 13 | // Most cache operations are no-ops on x86 | ||
| 14 | |||
| 15 | void DataCacheLineCleanByVAToPoU(void* start, size_t size) {} | ||
| 16 | void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size) {} | ||
| 17 | void DataCacheLineCleanByVAToPoC(void* start, size_t size) {} | ||
| 18 | void DataCacheZeroByVA(void* start, size_t size) { | ||
| 19 | std::memset(start, 0, size); | ||
| 20 | } | ||
| 21 | |||
| 22 | #elif defined(ARCHITECTURE_arm64) | ||
| 23 | |||
| 24 | // BS/DminLine is log2(cache size in words), we want size in bytes | ||
| 25 | #define EXTRACT_DMINLINE(ctr_el0) (1 << ((((ctr_el0) >> 16) & 0xf) + 2)) | ||
| 26 | #define EXTRACT_BS(dczid_el0) (1 << (((dczid_el0)&0xf) + 2)) | ||
| 27 | |||
| 28 | #define DEFINE_DC_OP(op_name, function_name) \ | ||
| 29 | void function_name(void* start, size_t size) { \ | ||
| 30 | size_t ctr_el0; \ | ||
| 31 | asm volatile("mrs %[ctr_el0], ctr_el0\n\t" : [ctr_el0] "=r"(ctr_el0)); \ | ||
| 32 | size_t cacheline_size = EXTRACT_DMINLINE(ctr_el0); \ | ||
| 33 | uintptr_t va_start = reinterpret_cast<uintptr_t>(start); \ | ||
| 34 | uintptr_t va_end = va_start + size; \ | ||
| 35 | for (uintptr_t va = va_start; va < va_end; va += cacheline_size) { \ | ||
| 36 | asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory"); \ | ||
| 37 | } \ | ||
| 38 | } | ||
| 39 | |||
| 40 | #define DEFINE_DC_OP_DCZID(op_name, function_name) \ | ||
| 41 | void function_name(void* start, size_t size) { \ | ||
| 42 | size_t dczid_el0; \ | ||
| 43 | asm volatile("mrs %[dczid_el0], dczid_el0\n\t" : [dczid_el0] "=r"(dczid_el0)); \ | ||
| 44 | size_t cacheline_size = EXTRACT_BS(dczid_el0); \ | ||
| 45 | uintptr_t va_start = reinterpret_cast<uintptr_t>(start); \ | ||
| 46 | uintptr_t va_end = va_start + size; \ | ||
| 47 | for (uintptr_t va = va_start; va < va_end; va += cacheline_size) { \ | ||
| 48 | asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory"); \ | ||
| 49 | } \ | ||
| 50 | } | ||
| 51 | |||
| 52 | DEFINE_DC_OP(cvau, DataCacheLineCleanByVAToPoU); | ||
| 53 | DEFINE_DC_OP(civac, DataCacheLineCleanAndInvalidateByVAToPoC); | ||
| 54 | DEFINE_DC_OP(cvac, DataCacheLineCleanByVAToPoC); | ||
| 55 | DEFINE_DC_OP_DCZID(zva, DataCacheZeroByVA); | ||
| 56 | |||
| 57 | #endif | ||
| 58 | |||
| 59 | } // namespace Common | ||
diff --git a/src/common/cache_management.h b/src/common/cache_management.h deleted file mode 100644 index 038323e95..000000000 --- a/src/common/cache_management.h +++ /dev/null | |||
| @@ -1,27 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <cstddef> | ||
| 7 | |||
| 8 | namespace Common { | ||
| 9 | |||
| 10 | // Data cache instructions enabled at EL0 by SCTLR_EL1.UCI. | ||
| 11 | // VA = virtual address | ||
| 12 | // PoC = point of coherency | ||
| 13 | // PoU = point of unification | ||
| 14 | |||
| 15 | // dc cvau | ||
| 16 | void DataCacheLineCleanByVAToPoU(void* start, size_t size); | ||
| 17 | |||
| 18 | // dc civac | ||
| 19 | void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size); | ||
| 20 | |||
| 21 | // dc cvac | ||
| 22 | void DataCacheLineCleanByVAToPoC(void* start, size_t size); | ||
| 23 | |||
| 24 | // dc zva | ||
| 25 | void DataCacheZeroByVA(void* start, size_t size); | ||
| 26 | |||
| 27 | } // namespace Common | ||
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 3141122f1..b24716455 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "common/atomic_ops.h" | 8 | #include "common/atomic_ops.h" |
| 9 | #include "common/cache_management.h" | ||
| 10 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 11 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 12 | #include "common/page_table.h" | 11 | #include "common/page_table.h" |
| @@ -342,10 +341,9 @@ struct Memory::Impl { | |||
| 342 | LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}", current_vaddr); | 341 | LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}", current_vaddr); |
| 343 | throw InvalidMemoryException(); | 342 | throw InvalidMemoryException(); |
| 344 | }, | 343 | }, |
| 345 | [&](const std::size_t block_size, u8* const host_ptr) { cb(block_size, host_ptr); }, | 344 | [&](const std::size_t block_size, u8* const host_ptr) {}, |
| 346 | [&](const VAddr current_vaddr, const std::size_t block_size, u8* const host_ptr) { | 345 | [&](const VAddr current_vaddr, const std::size_t block_size, u8* const host_ptr) { |
| 347 | system.GPU().FlushRegion(current_vaddr, block_size); | 346 | cb(current_vaddr, block_size); |
| 348 | cb(block_size, host_ptr); | ||
| 349 | }, | 347 | }, |
| 350 | [](const std::size_t block_size) {}); | 348 | [](const std::size_t block_size) {}); |
| 351 | } catch (InvalidMemoryException&) { | 349 | } catch (InvalidMemoryException&) { |
| @@ -356,27 +354,30 @@ struct Memory::Impl { | |||
| 356 | } | 354 | } |
| 357 | 355 | ||
| 358 | Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { | 356 | Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { |
| 359 | auto perform = [&](const std::size_t block_size, u8* const host_ptr) { | 357 | auto on_rasterizer = [&](const VAddr current_vaddr, const std::size_t block_size) { |
| 360 | // Do nothing; this operation (dc ivac) cannot be supported | 358 | // dc ivac: Invalidate to point of coherency |
| 361 | // from EL0 | 359 | // GPU flush -> CPU invalidate |
| 360 | system.GPU().FlushRegion(current_vaddr, block_size); | ||
| 362 | }; | 361 | }; |
| 363 | return PerformCacheOperation(process, dest_addr, size, perform); | 362 | return PerformCacheOperation(process, dest_addr, size, on_rasterizer); |
| 364 | } | 363 | } |
| 365 | 364 | ||
| 366 | Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { | 365 | Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { |
| 367 | auto perform = [&](const std::size_t block_size, u8* const host_ptr) { | 366 | auto on_rasterizer = [&](const VAddr current_vaddr, const std::size_t block_size) { |
| 368 | // dc cvac: Store to point of coherency | 367 | // dc cvac: Store to point of coherency |
| 369 | Common::DataCacheLineCleanByVAToPoC(host_ptr, block_size); | 368 | // CPU flush -> GPU invalidate |
| 369 | system.GPU().InvalidateRegion(current_vaddr, block_size); | ||
| 370 | }; | 370 | }; |
| 371 | return PerformCacheOperation(process, dest_addr, size, perform); | 371 | return PerformCacheOperation(process, dest_addr, size, on_rasterizer); |
| 372 | } | 372 | } |
| 373 | 373 | ||
| 374 | Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { | 374 | Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { |
| 375 | auto perform = [&](const std::size_t block_size, u8* const host_ptr) { | 375 | auto on_rasterizer = [&](const VAddr current_vaddr, const std::size_t block_size) { |
| 376 | // dc civac: Store to point of coherency, and invalidate from cache | 376 | // dc civac: Store to point of coherency, and invalidate from cache |
| 377 | Common::DataCacheLineCleanAndInvalidateByVAToPoC(host_ptr, block_size); | 377 | // CPU flush -> GPU invalidate |
| 378 | system.GPU().InvalidateRegion(current_vaddr, block_size); | ||
| 378 | }; | 379 | }; |
| 379 | return PerformCacheOperation(process, dest_addr, size, perform); | 380 | return PerformCacheOperation(process, dest_addr, size, on_rasterizer); |
| 380 | } | 381 | } |
| 381 | 382 | ||
| 382 | void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) { | 383 | void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) { |