diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 2348cdbef..c85991dc8 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -409,8 +409,9 @@ static void RemoveBreakpoint(BreakpointType type, VAddr addr) {
 
     LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:08x} bytes at {:08x} of type {}",
               bp->second.len, bp->second.addr, static_cast<int>(type));
-    Memory::WriteBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), bp->second.addr,
-                       bp->second.inst.data(), bp->second.inst.size());
+    Core::System::GetInstance().Memory().WriteBlock(
+        *Core::System::GetInstance().Kernel().GetCurrentProcess(), bp->second.addr,
+        bp->second.inst.data(), bp->second.inst.size());
     Core::CPU().ClearInstructionCache();
     p.erase(addr);
 }
@@ -837,8 +838,8 @@ static void ReadMemory() {
     }
 
     std::vector<u8> data(len);
-    Memory::ReadBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, data.data(),
-                      len);
+    Core::System::GetInstance().Memory().ReadBlock(
+        *Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, data.data(), len);
 
     MemToGdbHex(reply, data.data(), len);
     reply[len * 2] = '\0';
@@ -863,8 +864,8 @@ static void WriteMemory() {
     std::vector<u8> data(len);
 
     GdbHexToMem(data.data(), len_pos + 1, len);
-    Memory::WriteBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, data.data(),
-                       len);
+    Core::System::GetInstance().Memory().WriteBlock(
+        *Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, data.data(), len);
     Core::CPU().ClearInstructionCache();
     SendReply("OK");
 }
@@ -917,11 +918,13 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u32 len) {
     breakpoint.active = true;
     breakpoint.addr = addr;
     breakpoint.len = len;
-    Memory::ReadBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), addr,
-                      breakpoint.inst.data(), breakpoint.inst.size());
+    Core::System::GetInstance().Memory().ReadBlock(
+        *Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, breakpoint.inst.data(),
+        breakpoint.inst.size());
     static constexpr std::array<u8, 4> btrap{0x70, 0x00, 0x20, 0xe1};
-    Memory::WriteBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), addr,
-                       btrap.data(), btrap.size());
+    Core::System::GetInstance().Memory().WriteBlock(
+        *Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, btrap.data(),
+        btrap.size());
     Core::CPU().ClearInstructionCache();
     p.insert({addr, breakpoint});
 
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index a72d33dd9..746da245e 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -48,12 +48,13 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
         // the translation might need to read from it in order to retrieve the StaticBuffer
         // target addresses.
         std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buff;
-        Memory::ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
-                          cmd_buff.size() * sizeof(u32));
+        Memory::MemorySystem& memory = Core::System::GetInstance().Memory();
+        memory.ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
+                         cmd_buff.size() * sizeof(u32));
         context.WriteToOutgoingCommandBuffer(cmd_buff.data(), *process);
         // Copy the translated command buffer back into the thread's command buffer area.
-        Memory::WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
-                           cmd_buff.size() * sizeof(u32));
+        memory.WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
+                          cmd_buff.size() * sizeof(u32));
     };
 
     auto event = Core::System::GetInstance().Kernel().CreateEvent(Kernel::ResetType::OneShot,
@@ -142,7 +143,8 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr
 
             // Copy the input buffer into our own vector and store it.
             std::vector<u8> data(buffer_info.size);
-            Memory::ReadBlock(src_process, source_address, data.data(), data.size());
+            Core::System::GetInstance().Memory().ReadBlock(src_process, source_address, data.data(),
+                                                           data.size());
 
             AddStaticBuffer(buffer_info.buffer_id, std::move(data));
             cmd_buf[i++] = source_address;
@@ -209,7 +211,8 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf,
 
             ASSERT_MSG(target_descriptor.size >= data.size(), "Static buffer data is too big");
 
-            Memory::WriteBlock(dst_process, target_address, data.data(), data.size());
+            Core::System::GetInstance().Memory().WriteBlock(dst_process, target_address,
+                                                            data.data(), data.size());
 
             dst_cmdbuf[i++] = target_address;
             break;
@@ -242,13 +245,15 @@ MappedBuffer::MappedBuffer(const Process& process, u32 descriptor, VAddr address
 void MappedBuffer::Read(void* dest_buffer, std::size_t offset, std::size_t size) {
     ASSERT(perms & IPC::R);
     ASSERT(offset + size <= this->size);
-    Memory::ReadBlock(*process, address + static_cast<VAddr>(offset), dest_buffer, size);
+    Core::System::GetInstance().Memory().ReadBlock(*process, address + static_cast<VAddr>(offset),
+                                                   dest_buffer, size);
 }
 
 void MappedBuffer::Write(const void* src_buffer, std::size_t offset, std::size_t size) {
     ASSERT(perms & IPC::W);
     ASSERT(offset + size <= this->size);
-    Memory::WriteBlock(*process, address + static_cast<VAddr>(offset), src_buffer, size);
+    Core::System::GetInstance().Memory().WriteBlock(*process, address + static_cast<VAddr>(offset),
+                                                    src_buffer, size);
 }
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/ipc.cpp b/src/core/hle/kernel/ipc.cpp
index 7a59f0301..7eb16ba9e 100644
--- a/src/core/hle/kernel/ipc.cpp
+++ b/src/core/hle/kernel/ipc.cpp
@@ -4,6 +4,7 @@
 
 #include <algorithm>
 #include "common/alignment.h"
+#include "core/core.h"
 #include "core/hle/ipc.h"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/ipc.h"
@@ -19,13 +20,13 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
                                   VAddr src_address, VAddr dst_address,
                                   std::vector<MappedBufferContext>& mapped_buffer_context,
                                   bool reply) {
-
+    Memory::MemorySystem& memory = Core::System::GetInstance().Memory();
     auto& src_process = src_thread->owner_process;
     auto& dst_process = dst_thread->owner_process;
 
     IPC::Header header;
     // TODO(Subv): Replace by Memory::Read32 when possible.
-    Memory::ReadBlock(*src_process, src_address, &header.raw, sizeof(header.raw));
+    memory.ReadBlock(*src_process, src_address, &header.raw, sizeof(header.raw));
 
     std::size_t untranslated_size = 1u + header.normal_params_size;
     std::size_t command_size = untranslated_size + header.translate_params_size;
@@ -34,7 +35,7 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
     ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH);
 
     std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
-    Memory::ReadBlock(*src_process, src_address, cmd_buf.data(), command_size * sizeof(u32));
+    memory.ReadBlock(*src_process, src_address, cmd_buf.data(), command_size * sizeof(u32));
 
     std::size_t i = untranslated_size;
     while (i < command_size) {
@@ -90,7 +91,7 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
             VAddr static_buffer_src_address = cmd_buf[i];
 
             std::vector<u8> data(bufferInfo.size);
-            Memory::ReadBlock(*src_process, static_buffer_src_address, data.data(), data.size());
+            memory.ReadBlock(*src_process, static_buffer_src_address, data.data(), data.size());
 
             // Grab the address that the target thread set up to receive the response static buffer
             // and write our data there. The static buffers area is located right after the command
@@ -106,15 +107,15 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
 
             u32 static_buffer_offset = IPC::COMMAND_BUFFER_LENGTH * sizeof(u32) +
                                        sizeof(StaticBuffer) * bufferInfo.buffer_id;
-            Memory::ReadBlock(*dst_process, dst_address + static_buffer_offset, &target_buffer,
-                              sizeof(target_buffer));
+            memory.ReadBlock(*dst_process, dst_address + static_buffer_offset, &target_buffer,
+                             sizeof(target_buffer));
 
             // Note: The real kernel doesn't seem to have any error recovery mechanisms for this
             // case.
             ASSERT_MSG(target_buffer.descriptor.size >= data.size(),
                        "Static buffer data is too big");
 
-            Memory::WriteBlock(*dst_process, target_buffer.address, data.data(), data.size());
+            memory.WriteBlock(*dst_process, target_buffer.address, data.data(), data.size());
 
             cmd_buf[i++] = target_buffer.address;
             break;
@@ -153,8 +154,8 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
 
                 if (permissions != IPC::MappedBufferPermissions::R) {
                     // Copy the modified buffer back into the target process
-                    Memory::CopyBlock(*src_process, *dst_process, found->target_address,
-                                      found->source_address, size);
+                    memory.CopyBlock(*src_process, *dst_process, found->target_address,
+                                     found->source_address, size);
                 }
 
                 VAddr prev_reserve = page_start - Memory::PAGE_SIZE;
@@ -187,7 +188,7 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
                 Memory::PAGE_SIZE, Kernel::MemoryState::Reserved);
 
             auto buffer = std::make_unique<u8[]>(num_pages * Memory::PAGE_SIZE);
-            Memory::ReadBlock(*src_process, source_address, buffer.get() + page_offset, size);
+            memory.ReadBlock(*src_process, source_address, buffer.get() + page_offset, size);
 
             // Map the page(s) into the target process' address space.
             target_address =
@@ -215,7 +216,7 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
         }
     }
 
-    Memory::WriteBlock(*dst_process, dst_address, cmd_buf.data(), command_size * sizeof(u32));
+    memory.WriteBlock(*dst_process, dst_address, cmd_buf.data(), command_size * sizeof(u32));
 
     return RESULT_SUCCESS;
 }
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 7887832c3..78e9c030d 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -120,8 +120,8 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) {
     auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
                           MemoryState memory_state) {
         HeapAllocate(segment.addr, segment.size, permissions, memory_state, true);
-        Memory::WriteBlock(*this, segment.addr, codeset->memory->data() + segment.offset,
-                           segment.size);
+        kernel.memory.WriteBlock(*this, segment.addr, codeset->memory->data() + segment.offset,
+                                 segment.size);
     };
 
     // Map CodeSet segments
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 1e414c397..fd00ae623 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -802,7 +802,7 @@ void SVC::OutputDebugString(VAddr address, s32 len) {
     }
 
     std::string string(len, ' ');
-    Memory::ReadBlock(*kernel.GetCurrentProcess(), address, string.data(), len);
+    memory.ReadBlock(*kernel.GetCurrentProcess(), address, string.data(), len);
     LOG_DEBUG(Debug_Emulated, "{}", string);
 }
 
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 597678215..5b26b8214 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -364,7 +364,7 @@ ResultVal<SharedPtr<Thread>> KernelSystem::CreateThread(std::string name, VAddr
     thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
                           available_slot * Memory::TLS_ENTRY_SIZE;
 
-    Memory::ZeroBlock(owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE);
+    memory.ZeroBlock(owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE);
 
     // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
     // to initialize the context
diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp
index 78d2e268e..bf1bab8c0 100644
--- a/src/core/hle/service/cam/cam.cpp
+++ b/src/core/hle/service/cam/cam.cpp
@@ -113,7 +113,7 @@ void Module::CompletionEventCallBack(u64 port_id, s64) {
             if (copy_length <= 0) {
                 break;
             }
-            Memory::WriteBlock(*port.dest_process, dest_ptr, src_ptr, copy_length);
+            system.Memory().WriteBlock(*port.dest_process, dest_ptr, src_ptr, copy_length);
             dest_ptr += copy_length;
             dest_size_left -= copy_length;
             src_ptr += original_width;
@@ -125,8 +125,8 @@ void Module::CompletionEventCallBack(u64 port_id, s64) {
             LOG_ERROR(Service_CAM, "The destination size ({}) doesn't match the source ({})!",
                       port.dest_size, buffer_size);
         }
-        Memory::WriteBlock(*port.dest_process, port.dest, buffer.data(),
-                           std::min<std::size_t>(port.dest_size, buffer_size));
+        system.Memory().WriteBlock(*port.dest_process, port.dest, buffer.data(),
+                                   std::min<std::size_t>(port.dest_size, buffer_size));
     }
 
     port.is_receiving = false;
diff --git a/src/core/hle/service/gsp/gsp_gpu.cpp b/src/core/hle/service/gsp/gsp_gpu.cpp
index 9445aa3c3..50bb30bb9 100644
--- a/src/core/hle/service/gsp/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp/gsp_gpu.cpp
@@ -491,6 +491,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
     // GX request DMA - typically used for copying memory from GSP heap to VRAM
     case CommandId::REQUEST_DMA: {
         MICROPROFILE_SCOPE(GPU_GSP_DMA);
+        Memory::MemorySystem& memory = Core::System::GetInstance().Memory();
 
         // TODO: Consider attempting rasterizer-accelerated surface blit if that usage is ever
         // possible/likely
@@ -502,9 +503,9 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
 
         // TODO(Subv): These memory accesses should not go through the application's memory mapping.
         // They should go through the GSP module's memory mapping.
-        Memory::CopyBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(),
-                          command.dma_request.dest_address, command.dma_request.source_address,
-                          command.dma_request.size);
+        memory.CopyBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(),
+                         command.dma_request.dest_address, command.dma_request.source_address,
+                         command.dma_request.size);
         SignalInterrupt(InterruptId::DMA);
         break;
     }
diff --git a/src/core/hle/service/ldr_ro/cro_helper.cpp b/src/core/hle/service/ldr_ro/cro_helper.cpp
index 3d4a97d9f..5981a3b66 100644
--- a/src/core/hle/service/ldr_ro/cro_helper.cpp
+++ b/src/core/hle/service/ldr_ro/cro_helper.cpp
@@ -55,7 +55,7 @@ VAddr CROHelper::SegmentTagToAddress(SegmentTag segment_tag) const {
         return 0;
 
     SegmentEntry entry;
-    GetEntry(segment_tag.segment_index, entry);
+    GetEntry(memory, segment_tag.segment_index, entry);
 
     if (segment_tag.offset_into_segment >= entry.size)
         return 0;
@@ -121,7 +121,7 @@ ResultCode CROHelper::ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool
     VAddr relocation_address = batch;
     while (true) {
         RelocationEntry relocation;
-        Memory::ReadBlock(process, relocation_address, &relocation, sizeof(RelocationEntry));
+        memory.ReadBlock(process, relocation_address, &relocation, sizeof(RelocationEntry));
 
         VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
         if (relocation_target == 0) {
@@ -142,9 +142,9 @@ ResultCode CROHelper::ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool
     }
 
     RelocationEntry relocation;
-    Memory::ReadBlock(process, batch, &relocation, sizeof(RelocationEntry));
+    memory.ReadBlock(process, batch, &relocation, sizeof(RelocationEntry));
     relocation.is_batch_resolved = reset ? 0 : 1;
-    Memory::WriteBlock(process, batch, &relocation, sizeof(RelocationEntry));
+    memory.WriteBlock(process, batch, &relocation, sizeof(RelocationEntry));
     return RESULT_SUCCESS;
 }
 
@@ -154,13 +154,13 @@ VAddr CROHelper::FindExportNamedSymbol(const std::string& name) const {
 
     std::size_t len = name.size();
     ExportTreeEntry entry;
-    GetEntry(0, entry);
+    GetEntry(memory, 0, entry);
     ExportTreeEntry::Child next;
     next.raw = entry.left.raw;
     u32 found_id;
 
     while (true) {
-        GetEntry(next.next_index, entry);
+        GetEntry(memory, next.next_index, entry);
 
         if (next.is_end) {
             found_id = entry.export_table_index;
@@ -186,7 +186,7 @@ VAddr CROHelper::FindExportNamedSymbol(const std::string& name) const {
 
     u32 export_strings_size = GetField(ExportStringsSize);
     ExportNamedSymbolEntry symbol_entry;
-    GetEntry(found_id, symbol_entry);
+    GetEntry(memory, found_id, symbol_entry);
 
     if (memory.ReadCString(symbol_entry.name_offset, export_strings_size) != name)
         return 0;
@@ -279,7 +279,7 @@ ResultVal<VAddr> CROHelper::RebaseSegmentTable(u32 cro_size, VAddr data_segment_
     u32 segment_num = GetField(SegmentNum);
     for (u32 i = 0; i < segment_num; ++i) {
         SegmentEntry segment;
-        GetEntry(i, segment);
+        GetEntry(memory, i, segment);
         if (segment.type == SegmentType::Data) {
             if (segment.size != 0) {
                 if (segment.size > data_segment_size)
@@ -298,7 +298,7 @@ ResultVal<VAddr> CROHelper::RebaseSegmentTable(u32 cro_size, VAddr data_segment_
             if (segment.offset > module_address + cro_size)
                 return CROFormatError(0x19);
         }
-        SetEntry(i, segment);
+        SetEntry(memory, i, segment);
     }
     return MakeResult<u32>(prev_data_segment + module_address);
 }
@@ -310,7 +310,7 @@ ResultCode CROHelper::RebaseExportNamedSymbolTable() {
     u32 export_named_symbol_num = GetField(ExportNamedSymbolNum);
     for (u32 i = 0; i < export_named_symbol_num; ++i) {
         ExportNamedSymbolEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
 
         if (entry.name_offset != 0) {
             entry.name_offset += module_address;
@@ -320,7 +320,7 @@ ResultCode CROHelper::RebaseExportNamedSymbolTable() {
             }
         }
 
-        SetEntry(i, entry);
+        SetEntry(memory, i, entry);
     }
     return RESULT_SUCCESS;
 }
@@ -329,7 +329,7 @@ ResultCode CROHelper::VerifyExportTreeTable() const {
     u32 tree_num = GetField(ExportTreeNum);
     for (u32 i = 0; i < tree_num; ++i) {
         ExportTreeEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
 
         if (entry.left.next_index >= tree_num || entry.right.next_index >= tree_num) {
             return CROFormatError(0x11);
@@ -353,7 +353,7 @@ ResultCode CROHelper::RebaseImportModuleTable() {
     u32 module_num = GetField(ImportModuleNum);
     for (u32 i = 0; i < module_num; ++i) {
         ImportModuleEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
 
         if (entry.name_offset != 0) {
             entry.name_offset += module_address;
@@ -379,7 +379,7 @@ ResultCode CROHelper::RebaseImportModuleTable() {
             }
         }
 
-        SetEntry(i, entry);
+        SetEntry(memory, i, entry);
     }
     return RESULT_SUCCESS;
 }
@@ -395,7 +395,7 @@ ResultCode CROHelper::RebaseImportNamedSymbolTable() {
     u32 num = GetField(ImportNamedSymbolNum);
     for (u32 i = 0; i < num; ++i) {
         ImportNamedSymbolEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
 
         if (entry.name_offset != 0) {
             entry.name_offset += module_address;
@@ -413,7 +413,7 @@ ResultCode CROHelper::RebaseImportNamedSymbolTable() {
             }
         }
 
-        SetEntry(i, entry);
+        SetEntry(memory, i, entry);
     }
     return RESULT_SUCCESS;
 }
@@ -427,7 +427,7 @@ ResultCode CROHelper::RebaseImportIndexedSymbolTable() {
     u32 num = GetField(ImportIndexedSymbolNum);
     for (u32 i = 0; i < num; ++i) {
         ImportIndexedSymbolEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
 
         if (entry.relocation_batch_offset != 0) {
             entry.relocation_batch_offset += module_address;
@@ -437,7 +437,7 @@ ResultCode CROHelper::RebaseImportIndexedSymbolTable() {
             }
         }
 
-        SetEntry(i, entry);
+        SetEntry(memory, i, entry);
     }
     return RESULT_SUCCESS;
 }
@@ -451,7 +451,7 @@ ResultCode CROHelper::RebaseImportAnonymousSymbolTable() {
     u32 num = GetField(ImportAnonymousSymbolNum);
     for (u32 i = 0; i < num; ++i) {
         ImportAnonymousSymbolEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
 
         if (entry.relocation_batch_offset != 0) {
             entry.relocation_batch_offset += module_address;
@@ -461,7 +461,7 @@ ResultCode CROHelper::RebaseImportAnonymousSymbolTable() {
             }
         }
 
-        SetEntry(i, entry);
+        SetEntry(memory, i, entry);
     }
     return RESULT_SUCCESS;
 }
@@ -476,14 +476,14 @@ ResultCode CROHelper::ResetExternalRelocations() {
     ExternalRelocationEntry relocation;
 
     // Verifies that the last relocation is the end of a batch
-    GetEntry(external_relocation_num - 1, relocation);
+    GetEntry(memory, external_relocation_num - 1, relocation);
     if (!relocation.is_batch_end) {
         return CROFormatError(0x12);
     }
 
     bool batch_begin = true;
     for (u32 i = 0; i < external_relocation_num; ++i) {
-        GetEntry(i, relocation);
+        GetEntry(memory, i, relocation);
         VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
 
         if (relocation_target == 0) {
@@ -500,7 +500,7 @@ ResultCode CROHelper::ResetExternalRelocations() {
         if (batch_begin) {
             // resets to unresolved state
             relocation.is_batch_resolved = 0;
-            SetEntry(i, relocation);
+            SetEntry(memory, i, relocation);
         }
 
         // if current is an end, then the next is a beginning
@@ -516,7 +516,7 @@ ResultCode CROHelper::ClearExternalRelocations() {
 
     bool batch_begin = true;
     for (u32 i = 0; i < external_relocation_num; ++i) {
-        GetEntry(i, relocation);
+        GetEntry(memory, i, relocation);
         VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
 
         if (relocation_target == 0) {
@@ -532,7 +532,7 @@ ResultCode CROHelper::ClearExternalRelocations() {
         if (batch_begin) {
             // resets to unresolved state
             relocation.is_batch_resolved = 0;
-            SetEntry(i, relocation);
+            SetEntry(memory, i, relocation);
         }
 
         // if current is an end, then the next is a beginning
@@ -554,7 +554,7 @@ ResultCode CROHelper::ApplyStaticAnonymousSymbolToCRS(VAddr crs_address) {
              offset_export_num);
     for (u32 i = 0; i < offset_export_num; ++i) {
         StaticAnonymousSymbolEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
         u32 batch_address = entry.relocation_batch_offset + module_address;
 
         if (batch_address < static_relocation_table_offset ||
@@ -579,7 +579,7 @@ ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) {
     u32 internal_relocation_num = GetField(InternalRelocationNum);
     for (u32 i = 0; i < internal_relocation_num; ++i) {
         InternalRelocationEntry relocation;
-        GetEntry(i, relocation);
+        GetEntry(memory, i, relocation);
         VAddr target_addressB = SegmentTagToAddress(relocation.target_position);
         if (target_addressB == 0) {
             return CROFormatError(0x15);
@@ -587,7 +587,7 @@ ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) {
 
         VAddr target_address;
         SegmentEntry target_segment;
-        GetEntry(relocation.target_position.segment_index, target_segment);
+        GetEntry(memory, relocation.target_position.segment_index, target_segment);
 
         if (target_segment.type == SegmentType::Data) {
             // If the relocation is to the .data segment, we need to relocate it in the old buffer
@@ -602,7 +602,7 @@ ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) {
         }
 
         SegmentEntry symbol_segment;
-        GetEntry(relocation.symbol_segment, symbol_segment);
+        GetEntry(memory, relocation.symbol_segment, symbol_segment);
         LOG_TRACE(Service_LDR, "Internally relocates 0x{:08X} with 0x{:08X}", target_address,
                   symbol_segment.offset);
         ResultCode result = ApplyRelocation(target_address, relocation.type, relocation.addend,
@@ -619,7 +619,7 @@ ResultCode CROHelper::ClearInternalRelocations() {
     u32 internal_relocation_num = GetField(InternalRelocationNum);
     for (u32 i = 0; i < internal_relocation_num; ++i) {
         InternalRelocationEntry relocation;
-        GetEntry(i, relocation);
+        GetEntry(memory, i, relocation);
         VAddr target_address = SegmentTagToAddress(relocation.target_position);
 
         if (target_address == 0) {
@@ -639,13 +639,13 @@ void CROHelper::UnrebaseImportAnonymousSymbolTable() {
     u32 num = GetField(ImportAnonymousSymbolNum);
     for (u32 i = 0; i < num; ++i) {
         ImportAnonymousSymbolEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
 
         if (entry.relocation_batch_offset != 0) {
             entry.relocation_batch_offset -= module_address;
         }
 
-        SetEntry(i, entry);
+        SetEntry(memory, i, entry);
     }
 }
 
@@ -653,13 +653,13 @@ void CROHelper::UnrebaseImportIndexedSymbolTable() {
     u32 num = GetField(ImportIndexedSymbolNum);
     for (u32 i = 0; i < num; ++i) {
         ImportIndexedSymbolEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
 
         if (entry.relocation_batch_offset != 0) {
             entry.relocation_batch_offset -= module_address;
         }
 
-        SetEntry(i, entry);
+        SetEntry(memory, i, entry);
     }
 }
 
@@ -667,7 +667,7 @@ void CROHelper::UnrebaseImportNamedSymbolTable() {
     u32 num = GetField(ImportNamedSymbolNum);
     for (u32 i = 0; i < num; ++i) {
         ImportNamedSymbolEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
 
         if (entry.name_offset != 0) {
             entry.name_offset -= module_address;
@@ -677,7 +677,7 @@ void CROHelper::UnrebaseImportNamedSymbolTable() {
             entry.relocation_batch_offset -= module_address;
         }
 
-        SetEntry(i, entry);
+        SetEntry(memory, i, entry);
     }
 }
 
@@ -685,7 +685,7 @@ void CROHelper::UnrebaseImportModuleTable() {
     u32 module_num = GetField(ImportModuleNum);
     for (u32 i = 0; i < module_num; ++i) {
         ImportModuleEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
 
         if (entry.name_offset != 0) {
             entry.name_offset -= module_address;
@@ -699,7 +699,7 @@ void CROHelper::UnrebaseImportModuleTable() {
             entry.import_anonymous_symbol_table_offset -= module_address;
         }
 
-        SetEntry(i, entry);
+        SetEntry(memory, i, entry);
     }
 }
 
@@ -707,13 +707,13 @@ void CROHelper::UnrebaseExportNamedSymbolTable() {
     u32 export_named_symbol_num = GetField(ExportNamedSymbolNum);
     for (u32 i = 0; i < export_named_symbol_num; ++i) {
         ExportNamedSymbolEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
 
         if (entry.name_offset != 0) {
             entry.name_offset -= module_address;
         }
 
-        SetEntry(i, entry);
+        SetEntry(memory, i, entry);
     }
 }
 
@@ -721,7 +721,7 @@ void CROHelper::UnrebaseSegmentTable() {
     u32 segment_num = GetField(SegmentNum);
     for (u32 i = 0; i < segment_num; ++i) {
         SegmentEntry segment;
-        GetEntry(i, segment);
+        GetEntry(memory, i, segment);
 
         if (segment.type == SegmentType::BSS) {
             segment.offset = 0;
@@ -729,7 +729,7 @@ void CROHelper::UnrebaseSegmentTable() {
             segment.offset -= module_address;
         }
 
-        SetEntry(i, segment);
+        SetEntry(memory, i, segment);
     }
 }
 
@@ -751,11 +751,11 @@ ResultCode CROHelper::ApplyImportNamedSymbol(VAddr crs_address) {
     u32 symbol_import_num = GetField(ImportNamedSymbolNum);
     for (u32 i = 0; i < symbol_import_num; ++i) {
         ImportNamedSymbolEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
         VAddr relocation_addr = entry.relocation_batch_offset;
         ExternalRelocationEntry relocation_entry;
-        Memory::ReadBlock(process, relocation_addr, &relocation_entry,
-                          sizeof(ExternalRelocationEntry));
+        memory.ReadBlock(process, relocation_addr, &relocation_entry,
+                         sizeof(ExternalRelocationEntry));
 
         if (!relocation_entry.is_batch_resolved) {
             ResultCode result = ForEachAutoLinkCRO(
@@ -794,11 +794,11 @@ ResultCode CROHelper::ResetImportNamedSymbol() {
     u32 symbol_import_num = GetField(ImportNamedSymbolNum);
     for (u32 i = 0; i < symbol_import_num; ++i) {
         ImportNamedSymbolEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
         VAddr relocation_addr = entry.relocation_batch_offset;
         ExternalRelocationEntry relocation_entry;
-        Memory::ReadBlock(process, relocation_addr, &relocation_entry,
-                          sizeof(ExternalRelocationEntry));
+        memory.ReadBlock(process, relocation_addr, &relocation_entry,
+                         sizeof(ExternalRelocationEntry));
 
         ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
         if (result.IsError()) {
@@ -815,11 +815,11 @@ ResultCode CROHelper::ResetImportIndexedSymbol() {
     u32 import_num = GetField(ImportIndexedSymbolNum);
     for (u32 i = 0; i < import_num; ++i) {
         ImportIndexedSymbolEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
         VAddr relocation_addr = entry.relocation_batch_offset;
         ExternalRelocationEntry relocation_entry;
-        Memory::ReadBlock(process, relocation_addr, &relocation_entry,
-                          sizeof(ExternalRelocationEntry));
+        memory.ReadBlock(process, relocation_addr, &relocation_entry,
+                         sizeof(ExternalRelocationEntry));
 
         ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
         if (result.IsError()) {
@@ -836,11 +836,11 @@ ResultCode CROHelper::ResetImportAnonymousSymbol() {
     u32 import_num = GetField(ImportAnonymousSymbolNum);
     for (u32 i = 0; i < import_num; ++i) {
         ImportAnonymousSymbolEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
         VAddr relocation_addr = entry.relocation_batch_offset;
         ExternalRelocationEntry relocation_entry;
-        Memory::ReadBlock(process, relocation_addr, &relocation_entry,
-                          sizeof(ExternalRelocationEntry));
+        memory.ReadBlock(process, relocation_addr, &relocation_entry,
+                         sizeof(ExternalRelocationEntry));
 
         ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
         if (result.IsError()) {
@@ -857,7 +857,7 @@ ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) {
     u32 import_module_num = GetField(ImportModuleNum);
     for (u32 i = 0; i < import_module_num; ++i) {
         ImportModuleEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
         std::string want_cro_name = memory.ReadCString(entry.name_offset, import_strings_size);
 
         ResultCode result = ForEachAutoLinkCRO(
@@ -867,9 +867,9 @@ ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) {
                              ModuleName(), entry.import_indexed_symbol_num, source.ModuleName());
                     for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
                         ImportIndexedSymbolEntry im;
-                        entry.GetImportIndexedSymbolEntry(process, j, im);
+                        entry.GetImportIndexedSymbolEntry(process, memory, j, im);
                         ExportIndexedSymbolEntry ex;
-                        source.GetEntry(im.index, ex);
+                        source.GetEntry(memory, im.index, ex);
                         u32 symbol_address = source.SegmentTagToAddress(ex.symbol_position);
                         LOG_TRACE(Service_LDR, "    Imports 0x{:08X}", symbol_address);
                         ResultCode result =
@@ -884,7 +884,7 @@ ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) {
                              ModuleName(), entry.import_anonymous_symbol_num, source.ModuleName());
                     for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
                         ImportAnonymousSymbolEntry im;
-                        entry.GetImportAnonymousSymbolEntry(process, j, im);
+                        entry.GetImportAnonymousSymbolEntry(process, memory, j, im);
                         u32 symbol_address = source.SegmentTagToAddress(im.symbol_position);
                         LOG_TRACE(Service_LDR, "    Imports 0x{:08X}", symbol_address);
                         ResultCode result =
@@ -913,11 +913,11 @@ ResultCode CROHelper::ApplyExportNamedSymbol(CROHelper target) {
     u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum);
     for (u32 i = 0; i < target_symbol_import_num; ++i) {
         ImportNamedSymbolEntry entry;
-        target.GetEntry(i, entry);
+        target.GetEntry(memory, i, entry);
         VAddr relocation_addr = entry.relocation_batch_offset;
         ExternalRelocationEntry relocation_entry;
-        Memory::ReadBlock(process, relocation_addr, &relocation_entry,
-                          sizeof(ExternalRelocationEntry));
+        memory.ReadBlock(process, relocation_addr, &relocation_entry,
+                         sizeof(ExternalRelocationEntry));
 
         if (!relocation_entry.is_batch_resolved) {
             std::string symbol_name =
@@ -944,11 +944,11 @@ ResultCode CROHelper::ResetExportNamedSymbol(CROHelper target) {
     u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum);
     for (u32 i = 0; i < target_symbol_import_num; ++i) {
         ImportNamedSymbolEntry entry;
-        target.GetEntry(i, entry);
+        target.GetEntry(memory, i, entry);
         VAddr relocation_addr = entry.relocation_batch_offset;
         ExternalRelocationEntry relocation_entry;
-        Memory::ReadBlock(process, relocation_addr, &relocation_entry,
-                          sizeof(ExternalRelocationEntry));
+        memory.ReadBlock(process, relocation_addr, &relocation_entry,
+                         sizeof(ExternalRelocationEntry));
 
         if (relocation_entry.is_batch_resolved) {
             std::string symbol_name =
@@ -974,7 +974,7 @@ ResultCode CROHelper::ApplyModuleExport(CROHelper target) {
     u32 target_import_module_num = target.GetField(ImportModuleNum);
     for (u32 i = 0; i < target_import_module_num; ++i) {
         ImportModuleEntry entry;
-        target.GetEntry(i, entry);
+        target.GetEntry(memory, i, entry);
 
         if (memory.ReadCString(entry.name_offset, target_import_string_size) != module_name)
             continue;
@@ -983,9 +983,9 @@ ResultCode CROHelper::ApplyModuleExport(CROHelper target) {
                  entry.import_indexed_symbol_num, target.ModuleName());
         for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
             ImportIndexedSymbolEntry im;
-            entry.GetImportIndexedSymbolEntry(process, j, im);
+            entry.GetImportIndexedSymbolEntry(process, memory, j, im);
             ExportIndexedSymbolEntry ex;
-            GetEntry(im.index, ex);
+            GetEntry(memory, im.index, ex);
             u32 symbol_address = SegmentTagToAddress(ex.symbol_position);
             LOG_TRACE(Service_LDR, "    exports symbol 0x{:08X}", symbol_address);
             ResultCode result =
@@ -1000,7 +1000,7 @@ ResultCode CROHelper::ApplyModuleExport(CROHelper target) {
                  entry.import_anonymous_symbol_num, target.ModuleName());
         for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
             ImportAnonymousSymbolEntry im;
-            entry.GetImportAnonymousSymbolEntry(process, j, im);
+            entry.GetImportAnonymousSymbolEntry(process, memory, j, im);
             u32 symbol_address = SegmentTagToAddress(im.symbol_position);
             LOG_TRACE(Service_LDR, "    exports symbol 0x{:08X}", symbol_address);
             ResultCode result =
@@ -1023,7 +1023,7 @@ ResultCode CROHelper::ResetModuleExport(CROHelper target) {
     u32 target_import_module_num = target.GetField(ImportModuleNum);
     for (u32 i = 0; i < target_import_module_num; ++i) {
         ImportModuleEntry entry;
-        target.GetEntry(i, entry);
+        target.GetEntry(memory, i, entry);
 
         if (memory.ReadCString(entry.name_offset, target_import_string_size) != module_name)
             continue;
@@ -1032,7 +1032,7 @@ ResultCode CROHelper::ResetModuleExport(CROHelper target) {
                   target.ModuleName());
         for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
             ImportIndexedSymbolEntry im;
-            entry.GetImportIndexedSymbolEntry(process, j, im);
+            entry.GetImportIndexedSymbolEntry(process, memory, j, im);
             ResultCode result =
                 target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
             if (result.IsError()) {
@@ -1045,7 +1045,7 @@ ResultCode CROHelper::ResetModuleExport(CROHelper target) {
                   target.ModuleName());
         for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
             ImportAnonymousSymbolEntry im;
-            entry.GetImportAnonymousSymbolEntry(process, j, im);
+            entry.GetImportAnonymousSymbolEntry(process, memory, j, im);
             ResultCode result =
                 target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
             if (result.IsError()) {
@@ -1063,11 +1063,11 @@ ResultCode CROHelper::ApplyExitRelocations(VAddr crs_address) {
     u32 symbol_import_num = GetField(ImportNamedSymbolNum);
     for (u32 i = 0; i < symbol_import_num; ++i) {
         ImportNamedSymbolEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
         VAddr relocation_addr = entry.relocation_batch_offset;
         ExternalRelocationEntry relocation_entry;
-        Memory::ReadBlock(process, relocation_addr, &relocation_entry,
-                          sizeof(ExternalRelocationEntry));
+        memory.ReadBlock(process, relocation_addr, &relocation_entry,
+                         sizeof(ExternalRelocationEntry));
 
         if (memory.ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit") {
             ResultCode result = ForEachAutoLinkCRO(
@@ -1266,11 +1266,11 @@ ResultCode CROHelper::Link(VAddr crs_address, bool link_on_load_bug_fix) {
             // so we do the same
             if (GetField(SegmentNum) >= 2) { // means we have .data segment
                 SegmentEntry entry;
-                GetEntry(2, entry);
+                GetEntry(memory, 2, entry);
                 ASSERT(entry.type == SegmentType::Data);
                 data_segment_address = entry.offset;
                 entry.offset = GetField(DataOffset);
-                SetEntry(2, entry);
+                SetEntry(memory, 2, entry);
             }
         }
         SCOPE_EXIT({
@@ -1278,9 +1278,9 @@ ResultCode CROHelper::Link(VAddr crs_address, bool link_on_load_bug_fix) {
             if (link_on_load_bug_fix) {
                 if (GetField(SegmentNum) >= 2) {
                     SegmentEntry entry;
-                    GetEntry(2, entry);
+                    GetEntry(memory, 2, entry);
                     entry.offset = data_segment_address;
-                    SetEntry(2, entry);
+                    SetEntry(memory, 2, entry);
                 }
             }
         });
@@ -1516,7 +1516,7 @@ std::tuple<VAddr, u32> CROHelper::GetExecutablePages() const {
     u32 segment_num = GetField(SegmentNum);
     for (u32 i = 0; i < segment_num; ++i) {
         SegmentEntry entry;
-        GetEntry(i, entry);
+        GetEntry(memory, i, entry);
         if (entry.type == SegmentType::Code && entry.size != 0) {
             VAddr begin = Common::AlignDown(entry.offset, Memory::PAGE_SIZE);
             VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::PAGE_SIZE);
diff --git a/src/core/hle/service/ldr_ro/cro_helper.h b/src/core/hle/service/ldr_ro/cro_helper.h
index e868a66c8..1eee90045 100644
--- a/src/core/hle/service/ldr_ro/cro_helper.h
+++ b/src/core/hle/service/ldr_ro/cro_helper.h
@@ -318,20 +318,20 @@ private:
 
         static constexpr HeaderField TABLE_OFFSET_FIELD = ImportModuleTableOffset;
 
-        void GetImportIndexedSymbolEntry(Kernel::Process& process, u32 index,
-                                         ImportIndexedSymbolEntry& entry) {
-            Memory::ReadBlock(process,
-                              import_indexed_symbol_table_offset +
-                                  index * sizeof(ImportIndexedSymbolEntry),
-                              &entry, sizeof(ImportIndexedSymbolEntry));
+        void GetImportIndexedSymbolEntry(Kernel::Process& process, Memory::MemorySystem& memory,
+                                         u32 index, ImportIndexedSymbolEntry& entry) {
+            memory.ReadBlock(process,
+                             import_indexed_symbol_table_offset +
+                                 index * sizeof(ImportIndexedSymbolEntry),
+                             &entry, sizeof(ImportIndexedSymbolEntry));
         }
 
-        void GetImportAnonymousSymbolEntry(Kernel::Process& process, u32 index,
-                                           ImportAnonymousSymbolEntry& entry) {
-            Memory::ReadBlock(process,
-                              import_anonymous_symbol_table_offset +
-                                  index * sizeof(ImportAnonymousSymbolEntry),
-                              &entry, sizeof(ImportAnonymousSymbolEntry));
+        void GetImportAnonymousSymbolEntry(Kernel::Process& process, Memory::MemorySystem& memory,
+                                           u32 index, ImportAnonymousSymbolEntry& entry) {
+            memory.ReadBlock(process,
+                             import_anonymous_symbol_table_offset +
+                                 index * sizeof(ImportAnonymousSymbolEntry),
+                             &entry, sizeof(ImportAnonymousSymbolEntry));
         }
     };
     ASSERT_CRO_STRUCT(ImportModuleEntry, 20);
@@ -423,10 +423,10 @@ private:
      *       indicating which table the entry is in.
      */
     template <typename T>
-    void GetEntry(std::size_t index, T& data) const {
-        Memory::ReadBlock(process,
-                          GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)),
-                          &data, sizeof(T));
+    void GetEntry(Memory::MemorySystem& memory, std::size_t index, T& data) const {
+        memory.ReadBlock(process,
+                         GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)),
+                         &data, sizeof(T));
     }
 
     /**
@@ -437,10 +437,10 @@ private:
      *       indicating which table the entry is in.
      */
     template <typename T>
-    void SetEntry(std::size_t index, const T& data) {
-        Memory::WriteBlock(process,
-                           GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)),
-                           &data, sizeof(T));
+    void SetEntry(Memory::MemorySystem& memory, std::size_t index, const T& data) {
+        memory.WriteBlock(process,
+                          GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)),
+                          &data, sizeof(T));
     }
 
     /**
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index cf545ec8e..7e2d347e7 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -433,8 +433,8 @@ u64 MemorySystem::Read64(const VAddr addr) {
     return Read<u64_le>(addr);
 }
 
-void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
-               const std::size_t size) {
+void MemorySystem::ReadBlock(const Kernel::Process& process, const VAddr src_addr,
+                             void* dest_buffer, const std::size_t size) {
     auto& page_table = process.vm_manager.page_table;
 
     std::size_t remaining_size = size;
@@ -499,8 +499,8 @@ void MemorySystem::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) {
+void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_addr,
+                              const void* src_buffer, const std::size_t size) {
     auto& page_table = process.vm_manager.page_table;
     std::size_t remaining_size = size;
     std::size_t page_index = dest_addr >> PAGE_BITS;
@@ -547,7 +547,8 @@ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const voi
     }
 }
 
-void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
+void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_addr,
+                             const std::size_t size) {
     auto& page_table = process.vm_manager.page_table;
     std::size_t remaining_size = size;
     std::size_t page_index = dest_addr >> PAGE_BITS;
@@ -595,8 +596,8 @@ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std:
     }
 }
 
-void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
-               const std::size_t size) {
+void MemorySystem::CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
+                             const std::size_t size) {
     auto& page_table = process.vm_manager.page_table;
     std::size_t remaining_size = size;
     std::size_t page_index = src_addr >> PAGE_BITS;
@@ -647,8 +648,9 @@ void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
     }
 }
 
-void CopyBlock(const Kernel::Process& src_process, const Kernel::Process& dest_process,
-               VAddr src_addr, VAddr dest_addr, std::size_t size) {
+void MemorySystem::CopyBlock(const Kernel::Process& src_process,
+                             const Kernel::Process& dest_process, VAddr src_addr, VAddr dest_addr,
+                             std::size_t size) {
     auto& page_table = src_process.vm_manager.page_table;
     std::size_t remaining_size = size;
     std::size_t page_index = src_addr >> PAGE_BITS;
diff --git a/src/core/memory.h b/src/core/memory.h
index f99067705..33a2918cf 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -180,14 +180,6 @@ enum : VAddr {
 
 extern std::array<u8, Memory::FCRAM_N3DS_SIZE> fcram;
 
-void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, std::size_t size);
-void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
-                std::size_t size);
-void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, const std::size_t size);
-void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, std::size_t size);
-void CopyBlock(const Kernel::Process& src_process, const Kernel::Process& dest_process,
-               VAddr src_addr, VAddr dest_addr, std::size_t size);
-
 /**
  * Mark each page touching the region as cached.
  */
@@ -239,6 +231,16 @@ public:
     void Write32(VAddr addr, u32 data);
     void Write64(VAddr addr, u64 data);
 
+    void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
+                   std::size_t size);
+    void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
+                    std::size_t size);
+    void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, const std::size_t size);
+    void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
+                   std::size_t size);
+    void CopyBlock(const Kernel::Process& src_process, const Kernel::Process& dest_process,
+                   VAddr src_addr, VAddr dest_addr, std::size_t size);
+
     std::string ReadCString(VAddr vaddr, std::size_t max_length);
 
     /// Determines if the given VAddr is valid for the specified process.
diff --git a/src/core/rpc/rpc_server.cpp b/src/core/rpc/rpc_server.cpp
index 3a8b7f467..aec99f273 100644
--- a/src/core/rpc/rpc_server.cpp
+++ b/src/core/rpc/rpc_server.cpp
@@ -30,8 +30,9 @@ void RPCServer::HandleReadMemory(Packet& packet, u32 address, u32 data_size) {
     }
 
     // Note: Memory read occurs asynchronously from the state of the emulator
-    Memory::ReadBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), address,
-                      packet.GetPacketData().data(), data_size);
+    Core::System::GetInstance().Memory().ReadBlock(
+        *Core::System::GetInstance().Kernel().GetCurrentProcess(), address,
+        packet.GetPacketData().data(), data_size);
     packet.SetPacketDataSize(data_size);
     packet.SendReply();
 }
@@ -42,8 +43,8 @@ void RPCServer::HandleWriteMemory(Packet& packet, u32 address, const u8* data, u
         (address >= Memory::HEAP_VADDR && address <= Memory::HEAP_VADDR_END) ||
         (address >= Memory::N3DS_EXTRA_RAM_VADDR && address <= Memory::N3DS_EXTRA_RAM_VADDR_END)) {
         // Note: Memory write occurs asynchronously from the state of the emulator
-        Memory::WriteBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), address, data,
-                           data_size);
+        Core::System::GetInstance().Memory().WriteBlock(
+            *Core::System::GetInstance().Kernel().GetCurrentProcess(), address, data, data_size);
         // If the memory happens to be executable code, make sure the changes become visible
         Core::CPU().InvalidateCacheRange(address, data_size);
     }