1 // Copyright 2017 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <cstddef> 8 #include <memory> 9 #include <string> 10 #include <vector> 11 #include "common/bit_field.h" 12 #include "common/common_types.h" 13 #include "common/file_util.h" 14 #include "common/swap.h" 15 #include "core/core.h" 16 #include "core/file_sys/romfs_reader.h" 17 18 enum NCSDContentIndex { Main = 0, Manual = 1, DLP = 2, New3DSUpdate = 6, Update = 7 }; 19 20 struct NCSD_Partitions { 21 u32 offset; 22 u32 size; 23 }; 24 25 struct NCSD_Header { 26 u8 signature[0x100]; 27 u32_le magic; 28 u32_le media_size; 29 u8 media_id[8]; 30 u8 partition_fs_type[8]; 31 u8 partition_crypt_type[8]; 32 NCSD_Partitions partitions[8]; 33 u8 extended_header_hash[0x20]; 34 u32_le additional_header_size; 35 u32_le sector_zero_offset; 36 u8 partition_flags[8]; 37 u8 partition_id_table[0x40]; 38 u8 reserved[0x30]; 39 }; 40 41 static_assert(sizeof(NCSD_Header) == 0x200, "NCCH header structure size is wrong"); 42 43 //////////////////////////////////////////////////////////////////////////////////////////////////// 44 /// NCCH header (Note: "NCCH" appears to be a publicly unknown acronym) 45 46 struct NCCH_Header { 47 u8 signature[0x100]; 48 u32_le magic; 49 u32_le content_size; 50 u8 partition_id[8]; 51 u16_le maker_code; 52 u16_le version; 53 u8 reserved_0[4]; 54 u64_le program_id; 55 u8 reserved_1[0x10]; 56 u8 logo_region_hash[0x20]; 57 u8 product_code[0x10]; 58 u8 extended_header_hash[0x20]; 59 u32_le extended_header_size; 60 u8 reserved_2[4]; 61 u8 reserved_flag[3]; 62 u8 secondary_key_slot; 63 u8 platform; 64 enum class ContentType : u8 { 65 Application = 0, 66 SystemUpdate = 1, 67 Manual = 2, 68 Child = 3, 69 Trial = 4, 70 }; 71 union { 72 BitField<0, 1, u8> is_data; 73 BitField<1, 1, u8> is_executable; 74 BitField<2, 3, ContentType> content_type; 75 }; 76 u8 content_unit_size; 77 union { 78 BitField<0, 1, u8> fixed_key; 79 BitField<1, 1, u8> no_romfs; 80 BitField<2, 1, u8> no_crypto; 81 BitField<5, 1, u8> seed_crypto; 82 }; 83 u32_le plain_region_offset; 84 u32_le plain_region_size; 85 u32_le logo_region_offset; 86 u32_le logo_region_size; 87 u32_le exefs_offset; 88 u32_le exefs_size; 89 u32_le exefs_hash_region_size; 90 u8 reserved_3[4]; 91 u32_le romfs_offset; 92 u32_le romfs_size; 93 u32_le romfs_hash_region_size; 94 u8 reserved_4[4]; 95 u8 exefs_super_block_hash[0x20]; 96 u8 romfs_super_block_hash[0x20]; 97 }; 98 99 static_assert(sizeof(NCCH_Header) == 0x200, "NCCH header structure size is wrong"); 100 101 //////////////////////////////////////////////////////////////////////////////////////////////////// 102 // ExeFS (executable file system) headers 103 104 struct ExeFs_SectionHeader { 105 char name[8]; 106 u32 offset; 107 u32 size; 108 }; 109 110 struct ExeFs_Header { 111 ExeFs_SectionHeader section[8]; 112 u8 reserved[0x80]; 113 u8 hashes[8][0x20]; 114 }; 115 116 //////////////////////////////////////////////////////////////////////////////////////////////////// 117 // ExHeader (executable file system header) headers 118 119 struct ExHeader_SystemInfoFlags { 120 u8 reserved[5]; 121 u8 flag; 122 u8 remaster_version[2]; 123 }; 124 125 struct ExHeader_CodeSegmentInfo { 126 u32 address; 127 u32 num_max_pages; 128 u32 code_size; 129 }; 130 131 struct ExHeader_CodeSetInfo { 132 u8 name[8]; 133 ExHeader_SystemInfoFlags flags; 134 ExHeader_CodeSegmentInfo text; 135 u32 stack_size; 136 ExHeader_CodeSegmentInfo ro; 137 u8 reserved[4]; 138 ExHeader_CodeSegmentInfo data; 139 u32 bss_size; 140 }; 141 142 struct ExHeader_DependencyList { 143 u8 program_id[0x30][8]; 144 }; 145 146 struct ExHeader_SystemInfo { 147 u64 save_data_size; 148 u64_le jump_id; 149 u8 reserved_2[0x30]; 150 }; 151 152 struct ExHeader_StorageInfo { 153 union { 154 u64_le ext_save_data_id; 155 // When using extended savedata access 156 // Prefer the ID specified in the most significant bits 157 BitField<40, 20, u64> extdata_id3; 158 BitField<20, 20, u64> extdata_id4; 159 BitField<0, 20, u64> extdata_id5; 160 }; 161 u8 system_save_data_id[8]; 162 union { 163 u64_le storage_accessible_unique_ids; 164 // When using extended savedata access 165 // Prefer the ID specified in the most significant bits 166 BitField<40, 20, u64> extdata_id0; 167 BitField<20, 20, u64> extdata_id1; 168 BitField<0, 20, u64> extdata_id2; 169 }; 170 u8 access_info[7]; 171 u8 other_attributes; 172 }; 173 174 struct ExHeader_ARM11_SystemLocalCaps { 175 u64_le program_id; 176 u32_le core_version; 177 u8 reserved_flag; 178 u8 n3ds_mode; 179 union { 180 u8 flags0; 181 BitField<0, 2, u8> ideal_processor; 182 BitField<2, 2, u8> affinity_mask; 183 BitField<4, 4, u8> system_mode; 184 }; 185 u8 priority; 186 u8 resource_limit_descriptor[0x10][2]; 187 ExHeader_StorageInfo storage_info; 188 u8 service_access_control[0x20][8]; 189 u8 ex_service_access_control[0x2][8]; 190 u8 reserved[0xf]; 191 u8 resource_limit_category; 192 }; 193 194 struct ExHeader_ARM11_KernelCaps { 195 static constexpr std::size_t NUM_DESCRIPTORS = 28; 196 197 u32_le descriptors[NUM_DESCRIPTORS]; 198 u8 reserved[0x10]; 199 }; 200 201 struct ExHeader_ARM9_AccessControl { 202 static constexpr std::size_t NUM_DESCRIPTORS = 15; 203 204 u8 descriptors[NUM_DESCRIPTORS]; 205 u8 descversion; 206 }; 207 208 struct ExHeader_Header { 209 ExHeader_CodeSetInfo codeset_info; 210 ExHeader_DependencyList dependency_list; 211 ExHeader_SystemInfo system_info; 212 ExHeader_ARM11_SystemLocalCaps arm11_system_local_caps; 213 ExHeader_ARM11_KernelCaps arm11_kernel_caps; 214 ExHeader_ARM9_AccessControl arm9_access_control; 215 struct { 216 u8 signature[0x100]; 217 u8 ncch_public_key_modulus[0x100]; 218 ExHeader_ARM11_SystemLocalCaps arm11_system_local_caps; 219 ExHeader_ARM11_KernelCaps arm11_kernel_caps; 220 ExHeader_ARM9_AccessControl arm9_access_control; 221 } access_desc; 222 }; 223 224 static_assert(sizeof(ExHeader_Header) == 0x800, "ExHeader structure size is wrong"); 225 226 //////////////////////////////////////////////////////////////////////////////////////////////////// 227 // FileSys namespace 228 229 namespace FileSys { 230 231 /** 232 * Helper which implements an interface to deal with NCCH containers which can 233 * contain ExeFS archives or RomFS archives for games or other applications. 234 */ 235 class NCCHContainer { 236 public: 237 NCCHContainer(const std::string& filepath, u32 ncch_offset = 0, u32 partition = 0); NCCHContainer()238 NCCHContainer() {} 239 240 Loader::ResultStatus OpenFile(const std::string& filepath, u32 ncch_offset = 0, 241 u32 partition = 0); 242 243 /** 244 * Ensure NCCH header is loaded and ready for reading sections 245 * @return ResultStatus result of function 246 */ 247 Loader::ResultStatus LoadHeader(); 248 249 /** 250 * Ensure ExeFS and exheader is loaded and ready for reading sections 251 * @return ResultStatus result of function 252 */ 253 Loader::ResultStatus Load(); 254 255 /** 256 * Attempt to find overridden sections for the NCCH and mark the container as tainted 257 * if any are found. 258 * @return ResultStatus result of function 259 */ 260 Loader::ResultStatus LoadOverrides(); 261 262 /** 263 * Reads an application ExeFS section of an NCCH file (e.g. .code, .logo, etc.) 264 * @param name Name of section to read out of NCCH file 265 * @param buffer Vector to read data into 266 * @return ResultStatus result of function 267 */ 268 Loader::ResultStatus LoadSectionExeFS(const char* name, std::vector<u8>& buffer); 269 270 /** 271 * Reads an application ExeFS section from external files instead of an NCCH file, 272 * (e.g. code.bin, logo.bcma.lz, icon.icn, banner.bnr) 273 * @param name Name of section to read from external files 274 * @param buffer Vector to read data into 275 * @return ResultStatus result of function 276 */ 277 Loader::ResultStatus LoadOverrideExeFSSection(const char* name, std::vector<u8>& buffer); 278 279 /** 280 * Get the RomFS of the NCCH container 281 * Since the RomFS can be huge, we return a file reference instead of copying to a buffer 282 * @param romfs_file The file containing the RomFS 283 * @param offset The offset the romfs begins on 284 * @param size The size of the romfs 285 * @return ResultStatus result of function 286 */ 287 Loader::ResultStatus ReadRomFS(std::shared_ptr<RomFSReader>& romfs_file, 288 bool use_layered_fs = true); 289 290 /** 291 * Dump the RomFS of the NCCH container to the user folder. 292 * @param target_path target path to dump to 293 * @return ResultStatus result of function. 294 */ 295 Loader::ResultStatus DumpRomFS(const std::string& target_path); 296 297 /** 298 * Get the override RomFS of the NCCH container 299 * Since the RomFS can be huge, we return a file reference instead of copying to a buffer 300 * @param romfs_file The file containing the RomFS 301 * @param offset The offset the romfs begins on 302 * @param size The size of the romfs 303 * @return ResultStatus result of function 304 */ 305 Loader::ResultStatus ReadOverrideRomFS(std::shared_ptr<RomFSReader>& romfs_file); 306 307 /** 308 * Get the Program ID of the NCCH container 309 * @return ResultStatus result of function 310 */ 311 Loader::ResultStatus ReadProgramId(u64_le& program_id); 312 313 /** 314 * Get the Extdata ID of the NCCH container 315 * @return ResultStatus result of function 316 */ 317 Loader::ResultStatus ReadExtdataId(u64& extdata_id); 318 319 /** 320 * Apply a patch for .code (if it exists). 321 * This should only be called after allocating .bss. 322 * @return ResultStatus success if a patch was applied, ErrorNotUsed if no patch was found 323 */ 324 Loader::ResultStatus ApplyCodePatch(std::vector<u8>& code) const; 325 326 /** 327 * Checks whether the NCCH container contains an ExeFS 328 * @return bool check result 329 */ 330 bool HasExeFS(); 331 332 /** 333 * Checks whether the NCCH container contains a RomFS 334 * @return bool check result 335 */ 336 bool HasRomFS(); 337 338 /** 339 * Checks whether the NCCH container contains an ExHeader 340 * @return bool check result 341 */ 342 bool HasExHeader(); 343 344 NCCH_Header ncch_header; 345 ExeFs_Header exefs_header; 346 ExHeader_Header exheader_header; 347 348 private: 349 bool has_header = false; 350 bool has_exheader = false; 351 bool has_exefs = false; 352 bool has_romfs = false; 353 354 bool is_tainted = false; // Are there parts of this container being overridden? 355 bool is_loaded = false; 356 bool is_compressed = false; 357 358 bool is_encrypted = false; 359 // for decrypting exheader, exefs header and icon/banner section 360 std::array<u8, 16> primary_key{}; 361 std::array<u8, 16> secondary_key{}; // for decrypting romfs and .code section 362 std::array<u8, 16> exheader_ctr{}; 363 std::array<u8, 16> exefs_ctr{}; 364 std::array<u8, 16> romfs_ctr{}; 365 366 u32 ncch_offset = 0; // Offset to NCCH header, can be 0 for NCCHs or non-zero for CIAs/NCSDs 367 u32 exefs_offset = 0; 368 u32 partition = 0; 369 370 std::string filepath; 371 FileUtil::IOFile file; 372 FileUtil::IOFile exefs_file; 373 }; 374 375 } // namespace FileSys 376