summaryrefslogtreecommitdiff
path: root/src/core/loader
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/loader')
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp47
-rw-r--r--src/core/loader/elf.cpp6
-rw-r--r--src/core/loader/kip.cpp6
-rw-r--r--src/core/loader/nro.cpp8
-rw-r--r--src/core/loader/nso.cpp54
-rw-r--r--src/core/loader/nso.h3
6 files changed, 69 insertions, 55 deletions
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 53559e8b1..134e83412 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -14,6 +14,7 @@
14#include "core/file_sys/romfs_factory.h" 14#include "core/file_sys/romfs_factory.h"
15#include "core/gdbstub/gdbstub.h" 15#include "core/gdbstub/gdbstub.h"
16#include "core/hle/kernel/kernel.h" 16#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/memory/page_table.h"
17#include "core/hle/kernel/process.h" 18#include "core/hle/kernel/process.h"
18#include "core/hle/service/filesystem/filesystem.h" 19#include "core/hle/service/filesystem/filesystem.h"
19#include "core/loader/deconstructed_rom_directory.h" 20#include "core/loader/deconstructed_rom_directory.h"
@@ -129,27 +130,47 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
129 } 130 }
130 metadata.Print(); 131 metadata.Print();
131 132
132 if (process.LoadFromMetadata(metadata).IsError()) { 133 const auto static_modules = {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
133 return {ResultStatus::ErrorUnableToParseKernelMetadata, {}}; 134 "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"};
135
136 // Use the NSO module loader to figure out the code layout
137 std::size_t code_size{};
138 for (const auto& module : static_modules) {
139 const FileSys::VirtualFile module_file{dir->GetFile(module)};
140 if (!module_file) {
141 continue;
142 }
143
144 const bool should_pass_arguments{std::strcmp(module, "rtld") == 0};
145 const auto tentative_next_load_addr{AppLoader_NSO::LoadModule(
146 process, *module_file, code_size, should_pass_arguments, false)};
147 if (!tentative_next_load_addr) {
148 return {ResultStatus::ErrorLoadingNSO, {}};
149 }
150
151 code_size = *tentative_next_load_addr;
134 } 152 }
135 153
136 const FileSys::PatchManager pm(metadata.GetTitleID()); 154 // Setup the process code layout
155 if (process.LoadFromMetadata(metadata, code_size).IsError()) {
156 return {ResultStatus::ErrorUnableToParseKernelMetadata, {}};
157 }
137 158
138 // Load NSO modules 159 // Load NSO modules
139 modules.clear(); 160 modules.clear();
140 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); 161 const VAddr base_address{process.PageTable().GetCodeRegionStart()};
141 VAddr next_load_addr = base_address; 162 VAddr next_load_addr{base_address};
142 for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", 163 const FileSys::PatchManager pm{metadata.GetTitleID()};
143 "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { 164 for (const auto& module : static_modules) {
144 const FileSys::VirtualFile module_file = dir->GetFile(module); 165 const FileSys::VirtualFile module_file{dir->GetFile(module)};
145 if (module_file == nullptr) { 166 if (!module_file) {
146 continue; 167 continue;
147 } 168 }
148 169
149 const VAddr load_addr = next_load_addr; 170 const VAddr load_addr{next_load_addr};
150 const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; 171 const bool should_pass_arguments{std::strcmp(module, "rtld") == 0};
151 const auto tentative_next_load_addr = 172 const auto tentative_next_load_addr{AppLoader_NSO::LoadModule(
152 AppLoader_NSO::LoadModule(process, *module_file, load_addr, should_pass_arguments, pm); 173 process, *module_file, load_addr, should_pass_arguments, true, pm)};
153 if (!tentative_next_load_addr) { 174 if (!tentative_next_load_addr) {
154 return {ResultStatus::ErrorLoadingNSO, {}}; 175 return {ResultStatus::ErrorLoadingNSO, {}};
155 } 176 }
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 8908e5328..1e9ed2837 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -10,8 +10,8 @@
10#include "common/file_util.h" 10#include "common/file_util.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "core/hle/kernel/code_set.h" 12#include "core/hle/kernel/code_set.h"
13#include "core/hle/kernel/memory/page_table.h"
13#include "core/hle/kernel/process.h" 14#include "core/hle/kernel/process.h"
14#include "core/hle/kernel/vm_manager.h"
15#include "core/loader/elf.h" 15#include "core/loader/elf.h"
16#include "core/memory.h" 16#include "core/memory.h"
17 17
@@ -393,7 +393,7 @@ AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process) {
393 return {ResultStatus::ErrorIncorrectELFFileSize, {}}; 393 return {ResultStatus::ErrorIncorrectELFFileSize, {}};
394 } 394 }
395 395
396 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); 396 const VAddr base_address = process.PageTable().GetCodeRegionStart();
397 ElfReader elf_reader(&buffer[0]); 397 ElfReader elf_reader(&buffer[0]);
398 Kernel::CodeSet codeset = elf_reader.LoadInto(base_address); 398 Kernel::CodeSet codeset = elf_reader.LoadInto(base_address);
399 const VAddr entry_point = codeset.entrypoint; 399 const VAddr entry_point = codeset.entrypoint;
@@ -401,7 +401,7 @@ AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process) {
401 process.LoadModule(std::move(codeset), entry_point); 401 process.LoadModule(std::move(codeset), entry_point);
402 402
403 is_loaded = true; 403 is_loaded = true;
404 return {ResultStatus::Success, LoadParameters{48, Memory::DEFAULT_STACK_SIZE}}; 404 return {ResultStatus::Success, LoadParameters{48, Core::Memory::DEFAULT_STACK_SIZE}};
405} 405}
406 406
407} // namespace Loader 407} // namespace Loader
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp
index 092103abe..40fa03ad1 100644
--- a/src/core/loader/kip.cpp
+++ b/src/core/loader/kip.cpp
@@ -7,14 +7,16 @@
7#include "core/file_sys/program_metadata.h" 7#include "core/file_sys/program_metadata.h"
8#include "core/gdbstub/gdbstub.h" 8#include "core/gdbstub/gdbstub.h"
9#include "core/hle/kernel/code_set.h" 9#include "core/hle/kernel/code_set.h"
10#include "core/hle/kernel/memory/page_table.h"
10#include "core/hle/kernel/process.h" 11#include "core/hle/kernel/process.h"
11#include "core/loader/kip.h" 12#include "core/loader/kip.h"
13#include "core/memory.h"
12 14
13namespace Loader { 15namespace Loader {
14 16
15namespace { 17namespace {
16constexpr u32 PageAlignSize(u32 size) { 18constexpr u32 PageAlignSize(u32 size) {
17 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; 19 return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK;
18} 20}
19} // Anonymous namespace 21} // Anonymous namespace
20 22
@@ -68,7 +70,7 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process) {
68 kip->GetMainThreadCpuCore(), kip->GetMainThreadStackSize(), 70 kip->GetMainThreadCpuCore(), kip->GetMainThreadStackSize(),
69 kip->GetTitleID(), 0xFFFFFFFFFFFFFFFF, kip->GetKernelCapabilities()); 71 kip->GetTitleID(), 0xFFFFFFFFFFFFFFFF, kip->GetKernelCapabilities());
70 72
71 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); 73 const VAddr base_address = process.PageTable().GetCodeRegionStart();
72 Kernel::CodeSet codeset; 74 Kernel::CodeSet codeset;
73 Kernel::PhysicalMemory program_image; 75 Kernel::PhysicalMemory program_image;
74 76
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 175898b91..5d7e8136e 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -16,8 +16,8 @@
16#include "core/file_sys/vfs_offset.h" 16#include "core/file_sys/vfs_offset.h"
17#include "core/gdbstub/gdbstub.h" 17#include "core/gdbstub/gdbstub.h"
18#include "core/hle/kernel/code_set.h" 18#include "core/hle/kernel/code_set.h"
19#include "core/hle/kernel/memory/page_table.h"
19#include "core/hle/kernel/process.h" 20#include "core/hle/kernel/process.h"
20#include "core/hle/kernel/vm_manager.h"
21#include "core/hle/service/filesystem/filesystem.h" 21#include "core/hle/service/filesystem/filesystem.h"
22#include "core/loader/nro.h" 22#include "core/loader/nro.h"
23#include "core/loader/nso.h" 23#include "core/loader/nso.h"
@@ -127,7 +127,7 @@ FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& file) {
127} 127}
128 128
129static constexpr u32 PageAlignSize(u32 size) { 129static constexpr u32 PageAlignSize(u32 size) {
130 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; 130 return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK;
131} 131}
132 132
133static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data, 133static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data,
@@ -208,7 +208,7 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process) {
208 } 208 }
209 209
210 // Load NRO 210 // Load NRO
211 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); 211 const VAddr base_address = process.PageTable().GetCodeRegionStart();
212 212
213 if (!LoadNro(process, *file, base_address)) { 213 if (!LoadNro(process, *file, base_address)) {
214 return {ResultStatus::ErrorLoadingNRO, {}}; 214 return {ResultStatus::ErrorLoadingNRO, {}};
@@ -221,7 +221,7 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process) {
221 221
222 is_loaded = true; 222 is_loaded = true;
223 return {ResultStatus::Success, 223 return {ResultStatus::Success,
224 LoadParameters{Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE}}; 224 LoadParameters{Kernel::THREADPRIO_DEFAULT, Core::Memory::DEFAULT_STACK_SIZE}};
225} 225}
226 226
227ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) { 227ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 044067a5b..612ff9bf6 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -16,8 +16,8 @@
16#include "core/file_sys/patch_manager.h" 16#include "core/file_sys/patch_manager.h"
17#include "core/gdbstub/gdbstub.h" 17#include "core/gdbstub/gdbstub.h"
18#include "core/hle/kernel/code_set.h" 18#include "core/hle/kernel/code_set.h"
19#include "core/hle/kernel/memory/page_table.h"
19#include "core/hle/kernel/process.h" 20#include "core/hle/kernel/process.h"
20#include "core/hle/kernel/vm_manager.h"
21#include "core/loader/nso.h" 21#include "core/loader/nso.h"
22#include "core/memory.h" 22#include "core/memory.h"
23#include "core/settings.h" 23#include "core/settings.h"
@@ -47,7 +47,7 @@ std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data,
47} 47}
48 48
49constexpr u32 PageAlignSize(u32 size) { 49constexpr u32 PageAlignSize(u32 size) {
50 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; 50 return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK;
51} 51}
52} // Anonymous namespace 52} // Anonymous namespace
53 53
@@ -73,7 +73,7 @@ FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& file) {
73 73
74std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, 74std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
75 const FileSys::VfsFile& file, VAddr load_base, 75 const FileSys::VfsFile& file, VAddr load_base,
76 bool should_pass_arguments, 76 bool should_pass_arguments, bool load_into_process,
77 std::optional<FileSys::PatchManager> pm) { 77 std::optional<FileSys::PatchManager> pm) {
78 if (file.GetSize() < sizeof(NSOHeader)) { 78 if (file.GetSize() < sizeof(NSOHeader)) {
79 return {}; 79 return {};
@@ -97,21 +97,17 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
97 if (nso_header.IsSegmentCompressed(i)) { 97 if (nso_header.IsSegmentCompressed(i)) {
98 data = DecompressSegment(data, nso_header.segments[i]); 98 data = DecompressSegment(data, nso_header.segments[i]);
99 } 99 }
100 program_image.resize(nso_header.segments[i].location + 100 program_image.resize(nso_header.segments[i].location + static_cast<u32>(data.size()));
101 PageAlignSize(static_cast<u32>(data.size())));
102 std::memcpy(program_image.data() + nso_header.segments[i].location, data.data(), 101 std::memcpy(program_image.data() + nso_header.segments[i].location, data.data(),
103 data.size()); 102 data.size());
104 codeset.segments[i].addr = nso_header.segments[i].location; 103 codeset.segments[i].addr = nso_header.segments[i].location;
105 codeset.segments[i].offset = nso_header.segments[i].location; 104 codeset.segments[i].offset = nso_header.segments[i].location;
106 codeset.segments[i].size = PageAlignSize(static_cast<u32>(data.size())); 105 codeset.segments[i].size = nso_header.segments[i].size;
107 } 106 }
108 107
109 if (should_pass_arguments) { 108 if (should_pass_arguments && !Settings::values.program_args.empty()) {
110 std::vector<u8> arg_data{Settings::values.program_args.begin(), 109 const auto arg_data{Settings::values.program_args};
111 Settings::values.program_args.end()}; 110
112 if (arg_data.empty()) {
113 arg_data.resize(NSO_ARGUMENT_DEFAULT_SIZE);
114 }
115 codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE; 111 codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
116 NSOArgumentHeader args_header{ 112 NSOArgumentHeader args_header{
117 NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}}; 113 NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}};
@@ -123,24 +119,15 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
123 arg_data.size()); 119 arg_data.size());
124 } 120 }
125 121
126 // MOD header pointer is at .text offset + 4 122 codeset.DataSegment().size += nso_header.segments[2].bss_size;
127 u32 module_offset; 123 const u32 image_size{
128 std::memcpy(&module_offset, program_image.data() + 4, sizeof(u32)); 124 PageAlignSize(static_cast<u32>(program_image.size()) + nso_header.segments[2].bss_size)};
129
130 // Read MOD header
131 MODHeader mod_header{};
132 // Default .bss to size in segment header if MOD0 section doesn't exist
133 u32 bss_size{PageAlignSize(nso_header.segments[2].bss_size)};
134 std::memcpy(&mod_header, program_image.data() + module_offset, sizeof(MODHeader));
135 const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')};
136 if (has_mod_header) {
137 // Resize program image to include .bss section and page align each section
138 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset);
139 }
140 codeset.DataSegment().size += bss_size;
141 const u32 image_size{PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)};
142 program_image.resize(image_size); 125 program_image.resize(image_size);
143 126
127 for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
128 codeset.segments[i].size = PageAlignSize(codeset.segments[i].size);
129 }
130
144 // Apply patches if necessary 131 // Apply patches if necessary
145 if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) { 132 if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) {
146 std::vector<u8> pi_header; 133 std::vector<u8> pi_header;
@@ -154,6 +141,11 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
154 std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.data()); 141 std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.data());
155 } 142 }
156 143
144 // If we aren't actually loading (i.e. just computing the process code layout), we are done
145 if (!load_into_process) {
146 return load_base + image_size;
147 }
148
157 // Apply cheats if they exist and the program has a valid title ID 149 // Apply cheats if they exist and the program has a valid title ID
158 if (pm) { 150 if (pm) {
159 auto& system = Core::System::GetInstance(); 151 auto& system = Core::System::GetInstance();
@@ -182,8 +174,8 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process) {
182 modules.clear(); 174 modules.clear();
183 175
184 // Load module 176 // Load module
185 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); 177 const VAddr base_address = process.PageTable().GetCodeRegionStart();
186 if (!LoadModule(process, *file, base_address, true)) { 178 if (!LoadModule(process, *file, base_address, true, true)) {
187 return {ResultStatus::ErrorLoadingNSO, {}}; 179 return {ResultStatus::ErrorLoadingNSO, {}};
188 } 180 }
189 181
@@ -192,7 +184,7 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process) {
192 184
193 is_loaded = true; 185 is_loaded = true;
194 return {ResultStatus::Success, 186 return {ResultStatus::Success,
195 LoadParameters{Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE}}; 187 LoadParameters{Kernel::THREADPRIO_DEFAULT, Core::Memory::DEFAULT_STACK_SIZE}};
196} 188}
197 189
198ResultStatus AppLoader_NSO::ReadNSOModules(Modules& modules) { 190ResultStatus AppLoader_NSO::ReadNSOModules(Modules& modules) {
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index d2d600cd9..b210830f0 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -56,8 +56,6 @@ static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size.");
56static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable."); 56static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable.");
57 57
58constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000; 58constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000;
59// NOTE: Official software default argument state is unverified.
60constexpr u64 NSO_ARGUMENT_DEFAULT_SIZE = 1;
61 59
62struct NSOArgumentHeader { 60struct NSOArgumentHeader {
63 u32_le allocated_size; 61 u32_le allocated_size;
@@ -84,6 +82,7 @@ public:
84 82
85 static std::optional<VAddr> LoadModule(Kernel::Process& process, const FileSys::VfsFile& file, 83 static std::optional<VAddr> LoadModule(Kernel::Process& process, const FileSys::VfsFile& file,
86 VAddr load_base, bool should_pass_arguments, 84 VAddr load_base, bool should_pass_arguments,
85 bool load_into_process,
87 std::optional<FileSys::PatchManager> pm = {}); 86 std::optional<FileSys::PatchManager> pm = {});
88 87
89 LoadResult Load(Kernel::Process& process) override; 88 LoadResult Load(Kernel::Process& process) override;