load kips

This commit is contained in:
roblabla 2018-02-11 04:21:10 +01:00
parent f927335e88
commit e46e002f64
3 changed files with 171 additions and 1 deletions

132
Nxo.cpp
View file

@ -8,6 +8,138 @@ Nxo::Nxo(string fn) {
fp.seekg(0);
}
typedef struct {
uint32_t out_offset;
uint32_t out_size;
uint32_t compressed_size;
uint32_t attribute;
} kip_section_header_t;
typedef struct {
uint32_t magic;
char name[0xC];
uint64_t title_id;
uint32_t process_category;
uint8_t main_thread_priority;
uint8_t default_core;
uint8_t _0x1E;
uint8_t flags;
kip_section_header_t section_headers[6];
uint32_t capabilities[0x20];
} kip1_header_t;
typedef struct {
uint32_t compressed_size;
uint32_t init_index;
uint32_t uncompressed_added_size;
} blz_footer;
char *kip1_decompress(ifstream &fp, size_t offset, uint32_t csize, uint32_t usize) {
fp.seekg(offset);
unsigned char *compressed = new unsigned char[csize];
unsigned char *decompressed = new unsigned char[usize];
fp.read((char*)compressed, csize);
/*
memcpy(decompressed, compressed, csize);
memset(decompressed + csize, 0, usize - csize);*/
blz_footer *footer = (blz_footer*)(compressed + csize - 0xC);
assert(csize == footer->compressed_size);
assert(usize == footer->compressed_size + footer->uncompressed_added_size);
int index = csize - footer->init_index;
int outindex = usize;
while (outindex > 0) {
index -= 1;
unsigned char control = compressed[index];
for (int i = 0; i < 8; i++) {
if (control & 0x80) {
if (index < 2) {
// Compression out of bounds
assert(false);
}
index -= 2;
unsigned int segmentoffset = compressed[index] | (compressed[index + 1] << 8);
unsigned int segmentsize = ((segmentoffset >> 12) & 0xF) + 3;
segmentoffset &= 0x0FFF;
segmentoffset += 2;
if (outindex < segmentsize) {
// Compression out of bounds
assert(false);
}
for (int j = 0; j < segmentsize; j++) {
if (outindex + segmentoffset >= usize) {
// Compression out of boundds
assert(false);
}
char data = decompressed[outindex + segmentoffset];
outindex -= 1;
decompressed[outindex] = data;
}
} else {
if (outindex < 1) {
// Compression out of bounds
assert(false);
}
outindex -= 1;
index -= 1;
decompressed[outindex] = compressed[index];
}
control <<= 1;
control &= 0xFF;
if (outindex == 0)
break;
}
}
delete[] compressed;
return (char*)decompressed;
}
static uint32_t align(uint32_t offset, uint32_t alignment) {
uint32_t mask = ~(alignment-1);
return (offset + (alignment-1)) & mask;
}
guint Kip::load(Ctu &ctu, gptr base, bool relocate) {
kip1_header_t hdr;
fp.read((char*)&hdr, sizeof(kip1_header_t));
if (hdr.magic != FOURCC('K', 'I', 'P', '1'))
return 0;
// TODO: probably inaccurate
// Find max size
gptr tmaxsize = hdr.section_headers[0].out_offset + align(hdr.section_headers[0].out_size, 0x1000);
gptr romaxsize = hdr.section_headers[1].out_offset + align(hdr.section_headers[1].out_size, 0x1000);
gptr rwmaxsize = hdr.section_headers[2].out_offset + align(hdr.section_headers[2].out_size, 0x1000);
gptr bssmaxsize = hdr.section_headers[3].out_offset + align(hdr.section_headers[3].out_size, 0x1000);
gptr maxsize = std::max( { tmaxsize, romaxsize, rwmaxsize, bssmaxsize } );
printf("WTF IS THIS: %lx\n", maxsize);
ctu.cpu.map(base, maxsize);
size_t toff = 0x100;
size_t roff = toff + hdr.section_headers[0].compressed_size;
size_t doff = roff + hdr.section_headers[1].compressed_size;
char *text = kip1_decompress(fp, toff, hdr.section_headers[0].compressed_size, hdr.section_headers[0].out_size);
ctu.cpu.writemem(base + hdr.section_headers[0].out_offset, text, hdr.section_headers[0].out_size);
delete[] text;
char *ro = kip1_decompress(fp, roff, hdr.section_headers[1].compressed_size, hdr.section_headers[1].out_size);
ctu.cpu.writemem(base + hdr.section_headers[1].out_offset, ro, hdr.section_headers[1].out_size);
delete[] ro;
char *data = kip1_decompress(fp, doff, hdr.section_headers[2].compressed_size, hdr.section_headers[2].out_size);
ctu.cpu.writemem(base + hdr.section_headers[2].out_offset, data, hdr.section_headers[2].out_size);
delete[] data;
return maxsize;
}
typedef struct {
uint32_t magic, pad0, pad1, pad2;
uint32_t textOff, textLoc, textSize, pad3;

8
Nxo.h
View file

@ -14,6 +14,14 @@ protected:
uint32_t length;
};
class Kip : Nxo {
public:
Kip(string fn) : Nxo(fn) {}
virtual ~Kip() override {}
guint load(Ctu &ctu, gptr base, bool relocate=false) override;
};
class Nso : Nxo {
public:
Nso(string fn) : Nxo(fn) {}

View file

@ -38,7 +38,7 @@ struct Arg: public option::Arg
}
};
enum optionIndex { UNKNOWN, HELP, ENABLE_GDB, PORT, NSO, NRO, ENABLE_SOCKETS };
enum optionIndex { UNKNOWN, HELP, ENABLE_GDB, PORT, NSO, NRO, KIP, ENABLE_SOCKETS };
const option::Descriptor usage[] =
{
{UNKNOWN, 0, "", "",Arg::None, "USAGE: ctu [options] <load-directory>\n\n"
@ -48,6 +48,7 @@ const option::Descriptor usage[] =
{PORT, 0,"p","gdb-port",Arg::Numeric, " --gdb-port, -p \tSet port for GDB; default 24689." },
{NSO, 0,"","load-nso",Arg::NonEmpty, " --load-nso \tLoad an NSO without load directory"},
{NRO, 0,"","load-nro",Arg::NonEmpty, " --load-nro \tLoad an NRO without load directory (entry point .text+0x80)"},
{KIP, 0,"","load-kip",Arg::NonEmpty, " --load-kip \tLoad a KIP without load directory"},
{ENABLE_SOCKETS, 0, "b","enable-sockets",Arg::None, " -- enable-sockets, -b \tEnable BSD socket passthrough." },
{0,0,nullptr,nullptr,nullptr,nullptr}
};
@ -57,6 +58,18 @@ bool exists(string fn) {
return stat(fn.c_str(), &buffer) == 0;
}
void loadKip(Ctu &ctu, const string &lfn, gptr raddr) {
assert(exists(lfn));
Kip file(lfn);
if(file.load(ctu, raddr, false) == 0) {
LOG_ERROR(KipLoader, "Failed to load %s", lfn.c_str());
}
ctu.loadbase = min(raddr, ctu.loadbase);
auto top = raddr + 0x100000000;
ctu.loadsize = max(top - ctu.loadbase, ctu.loadsize);
LOG_INFO(KipLoader, "Loaded %s at " ADDRFMT, lfn.c_str(), ctu.loadbase);
}
void loadNso(Ctu &ctu, const string &lfn, gptr raddr) {
assert(exists(lfn));
Nso file(lfn);
@ -92,6 +105,13 @@ void runLisp(Ctu &ctu, const string &dir, shared_ptr<Atom> code) {
auto raddr = addr->numVal;
auto lfn = dir + "/" + fn->strVal;
loadNso(ctu, lfn, raddr);
} else if(head->strVal == "load-kip") {
assert(code->children.size() == 3);
auto fn = code->children[1], addr = code->children[2];
assert(fn->type == String && addr->type == Number);
auto raddr = addr->numVal;
auto lfn = dir + "/" + fn->strVal;
loadKip(ctu, lfn, raddr);
} else if(head->strVal == "run-from") {
assert(code->children.size() == 2 && code->children[1]->type == Number);
ctu.execProgram(code->children[1]->numVal);
@ -119,10 +139,17 @@ int main(int argc, char **argv) {
if(options[NSO].count() > 0) {
if(options[NSO].count() != 1) { goto printUsage; }
if(options[NRO].count() != 0) { goto printUsage; }
if(options[KIP].count() != 0) { goto printUsage; }
if(parse.nonOptionsCount() != 0) { goto printUsage; }
} else if(options[NRO].count() > 0) {
if(options[NRO].count() != 1) { goto printUsage; }
if(options[NSO].count() != 0) { goto printUsage; }
if(options[KIP].count() != 0) { goto printUsage; }
if(parse.nonOptionsCount() != 0) { goto printUsage; }
} else if(options[KIP].count() > 0) {
if(options[KIP].count() != 1) { goto printUsage; }
if(options[NSO].count() != 0) { goto printUsage; }
if(options[NRO].count() != 0) { goto printUsage; }
if(parse.nonOptionsCount() != 0) { goto printUsage; }
} else {
if(parse.nonOptionsCount() != 1) { goto printUsage; }
@ -150,6 +177,9 @@ int main(int argc, char **argv) {
} else if(options[NRO].count()) {
loadNro(ctu, options[NRO][0].arg, 0x7100000000);
ctu.execProgram(0x7100000080);
} else if(options[KIP].count()) {
loadKip(ctu, options[KIP][0].arg, 0x7100000000);
ctu.execProgram(0x7100000000);
} else {
string dir = parse.nonOption(0);
auto lfn = dir + "/load.meph";