mirror of
https://github.com/reswitched/Mephisto.git
synced 2024-05-11 01:04:53 -04:00
load kips
This commit is contained in:
parent
f927335e88
commit
e46e002f64
132
Nxo.cpp
132
Nxo.cpp
|
@ -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
8
Nxo.h
|
@ -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) {}
|
||||
|
|
32
main.cpp
32
main.cpp
|
@ -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";
|
||||
|
|
Loading…
Reference in a new issue