mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Loader: Added support for booting NCCH executables.
NCCH: Fixed typo in printing NCCH filename.
This commit is contained in:
		
							parent
							
								
									0aca202ae9
								
							
						
					
					
						commit
						3577dd027d
					
				
					 6 changed files with 384 additions and 0 deletions
				
			
		|  | @ -2,6 +2,7 @@ set(SRCS    core.cpp | ||||||
|             core_timing.cpp |             core_timing.cpp | ||||||
|             loader/elf_reader.cpp |             loader/elf_reader.cpp | ||||||
|             loader/loader.cpp |             loader/loader.cpp | ||||||
|  |             loader/ncch.cpp | ||||||
|             mem_map.cpp |             mem_map.cpp | ||||||
|             mem_map_funcs.cpp |             mem_map_funcs.cpp | ||||||
|             system.cpp |             system.cpp | ||||||
|  | @ -53,6 +54,7 @@ set(HEADERS core.h | ||||||
|             loader/elf_reader.h |             loader/elf_reader.h | ||||||
|             loader/elf_types.h |             loader/elf_types.h | ||||||
|             loader/loader.h |             loader/loader.h | ||||||
|  |             loader/ncch.h | ||||||
|             mem_map.h |             mem_map.h | ||||||
|             system.h |             system.h | ||||||
|             arm/disassembler/arm_disasm.h |             arm/disassembler/arm_disasm.h | ||||||
|  |  | ||||||
|  | @ -183,6 +183,7 @@ | ||||||
|     <ClCompile Include="hw\ndma.cpp" /> |     <ClCompile Include="hw\ndma.cpp" /> | ||||||
|     <ClCompile Include="loader\elf_reader.cpp" /> |     <ClCompile Include="loader\elf_reader.cpp" /> | ||||||
|     <ClCompile Include="loader\loader.cpp" /> |     <ClCompile Include="loader\loader.cpp" /> | ||||||
|  |     <ClCompile Include="loader\ncch.cpp" /> | ||||||
|     <ClCompile Include="mem_map.cpp" /> |     <ClCompile Include="mem_map.cpp" /> | ||||||
|     <ClCompile Include="mem_map_funcs.cpp" /> |     <ClCompile Include="mem_map_funcs.cpp" /> | ||||||
|     <ClCompile Include="system.cpp" /> |     <ClCompile Include="system.cpp" /> | ||||||
|  | @ -234,6 +235,7 @@ | ||||||
|     <ClInclude Include="loader\elf_reader.h" /> |     <ClInclude Include="loader\elf_reader.h" /> | ||||||
|     <ClInclude Include="loader\elf_types.h" /> |     <ClInclude Include="loader\elf_types.h" /> | ||||||
|     <ClInclude Include="loader\loader.h" /> |     <ClInclude Include="loader\loader.h" /> | ||||||
|  |     <ClInclude Include="loader\ncch.h" /> | ||||||
|     <ClInclude Include="mem_map.h" /> |     <ClInclude Include="mem_map.h" /> | ||||||
|     <ClInclude Include="system.h" /> |     <ClInclude Include="system.h" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|  |  | ||||||
|  | @ -173,6 +173,9 @@ | ||||||
|     <ClCompile Include="loader\loader.cpp"> |     <ClCompile Include="loader\loader.cpp"> | ||||||
|       <Filter>loader</Filter> |       <Filter>loader</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  |     <ClCompile Include="loader\ncch.cpp"> | ||||||
|  |       <Filter>loader</Filter> | ||||||
|  |     </ClCompile> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClInclude Include="arm\disassembler\arm_disasm.h"> |     <ClInclude Include="arm\disassembler\arm_disasm.h"> | ||||||
|  | @ -311,6 +314,9 @@ | ||||||
|     <ClInclude Include="loader\loader.h"> |     <ClInclude Include="loader\loader.h"> | ||||||
|       <Filter>loader</Filter> |       <Filter>loader</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|  |     <ClInclude Include="loader\ncch.h"> | ||||||
|  |       <Filter>loader</Filter> | ||||||
|  |     </ClInclude> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <Text Include="CMakeLists.txt" /> |     <Text Include="CMakeLists.txt" /> | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "core/loader/loader.h" | #include "core/loader/loader.h" | ||||||
| #include "core/loader/elf_reader.h" | #include "core/loader/elf_reader.h" | ||||||
|  | #include "core/loader/ncch.h" | ||||||
| #include "core/system.h" | #include "core/system.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
|  | @ -165,6 +166,10 @@ bool LoadFile(std::string &filename, std::string *error_string) { | ||||||
|     case FILETYPE_CTR_BIN: |     case FILETYPE_CTR_BIN: | ||||||
|         return Load_BIN(filename); |         return Load_BIN(filename); | ||||||
| 
 | 
 | ||||||
|  |     case FILETYPE_CTR_CXI: | ||||||
|  |     case FILETYPE_CTR_CCI: | ||||||
|  |         return Loader::Load_NCCH(filename, error_string); | ||||||
|  | 
 | ||||||
|     case FILETYPE_ERROR: |     case FILETYPE_ERROR: | ||||||
|         ERROR_LOG(LOADER, "Could not read file"); |         ERROR_LOG(LOADER, "Could not read file"); | ||||||
|         *error_string = "Error reading file"; |         *error_string = "Error reading file"; | ||||||
|  |  | ||||||
							
								
								
									
										348
									
								
								src/core/loader/ncch.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										348
									
								
								src/core/loader/ncch.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,348 @@ | ||||||
|  | // Copyright 2014 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include "common/file_util.h" | ||||||
|  | 
 | ||||||
|  | #include "core/loader/ncch.h" | ||||||
|  | #include "core/hle/kernel/kernel.h" | ||||||
|  | #include "core/mem_map.h" | ||||||
|  | 
 | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | /// NCCH header (Note: "NCCH" appears to be a publically unknown acronym)
 | ||||||
|  | 
 | ||||||
|  | struct NCCH_Header { | ||||||
|  |     u8 signature[0x100]; | ||||||
|  |     char magic[4]; | ||||||
|  |     u32 content_size; | ||||||
|  |     u8 partition_id[8]; | ||||||
|  |     u16 maker_code; | ||||||
|  |     u16 version; | ||||||
|  |     u8 reserved_0[4]; | ||||||
|  |     u8 program_id[8]; | ||||||
|  |     u8 temp_flag; | ||||||
|  |     u8 reserved_1[0x2f]; | ||||||
|  |     u8 product_code[0x10]; | ||||||
|  |     u8 extended_header_hash[0x20]; | ||||||
|  |     u32 extended_header_size; | ||||||
|  |     u8 reserved_2[4]; | ||||||
|  |     u8 flags[8]; | ||||||
|  |     u32 plain_region_offset; | ||||||
|  |     u32 plain_region_size; | ||||||
|  |     u8 reserved_3[8]; | ||||||
|  |     u32 exefs_offset; | ||||||
|  |     u32 exefs_size; | ||||||
|  |     u32 exefs_hash_region_size; | ||||||
|  |     u8 reserved_4[4]; | ||||||
|  |     u32 romfs_offset; | ||||||
|  |     u32 romfs_size; | ||||||
|  |     u32 romfs_hash_region_size; | ||||||
|  |     u8 reserved_5[4]; | ||||||
|  |     u8 exefs_super_block_hash[0x20]; | ||||||
|  |     u8 romfs_super_block_hash[0x20]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | // ExeFS (executable file system) headers
 | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     char name[8]; | ||||||
|  |     u32 offset; | ||||||
|  |     u32 size; | ||||||
|  | } ExeFs_SectionHeader; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     ExeFs_SectionHeader section[8]; | ||||||
|  |     u8 reserved[0x80]; | ||||||
|  |     u8 hashes[8][0x20]; | ||||||
|  | } ExeFs_Header; | ||||||
|  | 
 | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | // ExHeader (executable file system header) headers
 | ||||||
|  | 
 | ||||||
|  | struct ExHeader_SystemInfoFlags{ | ||||||
|  |     u8 reserved[5]; | ||||||
|  |     u8 flag; | ||||||
|  |     u8 remaster_version[2]; | ||||||
|  | } exheader_systeminfoflags; | ||||||
|  | 
 | ||||||
|  | struct ExHeader_CodeSegmentInfo{ | ||||||
|  |     u32 address; | ||||||
|  |     u32 num_max_pages; | ||||||
|  |     u32 code_size; | ||||||
|  | } exheader_codesegmentinfo; | ||||||
|  | 
 | ||||||
|  | struct ExHeader_CodeSetInfo { | ||||||
|  |     u8 name[8]; | ||||||
|  |     ExHeader_SystemInfoFlags flags; | ||||||
|  |     ExHeader_CodeSegmentInfo text; | ||||||
|  |     u8 stacksize[4]; | ||||||
|  |     ExHeader_CodeSegmentInfo ro; | ||||||
|  |     u8 reserved[4]; | ||||||
|  |     ExHeader_CodeSegmentInfo data; | ||||||
|  |     u8 bsssize[4]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct ExHeader_DependencyList{ | ||||||
|  |     u8 program_id[0x30][8]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct ExHeader_SystemInfo{ | ||||||
|  |     u32 save_data_size; | ||||||
|  |     u8 reserved[4]; | ||||||
|  |     u8 jump_id[8]; | ||||||
|  |     u8 reserved_2[0x30]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct ExHeader_StorageInfo{ | ||||||
|  |     u8 ext_save_data_id[8]; | ||||||
|  |     u8 system_save_data_id[8]; | ||||||
|  |     u8 reserved[8]; | ||||||
|  |     u8 access_info[7]; | ||||||
|  |     u8 other_attributes; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct ExHeader_ARM11_SystemLocalCaps{ | ||||||
|  |     u8 program_id[8]; | ||||||
|  |     u8 flags[8]; | ||||||
|  |     u8 resource_limit_descriptor[0x10][2]; | ||||||
|  |     ExHeader_StorageInfo storage_info; | ||||||
|  |     u8 service_access_control[0x20][8]; | ||||||
|  |     u8 reserved[0x1f]; | ||||||
|  |     u8 resource_limit_category; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct ExHeader_ARM11_KernelCaps{ | ||||||
|  |     u8 descriptors[28][4]; | ||||||
|  |     u8 reserved[0x10]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct ExHeader_ARM9_AccessControl{ | ||||||
|  |     u8 descriptors[15]; | ||||||
|  |     u8 descversion; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct ExHeader_Header{ | ||||||
|  |     ExHeader_CodeSetInfo codeset_info; | ||||||
|  |     ExHeader_DependencyList dependency_list; | ||||||
|  |     ExHeader_SystemInfo system_info; | ||||||
|  |     ExHeader_ARM11_SystemLocalCaps arm11_system_local_caps; | ||||||
|  |     ExHeader_ARM11_KernelCaps arm11_kernel_caps; | ||||||
|  |     ExHeader_ARM9_AccessControl arm9_access_control; | ||||||
|  |     struct { | ||||||
|  |         u8 signature[0x100]; | ||||||
|  |         u8 ncch_public_key_modulus[0x100]; | ||||||
|  |         ExHeader_ARM11_SystemLocalCaps arm11_system_local_caps; | ||||||
|  |         ExHeader_ARM11_KernelCaps arm11_kernel_caps; | ||||||
|  |         ExHeader_ARM9_AccessControl arm9_access_control; | ||||||
|  |     } access_desc; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | // Loader namespace
 | ||||||
|  | 
 | ||||||
|  | namespace Loader { | ||||||
|  | 
 | ||||||
|  | const int kExeFs_MaxSections    = 8;        ///< Maximum number of sections (files) in an ExeFs
 | ||||||
|  | const int kExeFs_BlockSize      = 0x200;    ///< Size of ExeFS blocks (in bytes)
 | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Get the decompressed size of an LZSS compressed ExeFS file | ||||||
|  |  * @param buffer Buffer of compressed file | ||||||
|  |  * @param size Size of compressed buffer | ||||||
|  |  * @return Size of decompressed buffer | ||||||
|  |  */ | ||||||
|  | u32 LZSS_GetDecompressedSize(u8* buffer, u32 size) { | ||||||
|  |     u32 offset_size = *(u32*)(buffer + size - 4); | ||||||
|  |     return offset_size + size; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Decompress ExeFS file (compressed with LZSS) | ||||||
|  |  * @param compressed Compressed buffer | ||||||
|  |  * @param compressed_size Size of compressed buffer | ||||||
|  |  * @param decompressed Decompressed buffer | ||||||
|  |  * @param decompressed_size Size of decompressed buffer | ||||||
|  |  * @param error_string String populated with error message on failure | ||||||
|  |  * @return True on success, otherwise false | ||||||
|  |  */ | ||||||
|  | bool LZSS_Decompress(u8* compressed, u32 compressed_size, u8* decompressed, u32 decompressed_size,  | ||||||
|  |     std::string* error_string) { | ||||||
|  |     u8* footer = compressed + compressed_size - 8; | ||||||
|  |     u32 buffer_top_and_bottom = *(u32*)footer; | ||||||
|  |     u32 i, j; | ||||||
|  |     u32 out = decompressed_size; | ||||||
|  |     u32 index = compressed_size - ((buffer_top_and_bottom >> 24) & 0xFF); | ||||||
|  |     u8 control; | ||||||
|  |     u32 stop_index = compressed_size - (buffer_top_and_bottom & 0xFFFFFF); | ||||||
|  | 
 | ||||||
|  |     memset(decompressed, 0, decompressed_size); | ||||||
|  |     memcpy(decompressed, compressed, compressed_size); | ||||||
|  | 
 | ||||||
|  |     while(index > stop_index) { | ||||||
|  |         control = compressed[--index]; | ||||||
|  | 
 | ||||||
|  |         for(i = 0; i < 8; i++) { | ||||||
|  |             if(index <= stop_index) | ||||||
|  |                 break; | ||||||
|  |             if(index <= 0) | ||||||
|  |                 break; | ||||||
|  |             if(out <= 0) | ||||||
|  |                 break; | ||||||
|  | 
 | ||||||
|  |             if(control & 0x80) { | ||||||
|  |                 if(index < 2) { | ||||||
|  |                     *error_string = "Compression out of bounds"; | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |                 index -= 2; | ||||||
|  | 
 | ||||||
|  |                 u32 segment_offset = compressed[index] | (compressed[index + 1] << 8); | ||||||
|  |                 u32 segment_size = ((segment_offset >> 12) & 15) + 3; | ||||||
|  |                 segment_offset &= 0x0FFF; | ||||||
|  |                 segment_offset += 2; | ||||||
|  | 
 | ||||||
|  |                 if(out < segment_size) { | ||||||
|  |                     *error_string = "Compression out of bounds"; | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |                 for(j = 0; j < segment_size; j++) { | ||||||
|  |                     u8 data; | ||||||
|  |                     if(out + segment_offset >= decompressed_size) { | ||||||
|  |                         *error_string = "Compression out of bounds"; | ||||||
|  |                         return false; | ||||||
|  |                     } | ||||||
|  |                     data  = decompressed[out + segment_offset]; | ||||||
|  |                     decompressed[--out] = data; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 if(out < 1) { | ||||||
|  |                     *error_string = "Compression out of bounds"; | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |                 decompressed[--out] = compressed[--index]; | ||||||
|  |             } | ||||||
|  |             control <<= 1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Load a data buffer into memory at the specified address | ||||||
|  |  * @param addr Address to load memory into | ||||||
|  |  * @param buffer Buffer of data to load into memory | ||||||
|  |  * @param size Size of data to load into memory | ||||||
|  |  * @todo Perhaps move this code somewhere more generic? | ||||||
|  |  */ | ||||||
|  | void LoadBuffer(const u32 addr, const u8* const buffer, const int size) { | ||||||
|  |     u32 *dst = (u32*)Memory::GetPointer(addr); | ||||||
|  |     u32 *src = (u32*)buffer; | ||||||
|  |     int size_aligned = (size + 3) / 4; | ||||||
|  | 
 | ||||||
|  |     for (int j = 0; j < size_aligned; j++) { | ||||||
|  |         *dst++ = (*src++); | ||||||
|  |     } | ||||||
|  |     return; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI) | ||||||
|  |  * @param filename String filename of NCCH file | ||||||
|  |  * @param error_string Pointer to string to put error message if an error has occurred | ||||||
|  |  * @todo Move NCSD parsing out of here and create a separate function for loading these | ||||||
|  |  * @return True on success, otherwise false | ||||||
|  |  */ | ||||||
|  | bool Load_NCCH(std::string& filename, std::string* error_string) { | ||||||
|  |     INFO_LOG(LOADER, "Loading NCCH file %s...", filename.c_str()); | ||||||
|  | 
 | ||||||
|  |     File::IOFile file(filename, "rb"); | ||||||
|  | 
 | ||||||
|  |     if (file.IsOpen()) { | ||||||
|  |         NCCH_Header ncch_header; | ||||||
|  |         file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); | ||||||
|  | 
 | ||||||
|  |         // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
 | ||||||
|  |         int ncch_off = 0; // Offset to NCCH header, can be 0 or after NCSD header
 | ||||||
|  |         if (memcmp(&ncch_header.magic, "NCSD", 4) == 0) { | ||||||
|  |             WARN_LOG(LOADER, "Only loading the first (bootable) NCCH within the NCSD file!"); | ||||||
|  |             ncch_off = 0x4000; | ||||||
|  |             file.Seek(ncch_off, 0); | ||||||
|  |             file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); | ||||||
|  |         } | ||||||
|  |         // Verify we are loading the correct file type...
 | ||||||
|  |         if (memcmp(&ncch_header.magic, "NCCH", 4) != 0) { | ||||||
|  |             *error_string = "Invalid NCCH magic number (likely incorrect file type)"; | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         // Read ExHeader
 | ||||||
|  |         ExHeader_Header exheader_header; | ||||||
|  |         file.ReadBytes(&exheader_header, sizeof(ExHeader_Header)); | ||||||
|  | 
 | ||||||
|  |         bool is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1; | ||||||
|  | 
 | ||||||
|  |         INFO_LOG(LOADER, "Name:            %s", exheader_header.codeset_info.name); | ||||||
|  |         INFO_LOG(LOADER, "Code compressed: %s", is_compressed ? "yes" : "no"); | ||||||
|  | 
 | ||||||
|  |         // Read ExeFS
 | ||||||
|  |         u32 exefs_offset = ncch_header.exefs_offset * kExeFs_BlockSize; | ||||||
|  |         u32 exefs_size = ncch_header.exefs_size * kExeFs_BlockSize; | ||||||
|  | 
 | ||||||
|  |         INFO_LOG(LOADER, "ExeFS offset:    0x%08X", exefs_offset); | ||||||
|  |         INFO_LOG(LOADER, "ExeFS size:      0x%08X", exefs_size); | ||||||
|  | 
 | ||||||
|  |         ExeFs_Header exefs_header; | ||||||
|  |         file.Seek(exefs_offset + ncch_off, 0); | ||||||
|  |         file.ReadBytes(&exefs_header, sizeof(ExeFs_Header)); | ||||||
|  | 
 | ||||||
|  |         // Iterate through the ExeFs archive until we find the .code file...
 | ||||||
|  |         for (int i = 0; i < kExeFs_MaxSections; i++) { | ||||||
|  |             INFO_LOG(LOADER, "ExeFS section %d:", i); | ||||||
|  |             INFO_LOG(LOADER, "    name:   %s", exefs_header.section[i].name); | ||||||
|  |             INFO_LOG(LOADER, "    offset: 0x%08X", exefs_header.section[i].offset); | ||||||
|  |             INFO_LOG(LOADER, "    size:   0x%08X", exefs_header.section[i].size); | ||||||
|  | 
 | ||||||
|  |             // Load the .code section (executable code)...
 | ||||||
|  |             if (strcmp((char*) exefs_header.section[i].name, ".code") == 0) { | ||||||
|  |                 file.Seek(exefs_header.section[i].offset + exefs_offset + sizeof(ExeFs_Header) +  | ||||||
|  |                     ncch_off, 0); | ||||||
|  | 
 | ||||||
|  |                 u8* buffer = new u8[exefs_header.section[i].size]; | ||||||
|  |                 file.ReadBytes(buffer, exefs_header.section[i].size); | ||||||
|  | 
 | ||||||
|  |                 // Load compressed executable...
 | ||||||
|  |                 if (i == 0 && is_compressed) { | ||||||
|  |                     u32 decompressed_size = LZSS_GetDecompressedSize(buffer,  | ||||||
|  |                         exefs_header.section[i].size); | ||||||
|  |                     u8* decompressed_buffer = new u8[decompressed_size]; | ||||||
|  | 
 | ||||||
|  |                     if (!LZSS_Decompress(buffer, exefs_header.section[i].size, decompressed_buffer, | ||||||
|  |                         decompressed_size, error_string)) { | ||||||
|  |                         return false; | ||||||
|  |                     } | ||||||
|  |                     // Load .code section into memory...
 | ||||||
|  |                     LoadBuffer(exheader_header.codeset_info.text.address, decompressed_buffer, | ||||||
|  |                         decompressed_size); | ||||||
|  | 
 | ||||||
|  |                     delete[] decompressed_buffer; | ||||||
|  | 
 | ||||||
|  |                 // Load uncompressed executable...
 | ||||||
|  |                 } else { | ||||||
|  |                     // Load .code section into memory...
 | ||||||
|  |                     LoadBuffer(exheader_header.codeset_info.text.address, buffer,  | ||||||
|  |                         exefs_header.section[i].size); | ||||||
|  |                 } | ||||||
|  |                 delete[] buffer; | ||||||
|  | 
 | ||||||
|  |                 // Setup kernel emulation to boot .code section...
 | ||||||
|  |                 Kernel::LoadExec(exheader_header.codeset_info.text.address); | ||||||
|  | 
 | ||||||
|  |                 // No need to load the other files from ExeFS until we do something with them...
 | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace Loader
 | ||||||
							
								
								
									
										21
									
								
								src/core/loader/ncch.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/core/loader/ncch.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | ||||||
|  | // Copyright 2014 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "common/common.h" | ||||||
|  | 
 | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | namespace Loader { | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Loads an NCCH file (e.g. from a CCI or CXI) | ||||||
|  |  * @param filename String filename of NCCH file | ||||||
|  |  * @param error_string Pointer to string to put error message if an error has occurred | ||||||
|  |  * @return True on success, otherwise false | ||||||
|  |  */ | ||||||
|  | bool Load_NCCH(std::string& filename, std::string* error_string); | ||||||
|  | 
 | ||||||
|  | } // namespace Loader
 | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue