summaryrefslogtreecommitdiff
path: root/src/core/loader/nso.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/loader/nso.cpp')
-rw-r--r--src/core/loader/nso.cpp93
1 files changed, 17 insertions, 76 deletions
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 7b3d6b837..2beb85fbf 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -38,6 +38,7 @@ struct NsoHeader {
38 std::array<u32_le, 3> segments_compressed_size; 38 std::array<u32_le, 3> segments_compressed_size;
39}; 39};
40static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size."); 40static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size.");
41static_assert(std::is_trivially_copyable_v<NsoHeader>, "NsoHeader isn't trivially copyable.");
41 42
42struct ModHeader { 43struct ModHeader {
43 u32_le magic; 44 u32_le magic;
@@ -50,15 +51,11 @@ struct ModHeader {
50}; 51};
51static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size."); 52static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size.");
52 53
53AppLoader_NSO::AppLoader_NSO(FileUtil::IOFile&& file, std::string filepath) 54AppLoader_NSO::AppLoader_NSO(FileSys::VirtualFile file) : AppLoader(std::move(file)) {}
54 : AppLoader(std::move(file)), filepath(std::move(filepath)) {}
55 55
56FileType AppLoader_NSO::IdentifyType(FileUtil::IOFile& file, const std::string&) { 56FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& file) {
57 u32 magic = 0; 57 u32 magic = 0;
58 file.Seek(0, SEEK_SET); 58 file->ReadObject(&magic);
59 if (1 != file.ReadArray<u32>(&magic, 1)) {
60 return FileType::Error;
61 }
62 59
63 if (Common::MakeMagic('N', 'S', 'O', '0') == magic) { 60 if (Common::MakeMagic('N', 'S', 'O', '0') == magic) {
64 return FileType::NSO; 61 return FileType::NSO;
@@ -99,13 +96,16 @@ static constexpr u32 PageAlignSize(u32 size) {
99 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; 96 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
100} 97}
101 98
102VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector<u8>& file_data, 99VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) {
103 VAddr load_base) { 100 if (file == nullptr)
104 if (file_data.size() < sizeof(NsoHeader))
105 return {}; 101 return {};
106 102
107 NsoHeader nso_header; 103 if (file->GetSize() < sizeof(NsoHeader))
108 std::memcpy(&nso_header, file_data.data(), sizeof(NsoHeader)); 104 return {};
105
106 NsoHeader nso_header{};
107 if (sizeof(NsoHeader) != file->ReadObject(&nso_header))
108 return {};
109 109
110 if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) 110 if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0'))
111 return {}; 111 return {};
@@ -114,9 +114,8 @@ VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector<u8>&
114 Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(""); 114 Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create("");
115 std::vector<u8> program_image; 115 std::vector<u8> program_image;
116 for (int i = 0; i < nso_header.segments.size(); ++i) { 116 for (int i = 0; i < nso_header.segments.size(); ++i) {
117 std::vector<u8> compressed_data(nso_header.segments_compressed_size[i]); 117 const std::vector<u8> compressed_data =
118 for (auto j = 0; j < nso_header.segments_compressed_size[i]; ++j) 118 file->ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset);
119 compressed_data[j] = file_data[nso_header.segments[i].offset + j];
120 std::vector<u8> data = DecompressSegment(compressed_data, nso_header.segments[i]); 119 std::vector<u8> data = DecompressSegment(compressed_data, nso_header.segments[i]);
121 program_image.resize(nso_header.segments[i].location); 120 program_image.resize(nso_header.segments[i].location);
122 program_image.insert(program_image.end(), data.begin(), data.end()); 121 program_image.insert(program_image.end(), data.begin(), data.end());
@@ -144,7 +143,7 @@ VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector<u8>&
144 program_image.resize(image_size); 143 program_image.resize(image_size);
145 144
146 // Load codeset for current process 145 // Load codeset for current process
147 codeset->name = name; 146 codeset->name = file->GetName();
148 codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); 147 codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image));
149 Core::CurrentProcess()->LoadModule(codeset, load_base); 148 Core::CurrentProcess()->LoadModule(codeset, load_base);
150 149
@@ -154,72 +153,14 @@ VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector<u8>&
154 return load_base + image_size; 153 return load_base + image_size;
155} 154}
156 155
157VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base) {
158 FileUtil::IOFile file(path, "rb");
159 if (!file.IsOpen()) {
160 return {};
161 }
162
163 // Read NSO header
164 NsoHeader nso_header{};
165 file.Seek(0, SEEK_SET);
166 if (sizeof(NsoHeader) != file.ReadBytes(&nso_header, sizeof(NsoHeader))) {
167 return {};
168 }
169 if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) {
170 return {};
171 }
172
173 // Build program image
174 Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create("");
175 std::vector<u8> program_image;
176 for (int i = 0; i < nso_header.segments.size(); ++i) {
177 std::vector<u8> data =
178 ReadSegment(file, nso_header.segments[i], nso_header.segments_compressed_size[i]);
179 program_image.resize(nso_header.segments[i].location);
180 program_image.insert(program_image.end(), data.begin(), data.end());
181 codeset->segments[i].addr = nso_header.segments[i].location;
182 codeset->segments[i].offset = nso_header.segments[i].location;
183 codeset->segments[i].size = PageAlignSize(static_cast<u32>(data.size()));
184 }
185
186 // MOD header pointer is at .text offset + 4
187 u32 module_offset;
188 std::memcpy(&module_offset, program_image.data() + 4, sizeof(u32));
189
190 // Read MOD header
191 ModHeader mod_header{};
192 // Default .bss to size in segment header if MOD0 section doesn't exist
193 u32 bss_size{PageAlignSize(nso_header.segments[2].bss_size)};
194 std::memcpy(&mod_header, program_image.data() + module_offset, sizeof(ModHeader));
195 const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')};
196 if (has_mod_header) {
197 // Resize program image to include .bss section and page align each section
198 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset);
199 }
200 codeset->data.size += bss_size;
201 const u32 image_size{PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)};
202 program_image.resize(image_size);
203
204 // Load codeset for current process
205 codeset->name = path;
206 codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image));
207 Core::CurrentProcess()->LoadModule(codeset, load_base);
208
209 return load_base + image_size;
210}
211
212ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) { 156ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
213 if (is_loaded) { 157 if (is_loaded) {
214 return ResultStatus::ErrorAlreadyLoaded; 158 return ResultStatus::ErrorAlreadyLoaded;
215 } 159 }
216 if (!file.IsOpen()) {
217 return ResultStatus::Error;
218 }
219 160
220 // Load module 161 // Load module
221 LoadModule(filepath, Memory::PROCESS_IMAGE_VADDR); 162 LoadModule(file, Memory::PROCESS_IMAGE_VADDR);
222 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", filepath, Memory::PROCESS_IMAGE_VADDR); 163 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR);
223 164
224 process->svc_access_mask.set(); 165 process->svc_access_mask.set();
225 process->address_mappings = default_address_mappings; 166 process->address_mappings = default_address_mappings;