From 9957dc3ff8120a1064c05c5e4eeeaa55a35ed5a0 Mon Sep 17 00:00:00 2001 From: chaoskagami Date: Thu, 2 Jun 2016 04:12:38 -0400 Subject: [PATCH] Misc stuff. * More work prepping for bytecode. * Improve decidedly shitty putc buffer to just directly render. Old behavior kept around via -DBUFFER=1. * I need to reimplement scrollback still --- README.md | 22 ++++++------ doc/todo.md | 1 + source/linker.c | 69 -------------------------------------- source/patch/aadowngrade.c | 4 +-- source/patch/prot.c | 4 +-- source/patch/sig.c | 3 +- source/patch/svc.c | 69 ++++++++++++++++++++------------------ source/patcher.c | 1 - source/std/draw.c | 44 ++++++++++++++++++++++-- 9 files changed, 97 insertions(+), 120 deletions(-) delete mode 100644 source/linker.c diff --git a/README.md b/README.md index d2bd42f..24c2032 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,33 @@ Corbenik ============================== -## Oh god yet another rebrand of-- +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. -No. Definitely not. +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. -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, and some OSDev and self-done RE with it. +## Oh god yet another rebrand of-- -Some parts are inherited from other CFWs - e.g. the firmware loading code in src/firm is mostly based on Cakes, and sigpatch/firmprot/svcbackdoor were loosely based on Luma3DS's patches. +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. -The *plan* at least is to be most similar to Cakes out of the bunch. That is, it will use external patches from the SD card's filesystem. +I also am not claiming to have written everything. See `doc/credits.md`. -Unlike cakes, patches will be some form of program, be it bytecode, a scripting language or dynamically loaded binaries. This is not yet implemented due to technical problems, but IS on the roadmap to get done as soon as I figure out *why* it isn't working. This code is located in a branch offline, due to the fact that it doesn't work. +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. ## 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. +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. ## Comparison -If you want to know how Corbenik sizes up to other CFWs as of NOW - see `doc/features.md`. I don't intend to sugarcoat - Corbenik is under development and is incomplete. There will be no stable release until a number of common features are implemented, and patches have been externalized. +If you want to know how Corbenik sizes up to other CFWs as of NOW - see `doc/features.md`. I don't intend to sugarcoat - Corbenik is under development and is incomplete. There will be no stable release until a number of common features are implemented, such as emunand. -That said, feedback is welcome, but don't report anything obvious. Chances are I know, since Corbenik is my day-to-day CFW now. +That said, feedback is welcome, but don't report anything obvious. Chances are I know, since Corbenik is my day-to-day CFW now, and I'll run into the same bugs as you. For compilation instructions, see `doc/compiling.md`. -Unless otherwise noted, everything original in this repo can be used under the terms of the GNU GPLv2 or later. This includes situations where there's no copyright header within a source file. I get lazy with those; assume everything can be used under the GPL, or files were from software licensed GPLv2 or later (and thus are upgraded.) No source files within this repo bear questionable licenses. +Unless otherwise noted, everything original in this repo can be used under the terms of the GNU GPLv3 or later. This includes situations where there's no copyright header within a source file. I get lazy with those; assume everything can be used under the GPL, or files were from software licensed GPLv2 or later (and thus are upgraded.) No source files within this repo bear questionable licenses. ## Quote of the Day diff --git a/doc/todo.md b/doc/todo.md index dbb2738..33c3036 100644 --- a/doc/todo.md +++ b/doc/todo.md @@ -4,6 +4,7 @@ Next * Make config file for corbenik plaintext. Nobody likes binary configs. They suck. Massively. Especially when you fuck up a setting and need to change it on something that isn't a 3ds. * In place firmware loading/patching. * Weird hack central - Developer 11.4 leaked. Allow injecting debug module? Ehehehehe. No clue what the point of this would be, but hey, it'd be FUCKING cool, man. + * Optimize the code in svc. It's slow, because it checks the filesystem for 0xff files that don't exist. It should list the dir instead. Shortterm ------------- diff --git a/source/linker.c b/source/linker.c deleted file mode 100644 index 46a7dd7..0000000 --- a/source/linker.c +++ /dev/null @@ -1,69 +0,0 @@ -#include "common.h" -#include "firm/fcram.h" -#include "firm/firm.h" - -// Yes, this is EXACTLY what it looks like. We dynamically link and -// load patches as binaries; they use functions from corbenik to do -// the work, and therefore must have a function table in them. - -// See vco/template for how this magic works. - -// This ensures relatively small patches while also having incredible -// flexibility unlike a 'patch format'. - -extern exefs_h* firm_p9_exefs; -exefs_h* -get_firm_proc9_exefs() -{ - return firm_p9_exefs; -} - -extern exefs_h* twl_firm_p9_exefs; -exefs_h* -get_twl_proc9_exefs() -{ - return twl_firm_p9_exefs; -} - -extern exefs_h* agb_firm_p9_exefs; -exefs_h* -get_agb_proc9_exefs() -{ - return agb_firm_p9_exefs; -} - -int -execp(char* path) -{ - int basename = 0; - for (basename = strlen(path); basename > 0; basename--) - if (path[basename] == '/') - break; - basename++; - - fprintf(stderr, "Exec: %s\n", &path[basename]); - - struct system_patch patch; - - // Load patch from path. - FILE* f = fopen(path, "r"); - fread(&patch, 1, sizeof(patch), f); - - fprintf(stderr, " [h]"); - - fread((uint8_t*)FCRAM_PATCHBIN_EXEC_LOC, 1, patch.patch_size, f); - - fprintf(stderr, "[x]"); - - fclose(f); - - fprintf(stderr, "[b]\n"); - - int (*patch_loc)() = (void*)FCRAM_PATCHBIN_EXEC_LOC; - - int ret = (*patch_loc)(); - - fprintf(stderr, " Exit: %d\n", ret); - - return ret; -} diff --git a/source/patch/aadowngrade.c b/source/patch/aadowngrade.c index 64132a9..e4d9e41 100644 --- a/source/patch/aadowngrade.c +++ b/source/patch/aadowngrade.c @@ -7,10 +7,10 @@ set 1, 0xE0 */ +extern exefs_h* firm_p9_exefs; + PATCH(aadowngrade) { - exefs_h* firm_p9_exefs = get_firm_proc9_exefs(); - uint8_t* firm_mem = (uint8_t*)firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset; uint32_t size = firm_p9_exefs->fileHeaders[0].size; diff --git a/source/patch/prot.c b/source/patch/prot.c index ec2c2f1..544c7f9 100644 --- a/source/patch/prot.c +++ b/source/patch/prot.c @@ -11,10 +11,10 @@ set 4, 0x00, 0x20, 0xC0, 0x46 */ +extern exefs_h* firm_p9_exefs; + PATCH(firmprot) { - exefs_h* firm_p9_exefs = get_firm_proc9_exefs(); - uint8_t* firm_mem = (uint8_t*)firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset; uint32_t size = firm_p9_exefs->fileHeaders[0].size; diff --git a/source/patch/sig.c b/source/patch/sig.c index b91e9ff..66bbe7e 100644 --- a/source/patch/sig.c +++ b/source/patch/sig.c @@ -11,9 +11,10 @@ set 4, 0x00, 0x20, 0x70, 0x47 */ +extern exefs_h* firm_p9_exefs; + PATCH(signatures) { - exefs_h* firm_p9_exefs = get_firm_proc9_exefs(); // Look for signature checks diff --git a/source/patch/svc.c b/source/patch/svc.c index ff9deed..e3b01d8 100644 --- a/source/patch/svc.c +++ b/source/patch/svc.c @@ -43,49 +43,54 @@ PATCH(services) char str[] = PATH_SERVICES "/00.bin"; char* at = str + (strlen(str) - 6); - for (uint32_t i = 0; i <= 0xff; i++) { - // Get string for svc. - at[0] = ("0123456789abcdef")[((i >> 4) & 0xf)]; - // This is just hexdump. Nothing complicated. - at[1] = ("0123456789abcdef")[(i & 0xf)]; + // FIXME - This is really slow. Some way to optimize it? + for (uint32_t i = 0; i <= 0xf; i++) { + // Get string for svc. + at[0] = ("0123456789abcdef")[i]; - FILE* data = fopen(str, "r"); - if (!data) { - continue; // No file for svc. Move on. - } + for (uint32_t j = 0; j < 0xf; j++) { + // This is just hexdump. Nothing complicated. + at[1] = ("0123456789abcdef")[j]; - // Refuse to replace non-NULL services unless the user says to. - if (svcTable[i] && !config.options[OPTION_REPLACE_ALLOCATED_SVC]) { - fclose(data); - fprintf(stderr, "Svc: %x non-null, moving on\n", i); - continue; - } + FILE* data = fopen(str, "r"); + if (!data) + continue; // No file for svc. Move on. - uint32_t size = fsize(data); - uint8_t* read_to = (void*)FCRAM_JUNK_LOCATION; + uint32_t svc = (i << 4) & j; - fprintf(stderr, "Svc: %s, %d bytes\n", at, size); + // Refuse to replace non-NULL services unless the user says to. + if (svcTable[svc] && !config.options[OPTION_REPLACE_ALLOCATED_SVC]) { + fclose(data); + fprintf(stderr, "Svc: %x non-null, moving on\n", i); + continue; + } - fread(read_to, 1, size, data); + uint32_t size = fsize(data); + uint8_t* read_to = (void*)FCRAM_JUNK_LOCATION; - fclose(data); + fprintf(stderr, "Svc: %s, %d bytes\n", at, size); - if (!freeSpace) { - for (freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; - freeSpace++) - ; - } + fread(read_to, 1, size, data); - fprintf(stderr, "Svc: Copy code to %x\n", (uint32_t)freeSpace); + fclose(data); - memcpy(freeSpace, read_to, size); - svcTable[i] = - 0xFFFF0000 + ((uint8_t*)freeSpace - (uint8_t*)exceptionsPage); + if (!freeSpace) { + for (freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; + freeSpace++) + ; + } - freeSpace += - size; // We keep track of this because there's more than 7B free. + fprintf(stderr, "Svc: Copy code to %x\n", (uint32_t)freeSpace); - fprintf(stderr, "Svc: entry set as %x\n", svcTable[0x7B]); + memcpy(freeSpace, read_to, size); + svcTable[svc] = + 0xFFFF0000 + ((uint8_t*)freeSpace - (uint8_t*)exceptionsPage); + + freeSpace += + size; // We keep track of this because there's more than 7B free. + + fprintf(stderr, "Svc: entry set as %x\n", svcTable[svc]); + } } return 0; diff --git a/source/patcher.c b/source/patcher.c index 720194d..a93332e 100644 --- a/source/patcher.c +++ b/source/patcher.c @@ -8,7 +8,6 @@ // TODO - Basically all this needs to move to patcher programs. uint32_t wait_key(); -int execp(char* path); extern int patch_signatures(); extern int patch_firmprot(); diff --git a/source/std/draw.c b/source/std/draw.c index 491910a..4828f23 100644 --- a/source/std/draw.c +++ b/source/std/draw.c @@ -12,11 +12,13 @@ static unsigned int top_cursor_x = 0, top_cursor_y = 0; static unsigned int bottom_cursor_x = 0, bottom_cursor_y = 0; +#ifdef BUFFER static char text_buffer_top[TEXT_TOP_HEIGHT * TEXT_TOP_WIDTH + 1]; static char text_buffer_bottom[TEXT_BOTTOM_HEIGHT * TEXT_BOTTOM_WIDTH + 1]; static char color_buffer_top[TEXT_TOP_HEIGHT * TEXT_TOP_WIDTH + 1]; static char color_buffer_bottom[TEXT_BOTTOM_HEIGHT * TEXT_BOTTOM_WIDTH + 1]; +#endif static uint32_t colors[16] = { 0x000000, // Black @@ -52,6 +54,7 @@ clear_disp(uint8_t* screen) } } +#ifdef BUFFER void clear_text(uint8_t* screen) { @@ -72,12 +75,15 @@ clear_text(uint8_t* screen) } } } +#endif void clear_screen(uint8_t* screen) { clear_disp(screen); +#ifdef BUFFER clear_text(screen); +#endif } void @@ -164,24 +170,35 @@ putc(void* buf, const int c) _UNUSED unsigned int height = 0; unsigned int* cursor_x = NULL; unsigned int* cursor_y = NULL; +#ifdef BUFFER char* colorbuf = NULL; char* strbuf = NULL; - +#else + uint8_t* screen = NULL; +#endif unsigned char* color = NULL; if (buf == TOP_SCREEN) { width = TEXT_TOP_WIDTH; height = TEXT_TOP_HEIGHT; +#ifdef BUFFER colorbuf = color_buffer_top; strbuf = text_buffer_top; +#else + screen = framebuffers->top_left; +#endif cursor_x = &top_cursor_x; cursor_y = &top_cursor_y; color = &color_top; } else if (buf == BOTTOM_SCREEN) { width = TEXT_BOTTOM_WIDTH; height = TEXT_BOTTOM_HEIGHT; +#ifdef BUFFER colorbuf = color_buffer_bottom; strbuf = text_buffer_bottom; +#else + screen = framebuffers->bottom; +#endif cursor_x = &bottom_cursor_x; cursor_y = &bottom_cursor_y; color = &color_bottom; @@ -193,6 +210,7 @@ putc(void* buf, const int c) } while (cursor_y[0] >= height) { +#ifdef BUFFER // Scroll. for (unsigned int y = 0; y < height - 1; y++) { memset(&strbuf[y * width], 0, width); @@ -204,21 +222,33 @@ putc(void* buf, const int c) memset(&strbuf[(height - 1) * width], 0, width); memset(&colorbuf[(height - 1) * width], 0, width); - cursor_y[0]--; - clear_disp(buf); // Clear screen. +#else + clear_disp(buf); + cursor_x[0] = 0; + cursor_y[0] = 0; +/* uint32_t col = SCREEN_TOP_HEIGHT * SCREEN_DEPTH; + uint32_t one_c = 8 * SCREEN_DEPTH; + for (unsigned int x = 0; x < width * 8; x++) { + memmove(&screen[x * col + one_c], &screen[x * col + one_c], col - one_c); + } */ +#endif + cursor_y[0]--; } switch (c) { case '\n': +#ifdef BUFFER strbuf[cursor_y[0] * width + cursor_x[0]] = 0; colorbuf[cursor_y[0] * width + cursor_x[0]] = 0; +#endif cursor_y[0]++; // Fall through intentional. case '\r': cursor_x[0] = 0; // Reset to beginning of line. break; default: +#ifdef BUFFER strbuf[cursor_y[0] * width + cursor_x[0]] = c; colorbuf[cursor_y[0] * width + cursor_x[0]] = *color; @@ -228,6 +258,10 @@ putc(void* buf, const int c) colorbuf[cursor_y[0] * width + cursor_x[0] + 1] = 0; } +#else + draw_character(screen, c, cursor_x[0], cursor_y[0], colors[(*color >> 4) & 0xF], colors[*color & 0xF]); +#endif + cursor_x[0]++; break; @@ -334,6 +368,7 @@ void fflush(void* channel) { if (channel == TOP_SCREEN) { +#ifdef BUFFER if (kill_output) return; @@ -350,7 +385,9 @@ fflush(void* channel) color_bg); } } +#endif } else if (channel == BOTTOM_SCREEN) { +#ifdef BUFFER if (kill_output) return; @@ -368,6 +405,7 @@ fflush(void* channel) color_bg); } } +#endif } else { f_sync(&(((FILE*)channel)->handle)); // Sync to disk. } -- 2.39.5