diff options
| author | 2018-07-07 20:24:51 -0700 | |
|---|---|---|
| committer | 2018-07-07 20:24:51 -0700 | |
| commit | 913896cbd99e414c325c9d47a987376ed6d9fffd (patch) | |
| tree | b660920a49f538f0ee00486c50a0d153d53c423d /src/core/loader/nso.cpp | |
| parent | Merge pull request #632 from FearlessTobi/add-discord-link (diff) | |
| download | yuzu-913896cbd99e414c325c9d47a987376ed6d9fffd.tar.gz yuzu-913896cbd99e414c325c9d47a987376ed6d9fffd.tar.xz yuzu-913896cbd99e414c325c9d47a987376ed6d9fffd.zip | |
Revert "Virtual Filesystem (#597)"
This reverts commit 77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2.
Diffstat (limited to 'src/core/loader/nso.cpp')
| -rw-r--r-- | src/core/loader/nso.cpp | 91 |
1 files changed, 75 insertions, 16 deletions
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 2ed12a5ab..7f84e4b1b 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -37,7 +37,6 @@ struct NsoHeader { | |||
| 37 | std::array<u32_le, 3> segments_compressed_size; | 37 | std::array<u32_le, 3> segments_compressed_size; |
| 38 | }; | 38 | }; |
| 39 | static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size."); | 39 | static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size."); |
| 40 | static_assert(std::is_trivially_copyable_v<NsoHeader>, "NsoHeader isn't trivially copyable."); | ||
| 41 | 40 | ||
| 42 | struct ModHeader { | 41 | struct ModHeader { |
| 43 | u32_le magic; | 42 | u32_le magic; |
| @@ -50,11 +49,15 @@ struct ModHeader { | |||
| 50 | }; | 49 | }; |
| 51 | static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size."); | 50 | static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size."); |
| 52 | 51 | ||
| 53 | AppLoader_NSO::AppLoader_NSO(FileSys::VirtualFile file) : AppLoader(std::move(file)) {} | 52 | AppLoader_NSO::AppLoader_NSO(FileUtil::IOFile&& file, std::string filepath) |
| 53 | : AppLoader(std::move(file)), filepath(std::move(filepath)) {} | ||
| 54 | 54 | ||
| 55 | FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& file) { | 55 | FileType AppLoader_NSO::IdentifyType(FileUtil::IOFile& file, const std::string&) { |
| 56 | u32 magic = 0; | 56 | u32 magic = 0; |
| 57 | file->ReadObject(&magic); | 57 | file.Seek(0, SEEK_SET); |
| 58 | if (1 != file.ReadArray<u32>(&magic, 1)) { | ||
| 59 | return FileType::Error; | ||
| 60 | } | ||
| 58 | 61 | ||
| 59 | if (Common::MakeMagic('N', 'S', 'O', '0') == magic) { | 62 | if (Common::MakeMagic('N', 'S', 'O', '0') == magic) { |
| 60 | return FileType::NSO; | 63 | return FileType::NSO; |
| @@ -95,27 +98,80 @@ static constexpr u32 PageAlignSize(u32 size) { | |||
| 95 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; | 98 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; |
| 96 | } | 99 | } |
| 97 | 100 | ||
| 98 | VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) { | 101 | VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector<u8>& file_data, |
| 99 | if (file == nullptr) | 102 | VAddr load_base) { |
| 103 | if (file_data.size() < sizeof(NsoHeader)) | ||
| 100 | return {}; | 104 | return {}; |
| 101 | 105 | ||
| 102 | if (file->GetSize() < sizeof(NsoHeader)) | 106 | NsoHeader nso_header; |
| 107 | std::memcpy(&nso_header, file_data.data(), sizeof(NsoHeader)); | ||
| 108 | |||
| 109 | if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) | ||
| 103 | return {}; | 110 | return {}; |
| 104 | 111 | ||
| 105 | NsoHeader nso_header{}; | 112 | // Build program image |
| 106 | if (sizeof(NsoHeader) != file->ReadObject(&nso_header)) | 113 | Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(""); |
| 114 | std::vector<u8> program_image; | ||
| 115 | for (int i = 0; i < nso_header.segments.size(); ++i) { | ||
| 116 | std::vector<u8> compressed_data(nso_header.segments_compressed_size[i]); | ||
| 117 | for (int j = 0; j < nso_header.segments_compressed_size[i]; ++j) | ||
| 118 | compressed_data[j] = file_data[nso_header.segments[i].offset + j]; | ||
| 119 | std::vector<u8> data = DecompressSegment(compressed_data, nso_header.segments[i]); | ||
| 120 | program_image.resize(nso_header.segments[i].location); | ||
| 121 | program_image.insert(program_image.end(), data.begin(), data.end()); | ||
| 122 | codeset->segments[i].addr = nso_header.segments[i].location; | ||
| 123 | codeset->segments[i].offset = nso_header.segments[i].location; | ||
| 124 | codeset->segments[i].size = PageAlignSize(static_cast<u32>(data.size())); | ||
| 125 | } | ||
| 126 | |||
| 127 | // MOD header pointer is at .text offset + 4 | ||
| 128 | u32 module_offset; | ||
| 129 | std::memcpy(&module_offset, program_image.data() + 4, sizeof(u32)); | ||
| 130 | |||
| 131 | // Read MOD header | ||
| 132 | ModHeader mod_header{}; | ||
| 133 | // Default .bss to size in segment header if MOD0 section doesn't exist | ||
| 134 | u32 bss_size{PageAlignSize(nso_header.segments[2].bss_size)}; | ||
| 135 | std::memcpy(&mod_header, program_image.data() + module_offset, sizeof(ModHeader)); | ||
| 136 | const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')}; | ||
| 137 | if (has_mod_header) { | ||
| 138 | // Resize program image to include .bss section and page align each section | ||
| 139 | bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset); | ||
| 140 | } | ||
| 141 | codeset->data.size += bss_size; | ||
| 142 | const u32 image_size{PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)}; | ||
| 143 | program_image.resize(image_size); | ||
| 144 | |||
| 145 | // Load codeset for current process | ||
| 146 | codeset->name = name; | ||
| 147 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | ||
| 148 | Core::CurrentProcess()->LoadModule(codeset, load_base); | ||
| 149 | |||
| 150 | return load_base + image_size; | ||
| 151 | } | ||
| 152 | |||
| 153 | VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base) { | ||
| 154 | FileUtil::IOFile file(path, "rb"); | ||
| 155 | if (!file.IsOpen()) { | ||
| 107 | return {}; | 156 | return {}; |
| 157 | } | ||
| 108 | 158 | ||
| 109 | if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) | 159 | // Read NSO header |
| 160 | NsoHeader nso_header{}; | ||
| 161 | file.Seek(0, SEEK_SET); | ||
| 162 | if (sizeof(NsoHeader) != file.ReadBytes(&nso_header, sizeof(NsoHeader))) { | ||
| 163 | return {}; | ||
| 164 | } | ||
| 165 | if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) { | ||
| 110 | return {}; | 166 | return {}; |
| 167 | } | ||
| 111 | 168 | ||
| 112 | // Build program image | 169 | // Build program image |
| 113 | Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(""); | 170 | Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(""); |
| 114 | std::vector<u8> program_image; | 171 | std::vector<u8> program_image; |
| 115 | for (int i = 0; i < nso_header.segments.size(); ++i) { | 172 | for (int i = 0; i < nso_header.segments.size(); ++i) { |
| 116 | const std::vector<u8> compressed_data = | 173 | std::vector<u8> data = |
| 117 | file->ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset); | 174 | ReadSegment(file, nso_header.segments[i], nso_header.segments_compressed_size[i]); |
| 118 | std::vector<u8> data = DecompressSegment(compressed_data, nso_header.segments[i]); | ||
| 119 | program_image.resize(nso_header.segments[i].location); | 175 | program_image.resize(nso_header.segments[i].location); |
| 120 | program_image.insert(program_image.end(), data.begin(), data.end()); | 176 | program_image.insert(program_image.end(), data.begin(), data.end()); |
| 121 | codeset->segments[i].addr = nso_header.segments[i].location; | 177 | codeset->segments[i].addr = nso_header.segments[i].location; |
| @@ -142,7 +198,7 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) { | |||
| 142 | program_image.resize(image_size); | 198 | program_image.resize(image_size); |
| 143 | 199 | ||
| 144 | // Load codeset for current process | 200 | // Load codeset for current process |
| 145 | codeset->name = file->GetName(); | 201 | codeset->name = path; |
| 146 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | 202 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); |
| 147 | Core::CurrentProcess()->LoadModule(codeset, load_base); | 203 | Core::CurrentProcess()->LoadModule(codeset, load_base); |
| 148 | 204 | ||
| @@ -153,10 +209,13 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||
| 153 | if (is_loaded) { | 209 | if (is_loaded) { |
| 154 | return ResultStatus::ErrorAlreadyLoaded; | 210 | return ResultStatus::ErrorAlreadyLoaded; |
| 155 | } | 211 | } |
| 212 | if (!file.IsOpen()) { | ||
| 213 | return ResultStatus::Error; | ||
| 214 | } | ||
| 156 | 215 | ||
| 157 | // Load module | 216 | // Load module |
| 158 | LoadModule(file, Memory::PROCESS_IMAGE_VADDR); | 217 | LoadModule(filepath, Memory::PROCESS_IMAGE_VADDR); |
| 159 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR); | 218 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", filepath, Memory::PROCESS_IMAGE_VADDR); |
| 160 | 219 | ||
| 161 | process->svc_access_mask.set(); | 220 | process->svc_access_mask.set(); |
| 162 | process->address_mappings = default_address_mappings; | 221 | process->address_mappings = default_address_mappings; |