From 687d9739802097703a09f63d20ece741932b431b Mon Sep 17 00:00:00 2001
From: Yuri Kunde Schlesner <yuriks@yuriks.net>
Date: Wed, 26 Aug 2015 03:34:31 -0300
Subject: [PATCH] Core: Improve APT Shared Font hack

Should fix invalid read loops in some games
---
 src/core/hle/kernel/shared_memory.cpp | 27 +++++++++++++++++++++++++--
 src/core/hle/kernel/shared_memory.h   |  2 ++
 src/core/hle/service/apt/apt.cpp      |  4 ++--
 3 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 4137683b5d..1f477664b7 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -20,6 +20,7 @@ SharedPtr<SharedMemory> SharedMemory::Create(u32 size, MemoryPermission permissi
 
     shared_memory->name = std::move(name);
     shared_memory->base_address = 0x0;
+    shared_memory->fixed_address = 0x0;
     shared_memory->size = size;
     shared_memory->permissions = permissions;
     shared_memory->other_permissions = other_permissions;
@@ -30,9 +31,31 @@ SharedPtr<SharedMemory> SharedMemory::Create(u32 size, MemoryPermission permissi
 ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions,
         MemoryPermission other_permissions) {
 
+    if (base_address != 0) {
+        LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s: already mapped at 0x%08X!",
+            GetObjectId(), address, name.c_str(), base_address);
+        // TODO: Verify error code with hardware
+        return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
+            ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
+    }
+
+    if (fixed_address != 0) {
+         if (address != 0 && address != fixed_address) {
+            LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s: fixed_addres is 0x%08X!",
+                    GetObjectId(), address, name.c_str(), fixed_address);
+            // TODO: Verify error code with hardware
+            return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
+                ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
+        }
+
+        // HACK(yuriks): This is only here to support the APT shared font mapping right now.
+        // Later, this should actually map the memory block onto the address space.
+        return RESULT_SUCCESS;
+    }
+
     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);
+        LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s outside of shared mem bounds!",
+                GetObjectId(), address, name.c_str());
         // TODO: Verify error code with hardware
         return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
                 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 7a29227762..35b550d12c 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -61,6 +61,8 @@ public:
 
     /// Address of shared memory block in the process.
     VAddr base_address;
+    /// Fixed address to allow mapping to. Used for blocks created from the linear heap.
+    VAddr fixed_address;
     /// Size of the memory block. Page-aligned.
     u32 size;
     /// Permission restrictions applied to the process which created the block.
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 6a2fdea2bf..ba66569b41 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -78,8 +78,8 @@ void GetSharedFont(Service::Interface* self) {
     if (shared_font != nullptr) {
         // TODO(yuriks): This is a hack to keep this working right now even with our completely
         // broken shared memory system.
-        shared_font_mem->base_address = SHARED_FONT_VADDR;
-        Kernel::g_current_process->vm_manager.MapMemoryBlock(shared_font_mem->base_address,
+        shared_font_mem->fixed_address = SHARED_FONT_VADDR;
+        Kernel::g_current_process->vm_manager.MapMemoryBlock(shared_font_mem->fixed_address,
                 shared_font, 0, shared_font_mem->size, Kernel::MemoryState::Shared);
 
         cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);