diff options
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.cpp | 20 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.h | 8 | ||||
| -rw-r--r-- | src/core/hle/service/ldr/ldr.cpp | 52 | ||||
| -rw-r--r-- | src/core/loader/nro.cpp | 21 | ||||
| -rw-r--r-- | src/core/loader/nro.h | 3 |
6 files changed, 101 insertions, 9 deletions
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 073dd5a7d..420218d59 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -232,6 +232,12 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { | |||
| 232 | MapSegment(module_.CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic); | 232 | MapSegment(module_.CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic); |
| 233 | MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable); | 233 | MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable); |
| 234 | MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); | 234 | MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); |
| 235 | |||
| 236 | // Clear instruction cache in CPU JIT | ||
| 237 | Core::System::GetInstance().ArmInterface(0).ClearInstructionCache(); | ||
| 238 | Core::System::GetInstance().ArmInterface(1).ClearInstructionCache(); | ||
| 239 | Core::System::GetInstance().ArmInterface(2).ClearInstructionCache(); | ||
| 240 | Core::System::GetInstance().ArmInterface(3).ClearInstructionCache(); | ||
| 235 | } | 241 | } |
| 236 | 242 | ||
| 237 | ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { | 243 | ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { |
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index e1a34eef1..1a92c8f70 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -143,6 +143,26 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me | |||
| 143 | return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); | 143 | return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | ResultVal<VAddr> VMManager::FindFreeRegion(u64 size) const { | ||
| 147 | // Find the first Free VMA. | ||
| 148 | const VAddr base = GetASLRRegionBaseAddress(); | ||
| 149 | const VMAHandle vma_handle = std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) { | ||
| 150 | if (vma.second.type != VMAType::Free) | ||
| 151 | return false; | ||
| 152 | |||
| 153 | const VAddr vma_end = vma.second.base + vma.second.size; | ||
| 154 | return vma_end > base && vma_end >= base + size; | ||
| 155 | }); | ||
| 156 | |||
| 157 | if (vma_handle == vma_map.end()) { | ||
| 158 | // TODO(Subv): Find the correct error code here. | ||
| 159 | return ResultCode(-1); | ||
| 160 | } | ||
| 161 | |||
| 162 | const VAddr target = std::max(base, vma_handle->second.base); | ||
| 163 | return MakeResult<VAddr>(target); | ||
| 164 | } | ||
| 165 | |||
| 146 | ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u64 size, | 166 | ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u64 size, |
| 147 | MemoryState state, | 167 | MemoryState state, |
| 148 | Memory::MemoryHookPointer mmio_handler) { | 168 | Memory::MemoryHookPointer mmio_handler) { |
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 84c890224..2447cbb8f 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h | |||
| @@ -158,6 +158,14 @@ public: | |||
| 158 | ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state); | 158 | ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state); |
| 159 | 159 | ||
| 160 | /** | 160 | /** |
| 161 | * Finds the first free address that can hold a region of the desired size. | ||
| 162 | * | ||
| 163 | * @param size Size of the desired region. | ||
| 164 | * @return The found free address. | ||
| 165 | */ | ||
| 166 | ResultVal<VAddr> FindFreeRegion(u64 size) const; | ||
| 167 | |||
| 168 | /** | ||
| 161 | * Maps a memory-mapped IO region at a given address. | 169 | * Maps a memory-mapped IO region at a given address. |
| 162 | * | 170 | * |
| 163 | * @param target The guest address to start the mapping at. | 171 | * @param target The guest address to start the mapping at. |
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index ec32faf15..d607d985e 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp | |||
| @@ -3,9 +3,13 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | #include <fmt/format.h> | ||
| 6 | 7 | ||
| 8 | #include "core/hle/ipc_helpers.h" | ||
| 9 | #include "core/hle/kernel/process.h" | ||
| 7 | #include "core/hle/service/ldr/ldr.h" | 10 | #include "core/hle/service/ldr/ldr.h" |
| 8 | #include "core/hle/service/service.h" | 11 | #include "core/hle/service/service.h" |
| 12 | #include "core/loader/nro.h" | ||
| 9 | 13 | ||
| 10 | namespace Service::LDR { | 14 | namespace Service::LDR { |
| 11 | 15 | ||
| @@ -59,16 +63,58 @@ public: | |||
| 59 | explicit RelocatableObject() : ServiceFramework{"ldr:ro"} { | 63 | explicit RelocatableObject() : ServiceFramework{"ldr:ro"} { |
| 60 | // clang-format off | 64 | // clang-format off |
| 61 | static const FunctionInfo functions[] = { | 65 | static const FunctionInfo functions[] = { |
| 62 | {0, nullptr, "LoadNro"}, | 66 | {0, &RelocatableObject::LoadNro, "LoadNro"}, |
| 63 | {1, nullptr, "UnloadNro"}, | 67 | {1, nullptr, "UnloadNro"}, |
| 64 | {2, nullptr, "LoadNrr"}, | 68 | {2, &RelocatableObject::LoadNrr, "LoadNrr"}, |
| 65 | {3, nullptr, "UnloadNrr"}, | 69 | {3, nullptr, "UnloadNrr"}, |
| 66 | {4, nullptr, "Initialize"}, | 70 | {4, &RelocatableObject::Initialize, "Initialize"}, |
| 67 | }; | 71 | }; |
| 68 | // clang-format on | 72 | // clang-format on |
| 69 | 73 | ||
| 70 | RegisterHandlers(functions); | 74 | RegisterHandlers(functions); |
| 71 | } | 75 | } |
| 76 | |||
| 77 | void LoadNrr(Kernel::HLERequestContext& ctx) { | ||
| 78 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 79 | rb.Push(RESULT_SUCCESS); | ||
| 80 | LOG_WARNING(Service_LDR, "(STUBBED) called"); | ||
| 81 | } | ||
| 82 | |||
| 83 | void LoadNro(Kernel::HLERequestContext& ctx) { | ||
| 84 | IPC::RequestParser rp{ctx}; | ||
| 85 | rp.Skip(2, false); | ||
| 86 | const VAddr nro_addr{rp.Pop<VAddr>()}; | ||
| 87 | const u64 nro_size{rp.Pop<u64>()}; | ||
| 88 | const VAddr bss_addr{rp.Pop<VAddr>()}; | ||
| 89 | const u64 bss_size{rp.Pop<u64>()}; | ||
| 90 | |||
| 91 | // Read NRO data from memory | ||
| 92 | std::vector<u8> nro_data(nro_size); | ||
| 93 | Memory::ReadBlock(nro_addr, nro_data.data(), nro_size); | ||
| 94 | |||
| 95 | // Load NRO as new executable module | ||
| 96 | const VAddr addr{*Core::CurrentProcess()->VMManager().FindFreeRegion(nro_size + bss_size)}; | ||
| 97 | Loader::AppLoader_NRO::LoadNro(nro_data, fmt::format("nro-{:08x}", addr), addr); | ||
| 98 | |||
| 99 | // TODO(bunnei): This is an incomplete implementation. It was tested with Super Mario Party. | ||
| 100 | // It is currently missing: | ||
| 101 | // - Signature checks with LoadNRR | ||
| 102 | // - Checking if a module has already been loaded | ||
| 103 | // - Using/validating BSS, etc. params (these are used from NRO header instead) | ||
| 104 | // - Error checking | ||
| 105 | // - ...Probably other things | ||
| 106 | |||
| 107 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 108 | rb.Push(RESULT_SUCCESS); | ||
| 109 | rb.Push(addr); | ||
| 110 | LOG_WARNING(Service_LDR, "(STUBBED) called"); | ||
| 111 | } | ||
| 112 | |||
| 113 | void Initialize(Kernel::HLERequestContext& ctx) { | ||
| 114 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 115 | rb.Push(RESULT_SUCCESS); | ||
| 116 | LOG_WARNING(Service_LDR, "(STUBBED) called"); | ||
| 117 | } | ||
| 72 | }; | 118 | }; |
| 73 | 119 | ||
| 74 | void InstallInterfaces(SM::ServiceManager& sm) { | 120 | void InstallInterfaces(SM::ServiceManager& sm) { |
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 243b499f2..bc8e402a8 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -127,18 +127,23 @@ static constexpr u32 PageAlignSize(u32 size) { | |||
| 127 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; | 127 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { | 130 | /*static*/ bool AppLoader_NRO::LoadNro(const std::vector<u8>& data, const std::string& name, |
| 131 | // Read NSO header | 131 | VAddr load_base) { |
| 132 | NroHeader nro_header{}; | 132 | |
| 133 | if (sizeof(NroHeader) != file.ReadObject(&nro_header)) { | 133 | if (data.size() < sizeof(NroHeader)) { |
| 134 | return {}; | 134 | return {}; |
| 135 | } | 135 | } |
| 136 | |||
| 137 | // Read NSO header | ||
| 138 | NroHeader nro_header{}; | ||
| 139 | std::memcpy(&nro_header, data.data(), sizeof(NroHeader)); | ||
| 136 | if (nro_header.magic != Common::MakeMagic('N', 'R', 'O', '0')) { | 140 | if (nro_header.magic != Common::MakeMagic('N', 'R', 'O', '0')) { |
| 137 | return {}; | 141 | return {}; |
| 138 | } | 142 | } |
| 139 | 143 | ||
| 140 | // Build program image | 144 | // Build program image |
| 141 | std::vector<u8> program_image = file.ReadBytes(PageAlignSize(nro_header.file_size)); | 145 | std::vector<u8> program_image(PageAlignSize(nro_header.file_size)); |
| 146 | std::memcpy(program_image.data(), data.data(), program_image.size()); | ||
| 142 | if (program_image.size() != PageAlignSize(nro_header.file_size)) { | 147 | if (program_image.size() != PageAlignSize(nro_header.file_size)) { |
| 143 | return {}; | 148 | return {}; |
| 144 | } | 149 | } |
| @@ -182,11 +187,15 @@ bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { | |||
| 182 | Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); | 187 | Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); |
| 183 | 188 | ||
| 184 | // Register module with GDBStub | 189 | // Register module with GDBStub |
| 185 | GDBStub::RegisterModule(file.GetName(), load_base, load_base); | 190 | GDBStub::RegisterModule(name, load_base, load_base); |
| 186 | 191 | ||
| 187 | return true; | 192 | return true; |
| 188 | } | 193 | } |
| 189 | 194 | ||
| 195 | bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { | ||
| 196 | return AppLoader_NRO::LoadNro(file.ReadAllBytes(), file.GetName(), load_base); | ||
| 197 | } | ||
| 198 | |||
| 190 | ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { | 199 | ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { |
| 191 | if (is_loaded) { | 200 | if (is_loaded) { |
| 192 | return ResultStatus::ErrorAlreadyLoaded; | 201 | return ResultStatus::ErrorAlreadyLoaded; |
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 50ee5a78a..3e6959302 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | 7 | #include <string> |
| 8 | #include <vector> | ||
| 8 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 9 | #include "core/loader/linker.h" | 10 | #include "core/loader/linker.h" |
| 10 | #include "core/loader/loader.h" | 11 | #include "core/loader/loader.h" |
| @@ -40,6 +41,8 @@ public: | |||
| 40 | ResultStatus ReadTitle(std::string& title) override; | 41 | ResultStatus ReadTitle(std::string& title) override; |
| 41 | bool IsRomFSUpdatable() const override; | 42 | bool IsRomFSUpdatable() const override; |
| 42 | 43 | ||
| 44 | static bool LoadNro(const std::vector<u8>& data, const std::string& name, VAddr load_base); | ||
| 45 | |||
| 43 | private: | 46 | private: |
| 44 | bool LoadNro(const FileSys::VfsFile& file, VAddr load_base); | 47 | bool LoadNro(const FileSys::VfsFile& file, VAddr load_base); |
| 45 | 48 | ||