diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index a8d89168997ff60e816f37ab91a9611207faf5c0..f6a7566bf601f5841c69c0ccc09ea3a5e4541afd 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -52,6 +52,7 @@ set(SRCS
             hle/service/apt/apt_a.cpp
             hle/service/apt/apt_s.cpp
             hle/service/apt/apt_u.cpp
+            hle/service/apt/bcfnt/bcfnt.cpp
             hle/service/boss/boss.cpp
             hle/service/boss/boss_p.cpp
             hle/service/boss/boss_u.cpp
@@ -185,6 +186,7 @@ set(HEADERS
             hle/service/apt/apt_a.h
             hle/service/apt/apt_s.h
             hle/service/apt/apt_u.h
+            hle/service/apt/bcfnt/bcfnt.h
             hle/service/boss/boss.h
             hle/service/boss/boss_p.h
             hle/service/boss/boss_u.h
diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h
index af442f81d57dc87e755bac536ef1890ad914fe20..754c6f7db52512152806bf352670cc52442ad3a3 100644
--- a/src/core/hle/applets/applet.h
+++ b/src/core/hle/applets/applet.h
@@ -65,6 +65,7 @@ protected:
     virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0;
 
     Service::APT::AppletId id; ///< Id of this Applet
+    std::shared_ptr<std::vector<u8>> heap_memory; ///< Heap memory for this Applet
 };
 
 /// Returns whether a library applet is currently running
diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp
index b4456ca90b9fad580b06a9404b53490b7a302749..bf39eca221238c18129e3a26a6812965be9b7f66 100644
--- a/src/core/hle/applets/mii_selector.cpp
+++ b/src/core/hle/applets/mii_selector.cpp
@@ -35,9 +35,14 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
     ASSERT(sizeof(capture_info) == parameter.buffer_size);
 
     memcpy(&capture_info, parameter.data, sizeof(capture_info));
+
     using Kernel::MemoryPermission;
-    framebuffer_memory = Kernel::SharedMemory::Create(capture_info.size, MemoryPermission::ReadWrite,
-                                                      MemoryPermission::ReadWrite, "MiiSelector Memory");
+    // Allocate a heap block of the required size for this applet.
+    heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
+    // Create a SharedMemory that directly points to this heap block.
+    framebuffer_memory = Kernel::SharedMemory::CreateForApplet(heap_memory, 0, heap_memory->size(),
+                                                               MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
+                                                               "MiiSelector Memory");
 
     // Send the response message with the newly created SharedMemory
     Service::APT::MessageParameter result;
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
index 87238aa1c9025bf2435b1d03284794074fc8c3c0..90c6adc65688980a6407d5a60ae0ed6403fdc3a7 100644
--- a/src/core/hle/applets/swkbd.cpp
+++ b/src/core/hle/applets/swkbd.cpp
@@ -40,8 +40,12 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
     memcpy(&capture_info, parameter.data, sizeof(capture_info));
 
     using Kernel::MemoryPermission;
-    framebuffer_memory = Kernel::SharedMemory::Create(capture_info.size, MemoryPermission::ReadWrite,
-                                                      MemoryPermission::ReadWrite, "SoftwareKeyboard Memory");
+    // Allocate a heap block of the required size for this applet.
+    heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
+    // Create a SharedMemory that directly points to this heap block.
+    framebuffer_memory = Kernel::SharedMemory::CreateForApplet(heap_memory, 0, heap_memory->size(),
+                                                               MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
+                                                               "SoftwareKeyboard Memory");
 
     // Send the response message with the newly created SharedMemory
     Service::APT::MessageParameter result;
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 4d718b681b836894a79221e7b2eefc544e97f0ae..bf7f875b6a4e263f517d32a811aadf12d7f9b4c4 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -170,7 +170,8 @@ template<ResultCode func(s64*, u32, s32)> void Wrap() {
 
 template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() {
     u32 param_1 = 0;
-    u32 retval = func(&param_1, PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw;
+    // The last parameter is passed in R0 instead of R4
+    u32 retval = func(&param_1, PARAM(1), PARAM(2), PARAM(3), PARAM(0)).raw;
     Core::g_app_core->SetReg(1, param_1);
     FuncReturn(retval);
 }
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp
index 61a741e28a8159f4d4de7a02ffb0b083970fed3b..4be20db22dd2ead5b10612101b5fb3f2f723a195 100644
--- a/src/core/hle/kernel/memory.cpp
+++ b/src/core/hle/kernel/memory.cpp
@@ -107,7 +107,6 @@ struct MemoryArea {
 
 // We don't declare the IO regions in here since its handled by other means.
 static MemoryArea memory_areas[] = {
-    {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE,     "Shared Memory"}, // Shared memory
     {VRAM_VADDR,          VRAM_SIZE,              "VRAM"},          // Video memory (VRAM)
 };
 
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 0546f6e16bc8b6e0d449a365760921a7b03f2fa1..69302cc825fcf20bedf05b8375a21925c5844783 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -209,7 +209,7 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p
         return ERR_INVALID_ADDRESS;
     }
 
-    // Expansion of the linear heap is only allowed if you do an allocation immediatelly at its
+    // Expansion of the linear heap is only allowed if you do an allocation immediately at its
     // end. It's possible to free gaps in the middle of the heap and then reallocate them later,
     // but expansions are only allowed at the end.
     if (target == heap_end) {
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index d90f0f00f0fdde2643dfe3e208b80602fd98da03..6a22c89860dfc88474566443a7abf08b37d9e586 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -7,6 +7,7 @@
 #include "common/logging/log.h"
 
 #include "core/memory.h"
+#include "core/hle/kernel/memory.h"
 #include "core/hle/kernel/shared_memory.h"
 
 namespace Kernel {
@@ -14,93 +15,157 @@ namespace Kernel {
 SharedMemory::SharedMemory() {}
 SharedMemory::~SharedMemory() {}
 
-SharedPtr<SharedMemory> SharedMemory::Create(u32 size, MemoryPermission permissions,
-        MemoryPermission other_permissions, std::string name) {
+SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions,
+        MemoryPermission other_permissions, VAddr address, MemoryRegion region, std::string name) {
     SharedPtr<SharedMemory> shared_memory(new SharedMemory);
 
+    shared_memory->owner_process = owner_process;
     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;
 
+    if (address == 0) {
+        // We need to allocate a block from the Linear Heap ourselves.
+        // We'll manually allocate some memory from the linear heap in the specified region.
+        MemoryRegionInfo* memory_region = GetMemoryRegion(region);
+        auto& linheap_memory = memory_region->linear_heap_memory;
+
+        ASSERT_MSG(linheap_memory->size() + size <= memory_region->size, "Not enough space in region to allocate shared memory!");
+
+        shared_memory->backing_block = linheap_memory;
+        shared_memory->backing_block_offset = linheap_memory->size();
+        // Allocate some memory from the end of the linear heap for this region.
+        linheap_memory->insert(linheap_memory->end(), size, 0);
+        memory_region->used += size;
+
+        shared_memory->linear_heap_phys_address = Memory::FCRAM_PADDR + memory_region->base + shared_memory->backing_block_offset;
+
+        // Increase the amount of used linear heap memory for the owner process.
+        if (shared_memory->owner_process != nullptr) {
+            shared_memory->owner_process->linear_heap_used += size;
+        }
+
+        // Refresh the address mappings for the current process.
+        if (Kernel::g_current_process != nullptr) {
+            Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
+        }
+    } else {
+        // TODO(Subv): What happens if an application tries to create multiple memory blocks pointing to the same address?
+        auto& vm_manager = shared_memory->owner_process->vm_manager;
+        // The memory is already available and mapped in the owner process.
+        auto vma = vm_manager.FindVMA(address)->second;
+        // Copy it over to our own storage
+        shared_memory->backing_block = std::make_shared<std::vector<u8>>(vma.backing_block->data() + vma.offset,
+                                                                         vma.backing_block->data() + vma.offset + size);
+        shared_memory->backing_block_offset = 0;
+        // Unmap the existing pages
+        vm_manager.UnmapRange(address, size);
+        // Map our own block into the address space
+        vm_manager.MapMemoryBlock(address, shared_memory->backing_block, 0, size, MemoryState::Shared);
+        // Reprotect the block with the new permissions
+        vm_manager.ReprotectRange(address, size, ConvertPermissions(permissions));
+    }
+
+    shared_memory->base_address = address;
     return shared_memory;
 }
 
-ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions,
-        MemoryPermission other_permissions) {
+SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size,
+                                                      MemoryPermission permissions, MemoryPermission other_permissions, std::string name) {
+    SharedPtr<SharedMemory> shared_memory(new SharedMemory);
 
-    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);
-    }
+    shared_memory->owner_process = nullptr;
+    shared_memory->name = std::move(name);
+    shared_memory->size = size;
+    shared_memory->permissions = permissions;
+    shared_memory->other_permissions = other_permissions;
+    shared_memory->backing_block = heap_block;
+    shared_memory->backing_block_offset = offset;
+    shared_memory->base_address = Memory::HEAP_VADDR + offset;
 
-    // TODO(Subv): Return E0E01BEE when permissions and other_permissions don't
-    // match what was specified when the memory block was created.
+    return shared_memory;
+}
 
-    // TODO(Subv): Return E0E01BEE when address should be 0.
-    // Note: Find out when that's the case.
+ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions,
+        MemoryPermission other_permissions) {
 
-    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);
-        }
+    MemoryPermission own_other_permissions = target_process == owner_process ? this->permissions : this->other_permissions;
 
-        // 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;
+    // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare
+    if (base_address == 0 && other_permissions != MemoryPermission::DontCare) {
+        return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
     }
 
-    if (address < Memory::SHARED_MEMORY_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) {
-        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);
+    // Error out if the requested permissions don't match what the creator process allows.
+    if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) {
+        LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
+                  GetObjectId(), address, name.c_str());
+        return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
     }
 
-    // TODO: Test permissions
+    // Heap-backed memory blocks can not be mapped with other_permissions = DontCare
+    if (base_address != 0 && other_permissions == MemoryPermission::DontCare) {
+        LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
+                  GetObjectId(), address, name.c_str());
+        return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+    }
 
-    // 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);
+    // Error out if the provided permissions are not compatible with what the creator process needs.
+    if (other_permissions != MemoryPermission::DontCare &&
+        static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) {
+        LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
+                  GetObjectId(), address, name.c_str());
+        return ResultCode(ErrorDescription::WrongPermission, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
     }
 
-    this->base_address = address;
+    // TODO(Subv): Check for the Shared Device Mem flag in the creator process.
+    /*if (was_created_with_shared_device_mem && address != 0) {
+        return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+    }*/
 
-    return RESULT_SUCCESS;
-}
+    // TODO(Subv): The same process that created a SharedMemory object
+    // can not map it in its own address space unless it was created with addr=0, result 0xD900182C.
 
-ResultCode SharedMemory::Unmap(VAddr address) {
-    if (base_address == 0) {
-        // TODO(Subv): Verify what actually happens when you want to unmap a memory block that
-        // was originally mapped with address = 0
-        return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+    if (address != 0) {
+        if (address < Memory::HEAP_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) {
+            LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, invalid address",
+                      GetObjectId(), address, name.c_str());
+            return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
+                              ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+        }
     }
 
-    if (base_address != address)
-        return ResultCode(ErrorDescription::WrongAddress, ErrorModule::OS, ErrorSummary::InvalidState, ErrorLevel::Usage);
+    VAddr target_address = address;
 
-    base_address = 0;
+    if (base_address == 0 && target_address == 0) {
+        // Calculate the address at which to map the memory block.
+        target_address = Memory::PhysicalToVirtualAddress(linear_heap_phys_address);
+    }
+
+    // Map the memory block into the target process
+    auto result = target_process->vm_manager.MapMemoryBlock(target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
+    if (result.Failed()) {
+        LOG_ERROR(Kernel, "cannot map id=%u, target_address=0x%08X name=%s, error mapping to virtual memory",
+                  GetObjectId(), target_address, name.c_str());
+        return result.Code();
+    }
 
-    return RESULT_SUCCESS;
+    return target_process->vm_manager.ReprotectRange(target_address, size, ConvertPermissions(permissions));
 }
 
-u8* SharedMemory::GetPointer(u32 offset) {
-    if (base_address != 0)
-        return Memory::GetPointer(base_address + offset);
+ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) {
+    // TODO(Subv): Verify what happens if the application tries to unmap an address that is not mapped to a SharedMemory.
+    return target_process->vm_manager.UnmapRange(address, size);
+}
+
+VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
+    u32 masked_permissions = static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute);
+    return static_cast<VMAPermission>(masked_permissions);
+};
 
-    LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId());
-    return nullptr;
+u8* SharedMemory::GetPointer(u32 offset) {
+    return backing_block->data() + backing_block_offset + offset;
 }
 
 } // namespace
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index b51049ad039280f3c2cf54a264738cc66708f312..0c404a9f8439eb7c18c8e2a88e8853bad3a83399 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -9,6 +9,7 @@
 #include "common/common_types.h"
 
 #include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/process.h"
 #include "core/hle/result.h"
 
 namespace Kernel {
@@ -29,14 +30,29 @@ enum class MemoryPermission : u32 {
 class SharedMemory final : public Object {
 public:
     /**
-     * Creates a shared memory object
+     * Creates a shared memory object.
+     * @param owner_process Process that created this shared memory object.
      * @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 address The address from which to map the Shared Memory.
+     * @param region If the address is 0, the shared memory will be allocated in this region of the linear heap.
      * @param name Optional object name, used for debugging purposes.
      */
-    static SharedPtr<SharedMemory> Create(u32 size, MemoryPermission permissions,
-            MemoryPermission other_permissions, std::string name = "Unknown");
+    static SharedPtr<SharedMemory> Create(SharedPtr<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.
+     * @param heap_block Heap block of the HLE applet.
+     * @param offset The offset into the heap block that the SharedMemory will map.
+     * @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> CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size,
+                                                   MemoryPermission permissions, MemoryPermission other_permissions, std::string name = "Unknown Applet");
 
     std::string GetTypeName() const override { return "SharedMemory"; }
     std::string GetName() const override { return name; }
@@ -45,19 +61,27 @@ public:
     HandleType GetHandleType() const override { return HANDLE_TYPE; }
 
     /**
-     * Maps a shared memory block to an address in system memory
+     * Converts the specified MemoryPermission into the equivalent VMAPermission.
+     * @param permission The MemoryPermission to convert.
+     */
+    static VMAPermission ConvertPermissions(MemoryPermission permission);
+
+    /**
+     * Maps a shared memory block to an address in the target process' address space
+     * @param target_process Process on which to map the memory block.
      * @param address Address in system memory to map shared memory block to
      * @param permissions Memory block map permissions (specified by SVC field)
      * @param other_permissions Memory block map other permissions (specified by SVC field)
      */
-    ResultCode Map(VAddr address, MemoryPermission permissions, MemoryPermission other_permissions);
+    ResultCode Map(Process* target_process, VAddr address, MemoryPermission permissions, MemoryPermission other_permissions);
 
     /**
      * Unmaps a shared memory block from the specified address in system memory
+     * @param target_process Process from which to umap the memory block.
      * @param address Address in system memory where the shared memory block is mapped
      * @return Result code of the unmap operation
      */
-    ResultCode Unmap(VAddr address);
+    ResultCode Unmap(Process* target_process, VAddr address);
 
     /**
     * Gets a pointer to the shared memory block
@@ -66,10 +90,16 @@ public:
     */
     u8* GetPointer(u32 offset = 0);
 
-    /// Address of shared memory block in the process.
+    /// Process that created this shared memory block.
+    SharedPtr<Process> owner_process;
+    /// Address of shared memory block in the owner process if specified.
     VAddr base_address;
-    /// Fixed address to allow mapping to. Used for blocks created from the linear heap.
-    VAddr fixed_address;
+    /// Physical address of the shared memory block in the linear heap if no address was specified during creation.
+    PAddr linear_heap_phys_address;
+    /// Backing memory for this shared memory block.
+    std::shared_ptr<std::vector<u8>> backing_block;
+    /// Offset into the backing block for this shared memory.
+    u32 backing_block_offset;
     /// 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/result.h b/src/core/hle/result.h
index 3fc1ab4eea231c78fb17c39539f5df61d7dc55ec..bfb3327ce0720451dddc0d8e5f0f5c3c5fba4c2b 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -17,6 +17,7 @@
 /// Detailed description of the error. This listing is likely incomplete.
 enum class ErrorDescription : u32 {
     Success = 0,
+    WrongPermission = 46,
     OS_InvalidBufferDescriptor = 48,
     WrongAddress = 53,
     FS_NotFound = 120,
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 6d72e818879690fa410cb3d2f9051d0e65ecc610..73fce60795669a0575c6517c68032ccbd92066ca 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -12,6 +12,7 @@
 #include "core/hle/service/apt/apt_a.h"
 #include "core/hle/service/apt/apt_s.h"
 #include "core/hle/service/apt/apt_u.h"
+#include "core/hle/service/apt/bcfnt/bcfnt.h"
 #include "core/hle/service/fs/archive.h"
 
 #include "core/hle/kernel/event.h"
@@ -22,23 +23,14 @@
 namespace Service {
 namespace APT {
 
-// Address used for shared font (as observed on HW)
-// TODO(bunnei): This is the hard-coded address where we currently dump the shared font from via
-// https://github.com/citra-emu/3dsutils. This is technically a hack, and will not work at any
-// address other than 0x18000000 due to internal pointers in the shared font dump that would need to
-// be relocated. This might be fixed by dumping the shared font @ address 0x00000000 and then
-// correctly mapping it in Citra, however we still do not understand how the mapping is determined.
-static const VAddr SHARED_FONT_VADDR = 0x18000000;
-
 /// Handle to shared memory region designated to for shared system font
 static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
+static bool shared_font_relocated = false;
 
 static Kernel::SharedPtr<Kernel::Mutex> lock;
 static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
 static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
 
-static std::shared_ptr<std::vector<u8>> shared_font;
-
 static u32 cpu_percent; ///< CPU time available to the running application
 
 /// Parameter data to be returned in the next call to Glance/ReceiveParameter
@@ -74,23 +66,25 @@ void Initialize(Service::Interface* self) {
 void GetSharedFont(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
 
-    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->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);
-        cmd_buff[1] = RESULT_SUCCESS.raw; // No error
-        cmd_buff[2] = SHARED_FONT_VADDR;
-        cmd_buff[3] = IPC::MoveHandleDesc();
-        cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom();
-    } else {
-        cmd_buff[0] = IPC::MakeHeader(0x44, 1, 0);
-        cmd_buff[1] = -1; // Generic error (not really possible to verify this on hardware)
-        LOG_ERROR(Kernel_SVC, "called, but %s has not been loaded!", SHARED_FONT);
+    // The shared font has to be relocated to the new address before being passed to the application.
+    VAddr target_address = Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address);
+    // The shared font dumped by 3dsutils (https://github.com/citra-emu/3dsutils) uses this address as base,
+    // so we relocate it from there to our real address.
+    // TODO(Subv): This address is wrong if the shared font is dumped from a n3DS,
+    // we need a way to automatically calculate the original address of the font from the file.
+    static const VAddr SHARED_FONT_VADDR = 0x18000000;
+    if (!shared_font_relocated) {
+        BCFNT::RelocateSharedFont(shared_font_mem, SHARED_FONT_VADDR, target_address);
+        shared_font_relocated = true;
     }
+    cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    // Since the SharedMemory interface doesn't provide the address at which the memory was allocated,
+    // the real APT service calculates this address by scanning the entire address space (using svcQueryMemory)
+    // and searches for an allocation of the same size as the Shared Font.
+    cmd_buff[2] = target_address;
+    cmd_buff[3] = IPC::MoveHandleDesc();
+    cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom();
 }
 
 void NotifyToWait(Service::Interface* self) {
@@ -433,14 +427,12 @@ void Init() {
     FileUtil::IOFile file(filepath, "rb");
 
     if (file.IsOpen()) {
-        // Read shared font data
-        shared_font = std::make_shared<std::vector<u8>>((size_t)file.GetSize());
-        file.ReadBytes(shared_font->data(), shared_font->size());
-
         // Create shared font memory object
         using Kernel::MemoryPermission;
-        shared_font_mem = Kernel::SharedMemory::Create(3 * 1024 * 1024, // 3MB
-                MemoryPermission::ReadWrite, MemoryPermission::Read, "APT_U:shared_font_mem");
+        shared_font_mem = Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB
+                MemoryPermission::ReadWrite, MemoryPermission::Read, 0, Kernel::MemoryRegion::SYSTEM, "APT:SharedFont");
+        // Read shared font data
+        file.ReadBytes(shared_font_mem->GetPointer(), file.GetSize());
     } else {
         LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str());
         shared_font_mem = nullptr;
@@ -459,8 +451,8 @@ void Init() {
 }
 
 void Shutdown() {
-    shared_font = nullptr;
     shared_font_mem = nullptr;
+    shared_font_relocated = false;
     lock = nullptr;
     notification_event = nullptr;
     parameter_event = nullptr;
diff --git a/src/core/hle/service/apt/bcfnt/bcfnt.cpp b/src/core/hle/service/apt/bcfnt/bcfnt.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b0d39d4a5b57abe400d90fb00005961a15aa392b
--- /dev/null
+++ b/src/core/hle/service/apt/bcfnt/bcfnt.cpp
@@ -0,0 +1,71 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/apt/bcfnt/bcfnt.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace APT {
+namespace BCFNT {
+
+void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAddr previous_address, VAddr new_address) {
+    static const u32 SharedFontStartOffset = 0x80;
+    u8* data = shared_font->GetPointer(SharedFontStartOffset);
+
+    CFNT cfnt;
+    memcpy(&cfnt, data, sizeof(cfnt));
+
+    // Advance past the header
+    data = shared_font->GetPointer(SharedFontStartOffset + cfnt.header_size);
+
+    for (unsigned block = 0; block < cfnt.num_blocks; ++block) {
+
+        u32 section_size = 0;
+        if (memcmp(data, "FINF", 4) == 0) {
+            BCFNT::FINF finf;
+            memcpy(&finf, data, sizeof(finf));
+            section_size = finf.section_size;
+
+            // Relocate the offsets in the FINF section
+            finf.cmap_offset += new_address - previous_address;
+            finf.cwdh_offset += new_address - previous_address;
+            finf.tglp_offset += new_address - previous_address;
+
+            memcpy(data, &finf, sizeof(finf));
+        } else if (memcmp(data, "CMAP", 4) == 0) {
+            BCFNT::CMAP cmap;
+            memcpy(&cmap, data, sizeof(cmap));
+            section_size = cmap.section_size;
+
+            // Relocate the offsets in the CMAP section
+            cmap.next_cmap_offset += new_address - previous_address;
+
+            memcpy(data, &cmap, sizeof(cmap));
+        } else if (memcmp(data, "CWDH", 4) == 0) {
+            BCFNT::CWDH cwdh;
+            memcpy(&cwdh, data, sizeof(cwdh));
+            section_size = cwdh.section_size;
+
+            // Relocate the offsets in the CWDH section
+            cwdh.next_cwdh_offset += new_address - previous_address;
+
+            memcpy(data, &cwdh, sizeof(cwdh));
+        } else if (memcmp(data, "TGLP", 4) == 0) {
+            BCFNT::TGLP tglp;
+            memcpy(&tglp, data, sizeof(tglp));
+            section_size = tglp.section_size;
+
+            // Relocate the offsets in the TGLP section
+            tglp.sheet_data_offset += new_address - previous_address;
+
+            memcpy(data, &tglp, sizeof(tglp));
+        }
+
+        data += section_size;
+    }
+}
+
+} // namespace BCFNT
+} // namespace APT
+} // namespace Service
\ No newline at end of file
diff --git a/src/core/hle/service/apt/bcfnt/bcfnt.h b/src/core/hle/service/apt/bcfnt/bcfnt.h
new file mode 100644
index 0000000000000000000000000000000000000000..388c6bea0e0454498258bf4aaa86ea7c7020c84b
--- /dev/null
+++ b/src/core/hle/service/apt/bcfnt/bcfnt.h
@@ -0,0 +1,87 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/swap.h"
+
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace APT {
+namespace BCFNT { ///< BCFNT Shared Font file structures
+
+struct CFNT {
+    u8 magic[4];
+    u16_le endianness;
+    u16_le header_size;
+    u32_le version;
+    u32_le file_size;
+    u32_le num_blocks;
+};
+
+struct FINF {
+    u8 magic[4];
+    u32_le section_size;
+    u8 font_type;
+    u8 line_feed;
+    u16_le alter_char_index;
+    u8 default_width[3];
+    u8 encoding;
+    u32_le tglp_offset;
+    u32_le cwdh_offset;
+    u32_le cmap_offset;
+    u8 height;
+    u8 width;
+    u8 ascent;
+    u8 reserved;
+};
+
+struct TGLP {
+    u8 magic[4];
+    u32_le section_size;
+    u8 cell_width;
+    u8 cell_height;
+    u8 baseline_position;
+    u8 max_character_width;
+    u32_le sheet_size;
+    u16_le num_sheets;
+    u16_le sheet_image_format;
+    u16_le num_columns;
+    u16_le num_rows;
+    u16_le sheet_width;
+    u16_le sheet_height;
+    u32_le sheet_data_offset;
+};
+
+struct CMAP {
+    u8 magic[4];
+    u32_le section_size;
+    u16_le code_begin;
+    u16_le code_end;
+    u16_le mapping_method;
+    u16_le reserved;
+    u32_le next_cmap_offset;
+};
+
+struct CWDH {
+    u8 magic[4];
+    u32_le section_size;
+    u16_le start_index;
+    u16_le end_index;
+    u32_le next_cwdh_offset;
+};
+
+/**
+ * Relocates the internal addresses of the BCFNT Shared Font to the new base.
+ * @param shared_font SharedMemory object that contains the Shared Font
+ * @param previous_address Previous address at which the offsets in the structure were based.
+ * @param new_address New base for the offsets in the structure.
+ */
+void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAddr previous_address, VAddr new_address);
+
+} // namespace BCFNT
+} // namespace APT
+} // namespace Service
diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp
index 6318bf2a7c0eaa96159b6058a24a3a0f9f31253e..d2bb8941cdeeea647536c7cae5a5b4c15ed9cd21 100644
--- a/src/core/hle/service/csnd_snd.cpp
+++ b/src/core/hle/service/csnd_snd.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <cstring>
+#include "common/alignment.h"
 #include "core/hle/hle.h"
 #include "core/hle/kernel/mutex.h"
 #include "core/hle/kernel/shared_memory.h"
@@ -41,14 +42,16 @@ static Kernel::SharedPtr<Kernel::Mutex> mutex = nullptr;
 void Initialize(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
 
-    shared_memory = Kernel::SharedMemory::Create(cmd_buff[1],
-            Kernel::MemoryPermission::ReadWrite,
-            Kernel::MemoryPermission::ReadWrite, "CSNDSharedMem");
+    u32 size = Common::AlignUp(cmd_buff[1], Memory::PAGE_SIZE);
+    using Kernel::MemoryPermission;
+    shared_memory = Kernel::SharedMemory::Create(nullptr, size,
+                                                 MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
+                                                 0, Kernel::MemoryRegion::BASE, "CSND:SharedMemory");
 
     mutex = Kernel::Mutex::Create(false);
 
-    cmd_buff[1] = 0;
-    cmd_buff[2] = 0x4000000;
+    cmd_buff[1] = RESULT_SUCCESS.raw;
+    cmd_buff[2] = IPC::MoveHandleDesc(2);
     cmd_buff[3] = Kernel::g_handle_table.Create(mutex).MoveFrom();
     cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).MoveFrom();
 }
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index b4c146e081b9a7f6710bec586da3eec77bdfdbd4..8ded9b09bcf36a11b0382a30d2ca9e7d93a1fa95 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -335,8 +335,9 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
     g_interrupt_event->name = "GSP_GPU::interrupt_event";
 
     using Kernel::MemoryPermission;
-    g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
-        MemoryPermission::ReadWrite, "GSPSharedMem");
+    g_shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000,
+                                                   MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
+                                                   0, Kernel::MemoryRegion::BASE, "GSP:SharedMemory");
 
     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 1053d0f40cc29bd018e08cbb3529f3f5d294fe10..d216cecb44d47bf7a9a3253b992d3ab99545f911 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -280,8 +280,9 @@ void Init() {
     AddService(new HID_SPVR_Interface);
 
     using Kernel::MemoryPermission;
-    shared_mem = SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
-            MemoryPermission::Read, "HID:SharedMem");
+    shared_mem = SharedMemory::Create(nullptr, 0x1000,
+                                      MemoryPermission::ReadWrite, MemoryPermission::Read,
+                                      0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
 
     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 505c441c6f7a09ae0af1393070c98b5a735a055c..079a87e4863f0fdb5d341424dcf423eb6fe437a6 100644
--- a/src/core/hle/service/ir/ir.cpp
+++ b/src/core/hle/service/ir/ir.cpp
@@ -94,8 +94,9 @@ void Init() {
     AddService(new IR_User_Interface);
 
     using Kernel::MemoryPermission;
-    shared_memory = SharedMemory::Create(0x1000, Kernel::MemoryPermission::ReadWrite,
-                                         Kernel::MemoryPermission::ReadWrite, "IR:SharedMemory");
+    shared_memory = SharedMemory::Create(nullptr, 0x1000,
+                                         Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::ReadWrite,
+                                         0, Kernel::MemoryRegion::BASE, "IR:SharedMemory");
     transfer_shared_memory = nullptr;
 
     // Create event handle(s)
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 60c8747f3d55b59be669311f138669087e426ce8..3a53126c170af560dc50a9f638761b98c9e5a9a7 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -99,6 +99,7 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add
     switch (operation & MEMOP_OPERATION_MASK) {
     case MEMOP_FREE:
     {
+        // TODO(Subv): What happens if an application tries to FREE a block of memory that has a SharedMemory pointing to it?
         if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) {
             ResultCode result = process.HeapFree(addr0, size);
             if (result.IsError()) return result;
@@ -160,8 +161,6 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o
     LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
         handle, addr, permissions, other_permissions);
 
-    // TODO(Subv): The same process that created a SharedMemory object can not map it in its own address space
-
     SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle);
     if (shared_memory == nullptr)
         return ERR_INVALID_HANDLE;
@@ -176,7 +175,7 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o
     case MemoryPermission::WriteExecute:
     case MemoryPermission::ReadWriteExecute:
     case MemoryPermission::DontCare:
-        return shared_memory->Map(addr, permissions_type,
+        return shared_memory->Map(Kernel::g_current_process.get(), addr, permissions_type,
                 static_cast<MemoryPermission>(other_permissions));
     default:
         LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions);
@@ -196,7 +195,7 @@ static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) {
     if (shared_memory == nullptr)
         return ERR_INVALID_HANDLE;
 
-    return shared_memory->Unmap(addr);
+    return shared_memory->Unmap(Kernel::g_current_process.get(), addr);
 }
 
 /// Connect to an OS service given the port name, returns the handle to the port to out
@@ -790,18 +789,44 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
     if (size % Memory::PAGE_SIZE != 0)
         return ResultCode(ErrorDescription::MisalignedSize, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
 
-    // TODO(Subv): Return E0A01BF5 if the address is not in the application's heap
-
-    // TODO(Subv): Implement this function properly
+    SharedPtr<SharedMemory> shared_memory = nullptr;
 
     using Kernel::MemoryPermission;
-    SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size,
-            (MemoryPermission)my_permission, (MemoryPermission)other_permission);
-    // Map the SharedMemory to the specified address
-    shared_memory->base_address = addr;
+    auto VerifyPermissions = [](MemoryPermission permission) {
+        // SharedMemory blocks can not be created with Execute permissions
+        switch (permission) {
+        case MemoryPermission::None:
+        case MemoryPermission::Read:
+        case MemoryPermission::Write:
+        case MemoryPermission::ReadWrite:
+        case MemoryPermission::DontCare:
+            return true;
+        default:
+            return false;
+        }
+    };
+
+    if (!VerifyPermissions(static_cast<MemoryPermission>(my_permission)) ||
+        !VerifyPermissions(static_cast<MemoryPermission>(other_permission)))
+        return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS,
+                          ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+
+    if (addr < Memory::PROCESS_IMAGE_VADDR || addr + size > Memory::SHARED_MEMORY_VADDR_END) {
+        return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+    }
+
+    // When trying to create a memory block with address = 0,
+    // if the process has the Shared Device Memory flag in the exheader,
+    // then we have to allocate from the same region as the caller process instead of the BASE region.
+    Kernel::MemoryRegion region = Kernel::MemoryRegion::BASE;
+    if (addr == 0 && Kernel::g_current_process->flags.shared_device_mem)
+        region = Kernel::g_current_process->flags.memory_region;
+
+    shared_memory = SharedMemory::Create(Kernel::g_current_process, size,
+                                static_cast<MemoryPermission>(my_permission), static_cast<MemoryPermission>(other_permission), addr, region);
     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory)));
 
-    LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr);
+    LOG_WARNING(Kernel_SVC, "called addr=0x%08X", addr);
     return RESULT_SUCCESS;
 }