summaryrefslogtreecommitdiff
path: root/src/core/loader/nro.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/loader/nro.cpp')
-rw-r--r--src/core/loader/nro.cpp62
1 files changed, 57 insertions, 5 deletions
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
25namespace Loader { 29namespace Loader {
26 30
27struct NroSegmentHeader { 31struct 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
142static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data) { 146static 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
213bool AppLoader_NRO::LoadNro(Kernel::KProcess& process, const FileSys::VfsFile& nro_file) { 264bool 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
217AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::System& system) { 269AppLoader_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