diff options
| author | 2023-11-30 09:20:55 -0500 | |
|---|---|---|
| committer | 2023-11-30 09:20:55 -0500 | |
| commit | 57a391e71db13ade7a3d96f59d53781eff18d2ac (patch) | |
| tree | 0b4223de40a2d77598ac9095b1374353c2e9da7c /src/core/loader/nro.cpp | |
| parent | Merge pull request #12223 from liamwhite/fruit-company (diff) | |
| parent | core: Rename patcher file (diff) | |
| download | yuzu-57a391e71db13ade7a3d96f59d53781eff18d2ac.tar.gz yuzu-57a391e71db13ade7a3d96f59d53781eff18d2ac.tar.xz yuzu-57a391e71db13ade7a3d96f59d53781eff18d2ac.zip | |
Merge pull request #12074 from GPUCode/yuwu-on-the-metal
Implement Native Code Execution (NCE)
Diffstat (limited to 'src/core/loader/nro.cpp')
| -rw-r--r-- | src/core/loader/nro.cpp | 63 |
1 files changed, 58 insertions, 5 deletions
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 69f1a54ed..e74697cda 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 HAS_NCE | ||
| 26 | #include "core/arm/nce/patcher.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 | } |
| @@ -194,14 +199,61 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data) | |||
| 194 | 199 | ||
| 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); |
| 202 | size_t image_size = program_image.size(); | ||
| 203 | |||
| 204 | #ifdef HAS_NCE | ||
| 205 | const auto& code = codeset.CodeSegment(); | ||
| 206 | |||
| 207 | // NROs always have a 39-bit address space. | ||
| 208 | Settings::SetNceEnabled(true); | ||
| 209 | |||
| 210 | // Create NCE patcher | ||
| 211 | Core::NCE::Patcher patch{}; | ||
| 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.GetPatchMode() == 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.GetSectionSize()); | ||
| 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 | }(); | ||
| 197 | 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(), false) | 242 | .LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), image_size, fastmem_base, |
| 243 | false) | ||
| 201 | .IsError()) { | 244 | .IsError()) { |
| 202 | return false; | 245 | return false; |
| 203 | } | 246 | } |
| 204 | 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 HAS_NCE | ||
| 251 | if (Settings::IsNceEnabled()) { | ||
| 252 | patch.RelocateAndCopy(process.GetEntryPoint(), code, program_image, | ||
| 253 | &process.GetPostHandlers()); | ||
| 254 | } | ||
| 255 | #endif | ||
| 256 | |||
| 205 | // Load codeset for current process | 257 | // Load codeset for current process |
| 206 | codeset.memory = std::move(program_image); | 258 | codeset.memory = std::move(program_image); |
| 207 | process.LoadModule(std::move(codeset), process.GetEntryPoint()); | 259 | process.LoadModule(std::move(codeset), process.GetEntryPoint()); |
| @@ -209,8 +261,9 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data) | |||
| 209 | return true; | 261 | return true; |
| 210 | } | 262 | } |
| 211 | 263 | ||
| 212 | bool AppLoader_NRO::LoadNro(Kernel::KProcess& process, const FileSys::VfsFile& nro_file) { | 264 | bool AppLoader_NRO::LoadNro(Core::System& system, Kernel::KProcess& process, |
| 213 | return LoadNroImpl(process, nro_file.ReadAllBytes()); | 265 | const FileSys::VfsFile& nro_file) { |
| 266 | return LoadNroImpl(system, process, nro_file.ReadAllBytes()); | ||
| 214 | } | 267 | } |
| 215 | 268 | ||
| 216 | 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) { |
| @@ -218,7 +271,7 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::S | |||
| 218 | return {ResultStatus::ErrorAlreadyLoaded, {}}; | 271 | return {ResultStatus::ErrorAlreadyLoaded, {}}; |
| 219 | } | 272 | } |
| 220 | 273 | ||
| 221 | if (!LoadNro(process, *file)) { | 274 | if (!LoadNro(system, process, *file)) { |
| 222 | return {ResultStatus::ErrorLoadingNRO, {}}; | 275 | return {ResultStatus::ErrorLoadingNRO, {}}; |
| 223 | } | 276 | } |
| 224 | 277 | ||