diff options
| author | 2018-07-18 21:07:11 -0400 | |
|---|---|---|
| committer | 2018-07-18 18:07:11 -0700 | |
| commit | 29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef (patch) | |
| tree | 3202e2ce55ab6387a4ca366a509eccdd963434c3 /src/core/loader/nso.cpp | |
| parent | Merge pull request #683 from DarkLordZach/touch (diff) | |
| download | yuzu-29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef.tar.gz yuzu-29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef.tar.xz yuzu-29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef.zip | |
Virtual Filesystem 2: Electric Boogaloo (#676)
* Virtual Filesystem
* Fix delete bug and documentate
* Review fixes + other stuff
* Fix puyo regression
Diffstat (limited to 'src/core/loader/nso.cpp')
| -rw-r--r-- | src/core/loader/nso.cpp | 93 |
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 | }; |
| 40 | static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size."); | 40 | static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size."); |
| 41 | static_assert(std::is_trivially_copyable_v<NsoHeader>, "NsoHeader isn't trivially copyable."); | ||
| 41 | 42 | ||
| 42 | struct ModHeader { | 43 | struct ModHeader { |
| 43 | u32_le magic; | 44 | u32_le magic; |
| @@ -50,15 +51,11 @@ struct ModHeader { | |||
| 50 | }; | 51 | }; |
| 51 | static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size."); | 52 | static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size."); |
| 52 | 53 | ||
| 53 | AppLoader_NSO::AppLoader_NSO(FileUtil::IOFile&& file, std::string filepath) | 54 | AppLoader_NSO::AppLoader_NSO(FileSys::VirtualFile file) : AppLoader(std::move(file)) {} |
| 54 | : AppLoader(std::move(file)), filepath(std::move(filepath)) {} | ||
| 55 | 55 | ||
| 56 | FileType AppLoader_NSO::IdentifyType(FileUtil::IOFile& file, const std::string&) { | 56 | FileType 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 | ||
| 102 | VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector<u8>& file_data, | 99 | VAddr 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 | ||
| 157 | VAddr 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 | |||
| 212 | ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) { | 156 | ResultStatus 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; |