Core: Port Exclusive memory impl from yuzu
core\arm\dynarmic\arm_dynarmic.cpp: fix build core\arm\dynarmic\arm_dynarmic.cpp: Fixes CPP 20
This commit is contained in:
parent
98d3b9c776
commit
fbe06234b1
|
@ -138,13 +138,13 @@ if (NOT ENABLE_GENERIC)
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
detect_architecture("_M_AMD64" x86_64)
|
detect_architecture("_M_AMD64" x86_64)
|
||||||
detect_architecture("_M_IX86" x86)
|
detect_architecture("_M_IX86" x86)
|
||||||
detect_architecture("_M_ARM" ARM)
|
detect_architecture("_M_ARM" arm)
|
||||||
detect_architecture("_M_ARM64" ARM64)
|
detect_architecture("_M_ARM64" arm64)
|
||||||
else()
|
else()
|
||||||
detect_architecture("__x86_64__" x86_64)
|
detect_architecture("__x86_64__" x86_64)
|
||||||
detect_architecture("__i386__" x86)
|
detect_architecture("__i386__" x86)
|
||||||
detect_architecture("__arm__" ARM)
|
detect_architecture("__arm__" arm)
|
||||||
detect_architecture("__aarch64__" ARM64)
|
detect_architecture("__aarch64__" arm64)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
if (NOT DEFINED ARCHITECTURE)
|
if (NOT DEFINED ARCHITECTURE)
|
||||||
|
|
|
@ -45,7 +45,7 @@ if (ARCHITECTURE_x86_64)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Dynarmic
|
# Dynarmic
|
||||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_ARM64)
|
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||||
set(DYNARMIC_TESTS OFF)
|
set(DYNARMIC_TESTS OFF)
|
||||||
set(DYNARMIC_NO_BUNDLED_FMT ON)
|
set(DYNARMIC_NO_BUNDLED_FMT ON)
|
||||||
set(DYNARMIC_FRONTENDS "A32")
|
set(DYNARMIC_FRONTENDS "A32")
|
||||||
|
|
|
@ -58,6 +58,7 @@ add_library(common STATIC
|
||||||
announce_multiplayer_room.h
|
announce_multiplayer_room.h
|
||||||
archives.h
|
archives.h
|
||||||
assert.h
|
assert.h
|
||||||
|
atomic_ops.h
|
||||||
detached_tasks.cpp
|
detached_tasks.cpp
|
||||||
detached_tasks.h
|
detached_tasks.h
|
||||||
bit_field.h
|
bit_field.h
|
||||||
|
@ -127,7 +128,7 @@ if(ARCHITECTURE_x86_64)
|
||||||
x64/xbyak_abi.h
|
x64/xbyak_abi.h
|
||||||
x64/xbyak_util.h
|
x64/xbyak_util.h
|
||||||
)
|
)
|
||||||
elseif(ARCHITECTURE_ARM64)
|
elseif(ARCHITECTURE_arm64)
|
||||||
target_sources(common
|
target_sources(common
|
||||||
PRIVATE
|
PRIVATE
|
||||||
aarch64/cpu_detect.cpp
|
aarch64/cpu_detect.cpp
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
#if _MSC_VER
|
||||||
|
#include <intrin.h>
|
||||||
|
#else
|
||||||
|
#include <cstring>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
|
||||||
|
#if _MSC_VER
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
|
||||||
|
const u8 result =
|
||||||
|
_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
|
||||||
|
return result == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
|
||||||
|
const u16 result =
|
||||||
|
_InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
|
||||||
|
return result == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
|
||||||
|
const u32 result =
|
||||||
|
_InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
|
||||||
|
return result == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
|
||||||
|
const u64 result = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer),
|
||||||
|
value, expected);
|
||||||
|
return result == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
|
||||||
|
return _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
|
||||||
|
value[0],
|
||||||
|
reinterpret_cast<__int64*>(expected.data())) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected,
|
||||||
|
u8& actual) {
|
||||||
|
actual =
|
||||||
|
_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected,
|
||||||
|
u16& actual) {
|
||||||
|
actual =
|
||||||
|
_InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected,
|
||||||
|
u32& actual) {
|
||||||
|
actual =
|
||||||
|
_InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected,
|
||||||
|
u64& actual) {
|
||||||
|
actual = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer), value,
|
||||||
|
expected);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected,
|
||||||
|
u128& actual) {
|
||||||
|
const bool result =
|
||||||
|
_InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
|
||||||
|
value[0], reinterpret_cast<__int64*>(expected.data())) != 0;
|
||||||
|
actual = expected;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) {
|
||||||
|
u128 result{};
|
||||||
|
_InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), result[1],
|
||||||
|
result[0], reinterpret_cast<__int64*>(result.data()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
|
||||||
|
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
|
||||||
|
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
|
||||||
|
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
|
||||||
|
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
|
||||||
|
unsigned __int128 value_a;
|
||||||
|
unsigned __int128 expected_a;
|
||||||
|
std::memcpy(&value_a, value.data(), sizeof(u128));
|
||||||
|
std::memcpy(&expected_a, expected.data(), sizeof(u128));
|
||||||
|
return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected,
|
||||||
|
u8& actual) {
|
||||||
|
actual = __sync_val_compare_and_swap(pointer, expected, value);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected,
|
||||||
|
u16& actual) {
|
||||||
|
actual = __sync_val_compare_and_swap(pointer, expected, value);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected,
|
||||||
|
u32& actual) {
|
||||||
|
actual = __sync_val_compare_and_swap(pointer, expected, value);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected,
|
||||||
|
u64& actual) {
|
||||||
|
actual = __sync_val_compare_and_swap(pointer, expected, value);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected,
|
||||||
|
u128& actual) {
|
||||||
|
unsigned __int128 value_a;
|
||||||
|
unsigned __int128 expected_a;
|
||||||
|
unsigned __int128 actual_a;
|
||||||
|
std::memcpy(&value_a, value.data(), sizeof(u128));
|
||||||
|
std::memcpy(&expected_a, expected.data(), sizeof(u128));
|
||||||
|
actual_a = __sync_val_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a);
|
||||||
|
std::memcpy(actual.data(), &actual_a, sizeof(u128));
|
||||||
|
return actual_a == expected_a;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) {
|
||||||
|
unsigned __int128 zeros_a = 0;
|
||||||
|
unsigned __int128 result_a =
|
||||||
|
__sync_val_compare_and_swap((unsigned __int128*)pointer, zeros_a, zeros_a);
|
||||||
|
|
||||||
|
u128 result;
|
||||||
|
std::memcpy(result.data(), &result_a, sizeof(u128));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace Common
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -50,6 +51,9 @@ typedef double f64; ///< 64-bit floating point
|
||||||
typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space.
|
typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space.
|
||||||
typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space.
|
typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space.
|
||||||
|
|
||||||
|
using u128 = std::array<std::uint64_t, 2>;
|
||||||
|
static_assert(sizeof(u128) == 16, "u128 must be 128 bits wide");
|
||||||
|
|
||||||
// An inheritable class to disallow the copy constructor and operator= functions
|
// An inheritable class to disallow the copy constructor and operator= functions
|
||||||
class NonCopyable {
|
class NonCopyable {
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -12,6 +12,8 @@ add_library(core STATIC
|
||||||
arm/dyncom/arm_dyncom_thumb.h
|
arm/dyncom/arm_dyncom_thumb.h
|
||||||
arm/dyncom/arm_dyncom_trans.cpp
|
arm/dyncom/arm_dyncom_trans.cpp
|
||||||
arm/dyncom/arm_dyncom_trans.h
|
arm/dyncom/arm_dyncom_trans.h
|
||||||
|
arm/exclusive_monitor.cpp
|
||||||
|
arm/exclusive_monitor.h
|
||||||
arm/skyeye_common/arm_regformat.h
|
arm/skyeye_common/arm_regformat.h
|
||||||
arm/skyeye_common/armstate.cpp
|
arm/skyeye_common/armstate.cpp
|
||||||
arm/skyeye_common/armstate.h
|
arm/skyeye_common/armstate.h
|
||||||
|
@ -482,12 +484,14 @@ if (ENABLE_WEB_SERVICE)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_ARM64)
|
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
arm/dynarmic/arm_dynarmic.cpp
|
arm/dynarmic/arm_dynarmic.cpp
|
||||||
arm/dynarmic/arm_dynarmic.h
|
arm/dynarmic/arm_dynarmic.h
|
||||||
arm/dynarmic/arm_dynarmic_cp15.cpp
|
arm/dynarmic/arm_dynarmic_cp15.cpp
|
||||||
arm/dynarmic/arm_dynarmic_cp15.h
|
arm/dynarmic/arm_dynarmic_cp15.h
|
||||||
|
arm/dynarmic/arm_exclusive_monitor.cpp
|
||||||
|
arm/dynarmic/arm_exclusive_monitor.h
|
||||||
)
|
)
|
||||||
target_link_libraries(core PRIVATE dynarmic)
|
target_link_libraries(core PRIVATE dynarmic)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -122,6 +122,9 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void InvalidateCacheRange(u32 start_address, std::size_t length) = 0;
|
virtual void InvalidateCacheRange(u32 start_address, std::size_t length) = 0;
|
||||||
|
|
||||||
|
/// Clears the exclusive monitor's state.
|
||||||
|
virtual void ClearExclusiveState() = 0;
|
||||||
|
|
||||||
/// Notify CPU emulation that page tables have changed
|
/// Notify CPU emulation that page tables have changed
|
||||||
virtual void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) = 0;
|
virtual void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) = 0;
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,14 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <dynarmic/A32/a32.h>
|
#include <dynarmic/interface/A32/a32.h>
|
||||||
#include <dynarmic/A32/context.h>
|
#include <dynarmic/interface/A32/context.h>
|
||||||
|
#include <dynarmic/interface/optimization_flags.h>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/microprofile.h"
|
#include "common/microprofile.h"
|
||||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||||
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
|
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
|
||||||
|
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/gdbstub/gdbstub.h"
|
#include "core/gdbstub/gdbstub.h"
|
||||||
|
@ -100,10 +102,23 @@ public:
|
||||||
memory.Write64(vaddr, value);
|
memory.Write64(vaddr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override {
|
||||||
|
return memory.WriteExclusive8(vaddr, value, expected);
|
||||||
|
}
|
||||||
|
bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override {
|
||||||
|
return memory.WriteExclusive16(vaddr, value, expected);
|
||||||
|
}
|
||||||
|
bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override {
|
||||||
|
return memory.WriteExclusive32(vaddr, value, expected);
|
||||||
|
}
|
||||||
|
bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override {
|
||||||
|
return memory.WriteExclusive64(vaddr, value, expected);
|
||||||
|
}
|
||||||
|
|
||||||
void InterpreterFallback(VAddr pc, std::size_t num_instructions) override {
|
void InterpreterFallback(VAddr pc, std::size_t num_instructions) override {
|
||||||
// Should never happen.
|
// Should never happen.
|
||||||
UNREACHABLE_MSG("InterpeterFallback reached with pc = 0x{:08x}, code = 0x{:08x}, num = {}",
|
UNREACHABLE_MSG("InterpeterFallback reached with pc = 0x{:08x}, code = 0x{:08x}, num = {}",
|
||||||
pc, MemoryReadCode(pc), num_instructions);
|
pc, MemoryReadCode(pc).value(), num_instructions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallSVC(std::uint32_t swi) override {
|
void CallSVC(std::uint32_t swi) override {
|
||||||
|
@ -114,6 +129,8 @@ public:
|
||||||
switch (exception) {
|
switch (exception) {
|
||||||
case Dynarmic::A32::Exception::UndefinedInstruction:
|
case Dynarmic::A32::Exception::UndefinedInstruction:
|
||||||
case Dynarmic::A32::Exception::UnpredictableInstruction:
|
case Dynarmic::A32::Exception::UnpredictableInstruction:
|
||||||
|
case Dynarmic::A32::Exception::DecodeError:
|
||||||
|
case Dynarmic::A32::Exception::NoExecuteFault:
|
||||||
break;
|
break;
|
||||||
case Dynarmic::A32::Exception::Breakpoint:
|
case Dynarmic::A32::Exception::Breakpoint:
|
||||||
if (GDBStub::IsConnected()) {
|
if (GDBStub::IsConnected()) {
|
||||||
|
@ -130,10 +147,11 @@ public:
|
||||||
case Dynarmic::A32::Exception::Yield:
|
case Dynarmic::A32::Exception::Yield:
|
||||||
case Dynarmic::A32::Exception::PreloadData:
|
case Dynarmic::A32::Exception::PreloadData:
|
||||||
case Dynarmic::A32::Exception::PreloadDataWithIntentToWrite:
|
case Dynarmic::A32::Exception::PreloadDataWithIntentToWrite:
|
||||||
|
case Dynarmic::A32::Exception::PreloadInstruction:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", exception,
|
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", exception,
|
||||||
pc, MemoryReadCode(pc));
|
pc, MemoryReadCode(pc).value());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddTicks(std::uint64_t ticks) override {
|
void AddTicks(std::uint64_t ticks) override {
|
||||||
|
@ -149,10 +167,12 @@ public:
|
||||||
Memory::MemorySystem& memory;
|
Memory::MemorySystem& memory;
|
||||||
};
|
};
|
||||||
|
|
||||||
ARM_Dynarmic::ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, u32 id,
|
ARM_Dynarmic::ARM_Dynarmic(Core::System* system_, Memory::MemorySystem& memory_, u32 core_id_,
|
||||||
std::shared_ptr<Core::Timing::Timer> timer)
|
std::shared_ptr<Core::Timing::Timer> timer_,
|
||||||
: ARM_Interface(id, timer), system(*system), memory(memory),
|
Core::ExclusiveMonitor& exclusive_monitor_)
|
||||||
cb(std::make_unique<DynarmicUserCallbacks>(*this)) {
|
: ARM_Interface(core_id_, timer_), system(*system_), memory(memory_),
|
||||||
|
cb(std::make_unique<DynarmicUserCallbacks>(*this)),
|
||||||
|
exclusive_monitor{dynamic_cast<Core::DynarmicExclusiveMonitor&>(exclusive_monitor_)} {
|
||||||
SetPageTable(memory.GetCurrentPageTable());
|
SetPageTable(memory.GetCurrentPageTable());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,6 +228,7 @@ u32 ARM_Dynarmic::GetVFPSystemReg(VFPSystemRegister reg) const {
|
||||||
default:
|
default:
|
||||||
UNREACHABLE_MSG("Unknown VFP system register: {}", reg);
|
UNREACHABLE_MSG("Unknown VFP system register: {}", reg);
|
||||||
}
|
}
|
||||||
|
return UINT_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic::SetVFPSystemReg(VFPSystemRegister reg, u32 value) {
|
void ARM_Dynarmic::SetVFPSystemReg(VFPSystemRegister reg, u32 value) {
|
||||||
|
@ -291,6 +312,10 @@ void ARM_Dynarmic::InvalidateCacheRange(u32 start_address, std::size_t length) {
|
||||||
jit->InvalidateCacheRange(start_address, length);
|
jit->InvalidateCacheRange(start_address, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ARM_Dynarmic::ClearExclusiveState() {
|
||||||
|
jit->ClearExclusiveState();
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<Memory::PageTable> ARM_Dynarmic::GetPageTable() const {
|
std::shared_ptr<Memory::PageTable> ARM_Dynarmic::GetPageTable() const {
|
||||||
return current_page_table;
|
return current_page_table;
|
||||||
}
|
}
|
||||||
|
@ -328,6 +353,11 @@ std::unique_ptr<Dynarmic::A32::Jit> ARM_Dynarmic::MakeJit() {
|
||||||
config.page_table = ¤t_page_table->GetPointerArray();
|
config.page_table = ¤t_page_table->GetPointerArray();
|
||||||
config.coprocessors[15] = std::make_shared<DynarmicCP15>(cp15_state);
|
config.coprocessors[15] = std::make_shared<DynarmicCP15>(cp15_state);
|
||||||
config.define_unpredictable_behaviour = true;
|
config.define_unpredictable_behaviour = true;
|
||||||
|
|
||||||
|
// Multi-process state
|
||||||
|
config.processor_id = GetID();
|
||||||
|
config.global_monitor = &exclusive_monitor.monitor;
|
||||||
|
|
||||||
return std::make_unique<Dynarmic::A32::Jit>(config);
|
return std::make_unique<Dynarmic::A32::Jit>(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <dynarmic/A32/a32.h>
|
#include <dynarmic/interface/A32/a32.h>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
|
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
|
||||||
|
@ -17,6 +17,8 @@ class MemorySystem;
|
||||||
} // namespace Memory
|
} // namespace Memory
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
class DynarmicExclusiveMonitor;
|
||||||
|
class ExclusiveMonitor;
|
||||||
class System;
|
class System;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +26,9 @@ class DynarmicUserCallbacks;
|
||||||
|
|
||||||
class ARM_Dynarmic final : public ARM_Interface {
|
class ARM_Dynarmic final : public ARM_Interface {
|
||||||
public:
|
public:
|
||||||
ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, u32 id,
|
explicit ARM_Dynarmic(Core::System* system_, Memory::MemorySystem& memory_, u32 core_id_,
|
||||||
std::shared_ptr<Core::Timing::Timer> timer);
|
std::shared_ptr<Core::Timing::Timer> timer,
|
||||||
|
Core::ExclusiveMonitor& exclusive_monitor_);
|
||||||
~ARM_Dynarmic() override;
|
~ARM_Dynarmic() override;
|
||||||
|
|
||||||
void Run() override;
|
void Run() override;
|
||||||
|
@ -52,6 +55,7 @@ public:
|
||||||
|
|
||||||
void ClearInstructionCache() override;
|
void ClearInstructionCache() override;
|
||||||
void InvalidateCacheRange(u32 start_address, std::size_t length) override;
|
void InvalidateCacheRange(u32 start_address, std::size_t length) override;
|
||||||
|
void ClearExclusiveState() override;
|
||||||
void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) override;
|
void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) override;
|
||||||
void PurgeState() override;
|
void PurgeState() override;
|
||||||
|
|
||||||
|
@ -69,6 +73,7 @@ private:
|
||||||
|
|
||||||
u32 fpexc = 0;
|
u32 fpexc = 0;
|
||||||
CP15State cp15_state;
|
CP15State cp15_state;
|
||||||
|
Core::DynarmicExclusiveMonitor& exclusive_monitor;
|
||||||
|
|
||||||
Dynarmic::A32::Jit* jit = nullptr;
|
Dynarmic::A32::Jit* jit = nullptr;
|
||||||
std::shared_ptr<Memory::PageTable> current_page_table = nullptr;
|
std::shared_ptr<Memory::PageTable> current_page_table = nullptr;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <dynarmic/A32/coprocessor.h>
|
#include <dynarmic/interface/A32/coprocessor.h>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
struct CP15State {
|
struct CP15State {
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
|
||||||
|
#include "core/memory.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::MemorySystem& memory_, std::size_t core_count_)
|
||||||
|
: monitor{core_count_}, memory{memory_} {}
|
||||||
|
|
||||||
|
DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;
|
||||||
|
|
||||||
|
u8 DynarmicExclusiveMonitor::ExclusiveRead8(std::size_t core_index, VAddr addr) {
|
||||||
|
return monitor.ReadAndMark<u8>(core_index, addr, [&]() -> u8 { return memory.Read8(addr); });
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 DynarmicExclusiveMonitor::ExclusiveRead16(std::size_t core_index, VAddr addr) {
|
||||||
|
return monitor.ReadAndMark<u16>(core_index, addr, [&]() -> u16 { return memory.Read16(addr); });
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 DynarmicExclusiveMonitor::ExclusiveRead32(std::size_t core_index, VAddr addr) {
|
||||||
|
return monitor.ReadAndMark<u32>(core_index, addr, [&]() -> u32 { return memory.Read32(addr); });
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 DynarmicExclusiveMonitor::ExclusiveRead64(std::size_t core_index, VAddr addr) {
|
||||||
|
return monitor.ReadAndMark<u64>(core_index, addr, [&]() -> u64 { return memory.Read64(addr); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynarmicExclusiveMonitor::ClearExclusive(std::size_t core_index) {
|
||||||
|
monitor.ClearProcessor(core_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) {
|
||||||
|
return monitor.DoExclusiveOperation<u8>(core_index, vaddr, [&](u8 expected) -> bool {
|
||||||
|
return memory.WriteExclusive8(vaddr, value, expected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) {
|
||||||
|
return monitor.DoExclusiveOperation<u16>(core_index, vaddr, [&](u16 expected) -> bool {
|
||||||
|
return memory.WriteExclusive16(vaddr, value, expected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) {
|
||||||
|
return monitor.DoExclusiveOperation<u32>(core_index, vaddr, [&](u32 expected) -> bool {
|
||||||
|
return memory.WriteExclusive32(vaddr, value, expected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) {
|
||||||
|
return monitor.DoExclusiveOperation<u64>(core_index, vaddr, [&](u64 expected) -> bool {
|
||||||
|
return memory.WriteExclusive64(vaddr, value, expected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core
|
|
@ -0,0 +1,40 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <dynarmic/interface/exclusive_monitor.h>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||||
|
#include "core/arm/exclusive_monitor.h"
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
|
||||||
|
public:
|
||||||
|
explicit DynarmicExclusiveMonitor( Memory::MemorySystem& memory_, std::size_t core_count_);
|
||||||
|
~DynarmicExclusiveMonitor() override;
|
||||||
|
|
||||||
|
u8 ExclusiveRead8(std::size_t core_index, VAddr addr) override;
|
||||||
|
u16 ExclusiveRead16(std::size_t core_index, VAddr addr) override;
|
||||||
|
u32 ExclusiveRead32(std::size_t core_index, VAddr addr) override;
|
||||||
|
u64 ExclusiveRead64(std::size_t core_index, VAddr addr) override;
|
||||||
|
void ClearExclusive(std::size_t core_index) override;
|
||||||
|
|
||||||
|
bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) override;
|
||||||
|
bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) override;
|
||||||
|
bool ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) override;
|
||||||
|
bool ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ::ARM_Dynarmic;
|
||||||
|
Dynarmic::ExclusiveMonitor monitor;
|
||||||
|
Memory::MemorySystem& memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core
|
|
@ -30,6 +30,7 @@ public:
|
||||||
|
|
||||||
void ClearInstructionCache() override;
|
void ClearInstructionCache() override;
|
||||||
void InvalidateCacheRange(u32 start_address, std::size_t length) override;
|
void InvalidateCacheRange(u32 start_address, std::size_t length) override;
|
||||||
|
void ClearExclusiveState() override {};
|
||||||
|
|
||||||
void SetPC(u32 pc) override;
|
void SetPC(u32 pc) override;
|
||||||
u32 GetPC() const override;
|
u32 GetPC() const override;
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
||||||
|
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
|
||||||
|
#endif
|
||||||
|
#include "core/arm/exclusive_monitor.h"
|
||||||
|
#include "core/memory.h"
|
||||||
|
#include "core/settings.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
ExclusiveMonitor::~ExclusiveMonitor() = default;
|
||||||
|
|
||||||
|
std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::MemorySystem& memory,
|
||||||
|
std::size_t num_cores) {
|
||||||
|
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
||||||
|
if (Settings::values.use_cpu_jit) {
|
||||||
|
return std::make_unique<Core::DynarmicExclusiveMonitor>(memory, num_cores);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// TODO(merry): Passthrough exclusive monitor
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core
|
|
@ -0,0 +1,35 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
class ExclusiveMonitor {
|
||||||
|
public:
|
||||||
|
virtual ~ExclusiveMonitor();
|
||||||
|
|
||||||
|
virtual u8 ExclusiveRead8(std::size_t core_index, VAddr addr) = 0;
|
||||||
|
virtual u16 ExclusiveRead16(std::size_t core_index, VAddr addr) = 0;
|
||||||
|
virtual u32 ExclusiveRead32(std::size_t core_index, VAddr addr) = 0;
|
||||||
|
virtual u64 ExclusiveRead64(std::size_t core_index, VAddr addr) = 0;
|
||||||
|
virtual void ClearExclusive(std::size_t core_index) = 0;
|
||||||
|
|
||||||
|
virtual bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) = 0;
|
||||||
|
virtual bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) = 0;
|
||||||
|
virtual bool ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) = 0;
|
||||||
|
virtual bool ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::MemorySystem& memory,
|
||||||
|
std::size_t num_cores);
|
||||||
|
|
||||||
|
} // namespace Core
|
|
@ -13,7 +13,8 @@
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/texture.h"
|
#include "common/texture.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_ARM64)
|
#include "core/arm/exclusive_monitor.h"
|
||||||
|
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
||||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||||
#endif
|
#endif
|
||||||
#include "core/arm/dyncom/arm_dyncom.h"
|
#include "core/arm/dyncom/arm_dyncom.h"
|
||||||
|
@ -364,11 +365,12 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
|
||||||
kernel = std::make_unique<Kernel::KernelSystem>(
|
kernel = std::make_unique<Kernel::KernelSystem>(
|
||||||
*memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores, n3ds_mode);
|
*memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores, n3ds_mode);
|
||||||
|
|
||||||
|
exclusive_monitor = MakeExclusiveMonitor(*memory, num_cores);
|
||||||
if (Settings::values.use_cpu_jit) {
|
if (Settings::values.use_cpu_jit) {
|
||||||
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_ARM64)
|
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
||||||
for (u32 i = 0; i < num_cores; ++i) {
|
for (u32 i = 0; i < num_cores; ++i) {
|
||||||
cpu_cores.push_back(
|
cpu_cores.push_back(
|
||||||
std::make_shared<ARM_Dynarmic>(this, *memory, i, timing->GetTimer(i)));
|
std::make_shared<ARM_Dynarmic>(this, *memory, i, timing->GetTimer(i), *exclusive_monitor));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
for (u32 i = 0; i < num_cores; ++i) {
|
for (u32 i = 0; i < num_cores; ++i) {
|
||||||
|
@ -543,6 +545,7 @@ void System::Shutdown(bool is_deserializing) {
|
||||||
dsp_core.reset();
|
dsp_core.reset();
|
||||||
kernel.reset();
|
kernel.reset();
|
||||||
cpu_cores.clear();
|
cpu_cores.clear();
|
||||||
|
exclusive_monitor.reset();
|
||||||
timing.reset();
|
timing.reset();
|
||||||
|
|
||||||
if (video_dumper && video_dumper->IsDumping()) {
|
if (video_dumper && video_dumper->IsDumping()) {
|
||||||
|
|
|
@ -61,6 +61,7 @@ class RendererBase;
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
|
class ExclusiveMonitor;
|
||||||
class Timing;
|
class Timing;
|
||||||
|
|
||||||
class System {
|
class System {
|
||||||
|
@ -363,6 +364,8 @@ private:
|
||||||
std::unique_ptr<Kernel::KernelSystem> kernel;
|
std::unique_ptr<Kernel::KernelSystem> kernel;
|
||||||
std::unique_ptr<Timing> timing;
|
std::unique_ptr<Timing> timing;
|
||||||
|
|
||||||
|
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static System s_instance;
|
static System s_instance;
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "audio_core/dsp_interface.h"
|
#include "audio_core/dsp_interface.h"
|
||||||
#include "common/archives.h"
|
#include "common/archives.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/atomic_ops.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
|
@ -373,6 +374,38 @@ void MemorySystem::Write(const VAddr vaddr, const T data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expected) {
|
||||||
|
u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||||
|
|
||||||
|
if (page_pointer) {
|
||||||
|
const auto volatile_pointer = reinterpret_cast<volatile T*>(&page_pointer[vaddr & PAGE_MASK]);
|
||||||
|
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS];
|
||||||
|
switch (type) {
|
||||||
|
case PageType::Unmapped:
|
||||||
|
LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}",
|
||||||
|
sizeof(data) * 8, (u32)data, vaddr, Core::GetRunningCore().GetPC());
|
||||||
|
return true;
|
||||||
|
case PageType::Memory:
|
||||||
|
ASSERT_MSG(false, "Mapped memory page without a pointer @ {:08X}", vaddr);
|
||||||
|
return true;
|
||||||
|
case PageType::RasterizerCachedMemory: {
|
||||||
|
RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Invalidate);
|
||||||
|
const auto volatile_pointer = reinterpret_cast<volatile T*>(GetPointerForRasterizerCache(vaddr).GetPtr());
|
||||||
|
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
|
||||||
|
}
|
||||||
|
case PageType::Special:
|
||||||
|
WriteMMIO<T>(GetMMIOHandler(*impl->current_page_table, vaddr), vaddr, data);
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
|
bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
|
||||||
auto& page_table = *process.vm_manager.page_table;
|
auto& page_table = *process.vm_manager.page_table;
|
||||||
|
|
||||||
|
@ -732,6 +765,22 @@ void MemorySystem::Write64(const VAddr addr, const u64 data) {
|
||||||
Write<u64_le>(addr, data);
|
Write<u64_le>(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MemorySystem::WriteExclusive8(const VAddr addr, const u8 data, const u8 expected) {
|
||||||
|
return WriteExclusive<u8>(addr, data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemorySystem::WriteExclusive16(const VAddr addr, const u16 data, const u16 expected) {
|
||||||
|
return WriteExclusive<u16_le>(addr, data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemorySystem::WriteExclusive32(const VAddr addr, const u32 data, const u32 expected) {
|
||||||
|
return WriteExclusive<u32_le>(addr, data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemorySystem::WriteExclusive64(const VAddr addr, const u64 data, const u64 expected) {
|
||||||
|
return WriteExclusive<u64_le>(addr, data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_addr,
|
void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_addr,
|
||||||
const void* src_buffer, const std::size_t size) {
|
const void* src_buffer, const std::size_t size) {
|
||||||
auto& page_table = *process.vm_manager.page_table;
|
auto& page_table = *process.vm_manager.page_table;
|
||||||
|
|
|
@ -327,6 +327,23 @@ public:
|
||||||
void Write32(VAddr addr, u32 data);
|
void Write32(VAddr addr, u32 data);
|
||||||
void Write64(VAddr addr, u64 data);
|
void Write64(VAddr addr, u64 data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a {8, 16, 32, 64}-bit unsigned integer to the given virtual address in
|
||||||
|
* the current process' address space if and only if the address contains
|
||||||
|
* the expected value. This operation is atomic.
|
||||||
|
*
|
||||||
|
* @param addr The virtual address to write the X-bit unsigned integer to.
|
||||||
|
* @param data The X-bit unsigned integer to write to the given virtual address.
|
||||||
|
* @param expected The X-bit unsigned integer to check against the given virtual address.
|
||||||
|
* @returns true if the operation failed
|
||||||
|
*
|
||||||
|
* @post The memory range [addr, sizeof(data)) contains the given data value.
|
||||||
|
*/
|
||||||
|
bool WriteExclusive8(const VAddr addr, const u8 data, const u8 expected);
|
||||||
|
bool WriteExclusive16(const VAddr addr, const u16 data, const u16 expected);
|
||||||
|
bool WriteExclusive32(const VAddr addr, const u32 data, const u32 expected);
|
||||||
|
bool WriteExclusive64(const VAddr addr, const u64 data, const u64 expected);
|
||||||
|
|
||||||
void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
|
void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
|
||||||
std::size_t size);
|
std::size_t size);
|
||||||
void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
|
void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
|
||||||
|
@ -384,6 +401,9 @@ private:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Write(const VAddr vaddr, const T data);
|
void Write(const VAddr vaddr, const T data);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool WriteExclusive(const VAddr vaddr, const T data, const T expected);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the pointer for virtual memory where the page is marked as RasterizerCachedMemory.
|
* Gets the pointer for virtual memory where the page is marked as RasterizerCachedMemory.
|
||||||
* This is used to access the memory where the page pointer is nullptr due to rasterizer cache.
|
* This is used to access the memory where the page pointer is nullptr due to rasterizer cache.
|
||||||
|
|
Reference in New Issue