From cfa9a322c723619c60e12d4630044ee79fea5718 Mon Sep 17 00:00:00 2001
From: Weiyi Wang <wwylele@gmail.com>
Date: Sat, 10 Nov 2018 11:14:29 -0500
Subject: [PATCH 1/2] Kernel/SharedMemory: set and reset source memory state

---
 src/core/hle/kernel/kernel.h           | 12 ++++++------
 src/core/hle/kernel/shared_memory.cpp  | 21 ++++++++++++++-------
 src/core/hle/kernel/svc.cpp            |  7 ++++---
 src/core/hle/service/apt/apt.cpp       |  9 +++++----
 src/core/hle/service/csnd/csnd_snd.cpp |  8 +++++---
 src/core/hle/service/gsp/gsp_gpu.cpp   |  8 +++++---
 src/core/hle/service/hid/hid.cpp       |  8 +++++---
 src/core/hle/service/ir/ir_rst.cpp     |  8 +++++---
 8 files changed, 49 insertions(+), 32 deletions(-)

diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index a6db1eb39..cf6e95fe4 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -170,12 +170,12 @@ public:
      * linear heap.
      * @param name Optional object name, used for debugging purposes.
      */
-    SharedPtr<SharedMemory> CreateSharedMemory(Process* owner_process, u32 size,
-                                               MemoryPermission permissions,
-                                               MemoryPermission other_permissions,
-                                               VAddr address = 0,
-                                               MemoryRegion region = MemoryRegion::BASE,
-                                               std::string name = "Unknown");
+    ResultVal<SharedPtr<SharedMemory>> CreateSharedMemory(Process* owner_process, u32 size,
+                                                          MemoryPermission permissions,
+                                                          MemoryPermission other_permissions,
+                                                          VAddr address = 0,
+                                                          MemoryRegion region = MemoryRegion::BASE,
+                                                          std::string name = "Unknown");
 
     /**
      * Creates a shared memory object from a block of memory managed by an HLE applet.
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index f32651d49..eec74bfde 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -17,13 +17,16 @@ SharedMemory::~SharedMemory() {
         kernel.GetMemoryRegion(MemoryRegion::SYSTEM)
             ->Free(interval.lower(), interval.upper() - interval.lower());
     }
+    if (base_address != 0 && owner_process != nullptr) {
+        owner_process->vm_manager.ChangeMemoryState(base_address, size, MemoryState::Locked,
+                                                    VMAPermission::None, MemoryState::Private,
+                                                    VMAPermission::ReadWrite);
+    }
 }
 
-SharedPtr<SharedMemory> KernelSystem::CreateSharedMemory(Process* owner_process, u32 size,
-                                                         MemoryPermission permissions,
-                                                         MemoryPermission other_permissions,
-                                                         VAddr address, MemoryRegion region,
-                                                         std::string name) {
+ResultVal<SharedPtr<SharedMemory>> KernelSystem::CreateSharedMemory(
+    Process* owner_process, u32 size, MemoryPermission permissions,
+    MemoryPermission other_permissions, VAddr address, MemoryRegion region, std::string name) {
     SharedPtr<SharedMemory> shared_memory(new SharedMemory(*this));
 
     shared_memory->owner_process = owner_process;
@@ -53,13 +56,17 @@ SharedPtr<SharedMemory> KernelSystem::CreateSharedMemory(Process* owner_process,
         auto& vm_manager = shared_memory->owner_process->vm_manager;
         // The memory is already available and mapped in the owner process.
 
+        CASCADE_CODE(vm_manager.ChangeMemoryState(address, size, MemoryState::Private,
+                                                  VMAPermission::ReadWrite, MemoryState::Locked,
+                                                  SharedMemory::ConvertPermissions(permissions)));
+
         auto backing_blocks = vm_manager.GetBackingBlocksForRange(address, size);
-        ASSERT_MSG(backing_blocks.Succeeded(), "Trying to share freed memory");
+        ASSERT(backing_blocks.Succeeded()); // should success after verifying memory state above
         shared_memory->backing_blocks = std::move(backing_blocks).Unwrap();
     }
 
     shared_memory->base_address = address;
-    return shared_memory;
+    return MakeResult(shared_memory);
 }
 
 SharedPtr<SharedMemory> KernelSystem::CreateSharedMemoryForApplet(
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 53728a66d..ab341a6bf 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1250,9 +1250,10 @@ ResultCode SVC::CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my
     if (addr == 0 && current_process->flags.shared_device_mem)
         region = current_process->flags.memory_region;
 
-    shared_memory = kernel.CreateSharedMemory(
-        current_process.get(), size, static_cast<MemoryPermission>(my_permission),
-        static_cast<MemoryPermission>(other_permission), addr, region);
+    CASCADE_RESULT(shared_memory,
+                   kernel.CreateSharedMemory(
+                       current_process.get(), size, static_cast<MemoryPermission>(my_permission),
+                       static_cast<MemoryPermission>(other_permission), addr, region));
     CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(shared_memory)));
 
     LOG_WARNING(Kernel_SVC, "called addr=0x{:08X}", addr);
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 44b81a0fd..db8247a2a 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -861,10 +861,11 @@ Module::Module(Core::System& system) : system(system) {
     applet_manager = std::make_shared<AppletManager>(system);
 
     using Kernel::MemoryPermission;
-    shared_font_mem =
-        system.Kernel().CreateSharedMemory(nullptr, 0x332000, // 3272 KB
-                                           MemoryPermission::ReadWrite, MemoryPermission::Read, 0,
-                                           Kernel::MemoryRegion::SYSTEM, "APT:SharedFont");
+    shared_font_mem = system.Kernel()
+                          .CreateSharedMemory(nullptr, 0x332000, // 3272 KB
+                                              MemoryPermission::ReadWrite, MemoryPermission::Read,
+                                              0, Kernel::MemoryRegion::SYSTEM, "APT:SharedFont")
+                          .Unwrap();
 
     lock = system.Kernel().CreateMutex(false, "APT_U:Lock");
 }
diff --git a/src/core/hle/service/csnd/csnd_snd.cpp b/src/core/hle/service/csnd/csnd_snd.cpp
index ec4f55c0d..432a405c6 100644
--- a/src/core/hle/service/csnd/csnd_snd.cpp
+++ b/src/core/hle/service/csnd/csnd_snd.cpp
@@ -20,9 +20,11 @@ void CSND_SND::Initialize(Kernel::HLERequestContext& ctx) {
 
     using Kernel::MemoryPermission;
     mutex = system.Kernel().CreateMutex(false, "CSND:mutex");
-    shared_memory = system.Kernel().CreateSharedMemory(
-        nullptr, size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, 0,
-        Kernel::MemoryRegion::BASE, "CSND:SharedMemory");
+    shared_memory = system.Kernel()
+                        .CreateSharedMemory(nullptr, size, MemoryPermission::ReadWrite,
+                                            MemoryPermission::ReadWrite, 0,
+                                            Kernel::MemoryRegion::BASE, "CSND:SharedMemory")
+                        .Unwrap();
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 3);
     rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/gsp/gsp_gpu.cpp b/src/core/hle/service/gsp/gsp_gpu.cpp
index 8ed79ebca..6e6d0e585 100644
--- a/src/core/hle/service/gsp/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp/gsp_gpu.cpp
@@ -787,9 +787,11 @@ GSP_GPU::GSP_GPU(Core::System& system) : ServiceFramework("gsp::Gpu", 2), system
     RegisterHandlers(functions);
 
     using Kernel::MemoryPermission;
-    shared_memory = system.Kernel().CreateSharedMemory(
-        nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, 0,
-        Kernel::MemoryRegion::BASE, "GSP:SharedMemory");
+    shared_memory = system.Kernel()
+                        .CreateSharedMemory(nullptr, 0x1000, MemoryPermission::ReadWrite,
+                                            MemoryPermission::ReadWrite, 0,
+                                            Kernel::MemoryRegion::BASE, "GSP:SharedMemory")
+                        .Unwrap();
 
     first_initialization = true;
 };
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 805cc6c91..e42b265df 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -361,9 +361,11 @@ std::shared_ptr<Module> Module::Interface::GetModule() const {
 Module::Module(Core::System& system) : system(system) {
     using namespace Kernel;
 
-    shared_mem = system.Kernel().CreateSharedMemory(nullptr, 0x1000, MemoryPermission::ReadWrite,
-                                                    MemoryPermission::Read, 0, MemoryRegion::BASE,
-                                                    "HID:SharedMemory");
+    shared_mem =
+        system.Kernel()
+            .CreateSharedMemory(nullptr, 0x1000, MemoryPermission::ReadWrite,
+                                MemoryPermission::Read, 0, MemoryRegion::BASE, "HID:SharedMemory")
+            .Unwrap();
 
     // Create event handles
     event_pad_or_touch_1 = system.Kernel().CreateEvent(ResetType::OneShot, "HID:EventPadOrTouch1");
diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp
index 33e4fc0ff..7b7849afd 100644
--- a/src/core/hle/service/ir/ir_rst.cpp
+++ b/src/core/hle/service/ir/ir_rst.cpp
@@ -149,9 +149,11 @@ IR_RST::IR_RST(Core::System& system) : ServiceFramework("ir:rst", 1), system(sys
     using namespace Kernel;
     // Note: these two kernel objects are even available before Initialize service function is
     // called.
-    shared_memory = system.Kernel().CreateSharedMemory(nullptr, 0x1000, MemoryPermission::ReadWrite,
-                                                       MemoryPermission::Read, 0,
-                                                       MemoryRegion::BASE, "IRRST:SharedMemory");
+    shared_memory =
+        system.Kernel()
+            .CreateSharedMemory(nullptr, 0x1000, MemoryPermission::ReadWrite,
+                                MemoryPermission::Read, 0, MemoryRegion::BASE, "IRRST:SharedMemory")
+            .Unwrap();
     update_event = system.Kernel().CreateEvent(ResetType::OneShot, "IRRST:UpdateEvent");
 
     update_callback_id = system.CoreTiming().RegisterEvent(

From d90094e8a722b9e35bda2fef33670b02345b7dd6 Mon Sep 17 00:00:00 2001
From: Weiyi Wang <wwylele@gmail.com>
Date: Sat, 10 Nov 2018 11:27:15 -0500
Subject: [PATCH 2/2] Service: release shared memory object when finalize

Since last commit SharedMemory only reset source memory set on dtor, service should always release the ref as soon as possible to make the reset happen
---
 src/core/hle/applets/swkbd.cpp  |  1 +
 src/core/hle/service/http_c.cpp | 13 ++++++++++++-
 src/core/hle/service/http_c.h   |  7 +++++++
 src/core/hle/service/mic_u.cpp  |  1 +
 4 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
index 750a20849..0de0555c0 100644
--- a/src/core/hle/applets/swkbd.cpp
+++ b/src/core/hle/applets/swkbd.cpp
@@ -136,6 +136,7 @@ void SoftwareKeyboard::Finalize() {
     SendParameter(message);
 
     is_running = false;
+    text_memory = nullptr;
 }
 
 Frontend::KeyboardConfig SoftwareKeyboard::ToFrontendConfig(
diff --git a/src/core/hle/service/http_c.cpp b/src/core/hle/service/http_c.cpp
index 869a3602d..f55d6ed0e 100644
--- a/src/core/hle/service/http_c.cpp
+++ b/src/core/hle/service/http_c.cpp
@@ -443,6 +443,17 @@ void HTTP_C::CloseClientCertContext(Kernel::HLERequestContext& ctx) {
     LOG_DEBUG(Service_HTTP, "called, cert_handle={}", cert_handle);
 }
 
+void HTTP_C::Finalize(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp(ctx, 0x39, 0, 0);
+
+    shared_memory = nullptr;
+
+    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+    rb.Push(RESULT_SUCCESS);
+
+    LOG_WARNING(Service_HTTP, "(STUBBED) called");
+}
+
 void HTTP_C::DecryptClCertA() {
     static constexpr u32 iv_length = 16;
 
@@ -575,7 +586,7 @@ HTTP_C::HTTP_C() : ServiceFramework("http:C", 32) {
         {0x00360000, nullptr, "ClearDNSCache"},
         {0x00370080, nullptr, "SetKeepAlive"},
         {0x003800C0, nullptr, "SetPostDataTypeSize"},
-        {0x00390000, nullptr, "Finalize"},
+        {0x00390000, &HTTP_C::Finalize, "Finalize"},
     };
     RegisterHandlers(functions);
 
diff --git a/src/core/hle/service/http_c.h b/src/core/hle/service/http_c.h
index 64dc4703b..515572a10 100644
--- a/src/core/hle/service/http_c.h
+++ b/src/core/hle/service/http_c.h
@@ -240,6 +240,13 @@ private:
      */
     void CloseClientCertContext(Kernel::HLERequestContext& ctx);
 
+    /**
+     * HTTP_C::Finalize service function
+     *  Outputs:
+     *      1 : Result of function, 0 on success, otherwise error code
+     */
+    void Finalize(Kernel::HLERequestContext& ctx);
+
     void DecryptClCertA();
 
     Kernel::SharedPtr<Kernel::SharedMemory> shared_memory = nullptr;
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp
index b2c24bd17..ce9594751 100644
--- a/src/core/hle/service/mic_u.cpp
+++ b/src/core/hle/service/mic_u.cpp
@@ -52,6 +52,7 @@ struct MIC_U::Impl {
     void UnmapSharedMem(Kernel::HLERequestContext& ctx) {
         IPC::RequestParser rp{ctx, 0x02, 0, 0};
         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+        shared_memory = nullptr;
         rb.Push(RESULT_SUCCESS);
         LOG_WARNING(Service_MIC, "called");
     }