diff --git a/include/loader/ncch.hpp b/include/loader/ncch.hpp index 9316eb33..ccc49e08 100644 --- a/include/loader/ncch.hpp +++ b/include/loader/ncch.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include "io_file.hpp" #include "helpers.hpp" @@ -10,6 +11,20 @@ struct NCCH { u64 hashRegionSize = 0; }; + // Descriptions for .text, .data and .rodata sections + struct CodeSetInfo { + u32 address = 0; + u32 pageCount = 0; + u32 size = 0; + + // Extract the code set info from the relevant header data + void extract(const u8* headerEntry) { + address = *(u32*)&headerEntry[0]; + pageCount = *(u32*)&headerEntry[4]; + size = *(u32*)&headerEntry[8]; + } + }; + u64 partitionIndex = 0; u64 fileOffset = 0; @@ -28,6 +43,10 @@ struct NCCH { FSInfo exeFS; FSInfo romFS; + CodeSetInfo text, data, rodata; + + // Contents of the .code file in the ExeFS + std::vector codeFile; // Header: 0x200 + 0x800 byte NCCH header + exheadr // Returns true on success, false on failure @@ -37,6 +56,7 @@ struct NCCH { bool hasExtendedHeader() { return exheaderSize != 0; } bool hasExeFS() { return exeFS.size != 0; } bool hasRomFS() { return romFS.size != 0; } + bool hasCode() { return codeFile.size() != 0; } private: std::array primaryKey = {}; // For exheader, ExeFS header and icons diff --git a/include/loader/ncsd.hpp b/include/loader/ncsd.hpp index a4b35081..a134ef23 100644 --- a/include/loader/ncsd.hpp +++ b/include/loader/ncsd.hpp @@ -16,4 +16,6 @@ struct NCSD { IOFile file; u64 size = 0; // Image size according to the header converted to bytes std::array partitions; // NCCH partitions + + u32 entrypoint; // Initial ARM11 PC }; diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index ee99189e..78d94157 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -49,6 +49,10 @@ bool NCCH::loadFromHeader(u8* header, IOFile& file) { compressCode = (exheader[0xD] & 1) != 0; stackSize = *(u32*)&exheader[0x1C]; bssSize = *(u32*)&exheader[0x3C]; + + text.extract(&exheader[0x10]); + rodata.extract(&exheader[0x20]); + data.extract(&exheader[0x30]); } printf("Stack size: %08X\nBSS size: %08X\n", stackSize, bssSize); @@ -84,7 +88,9 @@ bool NCCH::loadFromHeader(u8* header, IOFile& file) { } if (std::strcmp(name, ".code") == 0) { - std::vector code; + if (hasCode()) { + Helpers::panic("Second code file in a single NCCH partition. What should this do?\n"); + } if (compressCode) { std::vector tmp; @@ -96,15 +102,14 @@ bool NCCH::loadFromHeader(u8* header, IOFile& file) { file.readBytes(tmp.data(), fileSize); // Decompress .code file from the tmp vector to the "code" vector - if (!CartLZ77::decompress(code, tmp)) { + if (!CartLZ77::decompress(codeFile, tmp)) { printf("Failed to decompress .code file\n"); return false; } } else { - code.resize(fileSize); + codeFile.resize(fileSize); file.seek(exeFSOffset + exeFSHeaderSize + fileOffset); - file.readBytes(code.data(), fileSize); - Helpers::panic("Uncompressed .code file!"); + file.readBytes(codeFile.data(), fileSize); } } } diff --git a/src/core/loader/ncsd.cpp b/src/core/loader/ncsd.cpp index c3f3b761..8dd2d4b2 100644 --- a/src/core/loader/ncsd.cpp +++ b/src/core/loader/ncsd.cpp @@ -67,11 +67,20 @@ std::optional Memory::loadNCSD(const std::filesystem::path& path) { } } } - - if (!ncsd.partitions[0].ncch.hasExtendedHeader()) { - printf("NCSD's CXI doesn't have exheader?\n"); + + auto& cxi = ncsd.partitions[0].ncch; + if (!cxi.hasExtendedHeader() || !cxi.hasCode()) { + printf("NCSD with an invalid CXI in partition 0?\n"); return std::nullopt; } + + // Map code file to memory + const auto& code = cxi.codeFile; + printf("Text address = %08X page count = %08X\n", cxi.text.address, cxi.text.size); + printf("Rodata address = %08X page count = %08X\n", cxi.rodata.address, cxi.rodata.size); + printf("Data address = %08X page count = %08X\n", cxi.data.address, cxi.data.size); + + ncsd.entrypoint = cxi.text.address; return ncsd; } \ No newline at end of file diff --git a/src/emulator.cpp b/src/emulator.cpp index d51d5222..41082d78 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -70,6 +70,12 @@ bool Emulator::loadNCSD(const std::filesystem::path& path) { } loadedNCSD = opt.value(); + cpu.setReg(15, loadedNCSD.entrypoint); + + if (loadedNCSD.entrypoint & 1) { + Helpers::panic("Misaligned NCSD entrypoint; should this start the CPU in Thumb mode?"); + } + return true; }