summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
authorLioncash <mathew1800@gmail.com>2019-11-26 23:39:57 +0100
committerLioncash <mathew1800@gmail.com>2019-11-27 03:55:39 +0100
commite4c381b8850db96f162cfcf2cbe28b0e7c1f76f1 (patch)
tree14b95ea207543f3884558ebdf8673a511bf64dc3 /src/core
parentcore/memory: Migrate over Read{8, 16, 32, 64, Block} to the Memory class (diff)
downloadyuzu-e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1.tar
yuzu-e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1.tar.gz
yuzu-e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1.tar.bz2
yuzu-e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1.tar.lz
yuzu-e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1.tar.xz
yuzu-e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1.tar.zst
yuzu-e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1.zip
Diffstat (limited to 'src/core')
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp30
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h7
-rw-r--r--src/core/core_cpu.cpp5
-rw-r--r--src/core/core_cpu.h18
-rw-r--r--src/core/cpu_core_manager.cpp2
-rw-r--r--src/core/gdbstub/gdbstub.cpp16
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp6
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp9
-rw-r--r--src/core/hle/kernel/mutex.cpp4
-rw-r--r--src/core/hle/kernel/svc.cpp27
-rw-r--r--src/core/memory.cpp220
-rw-r--r--src/core/memory.h97
-rw-r--r--src/core/memory/cheat_engine.cpp2
-rw-r--r--src/core/tools/freezer.cpp8
14 files changed, 298 insertions, 153 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 585fb55a9..f8c7f0efd 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -45,20 +45,21 @@ public:
}
void MemoryWrite8(u64 vaddr, u8 value) override {
- Memory::Write8(vaddr, value);
+ parent.system.Memory().Write8(vaddr, value);
}
void MemoryWrite16(u64 vaddr, u16 value) override {
- Memory::Write16(vaddr, value);
+ parent.system.Memory().Write16(vaddr, value);
}
void MemoryWrite32(u64 vaddr, u32 value) override {
- Memory::Write32(vaddr, value);
+ parent.system.Memory().Write32(vaddr, value);
}
void MemoryWrite64(u64 vaddr, u64 value) override {
- Memory::Write64(vaddr, value);
+ parent.system.Memory().Write64(vaddr, value);
}
void MemoryWrite128(u64 vaddr, Vector value) override {
- Memory::Write64(vaddr, value[0]);
- Memory::Write64(vaddr + 8, value[1]);
+ auto& memory = parent.system.Memory();
+ memory.Write64(vaddr, value[0]);
+ memory.Write64(vaddr + 8, value[1]);
}
void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
@@ -266,7 +267,9 @@ void ARM_Dynarmic::PageTableChanged(Common::PageTable& page_table,
jit = MakeJit(page_table, new_address_space_size_in_bits);
}
-DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {}
+DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count)
+ : monitor(core_count), memory{memory_} {}
+
DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;
void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) {
@@ -279,29 +282,28 @@ void DynarmicExclusiveMonitor::ClearExclusive() {
}
bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) {
- return monitor.DoExclusiveOperation(core_index, vaddr, 1,
- [&] { Memory::Write8(vaddr, value); });
+ return monitor.DoExclusiveOperation(core_index, vaddr, 1, [&] { memory.Write8(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 2,
- [&] { Memory::Write16(vaddr, value); });
+ [&] { memory.Write16(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 4,
- [&] { Memory::Write32(vaddr, value); });
+ [&] { memory.Write32(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 8,
- [&] { Memory::Write64(vaddr, value); });
+ [&] { memory.Write64(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] {
- Memory::Write64(vaddr + 0, value[0]);
- Memory::Write64(vaddr + 8, value[1]);
+ memory.Write64(vaddr + 0, value[0]);
+ memory.Write64(vaddr + 8, value[1]);
});
}
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index d08de475f..9cd475cfb 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -12,6 +12,10 @@
#include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
+namespace Memory {
+class Memory;
+}
+
namespace Core {
class ARM_Dynarmic_Callbacks;
@@ -63,7 +67,7 @@ private:
class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
public:
- explicit DynarmicExclusiveMonitor(std::size_t core_count);
+ explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count);
~DynarmicExclusiveMonitor() override;
void SetExclusive(std::size_t core_index, VAddr addr) override;
@@ -78,6 +82,7 @@ public:
private:
friend class ARM_Dynarmic;
Dynarmic::A64::ExclusiveMonitor monitor;
+ Memory::Memory& memory;
};
} // namespace Core
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index 233ea572c..cf3fe0b0b 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -66,9 +66,10 @@ Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_ba
Cpu::~Cpu() = default;
-std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) {
+std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(
+ [[maybe_unused]] Memory::Memory& memory, [[maybe_unused]] std::size_t num_cores) {
#ifdef ARCHITECTURE_x86_64
- return std::make_unique<DynarmicExclusiveMonitor>(num_cores);
+ return std::make_unique<DynarmicExclusiveMonitor>(memory, num_cores);
#else
// TODO(merry): Passthrough exclusive monitor
return nullptr;
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h
index cafca8df7..78f5021a2 100644
--- a/src/core/core_cpu.h
+++ b/src/core/core_cpu.h
@@ -24,6 +24,10 @@ namespace Core::Timing {
class CoreTiming;
}
+namespace Memory {
+class Memory;
+}
+
namespace Core {
class ARM_Interface;
@@ -86,7 +90,19 @@ public:
void Shutdown();
- static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(std::size_t num_cores);
+ /**
+ * Creates an exclusive monitor to handle exclusive reads/writes.
+ *
+ * @param memory The current memory subsystem that the monitor may wish
+ * to keep track of.
+ *
+ * @param num_cores The number of cores to assume about the CPU.
+ *
+ * @returns The constructed exclusive monitor instance, or nullptr if the current
+ * CPU backend is unable to use an exclusive monitor.
+ */
+ static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory,
+ std::size_t num_cores);
private:
void Reschedule();
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp
index 8efd410bb..f04a34133 100644
--- a/src/core/cpu_core_manager.cpp
+++ b/src/core/cpu_core_manager.cpp
@@ -25,7 +25,7 @@ CpuCoreManager::~CpuCoreManager() = default;
void CpuCoreManager::Initialize() {
barrier = std::make_unique<CpuBarrier>();
- exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
+ exclusive_monitor = Cpu::MakeExclusiveMonitor(system.Memory(), cores.size());
for (std::size_t index = 0; index < cores.size(); ++index) {
cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index);
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 1c74a44d8..37cb28848 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -508,8 +508,9 @@ static void RemoveBreakpoint(BreakpointType type, VAddr addr) {
bp->second.len, bp->second.addr, static_cast<int>(type));
if (type == BreakpointType::Execute) {
- Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
- Core::System::GetInstance().InvalidateCpuInstructionCaches();
+ auto& system = Core::System::GetInstance();
+ system.Memory().WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
+ system.InvalidateCpuInstructionCaches();
}
p.erase(addr);
}
@@ -993,14 +994,14 @@ static void WriteMemory() {
const u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset));
auto& system = Core::System::GetInstance();
- const auto& memory = system.Memory();
+ auto& memory = system.Memory();
if (!memory.IsValidVirtualAddress(addr)) {
return SendReply("E00");
}
std::vector<u8> data(len);
GdbHexToMem(data.data(), len_pos + 1, len);
- Memory::WriteBlock(addr, data.data(), len);
+ memory.WriteBlock(addr, data.data(), len);
system.InvalidateCpuInstructionCaches();
SendReply("OK");
}
@@ -1058,13 +1059,14 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
breakpoint.addr = addr;
breakpoint.len = len;
- auto& memory = Core::System::GetInstance().Memory();
+ auto& system = Core::System::GetInstance();
+ auto& memory = system.Memory();
memory.ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4};
if (type == BreakpointType::Execute) {
- Memory::WriteBlock(addr, btrap.data(), btrap.size());
- Core::System::GetInstance().InvalidateCpuInstructionCaches();
+ memory.WriteBlock(addr, btrap.data(), btrap.size());
+ system.InvalidateCpuInstructionCaches();
}
p.insert({addr, breakpoint});
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 07f0dac67..98d07fa5b 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -78,7 +78,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32
return ERR_INVALID_STATE;
}
- Memory::Write32(address, static_cast<u32>(value + 1));
+ memory.Write32(address, static_cast<u32>(value + 1));
return SignalToAddressOnly(address, num_to_wake);
}
@@ -117,7 +117,7 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a
return ERR_INVALID_STATE;
}
- Memory::Write32(address, static_cast<u32>(updated_value));
+ memory.Write32(address, static_cast<u32>(updated_value));
WakeThreads(waiting_threads, num_to_wake);
return RESULT_SUCCESS;
}
@@ -151,7 +151,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6
}
if (should_decrement) {
- Memory::Write32(address, static_cast<u32>(cur_value - 1));
+ memory.Write32(address, static_cast<u32>(cur_value - 1));
}
// Short-circuit without rescheduling, if timeout is zero.
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 03745c449..8b01567a8 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -274,8 +274,8 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
}
// Copy the translated command buffer back into the thread's command buffer area.
- Memory::WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
- dst_cmdbuf.size() * sizeof(u32));
+ memory.WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
+ dst_cmdbuf.size() * sizeof(u32));
return RESULT_SUCCESS;
}
@@ -311,10 +311,11 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
size = buffer_size; // TODO(bunnei): This needs to be HW tested
}
+ auto& memory = Core::System::GetInstance().Memory();
if (is_buffer_b) {
- Memory::WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
+ memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
} else {
- Memory::WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
+ memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
}
return size;
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 88eede436..061e9bcb0 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -117,7 +117,7 @@ ResultCode Mutex::Release(VAddr address) {
// There are no more threads waiting for the mutex, release it completely.
if (thread == nullptr) {
- Memory::Write32(address, 0);
+ system.Memory().Write32(address, 0);
return RESULT_SUCCESS;
}
@@ -132,7 +132,7 @@ ResultCode Mutex::Release(VAddr address) {
}
// Grant the mutex to the next waiting thread and resume it.
- Memory::Write32(address, mutex_value);
+ system.Memory().Write32(address, mutex_value);
ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
thread->ResumeFromWait();
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index a6c377cfc..db3ae3eb8 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1120,7 +1120,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H
std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{});
}
- Memory::WriteBlock(thread_context, &ctx, sizeof(ctx));
+ system.Memory().WriteBlock(thread_context, &ctx, sizeof(ctx));
return RESULT_SUCCESS;
}
@@ -1280,20 +1280,21 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add
return ERR_INVALID_HANDLE;
}
+ auto& memory = system.Memory();
const auto& vm_manager = process->VMManager();
const MemoryInfo memory_info = vm_manager.QueryMemory(address);
- Memory::Write64(memory_info_address, memory_info.base_address);
- Memory::Write64(memory_info_address + 8, memory_info.size);
- Memory::Write32(memory_info_address + 16, memory_info.state);
- Memory::Write32(memory_info_address + 20, memory_info.attributes);
- Memory::Write32(memory_info_address + 24, memory_info.permission);
- Memory::Write32(memory_info_address + 32, memory_info.ipc_ref_count);
- Memory::Write32(memory_info_address + 28, memory_info.device_ref_count);
- Memory::Write32(memory_info_address + 36, 0);
+ memory.Write64(memory_info_address, memory_info.base_address);
+ memory.Write64(memory_info_address + 8, memory_info.size);
+ memory.Write32(memory_info_address + 16, memory_info.state);
+ memory.Write32(memory_info_address + 20, memory_info.attributes);
+ memory.Write32(memory_info_address + 24, memory_info.permission);
+ memory.Write32(memory_info_address + 32, memory_info.ipc_ref_count);
+ memory.Write32(memory_info_address + 28, memory_info.device_ref_count);
+ memory.Write32(memory_info_address + 36, 0);
// Page info appears to be currently unused by the kernel and is always set to zero.
- Memory::Write32(page_info_address, 0);
+ memory.Write32(page_info_address, 0);
return RESULT_SUCCESS;
}
@@ -2290,12 +2291,13 @@ static ResultCode GetProcessList(Core::System& system, u32* out_num_processes,
return ERR_INVALID_ADDRESS_STATE;
}
+ auto& memory = system.Memory();
const auto& process_list = kernel.GetProcessList();
const auto num_processes = process_list.size();
const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes);
for (std::size_t i = 0; i < copy_amount; ++i) {
- Memory::Write64(out_process_ids, process_list[i]->GetProcessID());
+ memory.Write64(out_process_ids, process_list[i]->GetProcessID());
out_process_ids += sizeof(u64);
}
@@ -2329,13 +2331,14 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd
return ERR_INVALID_ADDRESS_STATE;
}
+ auto& memory = system.Memory();
const auto& thread_list = current_process->GetThreadList();
const auto num_threads = thread_list.size();
const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads);
auto list_iter = thread_list.cbegin();
for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) {
- Memory::Write64(out_thread_ids, (*list_iter)->GetThreadID());
+ memory.Write64(out_thread_ids, (*list_iter)->GetThreadID());
out_thread_ids += sizeof(u64);
}
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 699c48107..5c940a82e 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -58,35 +58,6 @@ u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) {
u8* GetPointerFromVMA(VAddr vaddr) {
return ::Memory::GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr);
}
-
-template <typename T>
-void Write(const VAddr vaddr, const T data) {
- u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
- if (page_pointer != nullptr) {
- // NOTE: Avoid adding any extra logic to this fast-path block
- std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
- return;
- }
-
- Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
- switch (type) {
- case Common::PageType::Unmapped:
- LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
- static_cast<u32>(data), vaddr);
- return;
- case Common::PageType::Memory:
- ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
- break;
- case Common::PageType::RasterizerCachedMemory: {
- u8* const host_ptr{GetPointerFromVMA(vaddr)};
- Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T));
- std::memcpy(host_ptr, &data, sizeof(T));
- break;
- }
- default:
- UNREACHABLE();
- }
-}
} // Anonymous namespace
// Implementation class used to keep the specifics of the memory subsystem hidden
@@ -195,6 +166,22 @@ struct Memory::Impl {
return Read<u64_le>(addr);
}
+ void Write8(const VAddr addr, const u8 data) {
+ Write<u8>(addr, data);
+ }
+
+ void Write16(const VAddr addr, const u16 data) {
+ Write<u16_le>(addr, data);
+ }
+
+ void Write32(const VAddr addr, const u32 data) {
+ Write<u32_le>(addr, data);
+ }
+
+ void Write64(const VAddr addr, const u64 data) {
+ Write<u64_le>(addr, data);
+ }
+
std::string ReadCString(VAddr vaddr, std::size_t max_length) {
std::string string;
string.reserve(max_length);
@@ -259,6 +246,53 @@ struct Memory::Impl {
ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size);
}
+ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
+ const std::size_t size) {
+ const auto& page_table = process.VMManager().page_table;
+ std::size_t remaining_size = size;
+ std::size_t page_index = dest_addr >> PAGE_BITS;
+ std::size_t page_offset = dest_addr & PAGE_MASK;
+
+ while (remaining_size > 0) {
+ const std::size_t copy_amount =
+ std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
+ const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
+
+ switch (page_table.attributes[page_index]) {
+ case Common::PageType::Unmapped: {
+ LOG_ERROR(HW_Memory,
+ "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
+ current_vaddr, dest_addr, size);
+ break;
+ }
+ case Common::PageType::Memory: {
+ DEBUG_ASSERT(page_table.pointers[page_index]);
+
+ u8* const dest_ptr = page_table.pointers[page_index] + page_offset;
+ std::memcpy(dest_ptr, src_buffer, copy_amount);
+ break;
+ }
+ case Common::PageType::RasterizerCachedMemory: {
+ u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
+ system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
+ std::memcpy(host_ptr, src_buffer, copy_amount);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ page_index++;
+ page_offset = 0;
+ src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
+ remaining_size -= copy_amount;
+ }
+ }
+
+ void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
+ WriteBlock(*system.CurrentProcess(), dest_addr, src_buffer, size);
+ }
+
void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
const auto& page_table = process.VMManager().page_table;
std::size_t remaining_size = size;
@@ -501,6 +535,46 @@ struct Memory::Impl {
return {};
}
+ /**
+ * Writes a particular data type to memory at the given virtual address.
+ *
+ * @param vaddr The virtual address to write the data type to.
+ *
+ * @tparam T The data type to write to memory. This type *must* be
+ * trivially copyable, otherwise the behavior of this function
+ * is undefined.
+ *
+ * @returns The instance of T write to the specified virtual address.
+ */
+ template <typename T>
+ void Write(const VAddr vaddr, const T data) {
+ u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
+ if (page_pointer != nullptr) {
+ // NOTE: Avoid adding any extra logic to this fast-path block
+ std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
+ return;
+ }
+
+ const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
+ switch (type) {
+ case Common::PageType::Unmapped:
+ LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
+ static_cast<u32>(data), vaddr);
+ return;
+ case Common::PageType::Memory:
+ ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
+ break;
+ case Common::PageType::RasterizerCachedMemory: {
+ u8* const host_ptr{GetPointerFromVMA(vaddr)};
+ system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T));
+ std::memcpy(host_ptr, &data, sizeof(T));
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ }
+
Core::System& system;
};
@@ -562,6 +636,22 @@ u64 Memory::Read64(const VAddr addr) {
return impl->Read64(addr);
}
+void Memory::Write8(VAddr addr, u8 data) {
+ impl->Write8(addr, data);
+}
+
+void Memory::Write16(VAddr addr, u16 data) {
+ impl->Write16(addr, data);
+}
+
+void Memory::Write32(VAddr addr, u32 data) {
+ impl->Write32(addr, data);
+}
+
+void Memory::Write64(VAddr addr, u64 data) {
+ impl->Write64(addr, data);
+}
+
std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) {
return impl->ReadCString(vaddr, max_length);
}
@@ -575,6 +665,15 @@ void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_
impl->ReadBlock(src_addr, dest_buffer, size);
}
+void Memory::WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
+ std::size_t size) {
+ impl->WriteBlock(process, dest_addr, src_buffer, size);
+}
+
+void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
+ impl->WriteBlock(dest_addr, src_buffer, size);
+}
+
void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) {
impl->ZeroBlock(process, dest_addr, size);
}
@@ -612,67 +711,4 @@ bool IsKernelVirtualAddress(const VAddr vaddr) {
return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
}
-void Write8(const VAddr addr, const u8 data) {
- Write<u8>(addr, data);
-}
-
-void Write16(const VAddr addr, const u16 data) {
- Write<u16_le>(addr, data);
-}
-
-void Write32(const VAddr addr, const u32 data) {
- Write<u32_le>(addr, data);
-}
-
-void Write64(const VAddr addr, const u64 data) {
- Write<u64_le>(addr, data);
-}
-
-void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
- const std::size_t size) {
- const auto& page_table = process.VMManager().page_table;
- std::size_t remaining_size = size;
- std::size_t page_index = dest_addr >> PAGE_BITS;
- std::size_t page_offset = dest_addr & PAGE_MASK;
-
- while (remaining_size > 0) {
- const std::size_t copy_amount =
- std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
- const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
-
- switch (page_table.attributes[page_index]) {
- case Common::PageType::Unmapped: {
- LOG_ERROR(HW_Memory,
- "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
- current_vaddr, dest_addr, size);
- break;
- }
- case Common::PageType::Memory: {
- DEBUG_ASSERT(page_table.pointers[page_index]);
-
- u8* dest_ptr = page_table.pointers[page_index] + page_offset;
- std::memcpy(dest_ptr, src_buffer, copy_amount);
- break;
- }
- case Common::PageType::RasterizerCachedMemory: {
- const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)};
- Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
- std::memcpy(host_ptr, src_buffer, copy_amount);
- break;
- }
- default:
- UNREACHABLE();
- }
-
- page_index++;
- page_offset = 0;
- src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
- remaining_size -= copy_amount;
- }
-}
-
-void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
- WriteBlock(*Core::System::GetInstance().CurrentProcess(), dest_addr, src_buffer, size);
-}
-
} // namespace Memory
diff --git a/src/core/memory.h b/src/core/memory.h
index cc6ab920e..7878f3fb1 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -193,6 +193,50 @@ public:
u64 Read64(VAddr addr);
/**
+ * Writes an 8-bit unsigned integer to the given virtual address in
+ * the current process' address space.
+ *
+ * @param addr The virtual address to write the 8-bit unsigned integer to.
+ * @param data The 8-bit unsigned integer to write to the given virtual address.
+ *
+ * @post The memory at the given virtual address contains the specified data value.
+ */
+ void Write8(VAddr addr, u8 data);
+
+ /**
+ * Writes a 16-bit unsigned integer to the given virtual address in
+ * the current process' address space.
+ *
+ * @param addr The virtual address to write the 16-bit unsigned integer to.
+ * @param data The 16-bit unsigned integer to write to the given virtual address.
+ *
+ * @post The memory range [addr, sizeof(data)) contains the given data value.
+ */
+ void Write16(VAddr addr, u16 data);
+
+ /**
+ * Writes a 32-bit unsigned integer to the given virtual address in
+ * the current process' address space.
+ *
+ * @param addr The virtual address to write the 32-bit unsigned integer to.
+ * @param data The 32-bit unsigned integer to write to the given virtual address.
+ *
+ * @post The memory range [addr, sizeof(data)) contains the given data value.
+ */
+ void Write32(VAddr addr, u32 data);
+
+ /**
+ * Writes a 64-bit unsigned integer to the given virtual address in
+ * the current process' address space.
+ *
+ * @param addr The virtual address to write the 64-bit unsigned integer to.
+ * @param data The 64-bit unsigned integer to write to the given virtual address.
+ *
+ * @post The memory range [addr, sizeof(data)) contains the given data value.
+ */
+ void Write64(VAddr addr, u64 data);
+
+ /**
* Reads a null-terminated string from the given virtual address.
* This function will continually read characters until either:
*
@@ -248,6 +292,50 @@ public:
void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size);
/**
+ * Writes a range of bytes into a given process' address space at the specified
+ * virtual address.
+ *
+ * @param process The process to write data into the address space of.
+ * @param dest_addr The destination virtual address to begin writing the data at.
+ * @param src_buffer The data to write into the process' address space.
+ * @param size The size of the data to write, in bytes.
+ *
+ * @post The address range [dest_addr, size) in the process' address space
+ * contains the data that was within src_buffer.
+ *
+ * @post If an attempt is made to write into an unmapped region of memory, the writes
+ * will be ignored and an error will be logged.
+ *
+ * @post If a write is performed into a region of memory that is considered cached
+ * rasterizer memory, will cause the currently active rasterizer to be notified
+ * and will mark that region as invalidated to caches that the active
+ * graphics backend may be maintaining over the course of execution.
+ */
+ void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
+ std::size_t size);
+
+ /**
+ * Writes a range of bytes into the current process' address space at the specified
+ * virtual address.
+ *
+ * @param dest_addr The destination virtual address to begin writing the data at.
+ * @param src_buffer The data to write into the current process' address space.
+ * @param size The size of the data to write, in bytes.
+ *
+ * @post The address range [dest_addr, size) in the current process' address space
+ * contains the data that was within src_buffer.
+ *
+ * @post If an attempt is made to write into an unmapped region of memory, the writes
+ * will be ignored and an error will be logged.
+ *
+ * @post If a write is performed into a region of memory that is considered cached
+ * rasterizer memory, will cause the currently active rasterizer to be notified
+ * and will mark that region as invalidated to caches that the active
+ * graphics backend may be maintaining over the course of execution.
+ */
+ void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
+
+ /**
* Fills the specified address range within a process' address space with zeroes.
*
* @param process The process that will have a portion of its memory zeroed out.
@@ -320,13 +408,4 @@ void SetCurrentPageTable(Kernel::Process& process);
/// Determines if the given VAddr is a kernel address
bool IsKernelVirtualAddress(VAddr vaddr);
-void Write8(VAddr addr, u8 data);
-void Write16(VAddr addr, u16 data);
-void Write32(VAddr addr, u32 data);
-void Write64(VAddr addr, u64 data);
-
-void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
- std::size_t size);
-void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
-
} // namespace Memory
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index d6745af8b..d1e6bed93 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -30,7 +30,7 @@ void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) {
}
void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) {
- WriteBlock(SanitizeAddress(address), data, size);
+ system.Memory().WriteBlock(SanitizeAddress(address), data, size);
}
u64 StandardVmCallbacks::HidKeysDown() {
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index ab66f35f9..55e0dbc49 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -34,16 +34,16 @@ u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) {
void MemoryWriteWidth(Memory::Memory& memory, u32 width, VAddr addr, u64 value) {
switch (width) {
case 1:
- Memory::Write8(addr, static_cast<u8>(value));
+ memory.Write8(addr, static_cast<u8>(value));
break;
case 2:
- Memory::Write16(addr, static_cast<u16>(value));
+ memory.Write16(addr, static_cast<u16>(value));
break;
case 4:
- Memory::Write32(addr, static_cast<u32>(value));
+ memory.Write32(addr, static_cast<u32>(value));
break;
case 8:
- Memory::Write64(addr, value);
+ memory.Write64(addr, value);
break;
default:
UNREACHABLE();