diff options
| author | 2018-07-06 10:51:32 -0400 | |
|---|---|---|
| committer | 2018-07-06 10:51:32 -0400 | |
| commit | 77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2 (patch) | |
| tree | 38ef6451732c5eecb0efdd198f3db4d33848453c /src/core/loader/nso.cpp | |
| parent | Merge pull request #629 from Subv/depth_test (diff) | |
| download | yuzu-77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2.tar.gz yuzu-77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2.tar.xz yuzu-77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2.zip | |
Virtual Filesystem (#597)
* Add VfsFile and VfsDirectory classes
* Finish abstract Vfs classes
* Implement RealVfsFile (computer fs backend)
* Finish RealVfsFile and RealVfsDirectory
* Finished OffsetVfsFile
* More changes
* Fix import paths
* Major refactor
* Remove double const
* Use experimental/filesystem or filesystem depending on compiler
* Port partition_filesystem
* More changes
* More Overhaul
* FSP_SRV fixes
* Fixes and testing
* Try to get filesystem to compile
* Filesystem on linux
* Remove std::filesystem and document/test
* Compile fixes
* Missing include
* Bug fixes
* Fixes
* Rename v_file and v_dir
* clang-format fix
* Rename NGLOG_* to LOG_*
* Most review changes
* Fix TODO
* Guess 'main' to be Directory by filename
Diffstat (limited to 'src/core/loader/nso.cpp')
| -rw-r--r-- | src/core/loader/nso.cpp | 91 |
1 files changed, 16 insertions, 75 deletions
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 7f84e4b1b..2ed12a5ab 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -37,6 +37,7 @@ 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."); | ||
| 40 | 41 | ||
| 41 | struct ModHeader { | 42 | struct ModHeader { |
| 42 | u32_le magic; | 43 | u32_le magic; |
| @@ -49,15 +50,11 @@ struct ModHeader { | |||
| 49 | }; | 50 | }; |
| 50 | static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size."); | 51 | static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size."); |
| 51 | 52 | ||
| 52 | AppLoader_NSO::AppLoader_NSO(FileUtil::IOFile&& file, std::string filepath) | 53 | AppLoader_NSO::AppLoader_NSO(FileSys::VirtualFile file) : AppLoader(std::move(file)) {} |
| 53 | : AppLoader(std::move(file)), filepath(std::move(filepath)) {} | ||
| 54 | 54 | ||
| 55 | FileType AppLoader_NSO::IdentifyType(FileUtil::IOFile& file, const std::string&) { | 55 | FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& file) { |
| 56 | u32 magic = 0; | 56 | u32 magic = 0; |
| 57 | file.Seek(0, SEEK_SET); | 57 | file->ReadObject(&magic); |
| 58 | if (1 != file.ReadArray<u32>(&magic, 1)) { | ||
| 59 | return FileType::Error; | ||
| 60 | } | ||
| 61 | 58 | ||
| 62 | if (Common::MakeMagic('N', 'S', 'O', '0') == magic) { | 59 | if (Common::MakeMagic('N', 'S', 'O', '0') == magic) { |
| 63 | return FileType::NSO; | 60 | return FileType::NSO; |
| @@ -98,80 +95,27 @@ static constexpr u32 PageAlignSize(u32 size) { | |||
| 98 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; | 95 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; |
| 99 | } | 96 | } |
| 100 | 97 | ||
| 101 | VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector<u8>& file_data, | 98 | VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) { |
| 102 | VAddr load_base) { | 99 | if (file == nullptr) |
| 103 | if (file_data.size() < sizeof(NsoHeader)) | ||
| 104 | return {}; | 100 | return {}; |
| 105 | 101 | ||
| 106 | NsoHeader nso_header; | 102 | if (file->GetSize() < sizeof(NsoHeader)) |
| 107 | std::memcpy(&nso_header, file_data.data(), sizeof(NsoHeader)); | ||
| 108 | |||
| 109 | if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) | ||
| 110 | return {}; | 103 | return {}; |
| 111 | 104 | ||
| 112 | // Build program image | ||
| 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()) { | ||
| 156 | return {}; | ||
| 157 | } | ||
| 158 | |||
| 159 | // Read NSO header | ||
| 160 | NsoHeader nso_header{}; | 105 | NsoHeader nso_header{}; |
| 161 | file.Seek(0, SEEK_SET); | 106 | if (sizeof(NsoHeader) != file->ReadObject(&nso_header)) |
| 162 | if (sizeof(NsoHeader) != file.ReadBytes(&nso_header, sizeof(NsoHeader))) { | ||
| 163 | return {}; | 107 | return {}; |
| 164 | } | 108 | |
| 165 | if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) { | 109 | if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) |
| 166 | return {}; | 110 | return {}; |
| 167 | } | ||
| 168 | 111 | ||
| 169 | // Build program image | 112 | // Build program image |
| 170 | Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(""); | 113 | Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(""); |
| 171 | std::vector<u8> program_image; | 114 | std::vector<u8> program_image; |
| 172 | for (int i = 0; i < nso_header.segments.size(); ++i) { | 115 | for (int i = 0; i < nso_header.segments.size(); ++i) { |
| 173 | std::vector<u8> data = | 116 | const std::vector<u8> compressed_data = |
| 174 | ReadSegment(file, nso_header.segments[i], nso_header.segments_compressed_size[i]); | 117 | file->ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset); |
| 118 | std::vector<u8> data = DecompressSegment(compressed_data, nso_header.segments[i]); | ||
| 175 | program_image.resize(nso_header.segments[i].location); | 119 | program_image.resize(nso_header.segments[i].location); |
| 176 | program_image.insert(program_image.end(), data.begin(), data.end()); | 120 | program_image.insert(program_image.end(), data.begin(), data.end()); |
| 177 | codeset->segments[i].addr = nso_header.segments[i].location; | 121 | codeset->segments[i].addr = nso_header.segments[i].location; |
| @@ -198,7 +142,7 @@ VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base) { | |||
| 198 | program_image.resize(image_size); | 142 | program_image.resize(image_size); |
| 199 | 143 | ||
| 200 | // Load codeset for current process | 144 | // Load codeset for current process |
| 201 | codeset->name = path; | 145 | codeset->name = file->GetName(); |
| 202 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | 146 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); |
| 203 | Core::CurrentProcess()->LoadModule(codeset, load_base); | 147 | Core::CurrentProcess()->LoadModule(codeset, load_base); |
| 204 | 148 | ||
| @@ -209,13 +153,10 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||
| 209 | if (is_loaded) { | 153 | if (is_loaded) { |
| 210 | return ResultStatus::ErrorAlreadyLoaded; | 154 | return ResultStatus::ErrorAlreadyLoaded; |
| 211 | } | 155 | } |
| 212 | if (!file.IsOpen()) { | ||
| 213 | return ResultStatus::Error; | ||
| 214 | } | ||
| 215 | 156 | ||
| 216 | // Load module | 157 | // Load module |
| 217 | LoadModule(filepath, Memory::PROCESS_IMAGE_VADDR); | 158 | LoadModule(file, Memory::PROCESS_IMAGE_VADDR); |
| 218 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", filepath, Memory::PROCESS_IMAGE_VADDR); | 159 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR); |
| 219 | 160 | ||
| 220 | process->svc_access_mask.set(); | 161 | process->svc_access_mask.set(); |
| 221 | process->address_mappings = default_address_mappings; | 162 | process->address_mappings = default_address_mappings; |