summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2016-05-13 15:33:44 -0400
committerGravatar bunnei2016-05-13 15:33:44 -0400
commit18b517e236b7f6710567e57dab6a7c5329db948f (patch)
tree5257e9ace394fa6062768c27b95e807df87c61b2 /src
parentMerge pull request #1788 from MerryMage/ext-soundtouch (diff)
parentHLE/Applets: Give each applet its own block of heap memory, and use that when... (diff)
downloadyuzu-18b517e236b7f6710567e57dab6a7c5329db948f.tar.gz
yuzu-18b517e236b7f6710567e57dab6a7c5329db948f.tar.xz
yuzu-18b517e236b7f6710567e57dab6a7c5329db948f.zip
Merge pull request #1689 from Subv/shmem
Kernel: Implemented shared memory.
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/applets/applet.h1
-rw-r--r--src/core/hle/applets/mii_selector.cpp9
-rw-r--r--src/core/hle/applets/swkbd.cpp8
-rw-r--r--src/core/hle/function_wrappers.h3
-rw-r--r--src/core/hle/kernel/memory.cpp1
-rw-r--r--src/core/hle/kernel/process.cpp2
-rw-r--r--src/core/hle/kernel/shared_memory.cpp177
-rw-r--r--src/core/hle/kernel/shared_memory.h48
-rw-r--r--src/core/hle/result.h1
-rw-r--r--src/core/hle/service/apt/apt.cpp58
-rw-r--r--src/core/hle/service/apt/bcfnt/bcfnt.cpp71
-rw-r--r--src/core/hle/service/apt/bcfnt/bcfnt.h87
-rw-r--r--src/core/hle/service/csnd_snd.cpp13
-rw-r--r--src/core/hle/service/gsp_gpu.cpp5
-rw-r--r--src/core/hle/service/hid/hid.cpp5
-rw-r--r--src/core/hle/service/ir/ir.cpp5
-rw-r--r--src/core/hle/svc.cpp49
18 files changed, 417 insertions, 128 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index a8d891689..f6a7566bf 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -52,6 +52,7 @@ set(SRCS
52 hle/service/apt/apt_a.cpp 52 hle/service/apt/apt_a.cpp
53 hle/service/apt/apt_s.cpp 53 hle/service/apt/apt_s.cpp
54 hle/service/apt/apt_u.cpp 54 hle/service/apt/apt_u.cpp
55 hle/service/apt/bcfnt/bcfnt.cpp
55 hle/service/boss/boss.cpp 56 hle/service/boss/boss.cpp
56 hle/service/boss/boss_p.cpp 57 hle/service/boss/boss_p.cpp
57 hle/service/boss/boss_u.cpp 58 hle/service/boss/boss_u.cpp
@@ -185,6 +186,7 @@ set(HEADERS
185 hle/service/apt/apt_a.h 186 hle/service/apt/apt_a.h
186 hle/service/apt/apt_s.h 187 hle/service/apt/apt_s.h
187 hle/service/apt/apt_u.h 188 hle/service/apt/apt_u.h
189 hle/service/apt/bcfnt/bcfnt.h
188 hle/service/boss/boss.h 190 hle/service/boss/boss.h
189 hle/service/boss/boss_p.h 191 hle/service/boss/boss_p.h
190 hle/service/boss/boss_u.h 192 hle/service/boss/boss_u.h
diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h
index af442f81d..754c6f7db 100644
--- a/src/core/hle/applets/applet.h
+++ b/src/core/hle/applets/applet.h
@@ -65,6 +65,7 @@ protected:
65 virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0; 65 virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0;
66 66
67 Service::APT::AppletId id; ///< Id of this Applet 67 Service::APT::AppletId id; ///< Id of this Applet
68 std::shared_ptr<std::vector<u8>> heap_memory; ///< Heap memory for this Applet
68}; 69};
69 70
70/// Returns whether a library applet is currently running 71/// 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 b4456ca90..bf39eca22 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
35 ASSERT(sizeof(capture_info) == parameter.buffer_size); 35 ASSERT(sizeof(capture_info) == parameter.buffer_size);
36 36
37 memcpy(&capture_info, parameter.data, sizeof(capture_info)); 37 memcpy(&capture_info, parameter.data, sizeof(capture_info));
38
38 using Kernel::MemoryPermission; 39 using Kernel::MemoryPermission;
39 framebuffer_memory = Kernel::SharedMemory::Create(capture_info.size, MemoryPermission::ReadWrite, 40 // Allocate a heap block of the required size for this applet.
40 MemoryPermission::ReadWrite, "MiiSelector Memory"); 41 heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
42 // Create a SharedMemory that directly points to this heap block.
43 framebuffer_memory = Kernel::SharedMemory::CreateForApplet(heap_memory, 0, heap_memory->size(),
44 MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
45 "MiiSelector Memory");
41 46
42 // Send the response message with the newly created SharedMemory 47 // Send the response message with the newly created SharedMemory
43 Service::APT::MessageParameter result; 48 Service::APT::MessageParameter result;
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
index 87238aa1c..90c6adc65 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
40 memcpy(&capture_info, parameter.data, sizeof(capture_info)); 40 memcpy(&capture_info, parameter.data, sizeof(capture_info));
41 41
42 using Kernel::MemoryPermission; 42 using Kernel::MemoryPermission;
43 framebuffer_memory = Kernel::SharedMemory::Create(capture_info.size, MemoryPermission::ReadWrite, 43 // Allocate a heap block of the required size for this applet.
44 MemoryPermission::ReadWrite, "SoftwareKeyboard Memory"); 44 heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
45 // Create a SharedMemory that directly points to this heap block.
46 framebuffer_memory = Kernel::SharedMemory::CreateForApplet(heap_memory, 0, heap_memory->size(),
47 MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
48 "SoftwareKeyboard Memory");
45 49
46 // Send the response message with the newly created SharedMemory 50 // Send the response message with the newly created SharedMemory
47 Service::APT::MessageParameter result; 51 Service::APT::MessageParameter result;
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 4d718b681..bf7f875b6 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() {
170 170
171template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() { 171template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() {
172 u32 param_1 = 0; 172 u32 param_1 = 0;
173 u32 retval = func(&param_1, PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw; 173 // The last parameter is passed in R0 instead of R4
174 u32 retval = func(&param_1, PARAM(1), PARAM(2), PARAM(3), PARAM(0)).raw;
174 Core::g_app_core->SetReg(1, param_1); 175 Core::g_app_core->SetReg(1, param_1);
175 FuncReturn(retval); 176 FuncReturn(retval);
176} 177}
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp
index 61a741e28..4be20db22 100644
--- a/src/core/hle/kernel/memory.cpp
+++ b/src/core/hle/kernel/memory.cpp
@@ -107,7 +107,6 @@ struct MemoryArea {
107 107
108// We don't declare the IO regions in here since its handled by other means. 108// We don't declare the IO regions in here since its handled by other means.
109static MemoryArea memory_areas[] = { 109static MemoryArea memory_areas[] = {
110 {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory
111 {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM) 110 {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM)
112}; 111};
113 112
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 0546f6e16..69302cc82 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
209 return ERR_INVALID_ADDRESS; 209 return ERR_INVALID_ADDRESS;
210 } 210 }
211 211
212 // Expansion of the linear heap is only allowed if you do an allocation immediatelly at its 212 // Expansion of the linear heap is only allowed if you do an allocation immediately at its
213 // end. It's possible to free gaps in the middle of the heap and then reallocate them later, 213 // end. It's possible to free gaps in the middle of the heap and then reallocate them later,
214 // but expansions are only allowed at the end. 214 // but expansions are only allowed at the end.
215 if (target == heap_end) { 215 if (target == heap_end) {
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index d90f0f00f..6a22c8986 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -7,6 +7,7 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8 8
9#include "core/memory.h" 9#include "core/memory.h"
10#include "core/hle/kernel/memory.h"
10#include "core/hle/kernel/shared_memory.h" 11#include "core/hle/kernel/shared_memory.h"
11 12
12namespace Kernel { 13namespace Kernel {
@@ -14,93 +15,157 @@ namespace Kernel {
14SharedMemory::SharedMemory() {} 15SharedMemory::SharedMemory() {}
15SharedMemory::~SharedMemory() {} 16SharedMemory::~SharedMemory() {}
16 17
17SharedPtr<SharedMemory> SharedMemory::Create(u32 size, MemoryPermission permissions, 18SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions,
18 MemoryPermission other_permissions, std::string name) { 19 MemoryPermission other_permissions, VAddr address, MemoryRegion region, std::string name) {
19 SharedPtr<SharedMemory> shared_memory(new SharedMemory); 20 SharedPtr<SharedMemory> shared_memory(new SharedMemory);
20 21
22 shared_memory->owner_process = owner_process;
21 shared_memory->name = std::move(name); 23 shared_memory->name = std::move(name);
22 shared_memory->base_address = 0x0;
23 shared_memory->fixed_address = 0x0;
24 shared_memory->size = size; 24 shared_memory->size = size;
25 shared_memory->permissions = permissions; 25 shared_memory->permissions = permissions;
26 shared_memory->other_permissions = other_permissions; 26 shared_memory->other_permissions = other_permissions;
27 27
28 if (address == 0) {
29 // We need to allocate a block from the Linear Heap ourselves.
30 // We'll manually allocate some memory from the linear heap in the specified region.
31 MemoryRegionInfo* memory_region = GetMemoryRegion(region);
32 auto& linheap_memory = memory_region->linear_heap_memory;
33
34 ASSERT_MSG(linheap_memory->size() + size <= memory_region->size, "Not enough space in region to allocate shared memory!");
35
36 shared_memory->backing_block = linheap_memory;
37 shared_memory->backing_block_offset = linheap_memory->size();
38 // Allocate some memory from the end of the linear heap for this region.
39 linheap_memory->insert(linheap_memory->end(), size, 0);
40 memory_region->used += size;
41
42 shared_memory->linear_heap_phys_address = Memory::FCRAM_PADDR + memory_region->base + shared_memory->backing_block_offset;
43
44 // Increase the amount of used linear heap memory for the owner process.
45 if (shared_memory->owner_process != nullptr) {
46 shared_memory->owner_process->linear_heap_used += size;
47 }
48
49 // Refresh the address mappings for the current process.
50 if (Kernel::g_current_process != nullptr) {
51 Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
52 }
53 } else {
54 // TODO(Subv): What happens if an application tries to create multiple memory blocks pointing to the same address?
55 auto& vm_manager = shared_memory->owner_process->vm_manager;
56 // The memory is already available and mapped in the owner process.
57 auto vma = vm_manager.FindVMA(address)->second;
58 // Copy it over to our own storage
59 shared_memory->backing_block = std::make_shared<std::vector<u8>>(vma.backing_block->data() + vma.offset,
60 vma.backing_block->data() + vma.offset + size);
61 shared_memory->backing_block_offset = 0;
62 // Unmap the existing pages
63 vm_manager.UnmapRange(address, size);
64 // Map our own block into the address space
65 vm_manager.MapMemoryBlock(address, shared_memory->backing_block, 0, size, MemoryState::Shared);
66 // Reprotect the block with the new permissions
67 vm_manager.ReprotectRange(address, size, ConvertPermissions(permissions));
68 }
69
70 shared_memory->base_address = address;
28 return shared_memory; 71 return shared_memory;
29} 72}
30 73
31ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, 74SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size,
32 MemoryPermission other_permissions) { 75 MemoryPermission permissions, MemoryPermission other_permissions, std::string name) {
76 SharedPtr<SharedMemory> shared_memory(new SharedMemory);
33 77
34 if (base_address != 0) { 78 shared_memory->owner_process = nullptr;
35 LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s: already mapped at 0x%08X!", 79 shared_memory->name = std::move(name);
36 GetObjectId(), address, name.c_str(), base_address); 80 shared_memory->size = size;
37 // TODO: Verify error code with hardware 81 shared_memory->permissions = permissions;
38 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, 82 shared_memory->other_permissions = other_permissions;
39 ErrorSummary::InvalidArgument, ErrorLevel::Permanent); 83 shared_memory->backing_block = heap_block;
40 } 84 shared_memory->backing_block_offset = offset;
85 shared_memory->base_address = Memory::HEAP_VADDR + offset;
41 86
42 // TODO(Subv): Return E0E01BEE when permissions and other_permissions don't 87 return shared_memory;
43 // match what was specified when the memory block was created. 88}
44 89
45 // TODO(Subv): Return E0E01BEE when address should be 0. 90ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions,
46 // Note: Find out when that's the case. 91 MemoryPermission other_permissions) {
47 92
48 if (fixed_address != 0) { 93 MemoryPermission own_other_permissions = target_process == owner_process ? this->permissions : this->other_permissions;
49 if (address != 0 && address != fixed_address) {
50 LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s: fixed_addres is 0x%08X!",
51 GetObjectId(), address, name.c_str(), fixed_address);
52 // TODO: Verify error code with hardware
53 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
54 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
55 }
56 94
57 // HACK(yuriks): This is only here to support the APT shared font mapping right now. 95 // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare
58 // Later, this should actually map the memory block onto the address space. 96 if (base_address == 0 && other_permissions != MemoryPermission::DontCare) {
59 return RESULT_SUCCESS; 97 return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
60 } 98 }
61 99
62 if (address < Memory::SHARED_MEMORY_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) { 100 // Error out if the requested permissions don't match what the creator process allows.
63 LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s outside of shared mem bounds!", 101 if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) {
64 GetObjectId(), address, name.c_str()); 102 LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
65 // TODO: Verify error code with hardware 103 GetObjectId(), address, name.c_str());
66 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, 104 return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
67 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
68 } 105 }
69 106
70 // TODO: Test permissions 107 // Heap-backed memory blocks can not be mapped with other_permissions = DontCare
108 if (base_address != 0 && other_permissions == MemoryPermission::DontCare) {
109 LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
110 GetObjectId(), address, name.c_str());
111 return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
112 }
71 113
72 // HACK: Since there's no way to write to the memory block without mapping it onto the game 114 // Error out if the provided permissions are not compatible with what the creator process needs.
73 // process yet, at least initialize memory the first time it's mapped. 115 if (other_permissions != MemoryPermission::DontCare &&
74 if (address != this->base_address) { 116 static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) {
75 std::memset(Memory::GetPointer(address), 0, size); 117 LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
118 GetObjectId(), address, name.c_str());
119 return ResultCode(ErrorDescription::WrongPermission, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
76 } 120 }
77 121
78 this->base_address = address; 122 // TODO(Subv): Check for the Shared Device Mem flag in the creator process.
123 /*if (was_created_with_shared_device_mem && address != 0) {
124 return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
125 }*/
79 126
80 return RESULT_SUCCESS; 127 // TODO(Subv): The same process that created a SharedMemory object
81} 128 // can not map it in its own address space unless it was created with addr=0, result 0xD900182C.
82 129
83ResultCode SharedMemory::Unmap(VAddr address) { 130 if (address != 0) {
84 if (base_address == 0) { 131 if (address < Memory::HEAP_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) {
85 // TODO(Subv): Verify what actually happens when you want to unmap a memory block that 132 LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, invalid address",
86 // was originally mapped with address = 0 133 GetObjectId(), address, name.c_str());
87 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); 134 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
135 ErrorSummary::InvalidArgument, ErrorLevel::Usage);
136 }
88 } 137 }
89 138
90 if (base_address != address) 139 VAddr target_address = address;
91 return ResultCode(ErrorDescription::WrongAddress, ErrorModule::OS, ErrorSummary::InvalidState, ErrorLevel::Usage);
92 140
93 base_address = 0; 141 if (base_address == 0 && target_address == 0) {
142 // Calculate the address at which to map the memory block.
143 target_address = Memory::PhysicalToVirtualAddress(linear_heap_phys_address);
144 }
145
146 // Map the memory block into the target process
147 auto result = target_process->vm_manager.MapMemoryBlock(target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
148 if (result.Failed()) {
149 LOG_ERROR(Kernel, "cannot map id=%u, target_address=0x%08X name=%s, error mapping to virtual memory",
150 GetObjectId(), target_address, name.c_str());
151 return result.Code();
152 }
94 153
95 return RESULT_SUCCESS; 154 return target_process->vm_manager.ReprotectRange(target_address, size, ConvertPermissions(permissions));
96} 155}
97 156
98u8* SharedMemory::GetPointer(u32 offset) { 157ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) {
99 if (base_address != 0) 158 // TODO(Subv): Verify what happens if the application tries to unmap an address that is not mapped to a SharedMemory.
100 return Memory::GetPointer(base_address + offset); 159 return target_process->vm_manager.UnmapRange(address, size);
160}
161
162VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
163 u32 masked_permissions = static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute);
164 return static_cast<VMAPermission>(masked_permissions);
165};
101 166
102 LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId()); 167u8* SharedMemory::GetPointer(u32 offset) {
103 return nullptr; 168 return backing_block->data() + backing_block_offset + offset;
104} 169}
105 170
106} // namespace 171} // namespace
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index b51049ad0..0c404a9f8 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -9,6 +9,7 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10 10
11#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/process.h"
12#include "core/hle/result.h" 13#include "core/hle/result.h"
13 14
14namespace Kernel { 15namespace Kernel {
@@ -29,14 +30,29 @@ enum class MemoryPermission : u32 {
29class SharedMemory final : public Object { 30class SharedMemory final : public Object {
30public: 31public:
31 /** 32 /**
32 * Creates a shared memory object 33 * Creates a shared memory object.
34 * @param owner_process Process that created this shared memory object.
33 * @param size Size of the memory block. Must be page-aligned. 35 * @param size Size of the memory block. Must be page-aligned.
34 * @param permissions Permission restrictions applied to the process which created the block. 36 * @param permissions Permission restrictions applied to the process which created the block.
35 * @param other_permissions Permission restrictions applied to other processes mapping the block. 37 * @param other_permissions Permission restrictions applied to other processes mapping the block.
38 * @param address The address from which to map the Shared Memory.
39 * @param region If the address is 0, the shared memory will be allocated in this region of the linear heap.
36 * @param name Optional object name, used for debugging purposes. 40 * @param name Optional object name, used for debugging purposes.
37 */ 41 */
38 static SharedPtr<SharedMemory> Create(u32 size, MemoryPermission permissions, 42 static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions,
39 MemoryPermission other_permissions, std::string name = "Unknown"); 43 MemoryPermission other_permissions, VAddr address = 0, MemoryRegion region = MemoryRegion::BASE, std::string name = "Unknown");
44
45 /**
46 * Creates a shared memory object from a block of memory managed by an HLE applet.
47 * @param heap_block Heap block of the HLE applet.
48 * @param offset The offset into the heap block that the SharedMemory will map.
49 * @param size Size of the memory block. Must be page-aligned.
50 * @param permissions Permission restrictions applied to the process which created the block.
51 * @param other_permissions Permission restrictions applied to other processes mapping the block.
52 * @param name Optional object name, used for debugging purposes.
53 */
54 static SharedPtr<SharedMemory> CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size,
55 MemoryPermission permissions, MemoryPermission other_permissions, std::string name = "Unknown Applet");
40 56
41 std::string GetTypeName() const override { return "SharedMemory"; } 57 std::string GetTypeName() const override { return "SharedMemory"; }
42 std::string GetName() const override { return name; } 58 std::string GetName() const override { return name; }
@@ -45,19 +61,27 @@ public:
45 HandleType GetHandleType() const override { return HANDLE_TYPE; } 61 HandleType GetHandleType() const override { return HANDLE_TYPE; }
46 62
47 /** 63 /**
48 * Maps a shared memory block to an address in system memory 64 * Converts the specified MemoryPermission into the equivalent VMAPermission.
65 * @param permission The MemoryPermission to convert.
66 */
67 static VMAPermission ConvertPermissions(MemoryPermission permission);
68
69 /**
70 * Maps a shared memory block to an address in the target process' address space
71 * @param target_process Process on which to map the memory block.
49 * @param address Address in system memory to map shared memory block to 72 * @param address Address in system memory to map shared memory block to
50 * @param permissions Memory block map permissions (specified by SVC field) 73 * @param permissions Memory block map permissions (specified by SVC field)
51 * @param other_permissions Memory block map other permissions (specified by SVC field) 74 * @param other_permissions Memory block map other permissions (specified by SVC field)
52 */ 75 */
53 ResultCode Map(VAddr address, MemoryPermission permissions, MemoryPermission other_permissions); 76 ResultCode Map(Process* target_process, VAddr address, MemoryPermission permissions, MemoryPermission other_permissions);
54 77
55 /** 78 /**
56 * Unmaps a shared memory block from the specified address in system memory 79 * Unmaps a shared memory block from the specified address in system memory
80 * @param target_process Process from which to umap the memory block.
57 * @param address Address in system memory where the shared memory block is mapped 81 * @param address Address in system memory where the shared memory block is mapped
58 * @return Result code of the unmap operation 82 * @return Result code of the unmap operation
59 */ 83 */
60 ResultCode Unmap(VAddr address); 84 ResultCode Unmap(Process* target_process, VAddr address);
61 85
62 /** 86 /**
63 * Gets a pointer to the shared memory block 87 * Gets a pointer to the shared memory block
@@ -66,10 +90,16 @@ public:
66 */ 90 */
67 u8* GetPointer(u32 offset = 0); 91 u8* GetPointer(u32 offset = 0);
68 92
69 /// Address of shared memory block in the process. 93 /// Process that created this shared memory block.
94 SharedPtr<Process> owner_process;
95 /// Address of shared memory block in the owner process if specified.
70 VAddr base_address; 96 VAddr base_address;
71 /// Fixed address to allow mapping to. Used for blocks created from the linear heap. 97 /// Physical address of the shared memory block in the linear heap if no address was specified during creation.
72 VAddr fixed_address; 98 PAddr linear_heap_phys_address;
99 /// Backing memory for this shared memory block.
100 std::shared_ptr<std::vector<u8>> backing_block;
101 /// Offset into the backing block for this shared memory.
102 u32 backing_block_offset;
73 /// Size of the memory block. Page-aligned. 103 /// Size of the memory block. Page-aligned.
74 u32 size; 104 u32 size;
75 /// Permission restrictions applied to the process which created the block. 105 /// 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 3fc1ab4ee..bfb3327ce 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -17,6 +17,7 @@
17/// Detailed description of the error. This listing is likely incomplete. 17/// Detailed description of the error. This listing is likely incomplete.
18enum class ErrorDescription : u32 { 18enum class ErrorDescription : u32 {
19 Success = 0, 19 Success = 0,
20 WrongPermission = 46,
20 OS_InvalidBufferDescriptor = 48, 21 OS_InvalidBufferDescriptor = 48,
21 WrongAddress = 53, 22 WrongAddress = 53,
22 FS_NotFound = 120, 23 FS_NotFound = 120,
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 6d72e8188..73fce6079 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -12,6 +12,7 @@
12#include "core/hle/service/apt/apt_a.h" 12#include "core/hle/service/apt/apt_a.h"
13#include "core/hle/service/apt/apt_s.h" 13#include "core/hle/service/apt/apt_s.h"
14#include "core/hle/service/apt/apt_u.h" 14#include "core/hle/service/apt/apt_u.h"
15#include "core/hle/service/apt/bcfnt/bcfnt.h"
15#include "core/hle/service/fs/archive.h" 16#include "core/hle/service/fs/archive.h"
16 17
17#include "core/hle/kernel/event.h" 18#include "core/hle/kernel/event.h"
@@ -22,23 +23,14 @@
22namespace Service { 23namespace Service {
23namespace APT { 24namespace APT {
24 25
25// Address used for shared font (as observed on HW)
26// TODO(bunnei): This is the hard-coded address where we currently dump the shared font from via
27// https://github.com/citra-emu/3dsutils. This is technically a hack, and will not work at any
28// address other than 0x18000000 due to internal pointers in the shared font dump that would need to
29// be relocated. This might be fixed by dumping the shared font @ address 0x00000000 and then
30// correctly mapping it in Citra, however we still do not understand how the mapping is determined.
31static const VAddr SHARED_FONT_VADDR = 0x18000000;
32
33/// Handle to shared memory region designated to for shared system font 26/// Handle to shared memory region designated to for shared system font
34static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; 27static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
28static bool shared_font_relocated = false;
35 29
36static Kernel::SharedPtr<Kernel::Mutex> lock; 30static Kernel::SharedPtr<Kernel::Mutex> lock;
37static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event 31static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
38static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event 32static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
39 33
40static std::shared_ptr<std::vector<u8>> shared_font;
41
42static u32 cpu_percent; ///< CPU time available to the running application 34static u32 cpu_percent; ///< CPU time available to the running application
43 35
44/// Parameter data to be returned in the next call to Glance/ReceiveParameter 36/// Parameter data to be returned in the next call to Glance/ReceiveParameter
@@ -74,23 +66,25 @@ void Initialize(Service::Interface* self) {
74void GetSharedFont(Service::Interface* self) { 66void GetSharedFont(Service::Interface* self) {
75 u32* cmd_buff = Kernel::GetCommandBuffer(); 67 u32* cmd_buff = Kernel::GetCommandBuffer();
76 68
77 if (shared_font != nullptr) { 69 // The shared font has to be relocated to the new address before being passed to the application.
78 // TODO(yuriks): This is a hack to keep this working right now even with our completely 70 VAddr target_address = Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address);
79 // broken shared memory system. 71 // The shared font dumped by 3dsutils (https://github.com/citra-emu/3dsutils) uses this address as base,
80 shared_font_mem->fixed_address = SHARED_FONT_VADDR; 72 // so we relocate it from there to our real address.
81 Kernel::g_current_process->vm_manager.MapMemoryBlock(shared_font_mem->fixed_address, 73 // TODO(Subv): This address is wrong if the shared font is dumped from a n3DS,
82 shared_font, 0, shared_font_mem->size, Kernel::MemoryState::Shared); 74 // we need a way to automatically calculate the original address of the font from the file.
83 75 static const VAddr SHARED_FONT_VADDR = 0x18000000;
84 cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2); 76 if (!shared_font_relocated) {
85 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 77 BCFNT::RelocateSharedFont(shared_font_mem, SHARED_FONT_VADDR, target_address);
86 cmd_buff[2] = SHARED_FONT_VADDR; 78 shared_font_relocated = true;
87 cmd_buff[3] = IPC::MoveHandleDesc();
88 cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom();
89 } else {
90 cmd_buff[0] = IPC::MakeHeader(0x44, 1, 0);
91 cmd_buff[1] = -1; // Generic error (not really possible to verify this on hardware)
92 LOG_ERROR(Kernel_SVC, "called, but %s has not been loaded!", SHARED_FONT);
93 } 79 }
80 cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
81 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
82 // Since the SharedMemory interface doesn't provide the address at which the memory was allocated,
83 // the real APT service calculates this address by scanning the entire address space (using svcQueryMemory)
84 // and searches for an allocation of the same size as the Shared Font.
85 cmd_buff[2] = target_address;
86 cmd_buff[3] = IPC::MoveHandleDesc();
87 cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom();
94} 88}
95 89
96void NotifyToWait(Service::Interface* self) { 90void NotifyToWait(Service::Interface* self) {
@@ -433,14 +427,12 @@ void Init() {
433 FileUtil::IOFile file(filepath, "rb"); 427 FileUtil::IOFile file(filepath, "rb");
434 428
435 if (file.IsOpen()) { 429 if (file.IsOpen()) {
436 // Read shared font data
437 shared_font = std::make_shared<std::vector<u8>>((size_t)file.GetSize());
438 file.ReadBytes(shared_font->data(), shared_font->size());
439
440 // Create shared font memory object 430 // Create shared font memory object
441 using Kernel::MemoryPermission; 431 using Kernel::MemoryPermission;
442 shared_font_mem = Kernel::SharedMemory::Create(3 * 1024 * 1024, // 3MB 432 shared_font_mem = Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB
443 MemoryPermission::ReadWrite, MemoryPermission::Read, "APT_U:shared_font_mem"); 433 MemoryPermission::ReadWrite, MemoryPermission::Read, 0, Kernel::MemoryRegion::SYSTEM, "APT:SharedFont");
434 // Read shared font data
435 file.ReadBytes(shared_font_mem->GetPointer(), file.GetSize());
444 } else { 436 } else {
445 LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); 437 LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str());
446 shared_font_mem = nullptr; 438 shared_font_mem = nullptr;
@@ -459,8 +451,8 @@ void Init() {
459} 451}
460 452
461void Shutdown() { 453void Shutdown() {
462 shared_font = nullptr;
463 shared_font_mem = nullptr; 454 shared_font_mem = nullptr;
455 shared_font_relocated = false;
464 lock = nullptr; 456 lock = nullptr;
465 notification_event = nullptr; 457 notification_event = nullptr;
466 parameter_event = nullptr; 458 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 000000000..b0d39d4a5
--- /dev/null
+++ b/src/core/hle/service/apt/bcfnt/bcfnt.cpp
@@ -0,0 +1,71 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/service/apt/bcfnt/bcfnt.h"
6#include "core/hle/service/service.h"
7
8namespace Service {
9namespace APT {
10namespace BCFNT {
11
12void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAddr previous_address, VAddr new_address) {
13 static const u32 SharedFontStartOffset = 0x80;
14 u8* data = shared_font->GetPointer(SharedFontStartOffset);
15
16 CFNT cfnt;
17 memcpy(&cfnt, data, sizeof(cfnt));
18
19 // Advance past the header
20 data = shared_font->GetPointer(SharedFontStartOffset + cfnt.header_size);
21
22 for (unsigned block = 0; block < cfnt.num_blocks; ++block) {
23
24 u32 section_size = 0;
25 if (memcmp(data, "FINF", 4) == 0) {
26 BCFNT::FINF finf;
27 memcpy(&finf, data, sizeof(finf));
28 section_size = finf.section_size;
29
30 // Relocate the offsets in the FINF section
31 finf.cmap_offset += new_address - previous_address;
32 finf.cwdh_offset += new_address - previous_address;
33 finf.tglp_offset += new_address - previous_address;
34
35 memcpy(data, &finf, sizeof(finf));
36 } else if (memcmp(data, "CMAP", 4) == 0) {
37 BCFNT::CMAP cmap;
38 memcpy(&cmap, data, sizeof(cmap));
39 section_size = cmap.section_size;
40
41 // Relocate the offsets in the CMAP section
42 cmap.next_cmap_offset += new_address - previous_address;
43
44 memcpy(data, &cmap, sizeof(cmap));
45 } else if (memcmp(data, "CWDH", 4) == 0) {
46 BCFNT::CWDH cwdh;
47 memcpy(&cwdh, data, sizeof(cwdh));
48 section_size = cwdh.section_size;
49
50 // Relocate the offsets in the CWDH section
51 cwdh.next_cwdh_offset += new_address - previous_address;
52
53 memcpy(data, &cwdh, sizeof(cwdh));
54 } else if (memcmp(data, "TGLP", 4) == 0) {
55 BCFNT::TGLP tglp;
56 memcpy(&tglp, data, sizeof(tglp));
57 section_size = tglp.section_size;
58
59 // Relocate the offsets in the TGLP section
60 tglp.sheet_data_offset += new_address - previous_address;
61
62 memcpy(data, &tglp, sizeof(tglp));
63 }
64
65 data += section_size;
66 }
67}
68
69} // namespace BCFNT
70} // namespace APT
71} // 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 000000000..388c6bea0
--- /dev/null
+++ b/src/core/hle/service/apt/bcfnt/bcfnt.h
@@ -0,0 +1,87 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/swap.h"
8
9#include "core/hle/kernel/shared_memory.h"
10#include "core/hle/service/service.h"
11
12namespace Service {
13namespace APT {
14namespace BCFNT { ///< BCFNT Shared Font file structures
15
16struct CFNT {
17 u8 magic[4];
18 u16_le endianness;
19 u16_le header_size;
20 u32_le version;
21 u32_le file_size;
22 u32_le num_blocks;
23};
24
25struct FINF {
26 u8 magic[4];
27 u32_le section_size;
28 u8 font_type;
29 u8 line_feed;
30 u16_le alter_char_index;
31 u8 default_width[3];
32 u8 encoding;
33 u32_le tglp_offset;
34 u32_le cwdh_offset;
35 u32_le cmap_offset;
36 u8 height;
37 u8 width;
38 u8 ascent;
39 u8 reserved;
40};
41
42struct TGLP {
43 u8 magic[4];
44 u32_le section_size;
45 u8 cell_width;
46 u8 cell_height;
47 u8 baseline_position;
48 u8 max_character_width;
49 u32_le sheet_size;
50 u16_le num_sheets;
51 u16_le sheet_image_format;
52 u16_le num_columns;
53 u16_le num_rows;
54 u16_le sheet_width;
55 u16_le sheet_height;
56 u32_le sheet_data_offset;
57};
58
59struct CMAP {
60 u8 magic[4];
61 u32_le section_size;
62 u16_le code_begin;
63 u16_le code_end;
64 u16_le mapping_method;
65 u16_le reserved;
66 u32_le next_cmap_offset;
67};
68
69struct CWDH {
70 u8 magic[4];
71 u32_le section_size;
72 u16_le start_index;
73 u16_le end_index;
74 u32_le next_cwdh_offset;
75};
76
77/**
78 * Relocates the internal addresses of the BCFNT Shared Font to the new base.
79 * @param shared_font SharedMemory object that contains the Shared Font
80 * @param previous_address Previous address at which the offsets in the structure were based.
81 * @param new_address New base for the offsets in the structure.
82 */
83void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAddr previous_address, VAddr new_address);
84
85} // namespace BCFNT
86} // namespace APT
87} // namespace Service
diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp
index 6318bf2a7..d2bb8941c 100644
--- a/src/core/hle/service/csnd_snd.cpp
+++ b/src/core/hle/service/csnd_snd.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring> 5#include <cstring>
6#include "common/alignment.h"
6#include "core/hle/hle.h" 7#include "core/hle/hle.h"
7#include "core/hle/kernel/mutex.h" 8#include "core/hle/kernel/mutex.h"
8#include "core/hle/kernel/shared_memory.h" 9#include "core/hle/kernel/shared_memory.h"
@@ -41,14 +42,16 @@ static Kernel::SharedPtr<Kernel::Mutex> mutex = nullptr;
41void Initialize(Service::Interface* self) { 42void Initialize(Service::Interface* self) {
42 u32* cmd_buff = Kernel::GetCommandBuffer(); 43 u32* cmd_buff = Kernel::GetCommandBuffer();
43 44
44 shared_memory = Kernel::SharedMemory::Create(cmd_buff[1], 45 u32 size = Common::AlignUp(cmd_buff[1], Memory::PAGE_SIZE);
45 Kernel::MemoryPermission::ReadWrite, 46 using Kernel::MemoryPermission;
46 Kernel::MemoryPermission::ReadWrite, "CSNDSharedMem"); 47 shared_memory = Kernel::SharedMemory::Create(nullptr, size,
48 MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
49 0, Kernel::MemoryRegion::BASE, "CSND:SharedMemory");
47 50
48 mutex = Kernel::Mutex::Create(false); 51 mutex = Kernel::Mutex::Create(false);
49 52
50 cmd_buff[1] = 0; 53 cmd_buff[1] = RESULT_SUCCESS.raw;
51 cmd_buff[2] = 0x4000000; 54 cmd_buff[2] = IPC::MoveHandleDesc(2);
52 cmd_buff[3] = Kernel::g_handle_table.Create(mutex).MoveFrom(); 55 cmd_buff[3] = Kernel::g_handle_table.Create(mutex).MoveFrom();
53 cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).MoveFrom(); 56 cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).MoveFrom();
54} 57}
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index b4c146e08..8ded9b09b 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) {
335 g_interrupt_event->name = "GSP_GPU::interrupt_event"; 335 g_interrupt_event->name = "GSP_GPU::interrupt_event";
336 336
337 using Kernel::MemoryPermission; 337 using Kernel::MemoryPermission;
338 g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, 338 g_shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000,
339 MemoryPermission::ReadWrite, "GSPSharedMem"); 339 MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
340 0, Kernel::MemoryRegion::BASE, "GSP:SharedMemory");
340 341
341 Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); 342 Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom();
342 343
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 1053d0f40..d216cecb4 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -280,8 +280,9 @@ void Init() {
280 AddService(new HID_SPVR_Interface); 280 AddService(new HID_SPVR_Interface);
281 281
282 using Kernel::MemoryPermission; 282 using Kernel::MemoryPermission;
283 shared_mem = SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, 283 shared_mem = SharedMemory::Create(nullptr, 0x1000,
284 MemoryPermission::Read, "HID:SharedMem"); 284 MemoryPermission::ReadWrite, MemoryPermission::Read,
285 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
285 286
286 next_pad_index = 0; 287 next_pad_index = 0;
287 next_touch_index = 0; 288 next_touch_index = 0;
diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp
index 505c441c6..079a87e48 100644
--- a/src/core/hle/service/ir/ir.cpp
+++ b/src/core/hle/service/ir/ir.cpp
@@ -94,8 +94,9 @@ void Init() {
94 AddService(new IR_User_Interface); 94 AddService(new IR_User_Interface);
95 95
96 using Kernel::MemoryPermission; 96 using Kernel::MemoryPermission;
97 shared_memory = SharedMemory::Create(0x1000, Kernel::MemoryPermission::ReadWrite, 97 shared_memory = SharedMemory::Create(nullptr, 0x1000,
98 Kernel::MemoryPermission::ReadWrite, "IR:SharedMemory"); 98 Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::ReadWrite,
99 0, Kernel::MemoryRegion::BASE, "IR:SharedMemory");
99 transfer_shared_memory = nullptr; 100 transfer_shared_memory = nullptr;
100 101
101 // Create event handle(s) 102 // Create event handle(s)
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 60c8747f3..3a53126c1 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
99 switch (operation & MEMOP_OPERATION_MASK) { 99 switch (operation & MEMOP_OPERATION_MASK) {
100 case MEMOP_FREE: 100 case MEMOP_FREE:
101 { 101 {
102 // TODO(Subv): What happens if an application tries to FREE a block of memory that has a SharedMemory pointing to it?
102 if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) { 103 if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) {
103 ResultCode result = process.HeapFree(addr0, size); 104 ResultCode result = process.HeapFree(addr0, size);
104 if (result.IsError()) return result; 105 if (result.IsError()) return result;
@@ -160,8 +161,6 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o
160 LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", 161 LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
161 handle, addr, permissions, other_permissions); 162 handle, addr, permissions, other_permissions);
162 163
163 // TODO(Subv): The same process that created a SharedMemory object can not map it in its own address space
164
165 SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle); 164 SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle);
166 if (shared_memory == nullptr) 165 if (shared_memory == nullptr)
167 return ERR_INVALID_HANDLE; 166 return ERR_INVALID_HANDLE;
@@ -176,7 +175,7 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o
176 case MemoryPermission::WriteExecute: 175 case MemoryPermission::WriteExecute:
177 case MemoryPermission::ReadWriteExecute: 176 case MemoryPermission::ReadWriteExecute:
178 case MemoryPermission::DontCare: 177 case MemoryPermission::DontCare:
179 return shared_memory->Map(addr, permissions_type, 178 return shared_memory->Map(Kernel::g_current_process.get(), addr, permissions_type,
180 static_cast<MemoryPermission>(other_permissions)); 179 static_cast<MemoryPermission>(other_permissions));
181 default: 180 default:
182 LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); 181 LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions);
@@ -196,7 +195,7 @@ static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) {
196 if (shared_memory == nullptr) 195 if (shared_memory == nullptr)
197 return ERR_INVALID_HANDLE; 196 return ERR_INVALID_HANDLE;
198 197
199 return shared_memory->Unmap(addr); 198 return shared_memory->Unmap(Kernel::g_current_process.get(), addr);
200} 199}
201 200
202/// Connect to an OS service given the port name, returns the handle to the port to out 201/// 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
790 if (size % Memory::PAGE_SIZE != 0) 789 if (size % Memory::PAGE_SIZE != 0)
791 return ResultCode(ErrorDescription::MisalignedSize, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); 790 return ResultCode(ErrorDescription::MisalignedSize, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
792 791
793 // TODO(Subv): Return E0A01BF5 if the address is not in the application's heap 792 SharedPtr<SharedMemory> shared_memory = nullptr;
794
795 // TODO(Subv): Implement this function properly
796 793
797 using Kernel::MemoryPermission; 794 using Kernel::MemoryPermission;
798 SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size, 795 auto VerifyPermissions = [](MemoryPermission permission) {
799 (MemoryPermission)my_permission, (MemoryPermission)other_permission); 796 // SharedMemory blocks can not be created with Execute permissions
800 // Map the SharedMemory to the specified address 797 switch (permission) {
801 shared_memory->base_address = addr; 798 case MemoryPermission::None:
799 case MemoryPermission::Read:
800 case MemoryPermission::Write:
801 case MemoryPermission::ReadWrite:
802 case MemoryPermission::DontCare:
803 return true;
804 default:
805 return false;
806 }
807 };
808
809 if (!VerifyPermissions(static_cast<MemoryPermission>(my_permission)) ||
810 !VerifyPermissions(static_cast<MemoryPermission>(other_permission)))
811 return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS,
812 ErrorSummary::InvalidArgument, ErrorLevel::Usage);
813
814 if (addr < Memory::PROCESS_IMAGE_VADDR || addr + size > Memory::SHARED_MEMORY_VADDR_END) {
815 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
816 }
817
818 // When trying to create a memory block with address = 0,
819 // if the process has the Shared Device Memory flag in the exheader,
820 // then we have to allocate from the same region as the caller process instead of the BASE region.
821 Kernel::MemoryRegion region = Kernel::MemoryRegion::BASE;
822 if (addr == 0 && Kernel::g_current_process->flags.shared_device_mem)
823 region = Kernel::g_current_process->flags.memory_region;
824
825 shared_memory = SharedMemory::Create(Kernel::g_current_process, size,
826 static_cast<MemoryPermission>(my_permission), static_cast<MemoryPermission>(other_permission), addr, region);
802 CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); 827 CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory)));
803 828
804 LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); 829 LOG_WARNING(Kernel_SVC, "called addr=0x%08X", addr);
805 return RESULT_SUCCESS; 830 return RESULT_SUCCESS;
806} 831}
807 832