From: chaoskagami Date: Thu, 2 Jun 2016 14:23:04 +0000 (-0400) Subject: Prep for loader VM integration, etc X-Git-Tag: stable-1~13 X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=36bdcf916548db2a30ca18076ca237e8dec1fc40;p=corbenik%2Fcorbenik.git Prep for loader VM integration, etc --- diff --git a/Makefile b/Makefile index 5f76877..9ac4693 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ dir_out := out REVISION := r$(shell git rev-list --count HEAD):$(shell git rev-parse HEAD | head -c8) ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te -CFLAGS := -MMD -MP -Wall -Wextra -Werror -fno-omit-frame-pointer -Os $(ASFLAGS) -fno-builtin -std=c11 -DVERSION=\"$(REVISION)\" -DBUFFER=1 +CFLAGS := -MMD -MP -Wall -Wextra -Werror -fno-omit-frame-pointer -Os $(ASFLAGS) -fno-builtin -std=c11 -DVERSION=\"$(REVISION)\" FLAGS := dir_out=$(abspath $(dir_out)) --no-print-directory LDFLAGS := -nostdlib -Wl,-z,defs -lgcc -Wl,-Map,$(dir_build)/link.map diff --git a/README.md b/README.md index 24c2032..166da63 100644 --- a/README.md +++ b/README.md @@ -3,18 +3,9 @@ Corbenik This is (yet another) CFW for the 3DS. Unlike other CFWs, this was mostly written from scratch and for fun. I'm a control freak, and this carries quite a bit of my mindset being a LFS/Gentoo user. -Some parts are inherited from other CFWs - e.g. the firmware loading code in src/firm is mostly based on Cakes, and the signature patch bytecode is roughly based on the implementation in Luma3DS. - -Out of the bunch, corbenik is most similar to cakes of the bunch, in that it uses external patches. Unlike cakes, patches consist of a headered bytecode file. See `doc/bytecode.md`, `host/bytecode_asm.py` and `patch/*` for more on this. - -## Oh god yet another rebrand of-- - -No. This is >75% original code. If you notice, there's a large amount of history because I didn't just dump the code on github; it's been in a repo all along while I worked on it and before it was made public. - -I also am not claiming to have written everything. See `doc/credits.md`. - -It shares close to zero of the actual architecture with other CFWs, only trivially implemented parts that look the same no matter who coded them. +Some parts are inherited from other CFWs - e.g. the firmware loading code in src/firm is mostly based on Cakes, and the patch bytecode is based on Luma3DS' implementation in C (though, it isn't really derived from it) +Out of the bunch of CFWs in existence, Corbenik is most similar to cakes of the bunch, in that it uses external patches. External patches are headered, can have dependencies, and consist of a lightweight and specialized bytecode/assembly which is intended for patching. See `doc/bytecode.md`, `host/bytecode_asm.py` and `patch/*` for more on this. The assembler is a bit crappy at the moment, and I *do* plan to improve it. However, it outputs the correct code which gets the job done. ## Rationale I was initially going to make dynamic cakes, but I quickly realized a fatal flaw in any "patch" format: what you can do from a patch is limited to what the parser handles. This exact problem is why sempatches are used sometimes instead of classic diffs on the LKML, and it isn't a problem that will be solved without code. In my opinion, the best way to fix it is to simply externalize patches as programs. I also had a number of mad science experiments which would be very hard to perform in the context of ReiNAND based firmwares, and Cakes wouldn't make it easy either. diff --git a/external/loader/source/interp.c b/external/loader/source/interp.c new file mode 100644 index 0000000..d09955e --- /dev/null +++ b/external/loader/source/interp.c @@ -0,0 +1,27 @@ +// 'Tis not ready for the world at large yet. +// I don't want to delete it since I'm working on it though, +// so it's temporarliy #if'd 0. +#if 0 + +#define LOADER 1 + +#include <3ds.h> +#include "patcher.h" +#include "fsldr.h" +#include "internal.h" +#include "memory.h" +#include "logger.h" + +#ifndef PATH_MAX +#define PATH_MAX 255 +#define _MAX_LFN 255 +#endif +#include "config.h" +#include "../../../source/patch_format.h" + +#include "patch/patch.h" + +// Yes, we're including a C file. Problem? +#include "../../../source/interp.c" + +#endif diff --git a/host/compile_header.c b/host/compile_header.c deleted file mode 100644 index f912dda..0000000 --- a/host/compile_header.c +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include -#include -#include - -#include "../source/patch_format.h" - -void -read_file_u64(char* name, uint64_t* to) -{ - FILE* hdl = fopen(name, "rb"); - fscanf(hdl, "%llu", to); - fclose(hdl); -} - -void -read_file_u32(char* name, uint32_t* to) -{ - FILE* hdl = fopen(name, "rb"); - fscanf(hdl, "%u", to); - fclose(hdl); -} - -void -read_str(char* name, char* to, size_t len) -{ - FILE* hdl = fopen(name, "rb"); - int r = fread(to, 1, len - 1, hdl); - fclose(hdl); - - for (int i = len - 1; i >= 0; i--) { - if (to[i] == '\n') { - to[i] = 0; - break; - } - } -} - -uint32_t size = 0; - -uint8_t* -read_file_mem(char* name) -{ - FILE* hdl = fopen(name, "rb"); - - fseek(hdl, 0, SEEK_END); - size = ftell(hdl); - rewind(hdl); - - uint8_t* mem = malloc(size); - memset(mem, 0, size); - - int r = fread(mem, 1, size, hdl); - fclose(hdl); - - return mem; -} - -int -main(int c, char** v) -{ - struct system_patch patch; - int at = 0; - - memset(&patch, 0, sizeof(patch)); - - // Set magic. - patch.magic[0] = 'A'; - patch.magic[1] = 'I'; - patch.magic[2] = 'D'; - patch.magic[3] = 'A'; - - read_file_u32("meta/patch_version", &patch.patch_ver); - read_file_u32("meta/cfw_version", &patch.load_ver); - - read_file_u64("meta/uuid", &patch.patch_id); - read_file_u64("meta/title", &patch.tid); - - read_str("meta/name", patch.name, sizeof(patch.name)); - read_str("meta/desc", patch.desc, sizeof(patch.desc)); - - uint8_t* code = read_file_mem("out/patch.bin"); - - patch.patch_size = size; - - FILE* out = fopen("out/patch.vco", "wb"); - fwrite(&patch, 1, sizeof(patch), out); - fwrite(code, 1, patch.patch_size, out); - fclose(out); - - free(code); - - printf("Ver: %u\n" - "CFW: %u\n" - "UUID: %llu\n" - "TID: %llu\n" - "Name: %s\n" - "Desc: %s\n" - "Size: %u\n", - patch.patch_ver, patch.load_ver, patch.patch_id, patch.tid, - patch.name, patch.desc, patch.patch_size); - - return 0; -} diff --git a/source/interp.c b/source/interp.c index 4d52951..ad82970 100644 --- a/source/interp.c +++ b/source/interp.c @@ -1,9 +1,12 @@ #include -#include "std/unused.h" -#include "std/memory.h" -#include "firm/firm.h" -#include "config.h" -#include "common.h" +#include +#ifndef LOADER + #include "std/unused.h" + #include "std/memory.h" + #include "firm/firm.h" + #include "config.h" + #include "common.h" +#endif #define OP_NOP 0x00 #define OP_REL 0x01 @@ -17,6 +20,11 @@ #define OP_AND 0x09 #define OP_TITLE 0x0A +#ifdef LOADER + #define fprintf(a...) + #define abort(a...) +#endif + struct mode { uint8_t* memory; uint32_t size; @@ -27,6 +35,7 @@ int init_bytecode = 0; int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) { if (!init_bytecode) { +#ifndef LOADER modes[0].memory = (uint8_t*)firm_loc; modes[0].size = FCRAM_SPACING; // NATIVE_FIRM @@ -84,6 +93,7 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) { // TWL_FIRM Sect 3 modes[17].memory = (uint8_t*)&twl_firm_loc->section[3] + twl_firm_loc->section[3].offset; modes[17].size = twl_firm_loc->section[3].size; +#endif // Loader (not valid in bootmode) // modes[18] = { 0, 0 }; @@ -91,12 +101,16 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) { init_bytecode = 1; } - struct mode* current_mode = &modes[3]; +#ifdef LOADER + uint32_t set_mode = 18; +#else + uint32_t set_mode = 3; +#endif + struct mode* current_mode = &modes[set_mode]; + uint32_t offset = 0; uint8_t test_was_false = 0; - uint32_t set_mode = 0; - uint32_t i; uint8_t* code = bytecode; @@ -110,6 +124,10 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) { test_was_false = 0; break; case OP_REL: // Change relativity. +#ifdef LOADER + // Loader doesn't support this. Just treat it like a two-byte NOP. + code += 2; +#else if (debug) fprintf(stderr, "rel\n"); code++; @@ -119,6 +137,7 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) { test_was_false = 0; set_mode = *code; code++; +#endif break; case OP_FIND: // Find pattern. if (debug) @@ -185,8 +204,9 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) { code += 2; if(memcmp(current_mode->memory+offset, code, *(code-1))) { test_was_false = 1; - fprintf(stderr, "false\n"); - } else { + if (debug) + fprintf(stderr, "false\n"); + } else if (debug) { fprintf(stderr, "true\n"); } code += *(code-1); @@ -196,7 +216,8 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) { fprintf(stderr, "jmp\n"); code++; if (!test_was_false) { - fprintf(stderr, "jmp to %hu,%hu\n", code[0], code[1]); + if (debug) + fprintf(stderr, "jmp to %hu,%hu\n", code[0], code[1]); code = bytecode + code[1] + ( code[0] * 0x100 ); } else { code += 2; @@ -255,16 +276,54 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) { return 0; } +#ifdef LOADER +int execb(char* filename, uint64_t tid, uint8_t* search_mem, uint32_t search_len) { +#else int execb(char* filename) { +#endif + uint8_t* patch_mem; + uint32_t patch_len; + struct system_patch* patch; +#ifdef LOADER + // Loader can use actual allocation functions, so this isn't as much of an issue + + // Set memory. + modes[18].memory = search_mem; + modes[18].size = search_len; + + // Load patch. We need memory, so... + // svcControlMemory(&tmp, __loader_prog_heap, 0x0, __ctru_heap_size, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE); + + // Check magic. + + // Check TID supported. + +#else + // Read patch to scrap memory. + FILE* f = fopen(filename, "r"); size_t len = fsize(f); fread((uint8_t*)FCRAM_PATCH_LOC, 1, len, f); fclose(f); - struct system_patch* patch = (struct system_patch*)FCRAM_PATCH_LOC; - fprintf(stderr, "Name: %s\nDesc: %s\n", patch->name, patch->desc); - uint8_t* patch_mem = (uint8_t*)patch + sizeof(struct system_patch) + (patch->depends * 8) + (patch->titles * 8); - uint32_t patch_len = patch->size; + patch = (struct system_patch*)FCRAM_PATCH_LOC; + + // Make sure various bits are correct. + if (memcmp(patch->magic, "AIDA", 4)) { + // Incorrect magic. + return 1; + } + + if (patch->titles != 0) { + // Not an error, per se, but it means this patch is meant for loader, not us. + // Patches intended for use during boot will always be applied to zero titles. + return 0; + } + + fprintf(stderr, "Patch: %s\n", patch->name); - return exec_bytecode(patch_mem, patch_len, 1); + patch_mem = (uint8_t*)patch + sizeof(struct system_patch) + (patch->depends * 8) + (patch->titles * 8); + patch_len = patch->size; +#endif + return exec_bytecode(patch_mem, patch_len, 0); }