+++ /dev/null
-Corbenik
-==============================
-
-## This is the README intended for people looking at the code. If you're a user, read `README.user.md` instead.
-
-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 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 solely for effiecient 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 and gets the job done.
-
-## Rationale
-
-I was initially going to make cakes dynamic, 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. With Cakes, converting to a dynamic method isn't terribly difficult, but what about the patches that have a 'find, then seek backwards until' type of logic? Cakes would need have another construct to decribe that, and at that point, the .cake format has become a kludge.
-
-In my opinion, the best way to fix this was to externalize patches as programs - arm binaries or bytecode. The former didn't go so well (look back in the history of this repo. Fun times) and I ended up going with the latter.
-
-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 due to its limited patch format.
-
-## 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, such as emunand.
-
-However! It does have a few legs up on other CFWs, namely:
- * Injection of arbitrary ARM11 services, including svcBackdoor.
- * Bytecode patches? Bytecode patches.
- * Not only corbenik, but the loader replacement uses them too.
- * Loader can resize titles in memory and append code to segments. This isn't well tested, and it isn't enabled.
- * Pretty much every simple patch that Luma3DS has, and most every patch for loader.
- * All of the common bits aside from EmuNand, Reboot, and the exception vector hook, basically.
- * Loader is STILL smaller than Nintendo's by two units.
- * Loader is a little slower to boot than Cakes, and loader takes negligibly longer to load stuff. I may be able to optimize more, but at this point it is fast enough to not impact me.
-
-Feedback is welcome, but don't report anything obvious in nightlies. Corbenik is my day-to-day CFW now, so 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 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 GPLv3. No source files within this repo bear questionable licenses, I make sure when it is introduced.
-
-## Quote of the Day
-
-Welcome to "The World."
-
cp out/arm9loaderhax.bin $mnt/anim/boot/none.bin || exit 0
cp out/arm9loaderhax.bin $mnt/anim/boot/r.bin || exit 0
cp out/arm9loaderhax.bin $mnt/anim/boot/l.bin || exit 0
+rm -rf $mnt/corbenik
cp -r out/corbenik $mnt/ || exit 0
cp -r input/corbenik $mnt/ || exit 0
umount $mnt || exit 0
// 9.6 crypto may need us to get the key from somewhere else.
// Unless the console already has the key initialized, that is.
uint8_t key[AES_BLOCK_SIZE];
- if (read_file(key, PATH_SLOT0X11KEY96, AES_BLOCK_SIZE) || read_file(key, PATH_ALT_SLOT0X11KEY96, AES_BLOCK_SIZE)) {
+ if (read_file(key, PATH_SLOT0X11KEY96, AES_BLOCK_SIZE) != 0 || read_file(key, PATH_ALT_SLOT0X11KEY96, AES_BLOCK_SIZE) != 0) {
// Read key successfully.
aes_setkey(0x11, key, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
int status = 0;
int firmware_changed = 0;
- if (read_file(dest, path, *size)) {
+ if (read_file(dest, path, *size) == 0) {
fprintf(BOTTOM_SCREEN, "!");
// Only whine about this if it's NATIVE_FIRM, which is important.
"This is fatal. Aborting.\n");
}
- status = 1;
- goto exit_error;
- }
+ return 1;
+ } else {
+ fprintf(BOTTOM_SCREEN, "l");
+ }
// Check and decrypt FIRM if it is encrypted.
if (dest->magic != FIRM_MAGIC) {
if (firm_title == NATIVE_FIRM_TITLEID) {
fprintf(BOTTOM_SCREEN, "\nFailed to decrypt firmware.\n"
"This is fatal. Aborting.\n");
- status = 1;
- goto exit_error;
+ return 1;
}
}
firmware_changed = 1; // Decryption performed.
fprintf(BOTTOM_SCREEN, "\nCouldn't decrypt ARM9 FIRM binary.\n"
"Check if you have the needed key at:\n"
" " PATH_SLOT0X11KEY96 "\n");
- status = 1;
- goto exit_error;
+ return 1;
}
firmware_changed = 1; // Decryption of arm9bin performed.
} else {
}
return 0;
-
-exit_error:
-
- return status;
}
// FAIR WARNING; This function is arm11 code, not ARM9.
int
load_firms()
{
+ int state = 0;
+
if (firm_loaded)
return 0;
fprintf(BOTTOM_SCREEN, "FIRM load triggered.\n");
fprintf(BOTTOM_SCREEN, "NATIVE_FIRM\n [");
- if (load_firm(firm_loc, PATH_NATIVE_F, PATH_NATIVE_FIRMKEY, &firm_size, NATIVE_FIRM_TITLEID) != 0)
- return 1;
+ if (load_firm(firm_loc, PATH_NATIVE_F, PATH_NATIVE_FIRMKEY, &firm_size, NATIVE_FIRM_TITLEID) != 0) {
+ abort("]\n Failed to load NATIVE_FIRM.\n");
+ }
find_proc9(firm_loc, &firm_proc9, &firm_p9_exefs);
fprintf(BOTTOM_SCREEN, "]\nTWL_FIRM\n [");
- if (load_firm(twl_firm_loc, PATH_TWL_F, PATH_TWL_FIRMKEY, &twl_firm_size, TWL_FIRM_TITLEID))
- fprintf(BOTTOM_SCREEN, " \nTWL_FIRM failed to load.\n");
- else
+ if (load_firm(twl_firm_loc, PATH_TWL_F, PATH_TWL_FIRMKEY, &twl_firm_size, TWL_FIRM_TITLEID) != 0) {
+ fprintf(BOTTOM_SCREEN, "]\n TWL_FIRM failed to load.\n");
+ state =1;
+ } else {
+ fprintf(stderr, "]\n");
find_proc9(twl_firm_loc, &twl_firm_proc9, &twl_firm_p9_exefs);
+ }
- fprintf(BOTTOM_SCREEN, "]\nAGB_FIRM\n [");
- if (load_firm(agb_firm_loc, PATH_AGB_F, PATH_AGB_FIRMKEY, &agb_firm_size, AGB_FIRM_TITLEID))
- fprintf(BOTTOM_SCREEN, " \nAGB_FIRM failed to load.\n");
- else
+ fprintf(BOTTOM_SCREEN, "AGB_FIRM\n [");
+ if (load_firm(agb_firm_loc, PATH_AGB_F, PATH_AGB_FIRMKEY, &agb_firm_size, AGB_FIRM_TITLEID) != 0) {
+ fprintf(BOTTOM_SCREEN, "]\n AGB_FIRM failed to load.\n");
+ state = 1;
+ } else {
+ fprintf(stderr, "]\n");
find_proc9(agb_firm_loc, &agb_firm_proc9, &agb_firm_p9_exefs);
-
- fprintf(BOTTOM_SCREEN, "]\n");
+ }
firm_loaded = 1; // Loaded.
- return 0;
+ return state;
}
void
.version = 0x00,
.version_string = "9.0.0_AGB",
.console = console_n3ds },
- {.version = 0xFF } // Terminate list
+ {.version = 0xFF,
+ .version_string = "Not found" } // Terminate list
};
struct firm_signature *
get_firm_info(firm_h *firm)
{
- for (struct firm_signature *signature = firm_signatures; signature->version != 0xFF; signature++) {
+ for (struct firm_signature *signature = firm_signatures; ; signature++) {
if (memcmp(signature->sig, firm->section[0].hash, 0x10) == 0) {
return signature;
}
+ if (signature->version == 0xFF) {
+ return signature; // Error. Not found, invalid, etc.
+ }
}
return NULL;
// Read patch to scrap memory.
FILE *f = fopen(filename, "r");
+ if (!f) {
+ // File wasn't found. The user didn't enable anything.
+ return 0;
+ }
size_t len = fsize(f);
fread((uint8_t *)FCRAM_PATCH_LOC, 1, len, f);
fclose(f);
void list_patches_build(char* name, int desc_is_fname) {
current_menu_index_patches = 0;
+ memset(enable_list, 0, FCRAM_SPACING / 2);
+
char fpath[256];
strncpy(fpath, name, 256);
list_patches_build_back(fpath, desc_is_fname);
patches[current_menu_index_patches].index = -1;
- read_file(enable_list, PATH_TEMP "/PATCHENABLE", FCRAM_SPACING / 2);
+ FILE* f;
+ if ((f = fopen(PATH_TEMP "/PATCHENABLE", "r"))) {
+ fread(enable_list, 1, FCRAM_SPACING / 2, f);
+ fclose(f);
+ }
}
int show_menu(struct options_s *options, uint8_t* toggles);
" Version: %s (%x)\n"
"TWL_FIRM / DSi Firmware:\n"
" Version: %s (%x)\n",
- native->version_string, native->version, agb->version_string, agb->version, twl->version_string, twl->version);
+ native->version_string, native->version, agb->version_string, agb->version, twl->version_string, twl->version);
+
wait_key();
need_redraw = 1;
void
fclose(FILE *fp)
{
+ if (!fp->is_open)
+ return;
+
f_close(&(fp->handle));
memset(fp, 0, sizeof(FILE));
void
fseek(FILE *fp, int64_t offset, int whence)
{
+ if (!fp->is_open)
+ return;
+
uint32_t fixed_offset;
switch (whence) {
case SEEK_SET:
size_t
ftell(FILE *fp)
{
+ if (!fp->is_open)
+ return 0;
+
return f_tell(&(fp->handle));
}
int
feof(FILE *fp)
{
+ if (!fp->is_open)
+ return 0;
+
return f_eof(&(fp->handle));
}
size_t
fsize(FILE *fp)
{
+ if (!fp->is_open)
+ return 0;
+
return f_size(&(fp->handle));
}
size_t
fwrite(const void *buffer, size_t elementSize, size_t elementCnt, FILE *fp)
{
+ if (!fp->is_open)
+ return 0;
+
UINT br;
if (f_write(&(fp->handle), buffer, elementSize * elementCnt, &br))
return 0;
- if (br == elementSize * elementCnt)
+ if (elementSize != 1)
br /= elementSize;
- else
- return 0;
return br;
}
size_t
fread(void *buffer, size_t elementSize, size_t elementCnt, FILE *fp)
{
- UINT br;
+ if (!fp->is_open)
+ return 0;
+
+ size_t br;
if (f_read(&(fp->handle), buffer, elementSize * elementCnt, &br))
return 0;
- if (br == elementSize * elementCnt)
+
+ if (elementSize != 1)
br /= elementSize;
- else
- return 0;
return br;
}
{
FILE *temp = fopen(path, "w");
- if (!temp)
+ if (!temp || !temp->is_open)
return 0;
size_t wrote = fwrite(data, 1, size, temp);
{
FILE *temp = fopen(path, "r");
- if (!temp)
+ if (!temp || !temp->is_open)
return 0;
size_t read = fread(data, 1, size, temp);