diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/applets/applet.h | 1 | ||||
| -rw-r--r-- | src/core/hle/applets/mii_selector.cpp | 9 | ||||
| -rw-r--r-- | src/core/hle/applets/swkbd.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/function_wrappers.h | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/shared_memory.cpp | 177 | ||||
| -rw-r--r-- | src/core/hle/kernel/shared_memory.h | 48 | ||||
| -rw-r--r-- | src/core/hle/result.h | 1 | ||||
| -rw-r--r-- | src/core/hle/service/apt/apt.cpp | 58 | ||||
| -rw-r--r-- | src/core/hle/service/apt/bcfnt/bcfnt.cpp | 71 | ||||
| -rw-r--r-- | src/core/hle/service/apt/bcfnt/bcfnt.h | 87 | ||||
| -rw-r--r-- | src/core/hle/service/csnd_snd.cpp | 13 | ||||
| -rw-r--r-- | src/core/hle/service/gsp_gpu.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/service/ir/ir.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 49 |
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 | ||
| 171 | template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() { | 171 | template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() { |
| 172 | u32 param_1 = 0; | 172 | u32 param_1 = 0; |
| 173 | u32 retval = func(¶m_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(¶m_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. |
| 109 | static MemoryArea memory_areas[] = { | 109 | static 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 | ||
| 12 | namespace Kernel { | 13 | namespace Kernel { |
| @@ -14,93 +15,157 @@ namespace Kernel { | |||
| 14 | SharedMemory::SharedMemory() {} | 15 | SharedMemory::SharedMemory() {} |
| 15 | SharedMemory::~SharedMemory() {} | 16 | SharedMemory::~SharedMemory() {} |
| 16 | 17 | ||
| 17 | SharedPtr<SharedMemory> SharedMemory::Create(u32 size, MemoryPermission permissions, | 18 | SharedPtr<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 | ||
| 31 | ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, | 74 | SharedPtr<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. | 90 | ResultCode 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 | ||
| 83 | ResultCode 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 | ||
| 98 | u8* SharedMemory::GetPointer(u32 offset) { | 157 | ResultCode 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 | |||
| 162 | VMAPermission 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()); | 167 | u8* 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 | ||
| 14 | namespace Kernel { | 15 | namespace Kernel { |
| @@ -29,14 +30,29 @@ enum class MemoryPermission : u32 { | |||
| 29 | class SharedMemory final : public Object { | 30 | class SharedMemory final : public Object { |
| 30 | public: | 31 | public: |
| 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. |
| 18 | enum class ErrorDescription : u32 { | 18 | enum 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 @@ | |||
| 22 | namespace Service { | 23 | namespace Service { |
| 23 | namespace APT { | 24 | namespace 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. | ||
| 31 | static 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 |
| 34 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; | 27 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; |
| 28 | static bool shared_font_relocated = false; | ||
| 35 | 29 | ||
| 36 | static Kernel::SharedPtr<Kernel::Mutex> lock; | 30 | static Kernel::SharedPtr<Kernel::Mutex> lock; |
| 37 | static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event | 31 | static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event |
| 38 | static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event | 32 | static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event |
| 39 | 33 | ||
| 40 | static std::shared_ptr<std::vector<u8>> shared_font; | ||
| 41 | |||
| 42 | static u32 cpu_percent; ///< CPU time available to the running application | 34 | static 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) { | |||
| 74 | void GetSharedFont(Service::Interface* self) { | 66 | void 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 | ||
| 96 | void NotifyToWait(Service::Interface* self) { | 90 | void 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 | ||
| 461 | void Shutdown() { | 453 | void 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 | |||
| 8 | namespace Service { | ||
| 9 | namespace APT { | ||
| 10 | namespace BCFNT { | ||
| 11 | |||
| 12 | void 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 | |||
| 12 | namespace Service { | ||
| 13 | namespace APT { | ||
| 14 | namespace BCFNT { ///< BCFNT Shared Font file structures | ||
| 15 | |||
| 16 | struct 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 | |||
| 25 | struct 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 | |||
| 42 | struct 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 | |||
| 59 | struct 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 | |||
| 69 | struct 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 | */ | ||
| 83 | void 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; | |||
| 41 | void Initialize(Service::Interface* self) { | 42 | void 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 | ||