summaryrefslogtreecommitdiff
path: root/src/core/loader/nso.cpp
diff options
context:
space:
mode:
authorGravatar Zach Hilman2018-06-21 11:16:23 -0400
committerGravatar bunnei2018-06-21 11:16:23 -0400
commit63f26d5c40adb49094b03b232528672f526afe49 (patch)
treeb76a154e17c819df7803d5860f08406446507a5c /src/core/loader/nso.cpp
parentMerge pull request #576 from Subv/warnings1 (diff)
downloadyuzu-63f26d5c40adb49094b03b232528672f526afe49.tar.gz
yuzu-63f26d5c40adb49094b03b232528672f526afe49.tar.xz
yuzu-63f26d5c40adb49094b03b232528672f526afe49.zip
Add support for decrypted NCA files (#567)
* Start to add NCA support in loader * More nca stuff * More changes to nca.cpp * Now identifies decrypted NCA cont. * Game list fixes and more structs and stuff * More updates to Nca class * Now reads ExeFs (i think) * ACTUALLY LOADS EXEFS! * RomFS loads and games execute * Cleanup and Finalize * plumbing, cleanup and testing * fix some things that i didnt think of before * Preliminary Review Changes * Review changes for bunnei and subv
Diffstat (limited to 'src/core/loader/nso.cpp')
-rw-r--r--src/core/loader/nso.cpp79
1 files changed, 68 insertions, 11 deletions
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 01be9e217..845ed7e90 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -66,8 +66,22 @@ FileType AppLoader_NSO::IdentifyType(FileUtil::IOFile& file, const std::string&)
66 return FileType::Error; 66 return FileType::Error;
67} 67}
68 68
69static std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data,
70 const NsoSegmentHeader& header) {
71 std::vector<u8> uncompressed_data;
72 uncompressed_data.resize(header.size);
73 const int bytes_uncompressed = LZ4_decompress_safe(
74 reinterpret_cast<const char*>(compressed_data.data()),
75 reinterpret_cast<char*>(uncompressed_data.data()), compressed_data.size(), header.size);
76
77 ASSERT_MSG(bytes_uncompressed == header.size && bytes_uncompressed == uncompressed_data.size(),
78 "{} != {} != {}", bytes_uncompressed, header.size, uncompressed_data.size());
79
80 return uncompressed_data;
81}
82
69static std::vector<u8> ReadSegment(FileUtil::IOFile& file, const NsoSegmentHeader& header, 83static std::vector<u8> ReadSegment(FileUtil::IOFile& file, const NsoSegmentHeader& header,
70 int compressed_size) { 84 size_t compressed_size) {
71 std::vector<u8> compressed_data; 85 std::vector<u8> compressed_data;
72 compressed_data.resize(compressed_size); 86 compressed_data.resize(compressed_size);
73 87
@@ -77,22 +91,65 @@ static std::vector<u8> ReadSegment(FileUtil::IOFile& file, const NsoSegmentHeade
77 return {}; 91 return {};
78 } 92 }
79 93
80 std::vector<u8> uncompressed_data; 94 return DecompressSegment(compressed_data, header);
81 uncompressed_data.resize(header.size);
82 const int bytes_uncompressed = LZ4_decompress_safe(
83 reinterpret_cast<const char*>(compressed_data.data()),
84 reinterpret_cast<char*>(uncompressed_data.data()), compressed_size, header.size);
85
86 ASSERT_MSG(bytes_uncompressed == header.size && bytes_uncompressed == uncompressed_data.size(),
87 "{} != {} != {}", bytes_uncompressed, header.size, uncompressed_data.size());
88
89 return uncompressed_data;
90} 95}
91 96
92static constexpr u32 PageAlignSize(u32 size) { 97static constexpr u32 PageAlignSize(u32 size) {
93 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; 98 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
94} 99}
95 100
101VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector<u8>& file_data,
102 VAddr load_base) {
103 if (file_data.size() < sizeof(NsoHeader))
104 return {};
105
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'))
110 return {};
111
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
96VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base) { 153VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base) {
97 FileUtil::IOFile file(path, "rb"); 154 FileUtil::IOFile file(path, "rb");
98 if (!file.IsOpen()) { 155 if (!file.IsOpen()) {