From c084fc824cf4e076bb83e41af64f5cfaa9204dcb Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sat, 16 Apr 2016 08:46:11 +0100
Subject: [PATCH 01/17] Memory: IsValidVirtualAddress/IsValidPhysicalAddress

---
 src/core/memory.cpp | 21 +++++++++++++++++++++
 src/core/memory.h   |  3 +++
 src/core/mmio.h     |  2 ++
 3 files changed, 26 insertions(+)

diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index ee9b69f81..68a29b154 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -246,6 +246,26 @@ void Write(const VAddr vaddr, const T data) {
     }
 }
 
+bool IsValidVirtualAddress(const VAddr vaddr) {
+    const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
+    if (page_pointer)
+        return true;
+
+    if (current_page_table->attributes[vaddr >> PAGE_BITS] != PageType::Special)
+        return false;
+
+    MMIORegionPointer mmio_region = GetMMIOHandler(vaddr);
+    if (mmio_region) {
+        return mmio_region->IsValidAddress(vaddr);
+    }
+
+    return false;
+}
+
+bool IsValidPhysicalAddress(const PAddr paddr) {
+    return IsValidVirtualAddress(PhysicalToVirtualAddress(paddr));
+}
+
 u8* GetPointer(const VAddr vaddr) {
     u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
     if (page_pointer) {
@@ -261,6 +281,7 @@ u8* GetPointer(const VAddr vaddr) {
 }
 
 u8* GetPhysicalPointer(PAddr address) {
+    // TODO(Subv): This call should not go through the application's memory mapping.
     return GetPointer(PhysicalToVirtualAddress(address));
 }
 
diff --git a/src/core/memory.h b/src/core/memory.h
index 126d60471..9ada78fc8 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -110,6 +110,9 @@ enum : VAddr {
     NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE,
 };
 
+bool IsValidVirtualAddress(const VAddr addr);
+bool IsValidPhysicalAddress(const PAddr addr);
+
 u8 Read8(VAddr addr);
 u16 Read16(VAddr addr);
 u32 Read32(VAddr addr);
diff --git a/src/core/mmio.h b/src/core/mmio.h
index 06b555e98..cb644f51b 100644
--- a/src/core/mmio.h
+++ b/src/core/mmio.h
@@ -18,6 +18,8 @@ class MMIORegion {
 public:
     virtual ~MMIORegion() = default;
 
+    virtual bool IsValidAddress(VAddr addr) = 0;
+
     virtual u8 Read8(VAddr addr) = 0;
     virtual u16 Read16(VAddr addr) = 0;
     virtual u32 Read32(VAddr addr) = 0;

From 3873b36db333547152280b741e85aa54c69d8199 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sat, 16 Apr 2016 09:14:18 +0100
Subject: [PATCH 02/17] Memory: ReadBlock/WriteBlock

---
 src/core/memory.cpp | 77 +++++++++++++++++++++++++++++++++++++++++++--
 src/core/memory.h   |  4 ++-
 src/core/mmio.h     |  4 +++
 3 files changed, 81 insertions(+), 4 deletions(-)

diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 68a29b154..c7b99a467 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -364,6 +364,45 @@ u64 Read64(const VAddr addr) {
     return Read<u64_le>(addr);
 }
 
+void ReadBlock(const VAddr src_addr, u8* dest_buffer, const size_t size) {
+    size_t remaining_size = size;
+    size_t page_index = src_addr >> PAGE_BITS;
+    size_t page_offset = src_addr & PAGE_MASK;
+
+    while (remaining_size > 0) {
+        const size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size);
+        const VAddr current_vaddr = (page_index << PAGE_BITS) + page_offset;
+
+        switch (current_page_table->attributes[page_index]) {
+        case PageType::Unmapped: {
+            LOG_ERROR(HW_Memory, "unmapped ReadBlock @ 0x%08X (start address = 0x%08X, size = %zu)", current_vaddr, src_addr, size);
+            std::memset(dest_buffer, 0, copy_amount);
+            break;
+        }
+        case PageType::Memory: {
+            DEBUG_ASSERT(current_page_table->pointers[page_index]);
+
+            const u8* src_ptr = current_page_table->pointers[page_index] + page_offset;
+            std::memcpy(dest_buffer, src_ptr, copy_amount);
+            break;
+        }
+        case PageType::Special: {
+            DEBUG_ASSERT(GetMMIOHandler(current_vaddr));
+
+            GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, dest_buffer, copy_amount);
+            break;
+        }
+        default:
+            UNREACHABLE();
+        }
+
+        page_index++;
+        page_offset = 0;
+        dest_buffer += copy_amount;
+        remaining_size -= copy_amount;
+    }
+}
+
 void Write8(const VAddr addr, const u8 data) {
     Write<u8>(addr, data);
 }
@@ -380,9 +419,41 @@ void Write64(const VAddr addr, const u64 data) {
     Write<u64_le>(addr, data);
 }
 
-void WriteBlock(const VAddr addr, const u8* data, const size_t size) {
-    for (u32 offset = 0; offset < size; offset++) {
-        Write8(addr + offset, data[offset]);
+void WriteBlock(const VAddr dest_addr, const u8* src_buffer, const size_t size) {
+    size_t remaining_size = size;
+    size_t page_index = dest_addr >> PAGE_BITS;
+    size_t page_offset = dest_addr & PAGE_MASK;
+
+    while (remaining_size > 0) {
+        const size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size);
+        const VAddr current_vaddr = (page_index << PAGE_BITS) + page_offset;
+
+        switch (current_page_table->attributes[page_index]) {
+        case PageType::Unmapped: {
+            LOG_ERROR(HW_Memory, "unmapped WriteBlock @ 0x%08X (start address = 0x%08X, size = %zu)", current_vaddr, dest_addr, size);
+            break;
+        }
+        case PageType::Memory: {
+            DEBUG_ASSERT(current_page_table->pointers[page_index]);
+
+            u8* dest_ptr = current_page_table->pointers[page_index] + page_offset;
+            std::memcpy(dest_ptr, src_buffer, copy_amount);
+            break;
+        }
+        case PageType::Special: {
+            DEBUG_ASSERT(GetMMIOHandler(current_vaddr));
+
+            GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, src_buffer, copy_amount);
+            break;
+        }
+        default:
+            UNREACHABLE();
+        }
+
+        page_index++;
+        page_offset = 0;
+        src_buffer += copy_amount;
+        remaining_size -= copy_amount;
     }
 }
 
diff --git a/src/core/memory.h b/src/core/memory.h
index 9ada78fc8..35bd5eb0c 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -118,12 +118,14 @@ u16 Read16(VAddr addr);
 u32 Read32(VAddr addr);
 u64 Read64(VAddr addr);
 
+void ReadBlock(const VAddr src_addr, u8* dest_buffer, size_t size);
+
 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(VAddr addr, const u8* data, size_t size);
+void WriteBlock(const VAddr dest_addr, const u8* src_buffer, size_t size);
 
 u8* GetPointer(VAddr virtual_address);
 
diff --git a/src/core/mmio.h b/src/core/mmio.h
index cb644f51b..35b73b061 100644
--- a/src/core/mmio.h
+++ b/src/core/mmio.h
@@ -25,10 +25,14 @@ public:
     virtual u32 Read32(VAddr addr) = 0;
     virtual u64 Read64(VAddr addr) = 0;
 
+    virtual bool ReadBlock(VAddr src_addr, u8* dest_buffer, size_t size) = 0;
+
     virtual void Write8(VAddr addr, u8 data) = 0;
     virtual void Write16(VAddr addr, u16 data) = 0;
     virtual void Write32(VAddr addr, u32 data) = 0;
     virtual void Write64(VAddr addr, u64 data) = 0;
+
+    virtual bool WriteBlock(VAddr dest_addr, const u8* src_buffer, size_t size) = 0;
 };
 
 using MMIORegionPointer = std::shared_ptr<MMIORegion>;

From b3b3dd7591416319ee0d6c4d32065bb5a7b1209f Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sat, 16 Apr 2016 09:48:46 +0100
Subject: [PATCH 03/17] Debugger/Callstack: Replace Memory::GetPointer with
 Memory::IsValidVirtualAddress

---
 src/citra_qt/debugger/callstack.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp
index 793944639..1a3077495 100644
--- a/src/citra_qt/debugger/callstack.cpp
+++ b/src/citra_qt/debugger/callstack.cpp
@@ -37,10 +37,13 @@ void CallstackWidget::OnDebugModeEntered()
     int counter = 0;
     for (u32 addr = 0x10000000; addr >= sp; addr -= 4)
     {
+        if (!Memory::IsValidVirtualAddress(addr))
+            break;
+
         const u32 ret_addr = Memory::Read32(addr);
         const u32 call_addr = ret_addr - 4; //get call address???
 
-        if (Memory::GetPointer(call_addr) == nullptr)
+        if (!Memory::IsValidVirtualAddress(call_addr))
             break;
 
         /* TODO (mattvail) clean me, move to debugger interface */

From 2be17a0c6e0a386b78e09dc6341182d3fe605d41 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sat, 16 Apr 2016 10:01:43 +0100
Subject: [PATCH 04/17] FileSys/Path: Replace Memory::GetPointer with
 Memory::ReadBlock

---
 src/core/file_sys/archive_backend.cpp | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/core/file_sys/archive_backend.cpp b/src/core/file_sys/archive_backend.cpp
index 97adf0e12..cc0aa7022 100644
--- a/src/core/file_sys/archive_backend.cpp
+++ b/src/core/file_sys/archive_backend.cpp
@@ -19,22 +19,22 @@ Path::Path(LowPathType type, u32 size, u32 pointer) : type(type) {
     switch (type) {
     case Binary:
     {
-        u8* data = Memory::GetPointer(pointer);
-        binary = std::vector<u8>(data, data + size);
+        binary.resize(size);
+        Memory::ReadBlock(pointer, binary.data(), binary.size());
         break;
     }
 
     case Char:
     {
-        const char* data = reinterpret_cast<const char*>(Memory::GetPointer(pointer));
-        string = std::string(data, size - 1); // Data is always null-terminated.
+        string.resize(size - 1); // Data is always null-terminated.
+        Memory::ReadBlock(pointer, &string[0], string.size());
         break;
     }
 
     case Wchar:
     {
-        const char16_t* data = reinterpret_cast<const char16_t*>(Memory::GetPointer(pointer));
-        u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated.
+        u16str.resize(size / 2 - 1); // Data is always null-terminated.
+        Memory::ReadBlock(pointer, &u16str[0], u16str.size() * sizeof(char16_t));
         break;
     }
 

From ca17df5757f08c7bb673aec19e0fdd4698dd904f Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sat, 16 Apr 2016 10:21:41 +0100
Subject: [PATCH 05/17] Memory: ZeroBlock

---
 src/core/memory.cpp | 38 ++++++++++++++++++++++++++++++++++++++
 src/core/memory.h   |  1 +
 2 files changed, 39 insertions(+)

diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index c7b99a467..1604a7da5 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -457,6 +457,44 @@ void WriteBlock(const VAddr dest_addr, const u8* src_buffer, const size_t size)
     }
 }
 
+void ZeroBlock(const VAddr dest_addr, const size_t size) {
+    size_t remaining_size = size;
+    size_t page_index = dest_addr >> PAGE_BITS;
+    size_t page_offset = dest_addr & PAGE_MASK;
+
+    while (remaining_size > 0) {
+        const size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size);
+        const VAddr current_vaddr = (page_index << PAGE_BITS) + page_offset;
+
+        switch (current_page_table->attributes[page_index]) {
+        case PageType::Unmapped: {
+            LOG_ERROR(HW_Memory, "unmapped ZeroBlock @ 0x%08X (start address = 0x%08X, size = %zu)", current_vaddr, dest_addr, size);
+            break;
+        }
+        case PageType::Memory: {
+            DEBUG_ASSERT(current_page_table->pointers[page_index]);
+
+            u8* dest_ptr = current_page_table->pointers[page_index] + page_offset;
+            std::memset(dest_ptr, 0, copy_amount);
+            break;
+        }
+        case PageType::Special: {
+            DEBUG_ASSERT(GetMMIOHandler(current_vaddr));
+
+            static const std::array<u8, PAGE_SIZE> zeros = {};
+            GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, zeros.data(), copy_amount);
+            break;
+        }
+        default:
+            UNREACHABLE();
+        }
+
+        page_index++;
+        page_offset = 0;
+        remaining_size -= copy_amount;
+    }
+}
+
 template<>
 u8 ReadMMIO<u8>(MMIORegionPointer mmio_handler, VAddr addr) {
     return mmio_handler->Read8(addr);
diff --git a/src/core/memory.h b/src/core/memory.h
index 35bd5eb0c..713cdfb2f 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -126,6 +126,7 @@ void Write32(VAddr addr, u32 data);
 void Write64(VAddr addr, u64 data);
 
 void WriteBlock(const VAddr dest_addr, const u8* src_buffer, size_t size);
+void ZeroBlock(const VAddr dest_addr, const size_t size);
 
 u8* GetPointer(VAddr virtual_address);
 

From aa84cab4e9c27c947192d055dd06941415d6e590 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sat, 16 Apr 2016 10:11:10 +0100
Subject: [PATCH 06/17] Applets/swkdb: Remove use of Memory::GetPointer

---
 src/core/hle/applets/swkbd.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
index 90c6adc65..3ad950692 100644
--- a/src/core/hle/applets/swkbd.cpp
+++ b/src/core/hle/applets/swkbd.cpp
@@ -99,7 +99,7 @@ void SoftwareKeyboard::DrawScreenKeyboard() {
     auto info = bottom_screen->framebuffer_info[bottom_screen->index];
 
     // TODO(Subv): Draw the HLE keyboard, for now just zero-fill the framebuffer
-    memset(Memory::GetPointer(info.address_left), 0, info.stride * 320);
+    Memory::ZeroBlock(info.address_left, info.stride * 320);
 
     GSP_GPU::SetBufferSwap(1, info);
 }

From 1ebaaf9bb1f5f663f53edaeac026fb465a8c576e Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sat, 16 Apr 2016 10:27:32 +0100
Subject: [PATCH 07/17] Kernel/Thread: Remove use of Memory::GetPointer

---
 src/core/hle/kernel/thread.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 43def6146..3f6bec5fa 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -403,7 +403,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
         priority = new_priority;
     }
 
-    if (!Memory::GetPointer(entry_point)) {
+    if (!Memory::IsValidVirtualAddress(entry_point)) {
         LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point);
         // TODO: Verify error
         return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,

From fddd243b17edb0fe03ef1a85c2abdf95353a534d Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sat, 16 Apr 2016 11:18:49 +0100
Subject: [PATCH 08/17] APT: Remove use of Memory::GetPointer

---
 src/core/hle/applets/mii_selector.cpp | 21 +++++++++++----------
 src/core/hle/applets/mii_selector.h   |  4 +++-
 src/core/hle/applets/swkbd.cpp        | 15 +++++++--------
 src/core/hle/service/apt/apt.cpp      | 25 +++++++++++++------------
 src/core/hle/service/apt/apt.h        |  6 ++----
 5 files changed, 36 insertions(+), 35 deletions(-)

diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp
index bf39eca22..77f01d208 100644
--- a/src/core/hle/applets/mii_selector.cpp
+++ b/src/core/hle/applets/mii_selector.cpp
@@ -32,9 +32,9 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
     // The LibAppJustStarted message contains a buffer with the size of the framebuffer shared memory.
     // Create the SharedMemory that will hold the framebuffer data
     Service::APT::CaptureBufferInfo capture_info;
-    ASSERT(sizeof(capture_info) == parameter.buffer_size);
+    ASSERT(sizeof(capture_info) == parameter.buffer.size());
 
-    memcpy(&capture_info, parameter.data, sizeof(capture_info));
+    memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info));
 
     using Kernel::MemoryPermission;
     // Allocate a heap block of the required size for this applet.
@@ -47,8 +47,7 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
     // Send the response message with the newly created SharedMemory
     Service::APT::MessageParameter result;
     result.signal = static_cast<u32>(Service::APT::SignalType::LibAppFinished);
-    result.data = nullptr;
-    result.buffer_size = 0;
+    result.buffer.clear();
     result.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
     result.sender_id = static_cast<u32>(id);
     result.object = framebuffer_memory;
@@ -63,15 +62,17 @@ ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& pa
     // TODO(Subv): Set the expected fields in the response buffer before resending it to the application.
     // TODO(Subv): Reverse the parameter format for the Mii Selector
 
-    if(parameter.buffer_size >= sizeof(u32)) {
-        // TODO: defaults return no error, but garbage in other unknown fields
-        memset(parameter.data, 0, sizeof(u32));
-    }
+    memcpy(&config, parameter.buffer.data(), parameter.buffer.size());
+
+    // TODO(Subv): Find more about this structure, result code 0 is enough to let most games continue.
+    MiiResult result;
+    memset(&result, 0, sizeof(result));
+    result.result_code = 0;
 
     // Let the application know that we're closing
     Service::APT::MessageParameter message;
-    message.buffer_size = parameter.buffer_size;
-    message.data = parameter.data;
+    message.buffer.resize(sizeof(MiiResult));
+    std::memcpy(message.buffer.data(), &result, message.buffer.size());
     message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed);
     message.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
     message.sender_id = static_cast<u32>(id);
diff --git a/src/core/hle/applets/mii_selector.h b/src/core/hle/applets/mii_selector.h
index be6b04642..24e8e721d 100644
--- a/src/core/hle/applets/mii_selector.h
+++ b/src/core/hle/applets/mii_selector.h
@@ -24,7 +24,7 @@ struct MiiConfig {
     u8  unk_004;
     INSERT_PADDING_BYTES(3);
     u16 unk_008;
-    INSERT_PADDING_BYTES(0x8C - 0xA);
+    INSERT_PADDING_BYTES(0x82);
     u8  unk_08C;
     INSERT_PADDING_BYTES(3);
     u16 unk_090;
@@ -75,6 +75,8 @@ public:
 
     /// Whether this applet is currently running instead of the host application or not.
     bool started;
+
+    MiiConfig config;
 };
 
 }
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
index 3ad950692..d87bf3d57 100644
--- a/src/core/hle/applets/swkbd.cpp
+++ b/src/core/hle/applets/swkbd.cpp
@@ -35,9 +35,9 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
     // The LibAppJustStarted message contains a buffer with the size of the framebuffer shared memory.
     // Create the SharedMemory that will hold the framebuffer data
     Service::APT::CaptureBufferInfo capture_info;
-    ASSERT(sizeof(capture_info) == parameter.buffer_size);
+    ASSERT(sizeof(capture_info) == parameter.buffer.size());
 
-    memcpy(&capture_info, parameter.data, sizeof(capture_info));
+    memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info));
 
     using Kernel::MemoryPermission;
     // Allocate a heap block of the required size for this applet.
@@ -50,8 +50,7 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
     // Send the response message with the newly created SharedMemory
     Service::APT::MessageParameter result;
     result.signal = static_cast<u32>(Service::APT::SignalType::LibAppFinished);
-    result.data = nullptr;
-    result.buffer_size = 0;
+    result.buffer.clear();
     result.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
     result.sender_id = static_cast<u32>(id);
     result.object = framebuffer_memory;
@@ -61,9 +60,9 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
 }
 
 ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) {
-    ASSERT_MSG(parameter.buffer_size == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong");
+    ASSERT_MSG(parameter.buffer.size() == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong");
 
-    memcpy(&config, parameter.data, parameter.buffer_size);
+    memcpy(&config, parameter.buffer.data(), parameter.buffer.size());
     text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object);
 
     // TODO(Subv): Verify if this is the correct behavior
@@ -107,8 +106,8 @@ void SoftwareKeyboard::DrawScreenKeyboard() {
 void SoftwareKeyboard::Finalize() {
     // Let the application know that we're closing
     Service::APT::MessageParameter message;
-    message.buffer_size = sizeof(SoftwareKeyboardConfig);
-    message.data = reinterpret_cast<u8*>(&config);
+    message.buffer.resize(sizeof(SoftwareKeyboardConfig));
+    std::memcpy(message.buffer.data(), &config, message.buffer.size());
     message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed);
     message.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
     message.sender_id = static_cast<u32>(id);
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 73fce6079..e2304fa54 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -176,12 +176,12 @@ void SendParameter(Service::Interface* self) {
     }
 
     MessageParameter param;
-    param.buffer_size = buffer_size;
     param.destination_id = dst_app_id;
     param.sender_id = src_app_id;
     param.object = Kernel::g_handle_table.GetGeneric(handle);
     param.signal = signal_type;
-    param.data = Memory::GetPointer(buffer);
+    param.buffer.resize(buffer_size);
+    Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size());
 
     cmd_buff[1] = dest_applet->ReceiveParameter(param).raw;
 
@@ -199,16 +199,15 @@ void ReceiveParameter(Service::Interface* self) {
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
     cmd_buff[2] = next_parameter.sender_id;
     cmd_buff[3] = next_parameter.signal; // Signal type
-    cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
+    cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size
     cmd_buff[5] = 0x10;
     cmd_buff[6] = 0;
     if (next_parameter.object != nullptr)
         cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
-    cmd_buff[7] = (next_parameter.buffer_size << 14) | 2;
+    cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2;
     cmd_buff[8] = buffer;
 
-    if (next_parameter.data)
-        memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
+    Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size());
 
     LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
 }
@@ -222,16 +221,15 @@ void GlanceParameter(Service::Interface* self) {
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
     cmd_buff[2] = next_parameter.sender_id;
     cmd_buff[3] = next_parameter.signal; // Signal type
-    cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
+    cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size
     cmd_buff[5] = 0x10;
     cmd_buff[6] = 0;
     if (next_parameter.object != nullptr)
         cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
-    cmd_buff[7] = (next_parameter.buffer_size << 14) | 2;
+    cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2;
     cmd_buff[8] = buffer;
 
-    if (next_parameter.data)
-        memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
+    Memory::WriteBlock(buffer, next_parameter.buffer.data(), std::min(static_cast<size_t>(buffer_size), next_parameter.buffer.size()));
 
     LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
 }
@@ -365,10 +363,13 @@ void StartLibraryApplet(Service::Interface* self) {
         return;
     }
 
+    size_t buffer_size = cmd_buff[2];
+    VAddr buffer_addr = cmd_buff[6];
+
     AppletStartupParameter parameter;
-    parameter.buffer_size = cmd_buff[2];
     parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]);
-    parameter.data = Memory::GetPointer(cmd_buff[6]);
+    parameter.buffer.resize(buffer_size);
+    Memory::ReadBlock(buffer_addr, parameter.buffer.data(), parameter.buffer.size());
 
     cmd_buff[1] = applet->Start(parameter).raw;
 }
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index 1a1034fcc..66cda1d4c 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -20,16 +20,14 @@ struct MessageParameter {
     u32 sender_id = 0;
     u32 destination_id = 0;
     u32 signal = 0;
-    u32 buffer_size = 0;
     Kernel::SharedPtr<Kernel::Object> object = nullptr;
-    u8* data = nullptr;
+    std::vector<u8> buffer;
 };
 
 /// Holds information about the parameters used in StartLibraryApplet
 struct AppletStartupParameter {
-    u32 buffer_size = 0;
     Kernel::SharedPtr<Kernel::Object> object = nullptr;
-    u8* data = nullptr;
+    std::vector<u8> buffer;
 };
 
 /// Used by the application to pass information about the current framebuffer to applets.

From 64068583fbefb7268a1138828611d735eae1e212 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sat, 16 Apr 2016 11:51:48 +0100
Subject: [PATCH 09/17] CFG: Remove use of Memory::GetPointer

---
 src/core/hle/service/cfg/cfg.cpp | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index b9322c55d..3921653e5 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -191,28 +191,32 @@ void GetConfigInfoBlk2(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
     u32 size = cmd_buff[1];
     u32 block_id = cmd_buff[2];
-    u8* data_pointer = Memory::GetPointer(cmd_buff[4]);
+    VAddr data_pointer = cmd_buff[4];
 
-    if (data_pointer == nullptr) {
+    if (!Memory::IsValidVirtualAddress(data_pointer)) {
         cmd_buff[1] = -1; // TODO(Subv): Find the right error code
         return;
     }
 
-    cmd_buff[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x2, data_pointer).raw;
+    std::vector<u8> data(size);
+    cmd_buff[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x2, data.data()).raw;
+    Memory::WriteBlock(data_pointer, data.data(), data.size());
 }
 
 void GetConfigInfoBlk8(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
     u32 size = cmd_buff[1];
     u32 block_id = cmd_buff[2];
-    u8* data_pointer = Memory::GetPointer(cmd_buff[4]);
+    VAddr data_pointer = cmd_buff[4];
 
-    if (data_pointer == nullptr) {
+    if (!Memory::IsValidVirtualAddress(data_pointer)) {
         cmd_buff[1] = -1; // TODO(Subv): Find the right error code
         return;
     }
 
-    cmd_buff[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x8, data_pointer).raw;
+    std::vector<u8> data(size);
+    cmd_buff[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x8, data.data()).raw;
+    Memory::WriteBlock(data_pointer, data.data(), data.size());
 }
 
 void UpdateConfigNANDSavegame(Service::Interface* self) {

From 896e5009aeec0603ee3dd77e34462a503253b75f Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sat, 16 Apr 2016 12:49:35 +0100
Subject: [PATCH 10/17] FS/Archive: Remove use of Memory::GetPointer

---
 src/core/hle/service/fs/archive.cpp | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index cc51ede0c..a7ebfde25 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -108,11 +108,13 @@ ResultVal<bool> File::SyncRequest() {
                           offset, length, backend->GetSize());
             }
 
-            ResultVal<size_t> read = backend->Read(offset, length, Memory::GetPointer(address));
+            std::vector<u8> data(length);
+            ResultVal<size_t> read = backend->Read(offset, data.size(), data.data());
             if (read.Failed()) {
                 cmd_buff[1] = read.Code().raw;
                 return read.Code();
             }
+            Memory::WriteBlock(address, data.data(), *read);
             cmd_buff[2] = static_cast<u32>(*read);
             Memory::RasterizerFlushAndInvalidateRegion(Memory::VirtualToPhysicalAddress(address), length);
             break;
@@ -128,7 +130,9 @@ ResultVal<bool> File::SyncRequest() {
             LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
                       GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
 
-            ResultVal<size_t> written = backend->Write(offset, length, flush != 0, Memory::GetPointer(address));
+            std::vector<u8> data(length);
+            Memory::ReadBlock(address, data.data(), data.size());
+            ResultVal<size_t> written = backend->Write(offset, data.size(), flush != 0, data.data());
             if (written.Failed()) {
                 cmd_buff[1] = written.Code().raw;
                 return written.Code();
@@ -216,12 +220,14 @@ ResultVal<bool> Directory::SyncRequest() {
         {
             u32 count = cmd_buff[1];
             u32 address = cmd_buff[3];
-            auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address));
+            std::vector<FileSys::Entry> entries(count);
             LOG_TRACE(Service_FS, "Read %s %s: count=%d",
                 GetTypeName().c_str(), GetName().c_str(), count);
 
             // Number of entries actually read
-            cmd_buff[2] = backend->Read(count, entries);
+            u32 read = backend->Read(entries.size(), entries.data());
+            cmd_buff[2] = read;
+            Memory::WriteBlock(address, entries.data(), read * sizeof(FileSys::Entry));
             break;
         }
 
@@ -456,11 +462,12 @@ ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon
     if (result.IsError())
         return result;
 
-    u8* smdh_icon = Memory::GetPointer(icon_buffer);
-    if (!smdh_icon)
+    if (!Memory::IsValidVirtualAddress(icon_buffer))
         return ResultCode(-1); // TODO(Subv): Find the right error code
 
-    ext_savedata->WriteIcon(path, smdh_icon, icon_size);
+    std::vector<u8> smdh_icon(icon_size);
+    Memory::ReadBlock(icon_buffer, smdh_icon.data(), smdh_icon.size());
+    ext_savedata->WriteIcon(path, smdh_icon.data(), smdh_icon.size());
     return RESULT_SUCCESS;
 }
 

From e936f5952cd1de5db2758747396666a380843d9d Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sat, 16 Apr 2016 12:54:33 +0100
Subject: [PATCH 11/17] DSP_DSP: Remove use of Memory::GetPointer

---
 src/core/hle/service/dsp_dsp.cpp | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index 10730d7ac..c8aadd9db 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -140,12 +140,15 @@ static void LoadComponent(Service::Interface* self) {
 
     // TODO(bunnei): Implement real DSP firmware loading
 
-    ASSERT(Memory::GetPointer(buffer) != nullptr);
-    ASSERT(size > 0x37C);
+    ASSERT(Memory::IsValidVirtualAddress(buffer));
+
+    std::vector<u8> component_data(size);
+    Memory::ReadBlock(buffer, component_data.data(), component_data.size());
 
-    LOG_INFO(Service_DSP, "Firmware hash: %#" PRIx64, Common::ComputeHash64(Memory::GetPointer(buffer), size));
+    LOG_INFO(Service_DSP, "Firmware hash: %#" PRIx64, Common::ComputeHash64(component_data.data(), component_data.size()));
     // Some versions of the firmware have the location of DSP structures listed here.
-    LOG_INFO(Service_DSP, "Structures hash: %#" PRIx64, Common::ComputeHash64(Memory::GetPointer(buffer) + 0x340, 60));
+    ASSERT(size > 0x37C);
+    LOG_INFO(Service_DSP, "Structures hash: %#" PRIx64, Common::ComputeHash64(component_data.data() + 0x340, 60));
 
     LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%X, prog_mask=0x%08X, data_mask=0x%08X, buffer=0x%08X",
                 size, prog_mask, data_mask, buffer);
@@ -285,7 +288,7 @@ static void WriteProcessPipe(Service::Interface* self) {
         return;
     }
 
-    ASSERT_MSG(Memory::GetPointer(buffer) != nullptr, "Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe_index, size, buffer);
+    ASSERT_MSG(Memory::IsValidVirtualAddress(buffer), "Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer);
 
     std::vector<u8> message(size);
     for (u32 i = 0; i < size; i++) {
@@ -324,7 +327,7 @@ static void ReadPipeIfPossible(Service::Interface* self) {
 
     DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(pipe_index);
 
-    ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=%u, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe_index, unknown, size, addr);
+    ASSERT_MSG(Memory::IsValidVirtualAddress(addr), "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr);
 
     cmd_buff[0] = IPC::MakeHeader(0x10, 1, 2);
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -364,7 +367,7 @@ static void ReadPipe(Service::Interface* self) {
 
     DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(pipe_index);
 
-    ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=%u, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe_index, unknown, size, addr);
+    ASSERT_MSG(Memory::IsValidVirtualAddress(addr), "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr);
 
     if (DSP::HLE::GetPipeReadableSize(pipe) >= size) {
         std::vector<u8> response = DSP::HLE::PipeRead(pipe, size);

From 31d49e01094068519850bbfa414f314fdb27beee Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sat, 16 Apr 2016 15:22:45 +0100
Subject: [PATCH 12/17] Memory: CopyBlock

---
 src/core/memory.cpp | 41 +++++++++++++++++++++++++++++++++++++++++
 src/core/memory.h   |  4 ++--
 2 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 1604a7da5..bf2493270 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -495,6 +495,47 @@ void ZeroBlock(const VAddr dest_addr, const size_t size) {
     }
 }
 
+void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) {
+    size_t remaining_size = size;
+    size_t page_index = src_addr >> PAGE_BITS;
+    size_t page_offset = src_addr & PAGE_MASK;
+
+    while (remaining_size > 0) {
+        const size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size);
+        const VAddr current_vaddr = (page_index << PAGE_BITS) + page_offset;
+
+        switch (current_page_table->attributes[page_index]) {
+        case PageType::Unmapped: {
+            LOG_ERROR(HW_Memory, "unmapped CopyBlock @ 0x%08X (start address = 0x%08X, size = %zu)", current_vaddr, src_addr, size);
+            ZeroBlock(dest_addr, copy_amount);
+            break;
+        }
+        case PageType::Memory: {
+            DEBUG_ASSERT(current_page_table->pointers[page_index]);
+            const u8* src_ptr = current_page_table->pointers[page_index] + page_offset;
+            WriteBlock(dest_addr, src_ptr, copy_amount);
+            break;
+        }
+        case PageType::Special: {
+            DEBUG_ASSERT(GetMMIOHandler(current_vaddr));
+
+            std::vector<u8> buffer(copy_amount);
+            GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, buffer.data(), buffer.size());
+            WriteBlock(dest_addr, buffer.data(), buffer.size());
+            break;
+        }
+        default:
+            UNREACHABLE();
+        }
+
+        page_index++;
+        page_offset = 0;
+        dest_addr += copy_amount;
+        src_addr += copy_amount;
+        remaining_size -= copy_amount;
+    }
+}
+
 template<>
 u8 ReadMMIO<u8>(MMIORegionPointer mmio_handler, VAddr addr) {
     return mmio_handler->Read8(addr);
diff --git a/src/core/memory.h b/src/core/memory.h
index 713cdfb2f..bb5dd0d15 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -118,15 +118,15 @@ u16 Read16(VAddr addr);
 u32 Read32(VAddr addr);
 u64 Read64(VAddr addr);
 
-void ReadBlock(const VAddr src_addr, u8* dest_buffer, size_t size);
-
 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 ReadBlock(const VAddr src_addr, u8* dest_buffer, size_t size);
 void WriteBlock(const VAddr dest_addr, const u8* src_buffer, size_t size);
 void ZeroBlock(const VAddr dest_addr, const size_t size);
+void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size);
 
 u8* GetPointer(VAddr virtual_address);
 

From 5f33d2cf07d94af5304ec64371a404e709a9805f Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sat, 16 Apr 2016 15:24:14 +0100
Subject: [PATCH 13/17] GSP_GPU: Remove use of Memory::GetPointer

---
 src/core/hle/service/gsp_gpu.cpp | 83 +++++++++++++++++++-------------
 1 file changed, 50 insertions(+), 33 deletions(-)

diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 8ded9b09b..f3c7b7df3 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -65,15 +65,27 @@ static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
     return reinterpret_cast<InterruptRelayQueue*>(ptr);
 }
 
+/**
+ * Writes a single GSP GPU hardware registers with a single u32 value
+ * (For internal use.)
+ *
+ * @param base_address The address of the register in question
+ * @param data Data to be written
+ */
+static void WriteSingleHWReg(u32 base_address, u32 data) {
+    DEBUG_ASSERT_MSG((base_address & 3) == 0 && base_address < 0x420000, "Write address out of range or misaligned");
+    HW::Write<u32>(base_address + REGS_BEGIN, data);
+}
+
 /**
  * Writes sequential GSP GPU hardware registers using an array of source data
  *
  * @param base_address The address of the first register in the sequence
  * @param size_in_bytes The number of registers to update (size of data)
- * @param data A pointer to the source data
+ * @param data_vaddr A pointer to the source data
  * @return RESULT_SUCCESS if the parameters are valid, error code otherwise
  */
-static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
+static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, VAddr data_vaddr) {
     // This magic number is verified to be done by the gsp module
     const u32 max_size_in_bytes = 0x80;
 
@@ -87,10 +99,10 @@ static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* da
             return ERR_GSP_REGS_MISALIGNED;
         } else {
             while (size_in_bytes > 0) {
-                HW::Write<u32>(base_address + REGS_BEGIN, *data);
+                WriteSingleHWReg(base_address, Memory::Read32(data_vaddr));
 
                 size_in_bytes -= 4;
-                ++data;
+                data_vaddr += 4;
                 base_address += 4;
             }
             return RESULT_SUCCESS;
@@ -112,7 +124,7 @@ static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* da
  * @param masks A pointer to the masks
  * @return RESULT_SUCCESS if the parameters are valid, error code otherwise
  */
-static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* data, const u32* masks) {
+static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, VAddr data_vaddr, VAddr masks_vaddr) {
     // This magic number is verified to be done by the gsp module
     const u32 max_size_in_bytes = 0x80;
 
@@ -131,14 +143,17 @@ static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const
                 u32 reg_value;
                 HW::Read<u32>(reg_value, reg_address);
 
+                u32 data = Memory::Read32(data_vaddr);
+                u32 mask = Memory::Read32(masks_vaddr);
+
                 // Update the current value of the register only for set mask bits
-                reg_value = (reg_value & ~*masks) | (*data | *masks);
+                reg_value = (reg_value & ~mask) | (data | mask);
 
-                HW::Write<u32>(reg_address, reg_value);
+                WriteSingleHWReg(base_address, reg_value);
 
                 size_in_bytes -= 4;
-                ++data;
-                ++masks;
+                data_vaddr += 4;
+                masks_vaddr += 4;
                 base_address += 4;
             }
             return RESULT_SUCCESS;
@@ -164,8 +179,7 @@ static void WriteHWRegs(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
     u32 reg_addr = cmd_buff[1];
     u32 size = cmd_buff[2];
-
-    u32* src = (u32*)Memory::GetPointer(cmd_buff[4]);
+    VAddr src = cmd_buff[4];
 
     cmd_buff[1] = WriteHWRegs(reg_addr, size, src).raw;
 }
@@ -186,8 +200,8 @@ static void WriteHWRegsWithMask(Service::Interface* self) {
     u32 reg_addr = cmd_buff[1];
     u32 size = cmd_buff[2];
 
-    u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]);
-    u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]);
+    VAddr src_data = cmd_buff[4];
+    VAddr mask_data = cmd_buff[6];
 
     cmd_buff[1] = WriteHWRegsWithMask(reg_addr, size, src_data, mask_data).raw;
 }
@@ -210,13 +224,16 @@ static void ReadHWRegs(Service::Interface* self) {
         return;
     }
 
-    u32* dst = (u32*)Memory::GetPointer(cmd_buff[0x41]);
+    VAddr dst_vaddr = cmd_buff[0x41];
 
     while (size > 0) {
-        HW::Read<u32>(*dst, reg_addr + REGS_BEGIN);
+        u32 value;
+        HW::Read<u32>(value, reg_addr + REGS_BEGIN);
+
+        Memory::Write32(dst_vaddr, value);
 
         size -= 4;
-        ++dst;
+        dst_vaddr += 4;
         reg_addr += 4;
     }
 }
@@ -226,22 +243,22 @@ ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
     PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
     PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
     if (info.active_fb == 0) {
-        WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)),
-                    4, &phys_address_left);
-        WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)),
-                    4, &phys_address_right);
+        WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)),
+                         phys_address_left);
+        WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)),
+                         phys_address_right);
     } else {
-        WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)),
-                    4, &phys_address_left);
-        WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)),
-                    4, &phys_address_right);
+        WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)),
+                         phys_address_left);
+        WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)),
+                         phys_address_right);
     }
-    WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)),
-                4, &info.stride);
-    WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)),
-                4, &info.format);
-    WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)),
-                4, &info.shown_fb);
+    WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)),
+                     info.stride);
+    WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)),
+                     info.format);
+    WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)),
+                     info.shown_fb);
 
     if (Pica::g_debug_context)
         Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr);
@@ -432,9 +449,9 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
         Memory::RasterizerFlushAndInvalidateRegion(Memory::VirtualToPhysicalAddress(command.dma_request.dest_address),
                             command.dma_request.size);
 
-        memcpy(Memory::GetPointer(command.dma_request.dest_address),
-               Memory::GetPointer(command.dma_request.source_address),
-               command.dma_request.size);
+        // 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(command.dma_request.dest_address, command.dma_request.source_address, command.dma_request.size);
         SignalInterrupt(InterruptId::DMA);
         break;
     }

From 59b268de35d7ed9db55e2aadc449e945e896b937 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sat, 16 Apr 2016 15:24:39 +0100
Subject: [PATCH 14/17] SSL_C: Remove use of Memory::GetPointer

---
 src/core/hle/service/ssl_c.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp
index 14a4e98ec..a8aff1abf 100644
--- a/src/core/hle/service/ssl_c.cpp
+++ b/src/core/hle/service/ssl_c.cpp
@@ -31,7 +31,6 @@ static void GenerateRandomData(Service::Interface* self) {
 
     u32 size = cmd_buff[1];
     VAddr address = cmd_buff[3];
-    u8* output_buff = Memory::GetPointer(address);
 
     // Fill the output buffer with random data.
     u32 data = 0;
@@ -44,13 +43,13 @@ static void GenerateRandomData(Service::Interface* self) {
 
         if (size > 4) {
             // Use up the entire 4 bytes of the random data for as long as possible
-            *(u32*)(output_buff + i) = data;
+            Memory::Write32(address + i, data);
             i += 4;
         } else if (size == 2) {
-            *(u16*)(output_buff + i) = (u16)(data & 0xffff);
+            Memory::Write16(address + i, static_cast<u16>(data & 0xffff));
             i += 2;
         } else {
-            *(u8*)(output_buff + i) = (u8)(data & 0xff);
+            Memory::Write8(address + i, static_cast<u8>(data & 0xff));
             i++;
         }
     }

From 99695d03d2ecce9bb6f8dbf23e763378b89b6759 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Tue, 19 Apr 2016 01:08:16 -0500
Subject: [PATCH 15/17] SOC_U: Remove usage of GetPointer

---
 src/core/hle/service/soc_u.cpp | 100 ++++++++++++++++++++++++---------
 1 file changed, 73 insertions(+), 27 deletions(-)

diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index d3e5d4bca..a7404085b 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -373,14 +373,18 @@ static void Bind(Service::Interface* self) {
     u32* cmd_buffer = Kernel::GetCommandBuffer();
     u32 socket_handle = cmd_buffer[1];
     u32 len = cmd_buffer[2];
-    CTRSockAddr* ctr_sock_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[6]));
 
-    if (ctr_sock_addr == nullptr) {
+    // Virtual address of the sock_addr structure
+    VAddr sock_addr_addr = cmd_buffer[6];
+    if (!Memory::IsValidVirtualAddress(sock_addr_addr)) {
         cmd_buffer[1] = -1; // TODO(Subv): Correct code
         return;
     }
 
-    sockaddr sock_addr = CTRSockAddr::ToPlatform(*ctr_sock_addr);
+    CTRSockAddr ctr_sock_addr;
+    Memory::ReadBlock(sock_addr_addr, reinterpret_cast<u8*>(&ctr_sock_addr), sizeof(CTRSockAddr));
+
+    sockaddr sock_addr = CTRSockAddr::ToPlatform(ctr_sock_addr);
 
     int res = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len));
 
@@ -496,7 +500,7 @@ static void Accept(Service::Interface* self) {
         result = TranslateError(GET_ERRNO);
     } else {
         CTRSockAddr ctr_addr = CTRSockAddr::FromPlatform(addr);
-        Memory::WriteBlock(cmd_buffer[0x104 >> 2], (const u8*)&ctr_addr, max_addr_len);
+        Memory::WriteBlock(cmd_buffer[0x104 >> 2], &ctr_addr, sizeof(ctr_addr));
     }
 
     cmd_buffer[0] = IPC::MakeHeader(4, 2, 2);
@@ -547,20 +551,31 @@ static void SendTo(Service::Interface* self) {
     u32 flags = cmd_buffer[3];
     u32 addr_len = cmd_buffer[4];
 
-    u8* input_buff = Memory::GetPointer(cmd_buffer[8]);
-    CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[10]));
+    VAddr input_buff_address = cmd_buffer[8];
+    if (!Memory::IsValidVirtualAddress(input_buff_address)) {
+        cmd_buffer[1] = -1; // TODO(Subv): Find the right error code
+        return;
+    }
 
-    if (ctr_dest_addr == nullptr) {
+    // Memory address of the dest_addr structure
+    VAddr dest_addr_addr = cmd_buffer[10];
+    if (!Memory::IsValidVirtualAddress(dest_addr_addr)) {
         cmd_buffer[1] = -1; // TODO(Subv): Find the right error code
         return;
     }
 
+    std::vector<u8> input_buff(len);
+    Memory::ReadBlock(input_buff_address, input_buff.data(), input_buff.size());
+
+    CTRSockAddr ctr_dest_addr;
+    Memory::ReadBlock(dest_addr_addr, reinterpret_cast<u8*>(&ctr_dest_addr), sizeof(ctr_dest_addr));
+
     int ret = -1;
     if (addr_len > 0) {
-        sockaddr dest_addr = CTRSockAddr::ToPlatform(*ctr_dest_addr);
-        ret = ::sendto(socket_handle, (const char*)input_buff, len, flags, &dest_addr, sizeof(dest_addr));
+        sockaddr dest_addr = CTRSockAddr::ToPlatform(ctr_dest_addr);
+        ret = ::sendto(socket_handle, reinterpret_cast<const char*>(input_buff.data()), len, flags, &dest_addr, sizeof(dest_addr));
     } else {
-        ret = ::sendto(socket_handle, (const char*)input_buff, len, flags, nullptr, 0);
+        ret = ::sendto(socket_handle, reinterpret_cast<const char*>(input_buff.data()), len, flags, nullptr, 0);
     }
 
     int result = 0;
@@ -591,14 +606,24 @@ static void RecvFrom(Service::Interface* self) {
 
     std::memcpy(&buffer_parameters, &cmd_buffer[64], sizeof(buffer_parameters));
 
-    u8* output_buff = Memory::GetPointer(buffer_parameters.output_buffer_addr);
+    if (!Memory::IsValidVirtualAddress(buffer_parameters.output_buffer_addr)) {
+        cmd_buffer[1] = -1; // TODO(Subv): Find the right error code
+        return;
+    }
+
+    if (!Memory::IsValidVirtualAddress(buffer_parameters.output_src_address_buffer)) {
+        cmd_buffer[1] = -1; // TODO(Subv): Find the right error code
+        return;
+    }
+
+    std::vector<u8> output_buff(len);
     sockaddr src_addr;
     socklen_t src_addr_len = sizeof(src_addr);
-    int ret = ::recvfrom(socket_handle, (char*)output_buff, len, flags, &src_addr, &src_addr_len);
+    int ret = ::recvfrom(socket_handle, reinterpret_cast<char*>(output_buff.data()), len, flags, &src_addr, &src_addr_len);
 
     if (ret >= 0 && buffer_parameters.output_src_address_buffer != 0 && src_addr_len > 0) {
-        CTRSockAddr* ctr_src_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(buffer_parameters.output_src_address_buffer));
-        *ctr_src_addr = CTRSockAddr::FromPlatform(src_addr);
+        CTRSockAddr ctr_src_addr = CTRSockAddr::FromPlatform(src_addr);
+        Memory::WriteBlock(buffer_parameters.output_src_address_buffer, reinterpret_cast<u8*>(&ctr_src_addr), sizeof(ctr_src_addr));
     }
 
     int result = 0;
@@ -606,6 +631,9 @@ static void RecvFrom(Service::Interface* self) {
     if (ret == SOCKET_ERROR_VALUE) {
         result = TranslateError(GET_ERRNO);
         total_received = 0;
+    } else {
+        // Write only the data we received to avoid overwriting parts of the buffer with zeros
+        Memory::WriteBlock(buffer_parameters.output_buffer_addr, output_buff.data(), total_received);
     }
 
     cmd_buffer[1] = result;
@@ -617,18 +645,28 @@ static void Poll(Service::Interface* self) {
     u32* cmd_buffer = Kernel::GetCommandBuffer();
     u32 nfds = cmd_buffer[1];
     int timeout = cmd_buffer[2];
-    CTRPollFD* input_fds = reinterpret_cast<CTRPollFD*>(Memory::GetPointer(cmd_buffer[6]));
-    CTRPollFD* output_fds = reinterpret_cast<CTRPollFD*>(Memory::GetPointer(cmd_buffer[0x104 >> 2]));
+
+    VAddr input_fds_addr = cmd_buffer[6];
+    VAddr output_fds_addr = cmd_buffer[0x104 >> 2];
+    if (!Memory::IsValidVirtualAddress(input_fds_addr) || !Memory::IsValidVirtualAddress(output_fds_addr)) {
+        cmd_buffer[1] = -1; // TODO(Subv): Find correct error code.
+        return;
+    }
+
+    std::vector<CTRPollFD> ctr_fds(nfds);
+    Memory::ReadBlock(input_fds_addr, reinterpret_cast<u8*>(ctr_fds.data()), nfds * sizeof(CTRPollFD));
 
     // The 3ds_pollfd and the pollfd structures may be different (Windows/Linux have different sizes)
     // so we have to copy the data
     std::vector<pollfd> platform_pollfd(nfds);
-    std::transform(input_fds, input_fds + nfds, platform_pollfd.begin(), CTRPollFD::ToPlatform);
+    std::transform(ctr_fds.begin(), ctr_fds.end(), platform_pollfd.begin(), CTRPollFD::ToPlatform);
 
     const int ret = ::poll(platform_pollfd.data(), nfds, timeout);
 
     // Now update the output pollfd structure
-    std::transform(platform_pollfd.begin(), platform_pollfd.end(), output_fds, CTRPollFD::FromPlatform);
+    std::transform(platform_pollfd.begin(), platform_pollfd.end(), ctr_fds.begin(), CTRPollFD::FromPlatform);
+
+    Memory::WriteBlock(output_fds_addr, reinterpret_cast<u8*>(ctr_fds.data()), nfds * sizeof(CTRPollFD));
 
     int result = 0;
     if (ret == SOCKET_ERROR_VALUE)
@@ -643,14 +681,16 @@ static void GetSockName(Service::Interface* self) {
     u32 socket_handle = cmd_buffer[1];
     socklen_t ctr_len = cmd_buffer[2];
 
-    CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x104 >> 2]));
+    // Memory address of the ctr_dest_addr structure
+    VAddr ctr_dest_addr_addr = cmd_buffer[0x104 >> 2];
 
     sockaddr dest_addr;
     socklen_t dest_addr_len = sizeof(dest_addr);
     int ret = ::getsockname(socket_handle, &dest_addr, &dest_addr_len);
 
-    if (ctr_dest_addr != nullptr) {
-        *ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr);
+    if (ctr_dest_addr_addr != 0 && Memory::IsValidVirtualAddress(ctr_dest_addr_addr)) {
+        CTRSockAddr ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr);
+        Memory::WriteBlock(ctr_dest_addr_addr, reinterpret_cast<u8*>(&ctr_dest_addr), sizeof(ctr_dest_addr));
     } else {
         cmd_buffer[1] = -1; // TODO(Subv): Verify error
         return;
@@ -682,14 +722,16 @@ static void GetPeerName(Service::Interface* self) {
     u32 socket_handle = cmd_buffer[1];
     socklen_t len = cmd_buffer[2];
 
-    CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x104 >> 2]));
+    // Memory address of the ctr_dest_addr structure
+    VAddr ctr_dest_addr_addr = cmd_buffer[0x104 >> 2];
 
     sockaddr dest_addr;
     socklen_t dest_addr_len = sizeof(dest_addr);
     int ret = ::getpeername(socket_handle, &dest_addr, &dest_addr_len);
 
-    if (ctr_dest_addr != nullptr) {
-        *ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr);
+    if (ctr_dest_addr_addr != 0 && Memory::IsValidVirtualAddress(ctr_dest_addr_addr)) {
+        CTRSockAddr ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr);
+        Memory::WriteBlock(ctr_dest_addr_addr, reinterpret_cast<u8*>(&ctr_dest_addr), sizeof(ctr_dest_addr));
     } else {
         cmd_buffer[1] = -1;
         return;
@@ -711,13 +753,17 @@ static void Connect(Service::Interface* self) {
     u32 socket_handle = cmd_buffer[1];
     socklen_t len = cmd_buffer[2];
 
-    CTRSockAddr* ctr_input_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[6]));
-    if (ctr_input_addr == nullptr) {
+    // Memory address of the ctr_input_addr structure
+    VAddr ctr_input_addr_addr = cmd_buffer[6];
+    if (!Memory::IsValidVirtualAddress(ctr_input_addr_addr)) {
         cmd_buffer[1] = -1; // TODO(Subv): Verify error
         return;
     }
 
-    sockaddr input_addr = CTRSockAddr::ToPlatform(*ctr_input_addr);
+    CTRSockAddr ctr_input_addr;
+    Memory::ReadBlock(ctr_input_addr_addr, reinterpret_cast<u8*>(&ctr_input_addr), sizeof(ctr_input_addr));
+
+    sockaddr input_addr = CTRSockAddr::ToPlatform(ctr_input_addr);
     int ret = ::connect(socket_handle, &input_addr, sizeof(input_addr));
     int result = 0;
     if (ret != 0)

From 660499ac01b9244301a0642f4a0209ef8309ace4 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Tue, 19 Apr 2016 14:08:02 -0500
Subject: [PATCH 16/17] Memory: Make ReadBlock and WriteBlock accept void
 pointers.

---
 src/core/hle/service/frd/frd.cpp | 10 ++++------
 src/core/hle/service/soc_u.cpp   | 14 +++++++-------
 src/core/memory.cpp              |  8 ++++----
 src/core/memory.h                |  4 ++--
 src/core/mmio.h                  |  4 ++--
 5 files changed, 19 insertions(+), 21 deletions(-)

diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp
index 15d604bb6..29d144365 100644
--- a/src/core/hle/service/frd/frd.cpp
+++ b/src/core/hle/service/frd/frd.cpp
@@ -23,7 +23,7 @@ void GetMyPresence(Service::Interface* self) {
 
     ASSERT(shifted_out_size == ((sizeof(MyPresence) << 14) | 2));
 
-    Memory::WriteBlock(my_presence_addr, reinterpret_cast<const u8*>(&my_presence), sizeof(MyPresence));
+    Memory::WriteBlock(my_presence_addr, &my_presence, sizeof(MyPresence));
 
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 
@@ -39,8 +39,7 @@ void GetFriendKeyList(Service::Interface* self) {
 
     FriendKey zero_key = {};
     for (u32 i = 0; i < frd_count; ++i) {
-        Memory::WriteBlock(frd_key_addr + i * sizeof(FriendKey),
-                           reinterpret_cast<const u8*>(&zero_key), sizeof(FriendKey));
+        Memory::WriteBlock(frd_key_addr + i * sizeof(FriendKey), &zero_key, sizeof(FriendKey));
     }
 
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -58,8 +57,7 @@ void GetFriendProfile(Service::Interface* self) {
 
     Profile zero_profile = {};
     for (u32 i = 0; i < count; ++i) {
-        Memory::WriteBlock(profiles_addr + i * sizeof(Profile),
-            reinterpret_cast<const u8*>(&zero_profile), sizeof(Profile));
+        Memory::WriteBlock(profiles_addr + i * sizeof(Profile), &zero_profile, sizeof(Profile));
     }
 
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -88,7 +86,7 @@ void GetMyFriendKey(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
 
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
-    Memory::WriteBlock(cmd_buff[2], reinterpret_cast<const u8*>(&my_friend_key), sizeof(FriendKey));
+    Memory::WriteBlock(cmd_buff[2], &my_friend_key, sizeof(FriendKey));
     LOG_WARNING(Service_FRD, "(STUBBED) called");
 }
 
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index a7404085b..9b285567b 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -568,7 +568,7 @@ static void SendTo(Service::Interface* self) {
     Memory::ReadBlock(input_buff_address, input_buff.data(), input_buff.size());
 
     CTRSockAddr ctr_dest_addr;
-    Memory::ReadBlock(dest_addr_addr, reinterpret_cast<u8*>(&ctr_dest_addr), sizeof(ctr_dest_addr));
+    Memory::ReadBlock(dest_addr_addr, &ctr_dest_addr, sizeof(ctr_dest_addr));
 
     int ret = -1;
     if (addr_len > 0) {
@@ -623,7 +623,7 @@ static void RecvFrom(Service::Interface* self) {
 
     if (ret >= 0 && buffer_parameters.output_src_address_buffer != 0 && src_addr_len > 0) {
         CTRSockAddr ctr_src_addr = CTRSockAddr::FromPlatform(src_addr);
-        Memory::WriteBlock(buffer_parameters.output_src_address_buffer, reinterpret_cast<u8*>(&ctr_src_addr), sizeof(ctr_src_addr));
+        Memory::WriteBlock(buffer_parameters.output_src_address_buffer, &ctr_src_addr, sizeof(ctr_src_addr));
     }
 
     int result = 0;
@@ -654,7 +654,7 @@ static void Poll(Service::Interface* self) {
     }
 
     std::vector<CTRPollFD> ctr_fds(nfds);
-    Memory::ReadBlock(input_fds_addr, reinterpret_cast<u8*>(ctr_fds.data()), nfds * sizeof(CTRPollFD));
+    Memory::ReadBlock(input_fds_addr, ctr_fds.data(), nfds * sizeof(CTRPollFD));
 
     // The 3ds_pollfd and the pollfd structures may be different (Windows/Linux have different sizes)
     // so we have to copy the data
@@ -666,7 +666,7 @@ static void Poll(Service::Interface* self) {
     // Now update the output pollfd structure
     std::transform(platform_pollfd.begin(), platform_pollfd.end(), ctr_fds.begin(), CTRPollFD::FromPlatform);
 
-    Memory::WriteBlock(output_fds_addr, reinterpret_cast<u8*>(ctr_fds.data()), nfds * sizeof(CTRPollFD));
+    Memory::WriteBlock(output_fds_addr, ctr_fds.data(), nfds * sizeof(CTRPollFD));
 
     int result = 0;
     if (ret == SOCKET_ERROR_VALUE)
@@ -690,7 +690,7 @@ static void GetSockName(Service::Interface* self) {
 
     if (ctr_dest_addr_addr != 0 && Memory::IsValidVirtualAddress(ctr_dest_addr_addr)) {
         CTRSockAddr ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr);
-        Memory::WriteBlock(ctr_dest_addr_addr, reinterpret_cast<u8*>(&ctr_dest_addr), sizeof(ctr_dest_addr));
+        Memory::WriteBlock(ctr_dest_addr_addr, &ctr_dest_addr, sizeof(ctr_dest_addr));
     } else {
         cmd_buffer[1] = -1; // TODO(Subv): Verify error
         return;
@@ -731,7 +731,7 @@ static void GetPeerName(Service::Interface* self) {
 
     if (ctr_dest_addr_addr != 0 && Memory::IsValidVirtualAddress(ctr_dest_addr_addr)) {
         CTRSockAddr ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr);
-        Memory::WriteBlock(ctr_dest_addr_addr, reinterpret_cast<u8*>(&ctr_dest_addr), sizeof(ctr_dest_addr));
+        Memory::WriteBlock(ctr_dest_addr_addr, &ctr_dest_addr, sizeof(ctr_dest_addr));
     } else {
         cmd_buffer[1] = -1;
         return;
@@ -761,7 +761,7 @@ static void Connect(Service::Interface* self) {
     }
 
     CTRSockAddr ctr_input_addr;
-    Memory::ReadBlock(ctr_input_addr_addr, reinterpret_cast<u8*>(&ctr_input_addr), sizeof(ctr_input_addr));
+    Memory::ReadBlock(ctr_input_addr_addr, &ctr_input_addr, sizeof(ctr_input_addr));
 
     sockaddr input_addr = CTRSockAddr::ToPlatform(ctr_input_addr);
     int ret = ::connect(socket_handle, &input_addr, sizeof(input_addr));
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index bf2493270..2ac3e7de4 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -364,7 +364,7 @@ u64 Read64(const VAddr addr) {
     return Read<u64_le>(addr);
 }
 
-void ReadBlock(const VAddr src_addr, u8* dest_buffer, const size_t size) {
+void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) {
     size_t remaining_size = size;
     size_t page_index = src_addr >> PAGE_BITS;
     size_t page_offset = src_addr & PAGE_MASK;
@@ -398,7 +398,7 @@ void ReadBlock(const VAddr src_addr, u8* dest_buffer, const size_t size) {
 
         page_index++;
         page_offset = 0;
-        dest_buffer += copy_amount;
+        dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
         remaining_size -= copy_amount;
     }
 }
@@ -419,7 +419,7 @@ void Write64(const VAddr addr, const u64 data) {
     Write<u64_le>(addr, data);
 }
 
-void WriteBlock(const VAddr dest_addr, const u8* src_buffer, const size_t size) {
+void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size) {
     size_t remaining_size = size;
     size_t page_index = dest_addr >> PAGE_BITS;
     size_t page_offset = dest_addr & PAGE_MASK;
@@ -452,7 +452,7 @@ void WriteBlock(const VAddr dest_addr, const u8* src_buffer, const size_t size)
 
         page_index++;
         page_offset = 0;
-        src_buffer += copy_amount;
+        src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
         remaining_size -= copy_amount;
     }
 }
diff --git a/src/core/memory.h b/src/core/memory.h
index bb5dd0d15..ae5588dee 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -123,8 +123,8 @@ void Write16(VAddr addr, u16 data);
 void Write32(VAddr addr, u32 data);
 void Write64(VAddr addr, u64 data);
 
-void ReadBlock(const VAddr src_addr, u8* dest_buffer, size_t size);
-void WriteBlock(const VAddr dest_addr, const u8* src_buffer, size_t size);
+void ReadBlock(const VAddr src_addr, void* dest_buffer, size_t size);
+void WriteBlock(const VAddr dest_addr, const void* src_buffer, size_t size);
 void ZeroBlock(const VAddr dest_addr, const size_t size);
 void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size);
 
diff --git a/src/core/mmio.h b/src/core/mmio.h
index 35b73b061..d76f005d8 100644
--- a/src/core/mmio.h
+++ b/src/core/mmio.h
@@ -25,14 +25,14 @@ public:
     virtual u32 Read32(VAddr addr) = 0;
     virtual u64 Read64(VAddr addr) = 0;
 
-    virtual bool ReadBlock(VAddr src_addr, u8* dest_buffer, size_t size) = 0;
+    virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, size_t size) = 0;
 
     virtual void Write8(VAddr addr, u8 data) = 0;
     virtual void Write16(VAddr addr, u16 data) = 0;
     virtual void Write32(VAddr addr, u32 data) = 0;
     virtual void Write64(VAddr addr, u64 data) = 0;
 
-    virtual bool WriteBlock(VAddr dest_addr, const u8* src_buffer, size_t size) = 0;
+    virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, size_t size) = 0;
 };
 
 using MMIORegionPointer = std::shared_ptr<MMIORegion>;

From 0aef634a54f786c49241c24b8d0c7aa3555b0fa1 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Sun, 15 May 2016 12:43:52 -0500
Subject: [PATCH 17/17] Memory: Handle RasterizerCachedMemory and
 RasterizerCachedSpecial page types in the memory block manipulation
 functions.

---
 src/core/hle/service/fs/archive.cpp |  1 -
 src/core/memory.cpp                 | 61 ++++++++++++++++++++++++++++-
 2 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index a7ebfde25..81b9abe4c 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -116,7 +116,6 @@ ResultVal<bool> File::SyncRequest() {
             }
             Memory::WriteBlock(address, data.data(), *read);
             cmd_buff[2] = static_cast<u32>(*read);
-            Memory::RasterizerFlushAndInvalidateRegion(Memory::VirtualToPhysicalAddress(address), length);
             break;
         }
 
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 2ac3e7de4..8c9e5d46d 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -392,6 +392,20 @@ void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) {
             GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, dest_buffer, copy_amount);
             break;
         }
+        case PageType::RasterizerCachedMemory: {
+            RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount);
+
+            std::memcpy(dest_buffer, GetPointerFromVMA(current_vaddr), copy_amount);
+            break;
+        }
+        case PageType::RasterizerCachedSpecial: {
+            DEBUG_ASSERT(GetMMIOHandler(current_vaddr));
+
+            RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount);
+
+            GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, dest_buffer, copy_amount);
+            break;
+        }
         default:
             UNREACHABLE();
         }
@@ -446,6 +460,20 @@ void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size
             GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, src_buffer, copy_amount);
             break;
         }
+        case PageType::RasterizerCachedMemory: {
+            RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount);
+
+            std::memcpy(GetPointerFromVMA(current_vaddr), src_buffer, copy_amount);
+            break;
+        }
+        case PageType::RasterizerCachedSpecial: {
+            DEBUG_ASSERT(GetMMIOHandler(current_vaddr));
+
+            RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount);
+
+            GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, src_buffer, copy_amount);
+            break;
+        }
         default:
             UNREACHABLE();
         }
@@ -462,6 +490,8 @@ void ZeroBlock(const VAddr dest_addr, const size_t size) {
     size_t page_index = dest_addr >> PAGE_BITS;
     size_t page_offset = dest_addr & PAGE_MASK;
 
+    static const std::array<u8, PAGE_SIZE> zeros = {};
+
     while (remaining_size > 0) {
         const size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size);
         const VAddr current_vaddr = (page_index << PAGE_BITS) + page_offset;
@@ -481,7 +511,20 @@ void ZeroBlock(const VAddr dest_addr, const size_t size) {
         case PageType::Special: {
             DEBUG_ASSERT(GetMMIOHandler(current_vaddr));
 
-            static const std::array<u8, PAGE_SIZE> zeros = {};
+            GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, zeros.data(), copy_amount);
+            break;
+        }
+        case PageType::RasterizerCachedMemory: {
+            RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount);
+
+            std::memset(GetPointerFromVMA(current_vaddr), 0, copy_amount);
+            break;
+        }
+        case PageType::RasterizerCachedSpecial: {
+            DEBUG_ASSERT(GetMMIOHandler(current_vaddr));
+
+            RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount);
+
             GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, zeros.data(), copy_amount);
             break;
         }
@@ -524,6 +567,22 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) {
             WriteBlock(dest_addr, buffer.data(), buffer.size());
             break;
         }
+        case PageType::RasterizerCachedMemory: {
+            RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount);
+
+            WriteBlock(dest_addr, GetPointerFromVMA(current_vaddr), copy_amount);
+            break;
+        }
+        case PageType::RasterizerCachedSpecial: {
+            DEBUG_ASSERT(GetMMIOHandler(current_vaddr));
+
+            RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount);
+
+            std::vector<u8> buffer(copy_amount);
+            GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, buffer.data(), buffer.size());
+            WriteBlock(dest_addr, buffer.data(), buffer.size());
+            break;
+        }
         default:
             UNREACHABLE();
         }