diff options
| author | 2023-11-17 23:44:53 +0200 | |
|---|---|---|
| committer | 2023-11-25 00:46:47 -0500 | |
| commit | 9f91ba1f7357c61dd2c7c3b437ea203d467fd400 (patch) | |
| tree | 3cfe55acf5d2f8a0d75373934b4c22a4e9bb2a09 /src/core/loader | |
| parent | device_memory: Enable direct mapped addresses for nce (diff) | |
| download | yuzu-9f91ba1f7357c61dd2c7c3b437ea203d467fd400.tar.gz yuzu-9f91ba1f7357c61dd2c7c3b437ea203d467fd400.tar.xz yuzu-9f91ba1f7357c61dd2c7c3b437ea203d467fd400.zip | |
arm: Implement native code execution backend
Diffstat (limited to 'src/core/loader')
| -rw-r--r-- | src/core/loader/deconstructed_rom_directory.cpp | 61 | ||||
| -rw-r--r-- | src/core/loader/nro.cpp | 62 | ||||
| -rw-r--r-- | src/core/loader/nro.h | 2 | ||||
| -rw-r--r-- | src/core/loader/nso.cpp | 56 | ||||
| -rw-r--r-- | src/core/loader/nso.h | 7 |
5 files changed, 162 insertions, 26 deletions
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 48c0edaea..e7fc8f438 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include <cstring> | 4 | #include <cstring> |
| 5 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "common/settings.h" | ||
| 6 | #include "core/core.h" | 7 | #include "core/core.h" |
| 7 | #include "core/file_sys/content_archive.h" | 8 | #include "core/file_sys/content_archive.h" |
| 8 | #include "core/file_sys/control_metadata.h" | 9 | #include "core/file_sys/control_metadata.h" |
| @@ -14,6 +15,10 @@ | |||
| 14 | #include "core/loader/deconstructed_rom_directory.h" | 15 | #include "core/loader/deconstructed_rom_directory.h" |
| 15 | #include "core/loader/nso.h" | 16 | #include "core/loader/nso.h" |
| 16 | 17 | ||
| 18 | #ifdef ARCHITECTURE_arm64 | ||
| 19 | #include "core/arm/nce/patch.h" | ||
| 20 | #endif | ||
| 21 | |||
| 17 | namespace Loader { | 22 | namespace Loader { |
| 18 | 23 | ||
| 19 | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_, | 24 | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_, |
| @@ -124,21 +129,41 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 124 | } | 129 | } |
| 125 | metadata.Print(); | 130 | metadata.Print(); |
| 126 | 131 | ||
| 127 | const auto static_modules = {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", | 132 | // Enable NCE only for 64-bit programs. |
| 128 | "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", | 133 | Settings::SetNceEnabled(metadata.Is64BitProgram()); |
| 129 | "subsdk8", "subsdk9", "sdk"}; | 134 | |
| 135 | const std::array static_modules = {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", | ||
| 136 | "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", | ||
| 137 | "subsdk8", "subsdk9", "sdk"}; | ||
| 130 | 138 | ||
| 131 | // Use the NSO module loader to figure out the code layout | ||
| 132 | std::size_t code_size{}; | 139 | std::size_t code_size{}; |
| 133 | for (const auto& module : static_modules) { | 140 | |
| 141 | // Define an nce patch context for each potential module. | ||
| 142 | #ifdef ARCHITECTURE_arm64 | ||
| 143 | std::array<Core::NCE::Patcher, 13> module_patchers; | ||
| 144 | #endif | ||
| 145 | |||
| 146 | const auto GetPatcher = [&](size_t i) -> Core::NCE::Patcher* { | ||
| 147 | #ifdef ARCHITECTURE_arm64 | ||
| 148 | if (Settings::IsNceEnabled()) { | ||
| 149 | return &module_patchers[i]; | ||
| 150 | } | ||
| 151 | #endif | ||
| 152 | return nullptr; | ||
| 153 | }; | ||
| 154 | |||
| 155 | // Use the NSO module loader to figure out the code layout | ||
| 156 | for (size_t i = 0; i < static_modules.size(); i++) { | ||
| 157 | const auto& module = static_modules[i]; | ||
| 134 | const FileSys::VirtualFile module_file{dir->GetFile(module)}; | 158 | const FileSys::VirtualFile module_file{dir->GetFile(module)}; |
| 135 | if (!module_file) { | 159 | if (!module_file) { |
| 136 | continue; | 160 | continue; |
| 137 | } | 161 | } |
| 138 | 162 | ||
| 139 | const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; | 163 | const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; |
| 140 | const auto tentative_next_load_addr = AppLoader_NSO::LoadModule( | 164 | const auto tentative_next_load_addr = |
| 141 | process, system, *module_file, code_size, should_pass_arguments, false); | 165 | AppLoader_NSO::LoadModule(process, system, *module_file, code_size, |
| 166 | should_pass_arguments, false, {}, GetPatcher(i)); | ||
| 142 | if (!tentative_next_load_addr) { | 167 | if (!tentative_next_load_addr) { |
| 143 | return {ResultStatus::ErrorLoadingNSO, {}}; | 168 | return {ResultStatus::ErrorLoadingNSO, {}}; |
| 144 | } | 169 | } |
| @@ -146,8 +171,18 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 146 | code_size = *tentative_next_load_addr; | 171 | code_size = *tentative_next_load_addr; |
| 147 | } | 172 | } |
| 148 | 173 | ||
| 174 | // Enable direct memory mapping in case of NCE. | ||
| 175 | const u64 fastmem_base = [&]() -> size_t { | ||
| 176 | if (Settings::IsNceEnabled()) { | ||
| 177 | auto& buffer = system.DeviceMemory().buffer; | ||
| 178 | buffer.EnableDirectMappedAddress(); | ||
| 179 | return reinterpret_cast<u64>(buffer.VirtualBasePointer()); | ||
| 180 | } | ||
| 181 | return 0; | ||
| 182 | }(); | ||
| 183 | |||
| 149 | // Setup the process code layout | 184 | // Setup the process code layout |
| 150 | if (process.LoadFromMetadata(metadata, code_size, 0, is_hbl).IsError()) { | 185 | if (process.LoadFromMetadata(metadata, code_size, fastmem_base, is_hbl).IsError()) { |
| 151 | return {ResultStatus::ErrorUnableToParseKernelMetadata, {}}; | 186 | return {ResultStatus::ErrorUnableToParseKernelMetadata, {}}; |
| 152 | } | 187 | } |
| 153 | 188 | ||
| @@ -157,7 +192,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 157 | VAddr next_load_addr{base_address}; | 192 | VAddr next_load_addr{base_address}; |
| 158 | const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(), | 193 | const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(), |
| 159 | system.GetContentProvider()}; | 194 | system.GetContentProvider()}; |
| 160 | for (const auto& module : static_modules) { | 195 | for (size_t i = 0; i < static_modules.size(); i++) { |
| 196 | const auto& module = static_modules[i]; | ||
| 161 | const FileSys::VirtualFile module_file{dir->GetFile(module)}; | 197 | const FileSys::VirtualFile module_file{dir->GetFile(module)}; |
| 162 | if (!module_file) { | 198 | if (!module_file) { |
| 163 | continue; | 199 | continue; |
| @@ -165,15 +201,16 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 165 | 201 | ||
| 166 | const VAddr load_addr{next_load_addr}; | 202 | const VAddr load_addr{next_load_addr}; |
| 167 | const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; | 203 | const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; |
| 168 | const auto tentative_next_load_addr = AppLoader_NSO::LoadModule( | 204 | const auto tentative_next_load_addr = |
| 169 | process, system, *module_file, load_addr, should_pass_arguments, true, pm); | 205 | AppLoader_NSO::LoadModule(process, system, *module_file, load_addr, |
| 206 | should_pass_arguments, true, pm, GetPatcher(i)); | ||
| 170 | if (!tentative_next_load_addr) { | 207 | if (!tentative_next_load_addr) { |
| 171 | return {ResultStatus::ErrorLoadingNSO, {}}; | 208 | return {ResultStatus::ErrorLoadingNSO, {}}; |
| 172 | } | 209 | } |
| 173 | 210 | ||
| 174 | next_load_addr = *tentative_next_load_addr; | 211 | next_load_addr = *tentative_next_load_addr; |
| 175 | modules.insert_or_assign(load_addr, module); | 212 | modules.insert_or_assign(load_addr, module); |
| 176 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); | 213 | LOG_DEBUG(Loader, "loaded module {} @ {:#X}", module, load_addr); |
| 177 | } | 214 | } |
| 178 | 215 | ||
| 179 | // Find the RomFS by searching for a ".romfs" file in this directory | 216 | // Find the RomFS by searching for a ".romfs" file in this directory |
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index dfed296a5..49cf90317 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -22,6 +22,10 @@ | |||
| 22 | #include "core/loader/nso.h" | 22 | #include "core/loader/nso.h" |
| 23 | #include "core/memory.h" | 23 | #include "core/memory.h" |
| 24 | 24 | ||
| 25 | #ifdef ARCHITECTURE_arm64 | ||
| 26 | #include "core/arm/nce/patch.h" | ||
| 27 | #endif | ||
| 28 | |||
| 25 | namespace Loader { | 29 | namespace Loader { |
| 26 | 30 | ||
| 27 | struct NroSegmentHeader { | 31 | struct NroSegmentHeader { |
| @@ -139,7 +143,8 @@ static constexpr u32 PageAlignSize(u32 size) { | |||
| 139 | return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK); | 143 | return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK); |
| 140 | } | 144 | } |
| 141 | 145 | ||
| 142 | static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data) { | 146 | static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process, |
| 147 | const std::vector<u8>& data) { | ||
| 143 | if (data.size() < sizeof(NroHeader)) { | 148 | if (data.size() < sizeof(NroHeader)) { |
| 144 | return {}; | 149 | return {}; |
| 145 | } | 150 | } |
| @@ -195,14 +200,60 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data) | |||
| 195 | codeset.DataSegment().size += bss_size; | 200 | codeset.DataSegment().size += bss_size; |
| 196 | program_image.resize(static_cast<u32>(program_image.size()) + bss_size); | 201 | program_image.resize(static_cast<u32>(program_image.size()) + bss_size); |
| 197 | 202 | ||
| 203 | #ifdef ARCHITECTURE_arm64 | ||
| 204 | const auto& code = codeset.CodeSegment(); | ||
| 205 | |||
| 206 | // NROs are always 64-bit programs. | ||
| 207 | Settings::SetNceEnabled(true); | ||
| 208 | |||
| 209 | // Create NCE patcher | ||
| 210 | Core::NCE::Patcher patch{}; | ||
| 211 | size_t image_size = program_image.size(); | ||
| 212 | |||
| 213 | if (Settings::IsNceEnabled()) { | ||
| 214 | // Patch SVCs and MRS calls in the guest code | ||
| 215 | patch.PatchText(program_image, code); | ||
| 216 | |||
| 217 | // We only support PostData patching for NROs. | ||
| 218 | ASSERT(patch.Mode() == Core::NCE::PatchMode::PostData); | ||
| 219 | |||
| 220 | // Update patch section. | ||
| 221 | auto& patch_segment = codeset.PatchSegment(); | ||
| 222 | patch_segment.addr = image_size; | ||
| 223 | patch_segment.size = static_cast<u32>(patch.SectionSize()); | ||
| 224 | |||
| 225 | // Add patch section size to the module size. | ||
| 226 | image_size += patch_segment.size; | ||
| 227 | } | ||
| 228 | #endif | ||
| 229 | |||
| 230 | // Enable direct memory mapping in case of NCE. | ||
| 231 | const u64 fastmem_base = [&]() -> size_t { | ||
| 232 | if (Settings::IsNceEnabled()) { | ||
| 233 | auto& buffer = system.DeviceMemory().buffer; | ||
| 234 | buffer.EnableDirectMappedAddress(); | ||
| 235 | return reinterpret_cast<u64>(buffer.VirtualBasePointer()); | ||
| 236 | } | ||
| 237 | return 0; | ||
| 238 | }(); | ||
| 239 | |||
| 198 | // Setup the process code layout | 240 | // Setup the process code layout |
| 199 | if (process | 241 | if (process |
| 200 | .LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size(), 0, | 242 | .LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), image_size, fastmem_base, |
| 201 | false) | 243 | false) |
| 202 | .IsError()) { | 244 | .IsError()) { |
| 203 | return false; | 245 | return false; |
| 204 | } | 246 | } |
| 205 | 247 | ||
| 248 | // Relocate code patch and copy to the program_image if running under NCE. | ||
| 249 | // This needs to be after LoadFromMetadata so we can use the process entry point. | ||
| 250 | #ifdef ARCHITECTURE_arm64 | ||
| 251 | if (Settings::IsNceEnabled()) { | ||
| 252 | patch.RelocateAndCopy(process.GetEntryPoint(), code, program_image, | ||
| 253 | &process.GetPostHandlers()); | ||
| 254 | } | ||
| 255 | #endif | ||
| 256 | |||
| 206 | // Load codeset for current process | 257 | // Load codeset for current process |
| 207 | codeset.memory = std::move(program_image); | 258 | codeset.memory = std::move(program_image); |
| 208 | process.LoadModule(std::move(codeset), process.GetEntryPoint()); | 259 | process.LoadModule(std::move(codeset), process.GetEntryPoint()); |
| @@ -210,8 +261,9 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data) | |||
| 210 | return true; | 261 | return true; |
| 211 | } | 262 | } |
| 212 | 263 | ||
| 213 | bool AppLoader_NRO::LoadNro(Kernel::KProcess& process, const FileSys::VfsFile& nro_file) { | 264 | bool AppLoader_NRO::LoadNro(Core::System& system, Kernel::KProcess& process, |
| 214 | return LoadNroImpl(process, nro_file.ReadAllBytes()); | 265 | const FileSys::VfsFile& nro_file) { |
| 266 | return LoadNroImpl(system, process, nro_file.ReadAllBytes()); | ||
| 215 | } | 267 | } |
| 216 | 268 | ||
| 217 | AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::System& system) { | 269 | AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::System& system) { |
| @@ -219,7 +271,7 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::S | |||
| 219 | return {ResultStatus::ErrorAlreadyLoaded, {}}; | 271 | return {ResultStatus::ErrorAlreadyLoaded, {}}; |
| 220 | } | 272 | } |
| 221 | 273 | ||
| 222 | if (!LoadNro(process, *file)) { | 274 | if (!LoadNro(system, process, *file)) { |
| 223 | return {ResultStatus::ErrorLoadingNRO, {}}; | 275 | return {ResultStatus::ErrorLoadingNRO, {}}; |
| 224 | } | 276 | } |
| 225 | 277 | ||
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 8de6eebc6..d2928cba0 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h | |||
| @@ -54,7 +54,7 @@ public: | |||
| 54 | bool IsRomFSUpdatable() const override; | 54 | bool IsRomFSUpdatable() const override; |
| 55 | 55 | ||
| 56 | private: | 56 | private: |
| 57 | bool LoadNro(Kernel::KProcess& process, const FileSys::VfsFile& nro_file); | 57 | bool LoadNro(Core::System& system, Kernel::KProcess& process, const FileSys::VfsFile& nro_file); |
| 58 | 58 | ||
| 59 | std::vector<u8> icon_data; | 59 | std::vector<u8> icon_data; |
| 60 | std::unique_ptr<FileSys::NACP> nacp; | 60 | std::unique_ptr<FileSys::NACP> nacp; |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 1350da8dc..34b10ef2e 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -20,6 +20,10 @@ | |||
| 20 | #include "core/loader/nso.h" | 20 | #include "core/loader/nso.h" |
| 21 | #include "core/memory.h" | 21 | #include "core/memory.h" |
| 22 | 22 | ||
| 23 | #ifdef ARCHITECTURE_arm64 | ||
| 24 | #include "core/arm/nce/patch.h" | ||
| 25 | #endif | ||
| 26 | |||
| 23 | namespace Loader { | 27 | namespace Loader { |
| 24 | namespace { | 28 | namespace { |
| 25 | struct MODHeader { | 29 | struct MODHeader { |
| @@ -72,7 +76,8 @@ FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& in_file) { | |||
| 72 | std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::System& system, | 76 | std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::System& system, |
| 73 | const FileSys::VfsFile& nso_file, VAddr load_base, | 77 | const FileSys::VfsFile& nso_file, VAddr load_base, |
| 74 | bool should_pass_arguments, bool load_into_process, | 78 | bool should_pass_arguments, bool load_into_process, |
| 75 | std::optional<FileSys::PatchManager> pm) { | 79 | std::optional<FileSys::PatchManager> pm, |
| 80 | Core::NCE::Patcher* patch) { | ||
| 76 | if (nso_file.GetSize() < sizeof(NSOHeader)) { | 81 | if (nso_file.GetSize() < sizeof(NSOHeader)) { |
| 77 | return std::nullopt; | 82 | return std::nullopt; |
| 78 | } | 83 | } |
| @@ -86,6 +91,16 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core:: | |||
| 86 | return std::nullopt; | 91 | return std::nullopt; |
| 87 | } | 92 | } |
| 88 | 93 | ||
| 94 | // Allocate some space at the beginning if we are patching in PreText mode. | ||
| 95 | const size_t module_start = [&]() -> size_t { | ||
| 96 | #ifdef ARCHITECTURE_arm64 | ||
| 97 | if (patch && patch->Mode() == Core::NCE::PatchMode::PreText) { | ||
| 98 | return patch->SectionSize(); | ||
| 99 | } | ||
| 100 | #endif | ||
| 101 | return 0; | ||
| 102 | }(); | ||
| 103 | |||
| 89 | // Build program image | 104 | // Build program image |
| 90 | Kernel::CodeSet codeset; | 105 | Kernel::CodeSet codeset; |
| 91 | Kernel::PhysicalMemory program_image; | 106 | Kernel::PhysicalMemory program_image; |
| @@ -95,11 +110,12 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core:: | |||
| 95 | if (nso_header.IsSegmentCompressed(i)) { | 110 | if (nso_header.IsSegmentCompressed(i)) { |
| 96 | data = DecompressSegment(data, nso_header.segments[i]); | 111 | data = DecompressSegment(data, nso_header.segments[i]); |
| 97 | } | 112 | } |
| 98 | program_image.resize(nso_header.segments[i].location + static_cast<u32>(data.size())); | 113 | program_image.resize(module_start + nso_header.segments[i].location + |
| 99 | std::memcpy(program_image.data() + nso_header.segments[i].location, data.data(), | 114 | static_cast<u32>(data.size())); |
| 100 | data.size()); | 115 | std::memcpy(program_image.data() + module_start + nso_header.segments[i].location, |
| 101 | codeset.segments[i].addr = nso_header.segments[i].location; | 116 | data.data(), data.size()); |
| 102 | codeset.segments[i].offset = nso_header.segments[i].location; | 117 | codeset.segments[i].addr = module_start + nso_header.segments[i].location; |
| 118 | codeset.segments[i].offset = module_start + nso_header.segments[i].location; | ||
| 103 | codeset.segments[i].size = nso_header.segments[i].size; | 119 | codeset.segments[i].size = nso_header.segments[i].size; |
| 104 | } | 120 | } |
| 105 | 121 | ||
| @@ -118,7 +134,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core:: | |||
| 118 | } | 134 | } |
| 119 | 135 | ||
| 120 | codeset.DataSegment().size += nso_header.segments[2].bss_size; | 136 | codeset.DataSegment().size += nso_header.segments[2].bss_size; |
| 121 | const u32 image_size{ | 137 | u32 image_size{ |
| 122 | PageAlignSize(static_cast<u32>(program_image.size()) + nso_header.segments[2].bss_size)}; | 138 | PageAlignSize(static_cast<u32>(program_image.size()) + nso_header.segments[2].bss_size)}; |
| 123 | program_image.resize(image_size); | 139 | program_image.resize(image_size); |
| 124 | 140 | ||
| @@ -139,6 +155,32 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core:: | |||
| 139 | std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.data()); | 155 | std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.data()); |
| 140 | } | 156 | } |
| 141 | 157 | ||
| 158 | #ifdef ARCHITECTURE_arm64 | ||
| 159 | // If we are computing the process code layout and using nce backend, patch. | ||
| 160 | const auto& code = codeset.CodeSegment(); | ||
| 161 | if (patch && patch->Mode() == Core::NCE::PatchMode::None) { | ||
| 162 | // Patch SVCs and MRS calls in the guest code | ||
| 163 | patch->PatchText(program_image, code); | ||
| 164 | |||
| 165 | // Add patch section size to the module size. | ||
| 166 | image_size += patch->SectionSize(); | ||
| 167 | } else if (patch) { | ||
| 168 | // Relocate code patch and copy to the program_image. | ||
| 169 | patch->RelocateAndCopy(load_base, code, program_image, &process.GetPostHandlers()); | ||
| 170 | |||
| 171 | // Update patch section. | ||
| 172 | auto& patch_segment = codeset.PatchSegment(); | ||
| 173 | patch_segment.addr = patch->Mode() == Core::NCE::PatchMode::PreText ? 0 : image_size; | ||
| 174 | patch_segment.size = static_cast<u32>(patch->SectionSize()); | ||
| 175 | |||
| 176 | // Add patch section size to the module size. In PreText mode image_size | ||
| 177 | // already contains the patch segment as part of module_start. | ||
| 178 | if (patch->Mode() == Core::NCE::PatchMode::PostData) { | ||
| 179 | image_size += patch_segment.size; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | #endif | ||
| 183 | |||
| 142 | // If we aren't actually loading (i.e. just computing the process code layout), we are done | 184 | // If we aren't actually loading (i.e. just computing the process code layout), we are done |
| 143 | if (!load_into_process) { | 185 | if (!load_into_process) { |
| 144 | return load_base + image_size; | 186 | return load_base + image_size; |
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 0b53b4ecd..29b86ed4c 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h | |||
| @@ -15,6 +15,10 @@ namespace Core { | |||
| 15 | class System; | 15 | class System; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | namespace Core::NCE { | ||
| 19 | class Patcher; | ||
| 20 | } | ||
| 21 | |||
| 18 | namespace Kernel { | 22 | namespace Kernel { |
| 19 | class KProcess; | 23 | class KProcess; |
| 20 | } | 24 | } |
| @@ -88,7 +92,8 @@ public: | |||
| 88 | static std::optional<VAddr> LoadModule(Kernel::KProcess& process, Core::System& system, | 92 | static std::optional<VAddr> LoadModule(Kernel::KProcess& process, Core::System& system, |
| 89 | const FileSys::VfsFile& nso_file, VAddr load_base, | 93 | const FileSys::VfsFile& nso_file, VAddr load_base, |
| 90 | bool should_pass_arguments, bool load_into_process, | 94 | bool should_pass_arguments, bool load_into_process, |
| 91 | std::optional<FileSys::PatchManager> pm = {}); | 95 | std::optional<FileSys::PatchManager> pm = {}, |
| 96 | Core::NCE::Patcher* patch = nullptr); | ||
| 92 | 97 | ||
| 93 | LoadResult Load(Kernel::KProcess& process, Core::System& system) override; | 98 | LoadResult Load(Kernel::KProcess& process, Core::System& system) override; |
| 94 | 99 | ||