From c96f22490a4a459d477f446fd4e5f894f580b69c Mon Sep 17 00:00:00 2001
From: Yuri Kunde Schlesner <yuriks@yuriks.net>
Date: Sun, 10 May 2015 19:47:07 -0300
Subject: [PATCH 1/4] Kernel: Capture SharedMemory attributes at creation, not
 when mapping

---
 src/core/hle/kernel/shared_memory.cpp | 20 +++++++++++---------
 src/core/hle/kernel/shared_memory.h   | 25 ++++++++++++++++++-------
 src/core/hle/service/apt/apt.cpp      |  4 +++-
 src/core/hle/service/gsp_gpu.cpp      | 16 +++++++++-------
 src/core/hle/service/hid/hid.cpp      |  6 ++++--
 src/core/hle/service/ir/ir.cpp        |  4 +++-
 src/core/hle/svc.cpp                  |  4 +++-
 7 files changed, 51 insertions(+), 28 deletions(-)

diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index cb5c16696..178589cbb 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -12,11 +12,15 @@ namespace Kernel {
 SharedMemory::SharedMemory() {}
 SharedMemory::~SharedMemory() {}
 
-SharedPtr<SharedMemory> SharedMemory::Create(std::string name) {
+SharedPtr<SharedMemory> SharedMemory::Create(u32 size, MemoryPermission permissions,
+        MemoryPermission other_permissions, std::string name) {
     SharedPtr<SharedMemory> shared_memory(new SharedMemory);
 
     shared_memory->name = std::move(name);
     shared_memory->base_address = 0x0;
+    shared_memory->size = size;
+    shared_memory->permissions = permissions;
+    shared_memory->other_permissions = other_permissions;
 
     return shared_memory;
 }
@@ -24,7 +28,7 @@ SharedPtr<SharedMemory> SharedMemory::Create(std::string name) {
 ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions,
         MemoryPermission other_permissions) {
 
-    if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) {
+    if (address < Memory::SHARED_MEMORY_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) {
         LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X outside of shared mem bounds!",
                 GetObjectId(), address);
         // TODO: Verify error code with hardware
@@ -32,21 +36,19 @@ ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions,
                 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
     }
 
+    // TODO: Test permissions
+
     this->base_address = address;
-    this->permissions = permissions;
-    this->other_permissions = other_permissions;
 
     return RESULT_SUCCESS;
 }
 
-ResultVal<u8*> SharedMemory::GetPointer(u32 offset) {
+u8* SharedMemory::GetPointer(u32 offset) {
     if (base_address != 0)
-        return MakeResult<u8*>(Memory::GetPointer(base_address + offset));
+        return Memory::GetPointer(base_address + offset);
 
     LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId());
-    // TODO(yuriks): Verify error code.
-    return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
-            ErrorSummary::InvalidState, ErrorLevel::Permanent);
+    return nullptr;
 }
 
 } // namespace
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 5833b411c..204266896 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -27,11 +27,16 @@ class SharedMemory final : public Object {
 public:
     /**
      * Creates a shared memory object
-     * @param name Optional object name, used only for debugging purposes.
+     * @param size Size of the memory block. Must be page-aligned.
+     * @param permissions Permission restrictions applied to the process which created the block.
+     * @param other_permissions Permission restrictions applied to other processes mapping the block.
+     * @param name Optional object name, used for debugging purposes.
      */
-    static SharedPtr<SharedMemory> Create(std::string name = "Unknown");
+    static SharedPtr<SharedMemory> Create(u32 size, MemoryPermission permissions,
+            MemoryPermission other_permissions, std::string name = "Unknown");
 
     std::string GetTypeName() const override { return "SharedMemory"; }
+    std::string GetName() const override { return name; }
 
     static const HandleType HANDLE_TYPE = HandleType::SharedMemory;
     HandleType GetHandleType() const override { return HANDLE_TYPE; }
@@ -49,12 +54,18 @@ public:
     * @param offset Offset from the start of the shared memory block to get pointer
     * @return Pointer to the shared memory block from the specified offset
     */
-    ResultVal<u8*> GetPointer(u32 offset = 0);
+    u8* GetPointer(u32 offset = 0);
 
-    VAddr base_address;                 ///< Address of shared memory block in RAM
-    MemoryPermission permissions;       ///< Permissions of shared memory block (SVC field)
-    MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field)
-    std::string name;                   ///< Name of shared memory object (optional)
+    /// Address of shared memory block in the process.
+    VAddr base_address;
+    /// Size of the memory block. Page-aligned.
+    u32 size;
+    /// Permission restrictions applied to the process which created the block.
+    MemoryPermission permissions;
+    /// Permission restrictions applied to other processes mapping the block.
+    MemoryPermission other_permissions;
+    /// Name of shared memory object.
+    std::string name;
 
 private:
     SharedMemory();
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 560c9dcf6..09d463dd5 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -304,7 +304,9 @@ void Init() {
         file.ReadBytes(shared_font.data(), (size_t)file.GetSize());
 
         // Create shared font memory object
-        shared_font_mem = Kernel::SharedMemory::Create("APT_U:shared_font_mem");
+        using Kernel::MemoryPermission;
+        shared_font_mem = Kernel::SharedMemory::Create(3 * 1024 * 1024, // 3MB
+                MemoryPermission::ReadWrite, MemoryPermission::Read, "APT_U:shared_font_mem");
     } else {
         LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str());
         shared_font_mem = nullptr;
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 8da063bd2..e2b6b0b02 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -35,8 +35,7 @@ u32 g_thread_id = 1;
 
 /// Gets a pointer to a thread command buffer in GSP shared memory
 static inline u8* GetCommandBuffer(u32 thread_id) {
-    ResultVal<u8*> ptr = g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer)));
-    return ptr.ValueOr(nullptr);
+    return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer)));
 }
 
 static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) {
@@ -44,14 +43,14 @@ static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_in
 
     // For each thread there are two FrameBufferUpdate fields
     u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate);
-    ResultVal<u8*> ptr = g_shared_memory->GetPointer(offset);
-    return reinterpret_cast<FrameBufferUpdate*>(ptr.ValueOr(nullptr));
+    u8* ptr = g_shared_memory->GetPointer(offset);
+    return reinterpret_cast<FrameBufferUpdate*>(ptr);
 }
 
 /// Gets a pointer to the interrupt relay queue for a given thread index
 static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
-    ResultVal<u8*> ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id);
-    return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr));
+    u8* ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id);
+    return reinterpret_cast<InterruptRelayQueue*>(ptr);
 }
 
 /**
@@ -288,7 +287,10 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
 
     g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]);
     ASSERT_MSG((g_interrupt_event != nullptr), "handle is not valid!");
-    g_shared_memory = Kernel::SharedMemory::Create("GSPSharedMem");
+
+    using Kernel::MemoryPermission;
+    g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
+            MemoryPermission::ReadWrite, "GSPSharedMem");
 
     Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom();
 
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index dd85848d0..9695f7e56 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -48,7 +48,7 @@ static u32 next_touch_index;
 //     * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41
 
 void Update() {
-    SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer().ValueOr(nullptr));
+    SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
     const PadState state = VideoCore::g_emu_window->GetPadState();
 
     if (mem == nullptr) {
@@ -163,7 +163,9 @@ void Init() {
     AddService(new HID_U_Interface);
     AddService(new HID_SPVR_Interface);
 
-    shared_mem = SharedMemory::Create("HID:SharedMem");
+    using Kernel::MemoryPermission;
+    shared_mem = SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
+            MemoryPermission::Read, "HID:SharedMem");
 
     next_pad_index = 0;
     next_touch_index = 0;
diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp
index 15ac477ef..adfbb258d 100644
--- a/src/core/hle/service/ir/ir.cpp
+++ b/src/core/hle/service/ir/ir.cpp
@@ -34,7 +34,9 @@ void Init() {
     AddService(new IR_U_Interface);
     AddService(new IR_User_Interface);
 
-    shared_memory = SharedMemory::Create("IR:SharedMemory");
+    using Kernel::MemoryPermission;
+    shared_memory = SharedMemory::Create(0x1000, Kernel::MemoryPermission::ReadWrite,
+            Kernel::MemoryPermission::ReadWrite, "IR:SharedMemory");
 
     // Create event handle(s)
     handle_event  = Event::Create(RESETTYPE_ONESHOT, "IR:HandleEvent");
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 393cfbe79..1ec6599c7 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -601,7 +601,9 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
     using Kernel::SharedMemory;
     // TODO(Subv): Implement this function
 
-    SharedPtr<SharedMemory> shared_memory = SharedMemory::Create();
+    using Kernel::MemoryPermission;
+    SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size,
+            (MemoryPermission)my_permission, (MemoryPermission)other_permission);
     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory)));
 
     LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr);

From 774eea83741286338e249e1bf188f53b53243411 Mon Sep 17 00:00:00 2001
From: Yuri Kunde Schlesner <yuriks@yuriks.net>
Date: Sun, 10 May 2015 19:49:46 -0300
Subject: [PATCH 2/4] Kernel: Zero-fill shared memory blocks when mapping

This works around crashes related to GSP/HID/etc. shared memory blocks
having garbage values. The proper fix requires proper management of
mapped memory blocks in the process.
---
 src/core/hle/kernel/shared_memory.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 178589cbb..0c59f4876 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -2,6 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <cstring>
+
 #include "common/logging/log.h"
 
 #include "core/mem_map.h"
@@ -38,6 +40,12 @@ ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions,
 
     // TODO: Test permissions
 
+    // HACK: Since there's no way to write to the memory block without mapping it onto the game
+    // process yet, at least initialize memory the first time it's mapped.
+    if (address != this->base_address) {
+        std::memset(Memory::GetPointer(address), 0, size);
+    }
+
     this->base_address = address;
 
     return RESULT_SUCCESS;

From 1538a34eda324782bf88fa382201e1e5cf8a237c Mon Sep 17 00:00:00 2001
From: Yuri Kunde Schlesner <yuriks@yuriks.net>
Date: Sun, 10 May 2015 19:51:37 -0300
Subject: [PATCH 3/4] GSP: Small tweaks to shared memory initialization

---
 src/core/hle/service/gsp_gpu.cpp | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index e2b6b0b02..917f4685f 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -31,7 +31,7 @@ Kernel::SharedPtr<Kernel::Event> g_interrupt_event;
 /// GSP shared memoryings
 Kernel::SharedPtr<Kernel::SharedMemory> g_shared_memory;
 /// Thread index into interrupt relay queue, 1 is arbitrary
-u32 g_thread_id = 1;
+u32 g_thread_id = 0;
 
 /// Gets a pointer to a thread command buffer in GSP shared memory
 static inline u8* GetCommandBuffer(u32 thread_id) {
@@ -277,7 +277,7 @@ static void FlushDataCache(Service::Interface* self) {
  *      1 : "Flags" field, purpose is unknown
  *      3 : Handle to GSP synchronization event
  *  Outputs:
- *      0 : Result of function, 0 on success, otherwise error code
+ *      1 : Result of function, 0x2A07 on success, otherwise error code
  *      2 : Thread index into GSP command buffer
  *      4 : Handle to GSP shared memory
  */
@@ -288,13 +288,11 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
     g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]);
     ASSERT_MSG((g_interrupt_event != nullptr), "handle is not valid!");
 
-    using Kernel::MemoryPermission;
-    g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
-            MemoryPermission::ReadWrite, "GSPSharedMem");
-
     Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom();
 
-    cmd_buff[1] = 0x2A07; // Value verified by 3dmoo team, purpose unknown, but needed for GSP init
+    // This specific code is required for a successful initialization, rather than 0
+    cmd_buff[1] = ResultCode((ErrorDescription)519, ErrorModule::GX,
+                             ErrorSummary::Success, ErrorLevel::Success).raw;
     cmd_buff[2] = g_thread_id++; // Thread ID
     cmd_buff[4] = shmem_handle; // GSP shared memory
 
@@ -529,8 +527,12 @@ Interface::Interface() {
     Register(FunctionTable);
 
     g_interrupt_event = 0;
-    g_shared_memory = 0;
-    g_thread_id = 1;
+
+    using Kernel::MemoryPermission;
+    g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
+            MemoryPermission::ReadWrite, "GSPSharedMem");
+
+    g_thread_id = 0;
 }
 
 } // namespace

From fd85367621a1428552ed4d8f43605dd0d7b5f100 Mon Sep 17 00:00:00 2001
From: Yuri Kunde Schlesner <yuriks@yuriks.net>
Date: Sun, 10 May 2015 20:09:41 -0300
Subject: [PATCH 4/4] fixup! GSP: Small tweaks to shared memory initialization

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

diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 917f4685f..c6252a03b 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -30,7 +30,7 @@ namespace GSP_GPU {
 Kernel::SharedPtr<Kernel::Event> g_interrupt_event;
 /// GSP shared memoryings
 Kernel::SharedPtr<Kernel::SharedMemory> g_shared_memory;
-/// Thread index into interrupt relay queue, 1 is arbitrary
+/// Thread index into interrupt relay queue
 u32 g_thread_id = 0;
 
 /// Gets a pointer to a thread command buffer in GSP shared memory