]> Chaos Git - corbenik/corbenik.git/commitdiff
Import cakes' FIRM decryption with heavy alterations, start on menuing
authorchaoskagami <chaos.kagami@gmail.com>
Tue, 26 Apr 2016 09:12:55 +0000 (05:12 -0400)
committerchaoskagami <chaos.kagami@gmail.com>
Tue, 26 Apr 2016 09:12:55 +0000 (05:12 -0400)
16 files changed:
source/common.h
source/config.c [new file with mode: 0644]
source/config.h [new file with mode: 0644]
source/firm/crypto.c [moved from source/crypto.c with 99% similarity]
source/firm/crypto.h [moved from source/crypto.h with 98% similarity]
source/firm/fcram.c [new file with mode: 0644]
source/firm/fcram.h [new file with mode: 0644]
source/firm/firm.c [new file with mode: 0644]
source/firm/firm.h [new file with mode: 0644]
source/firm/headers.h [moved from source/headers.h with 98% similarity]
source/main.c
source/patch_format.h
source/std/draw.c
source/std/draw.h
source/std/fs.c
source/std/fs.h

index 2861a82f9aa236765b466ec2c559c63bbbd1ef8b..f603257718eea28de0b6bd72716ca809494e33cc 100644 (file)
@@ -7,8 +7,11 @@
 #include "std/fs.h"
 #include "std/memory.h"
 
-#include "crypto.h"
-#include "headers.h"
+#include "firm/fcram.h"
+#include "firm/crypto.h"
+#include "firm/headers.h"
+
 #include "patch_format.h"
+#include "config.h"
 
 #endif
diff --git a/source/config.c b/source/config.c
new file mode 100644 (file)
index 0000000..161d77b
--- /dev/null
@@ -0,0 +1,63 @@
+#include "common.h"
+
+FILE conf_handle;
+
+void regenerate_config() {
+       f_mkdir(PATH_CFW);
+    f_mkdir(PATH_FIRMWARES);
+    f_mkdir(PATH_PATCHES);
+    f_mkdir(PATH_LOCEMU);
+    f_mkdir(PATH_TEMP);
+    f_mkdir(PATH_KEYS);
+    f_mkdir(PATH_EXEFS);
+
+    cprintf(BOTTOM_SCREEN, "Created directory structure.\n");
+
+    memset(&config, 0, sizeof(config));
+    memcpy(&(config.magic), CONFIG_MAGIC, 4);
+    config.config_ver = config_version;
+
+    fopen(&conf_handle, PATH_CONFIG, "w");
+    fwrite(&config, 1, sizeof(config), &conf_handle);
+    fclose(&conf_handle);
+
+    cprintf(BOTTOM_SCREEN, "Config file written.\n");
+}
+
+void load_config() {
+    // Zero on success.
+    if (fopen(&conf_handle, PATH_CONFIG, "r")) {
+        cprintf(BOTTOM_SCREEN, "Config file is missing:\n"
+                               "  %s\n"
+                               "Will create it with defaults.\n",
+                               PATH_CONFIG);
+        regenerate_config();
+    } else {
+        fread(&config, 1, sizeof(config), &conf_handle);
+        fclose(&conf_handle);
+
+        if (memcmp(&(config.magic), CONFIG_MAGIC, 4)) {
+            cprintf(BOTTOM_SCREEN, "Config file at:\n"
+                                   "  %s\n"
+                                   "has incorrect magic:\n"
+                                   "  '%c%c%c%c'\n"
+                                   "Regenerating with defaults.\n",
+                                   PATH_CONFIG,
+                                   config.magic[0], config.magic[1], config.magic[2], config.magic[3]);
+            f_unlink(PATH_CONFIG);
+            regenerate_config();
+        }
+
+        if (config.config_ver < config_version) {
+            cprintf(BOTTOM_SCREEN, "Config file has outdated version:\n"
+                                   "  %s\n"
+                                   "Regenerating with defaults.\n",
+                                   PATH_CONFIG);
+            f_unlink(PATH_CONFIG);
+            regenerate_config();
+        }
+    }
+
+    cprintf(BOTTOM_SCREEN, "Config file loaded.\n");
+}
+
diff --git a/source/config.h b/source/config.h
new file mode 100644 (file)
index 0000000..59bd197
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+static unsigned int config_version = 1;
+
+#define CONFIG_MAGIC "OVAN"
+
+// Structure of config file
+struct config_file {
+    char magic[4];              // "OVAN" for shits and giggles again.
+    uint32_t config_ver;        // Config file version.
+
+    uint8_t  options[256];      // Options in the menu - deliberately large to avoid config version bumps.
+
+    uint64_t patch_ids[256];    // What patches are enabled by UUID. 256 is an arbitrary limit - contact me if you hit it.
+}__attribute__((packed));
+
+static struct config_file config;
+
+#define OPTION_AUTOBOOT 0
+#define OPTION_SILENCE  1
+#define OPTION_TRACE    2
+
+void load_config();
+
+/*
+[CORBENIK]
+version=1
+option_<name>=<int>
+...
+[PATCHES]
+<uuid>=<1|0>
+...
+*/
+
+
+#endif
similarity index 99%
rename from source/crypto.c
rename to source/firm/crypto.c
index 29b6dfccbb6f5a09d4f35598f0ce420cbeb75f69..ee929ae54ba383d4b82364571d2489e44b40b0a5 100644 (file)
@@ -3,7 +3,7 @@
 #include "crypto.h"
 
 #include <stddef.h>
-#include "std/memory.h"
+#include "../std/memory.h"
 /* original version by megazig */
 
 #ifndef __thumb__
similarity index 98%
rename from source/crypto.h
rename to source/firm/crypto.h
index c9176a02185139a221bfc07e71df92d60332d584..ba490f9b961bd0b18662714376d80d8623adde69 100644 (file)
@@ -1,6 +1,7 @@
 // From http://github.com/b1l1s/ctr
 
-#pragma once
+#ifndef __CRYPTO_H
+#define __CRYPTO_H
 
 #include <stdint.h>
 #include "headers.h"
@@ -132,3 +133,5 @@ typedef enum
 } ctr_ncchtypes;
 
 void ncch_getctr(const ncch_h* ncch, uint8_t* ctr, uint8_t type);
+
+#endif
diff --git a/source/firm/fcram.c b/source/firm/fcram.c
new file mode 100644 (file)
index 0000000..6ab1f67
--- /dev/null
@@ -0,0 +1,3 @@
+#include "fcram.h"
+
+void *fcram_temp = (void *)0x23000000;
diff --git a/source/firm/fcram.h b/source/firm/fcram.h
new file mode 100644 (file)
index 0000000..cfc5ca9
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __FCRAM_H
+#define __FCRAM_H
+
+// File to keep track of all the fcram offsets in use.
+// It provides an easy overview of all that is used.
+
+#include <stdint.h>
+
+extern void *fcram_temp;
+
+// Space between most of the locations
+#define FCRAM_SPACING 0x100000
+
+// Start of the space we use
+#define FCRAM_START 0x24000000
+
+// firm.c
+#define FCRAM_FIRM_LOC FCRAM_START
+#define FCRAM_TWL_FIRM_LOC (FCRAM_START + FCRAM_SPACING)  // Double size
+#define FCRAM_AGB_FIRM_LOC (FCRAM_START + FCRAM_SPACING * 3)
+
+// patch.c
+#define FCRAM_MEMORY_LOC (FCRAM_START + FCRAM_SPACING * 4)
+
+static uint8_t *memory_loc = (uint8_t *)FCRAM_MEMORY_LOC;
+static void *current_memory_loc;
+
+#endif
diff --git a/source/firm/firm.c b/source/firm/firm.c
new file mode 100644 (file)
index 0000000..2f885d8
--- /dev/null
@@ -0,0 +1,398 @@
+#include "firm.h"
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "../common.h"
+
+firm_h *firm_loc = (firm_h *)FCRAM_FIRM_LOC;
+static uint32_t firm_size = FCRAM_SPACING;
+
+firm_h *twl_firm_loc = (firm_h *)FCRAM_TWL_FIRM_LOC;
+static uint32_t twl_firm_size = FCRAM_SPACING * 2;
+
+firm_h *agb_firm_loc = (firm_h *)FCRAM_AGB_FIRM_LOC;
+static uint32_t agb_firm_size = FCRAM_SPACING;
+
+static int update_96_keys = 0;
+static int save_firm = 0;
+
+static volatile uint32_t *const a11_entry = (volatile uint32_t *)0x1FFFFFF8;
+
+void slot0x11key96_init()
+{
+    // 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 we can't read the key, we assume it's not needed, and the firmware is the right version.
+        // Otherwise, we make sure the error message for decrypting arm9bin mentions this.
+        aes_setkey(0x11, key, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
+
+        // Tell boot_firm it needs to regenerate the keys.
+        update_96_keys = 1;
+    }
+}
+
+int decrypt_cetk_key(void *key, const void *cetk)
+{
+    // This function only decrypts the NATIVE_FIRM CETK.
+    // I don't need it for anything else atm.
+    // Either way, this is the reason for the two checks here at the top.
+
+    static int common_key_y_init = 0;
+    uint8_t iv[AES_BLOCK_SIZE] = {0};
+
+    uint32_t sigtype = __builtin_bswap32(*(uint32_t *)cetk);
+    if (sigtype != SIG_TYPE_RSA2048_SHA256) return 1;
+
+    ticket_h *ticket = (ticket_h *)(cetk + sizeof(sigtype) + 0x13C);
+    if (ticket->ticketCommonKeyYIndex != 1) return 1;
+
+    if (!common_key_y_init) {
+        uint8_t common_key_y[AES_BLOCK_SIZE] = {0};
+        uint8_t *p9_base = (uint8_t *)0x08028000;
+        uint8_t *i;
+        for (i = p9_base + 0x70000 - AES_BLOCK_SIZE; i >= p9_base; i--) {
+            if (i[0] == 0xD0 && i[4] == 0x9C && i[8] == 0x32 && i[12] == 0x23) {
+                // At i, there's 7 keys with 4 bytes padding between them.
+                // We only need the 2nd.
+                memcpy(common_key_y, i + AES_BLOCK_SIZE + 4, sizeof(common_key_y));
+                cprintf(BOTTOM_SCREEN, "Found the common key Y\n");
+
+                break;
+            }
+        }
+        if (i < p9_base) return 1;
+
+        aes_setkey(0x3D, common_key_y, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
+        common_key_y_init = 1;
+    }
+
+    aes_use_keyslot(0x3D);
+
+    memcpy(iv, ticket->titleID, sizeof(ticket->titleID));
+
+    cprintf(BOTTOM_SCREEN, "Decrypting key\n");
+    memcpy(key, ticket->titleKey, sizeof(ticket->titleKey));
+    aes(key, key, 1, iv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
+
+    return 0;
+}
+
+int decrypt_firm_title(firm_h *dest, ncch_h *ncch, uint32_t *size, void *key)
+{
+    uint8_t firm_iv[16] = {0};
+    uint8_t exefs_key[16] = {0};
+    uint8_t exefs_iv[16] = {0};
+
+    cprintf(BOTTOM_SCREEN, "Decrypting the NCCH\n");
+    aes_setkey(0x16, key, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
+    aes_use_keyslot(0x16);
+    aes(ncch, ncch, *size / AES_BLOCK_SIZE, firm_iv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
+
+    if (ncch->magic != NCCH_MAGIC)
+        return 1;
+
+    memcpy(exefs_key, ncch, 16);
+    ncch_getctr(ncch, exefs_iv, NCCHTYPE_EXEFS);
+
+    // Get the exefs offset and size from the NCCH
+    exefs_h *exefs = (exefs_h *)((void *)ncch + ncch->exeFSOffset * MEDIA_UNITS);
+    uint32_t exefs_size = ncch->exeFSSize * MEDIA_UNITS;
+
+    cprintf(BOTTOM_SCREEN, "Decrypting the exefs\n");
+    aes_setkey(0x2C, exefs_key, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
+    aes_use_keyslot(0x2C);
+    aes(exefs, exefs, exefs_size / AES_BLOCK_SIZE, exefs_iv, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
+
+    // Get the decrypted FIRM
+    // We assume the firm.bin is always the first file
+    firm_h *firm = (firm_h *)&exefs[1];  // The offset right behind the exefs header; the first file.
+    *size = exefs->fileHeaders[0].size;
+
+    if (firm->magic != FIRM_MAGIC)
+        return 1;
+
+    memcpy(dest, firm, *size);
+
+    return 0;
+}
+
+int decrypt_arm9bin(arm9bin_h *header, uint64_t firm_title) {
+    uint8_t slot = 0x15;
+
+    cprintf(BOTTOM_SCREEN, "Decrypting ARM9 FIRM binary\n");
+
+//    if (firm_title == NATIVE_FIRM_TITLEID && version > 0x0F) {
+    if (firm_title == NATIVE_FIRM_TITLEID) {
+        uint8_t decrypted_keyx[AES_BLOCK_SIZE];
+
+        slot0x11key96_init();
+        slot = 0x16;
+
+        aes_use_keyslot(0x11);
+        aes(decrypted_keyx, header->slot0x16keyX, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
+        aes_setkey(slot, decrypted_keyx, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
+    }
+
+    aes_setkey(slot, header->keyy, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
+    aes_setiv(header->ctr, AES_INPUT_BE | AES_INPUT_NORMAL);
+
+    void *arm9bin = (uint8_t *)header + 0x800;
+    int size = atoi(header->size);
+
+    aes_use_keyslot(slot);
+    aes(arm9bin, arm9bin, size / AES_BLOCK_SIZE, header->ctr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
+
+    if (firm_title == NATIVE_FIRM_TITLEID)
+        return *(uint32_t *)arm9bin != ARM9BIN_MAGIC;
+    else if (firm_title == AGB_FIRM_TITLEID || firm_title == TWL_FIRM_TITLEID)
+        return *(uint32_t *)arm9bin != LGY_ARM9BIN_MAGIC;
+    else return 0;
+}
+
+int decrypt_firm(firm_h *dest, char *path_firmkey, char *path_cetk, uint32_t *size, uint64_t firm_title) {
+    uint8_t firm_key[AES_BLOCK_SIZE];
+
+    // Firmware is likely encrypted. Decrypt.
+    if (!read_file(firm_key, path_firmkey, AES_BLOCK_SIZE)) {
+        cprintf(BOTTOM_SCREEN, "Failed to load FIRM key,\n"
+                               "  Attempting to generate with CETK.\n");
+
+        if (!read_file(fcram_temp, path_cetk, FCRAM_SPACING)) {
+            cprintf(BOTTOM_SCREEN, "Failed to load CETK\n");
+            return 1;
+        }
+        cprintf(BOTTOM_SCREEN, "Loaded CETK\n");
+
+        if (decrypt_cetk_key(firm_key, fcram_temp) != 0) {
+            cprintf(BOTTOM_SCREEN, "Failed to decrypt the CETK\n");
+            return 1;
+        }
+        cprintf(BOTTOM_SCREEN, "Saving FIRM key for future use\n");
+        write_file(firm_key, path_firmkey, AES_BLOCK_SIZE);
+    } else {
+        cprintf(BOTTOM_SCREEN, "Loaded FIRM key\n");
+    }
+
+    cprintf(BOTTOM_SCREEN, "Decrypting FIRM\n");
+    if (decrypt_firm_title(dest, (void *)dest, size, firm_key) != 0) {
+        cprintf(BOTTOM_SCREEN, "Failed to decrypt the firmware\n");
+        return 1;
+    }
+       return 0;
+}
+
+int load_firm(firm_h *dest, char *path, char *path_firmkey, char *path_cetk, uint32_t *size, uint64_t firm_title) {
+    int status = 0;
+    int firmware_changed = 0;
+
+    if (read_file(dest, path, *size)) {
+        cprintf(BOTTOM_SCREEN, "Failed to read FIRM from SD\n");
+
+        // Only whine about this if it's NATIVE_FIRM, which is important.
+        if (firm_title == NATIVE_FIRM_TITLEID) {
+            cprintf(BOTTOM_SCREEN, "Failed to load NATIVE_FIRM from:\n"
+                                   "  " PATH_NATIVE_F "\n"
+                                   "This is fatal. Aborting.\n");
+        }
+
+        status = 1;
+        goto exit_error;
+    }
+
+       // Check and decrypt FIRM if it is encrypted.
+    if (dest->magic != FIRM_MAGIC) {
+        status = decrypt_firm(dest, path_firmkey, path_cetk, size, firm_title);
+        if (status != 0) {
+            if (firm_title == NATIVE_FIRM_TITLEID) {
+                cprintf(BOTTOM_SCREEN, "Failed to decrypt firmware.\n"
+                                       "This is fatal. Aborting.\n");
+            }
+            goto exit_error;
+        }
+        firmware_changed = 1; // Decryption performed.
+    } else {
+        cprintf(BOTTOM_SCREEN, "FIRM not encrypted\n");
+    }
+
+    // The N3DS firm has an additional encryption layer for ARM9
+    // Only run if n3ds.
+    {
+        // Look for the arm9 section
+        for (firm_section_h *section = dest->section;
+                section < dest->section + 4; section++) {
+            if (section->type == FIRM_TYPE_ARM9) {
+                // Check whether the arm9bin is encrypted.
+                int arm9bin_iscrypt = 0;
+                uint32_t magic = *(uint32_t*)((uintptr_t)dest + section->offset + 0x800);
+                if (firm_title == NATIVE_FIRM_TITLEID)
+                    arm9bin_iscrypt = (magic != ARM9BIN_MAGIC);
+                else if (firm_title == AGB_FIRM_TITLEID || firm_title == TWL_FIRM_TITLEID)
+                    arm9bin_iscrypt = (magic != LGY_ARM9BIN_MAGIC);
+
+                if (arm9bin_iscrypt) {
+                    // Decrypt the arm9bin.
+                    if (decrypt_arm9bin((arm9bin_h *)((uintptr_t)dest + section->offset), firm_title)) {
+                        cprintf(BOTTOM_SCREEN, "Couldn't decrypt ARM9 FIRM binary.\n"
+                                               "Check if you have the needed key at:\n"
+                                               "  " PATH_SLOT0X11KEY96 "\n");
+                        status = 1;
+                        goto exit_error;
+                    }
+                    firmware_changed = 1; // Decryption of arm9bin performed.
+                } else {
+                    cprintf(BOTTOM_SCREEN, "ARM9 FIRM binary not encrypted\n");
+//                    if (firm_type == NATIVE_FIRM && firm_current->version > 0x0F) {
+                        slot0x11key96_init(); // This has to be loaded regardless, otherwise boot will fail.
+//                    }
+                }
+
+                // We assume there's only one section to decrypt.
+                break;
+            }
+        }
+    }
+
+    // Save firmware.bin if decryption was done.
+    if (firmware_changed) {
+        cprintf(BOTTOM_SCREEN, "Saving decrypted FIRM\n");
+        write_file(dest, path, *size);
+    }
+
+    //if (firm_current->console == console_n3ds)
+    {
+        cprintf(BOTTOM_SCREEN, "Fixing arm9 entrypoint\n");
+
+        // Patch the entrypoint to skip arm9loader
+        if (firm_title == NATIVE_FIRM_TITLEID) {
+            dest->a9Entry = 0x0801B01C;
+        } else if (firm_title == AGB_FIRM_TITLEID ||
+                   firm_title == TWL_FIRM_TITLEID) {
+            dest->a9Entry = 0x0801301C;
+        }
+        // The entrypoints seem to be the same across different FIRM versions,
+        //  so we don't change them.
+    }
+
+    return 0;
+
+exit_error:
+
+    return status;
+}
+
+void __attribute__((naked)) disable_lcds() {
+    *a11_entry = 0;  // Don't wait for us
+
+    *(volatile uint32_t *)0x10202A44 = 0;
+    *(volatile uint32_t *)0x10202244 = 0;
+    *(volatile uint32_t *)0x1020200C = 0;
+    *(volatile uint32_t *)0x10202014 = 0;
+
+    while (!*a11_entry);
+    ((void (*)())*a11_entry)();
+}
+
+void boot_firm() {
+    // Set up the keys needed to boot a few firmwares, due to them being unset, depending on which firmware you're booting from.
+    // TODO: Don't use the hardcoded offset.
+    if (update_96_keys) {
+        void *keydata = (void *)((uintptr_t)firm_loc + firm_loc->section[2].offset + 0x89814);
+
+        aes_use_keyslot(0x11);
+        uint8_t keyx[AES_BLOCK_SIZE];
+        for (int slot = 0x19; slot < 0x20; slot++) {
+            aes(keyx, keydata, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
+            aes_setkey(slot, keyx, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
+            *(uint8_t *)(keydata + 0xF) += 1;
+        }
+
+        cprintf(BOTTOM_SCREEN, "Updated keyX keyslots\n");
+    }
+
+    struct memory_header *memory = (void *)(memory_loc + 1);
+    while ((uintptr_t)memory < (uintptr_t)memory_loc + *memory_loc) {
+        memcpy((void *)memory->location, memory + 1, memory->size);
+        memory = (void *)((uintptr_t)(memory + 1) + memory->size);
+    }
+    cprintf(BOTTOM_SCREEN, "Copied memory\n");
+
+    for (firm_section_h *section = firm_loc->section;
+            section < firm_loc->section + 4 && section->address != 0; section++) {
+        memcpy((void *)section->address, (void *)firm_loc + section->offset, section->size);
+    }
+    cprintf(BOTTOM_SCREEN, "Copied FIRM\n");
+
+    *a11_entry = (uint32_t)disable_lcds;
+    while (*a11_entry);  // Make sure it jumped there correctly before changing it.
+    *a11_entry = (uint32_t)firm_loc->a11Entry;
+
+    cprintf(BOTTOM_SCREEN, "Prepared arm11 entry, jumping to FIRM\n");
+
+    ((void (*)())firm_loc->a9Entry)();
+}
+
+int load_firms() {
+    cprintf(TOP_SCREEN, "[Loading FIRM]");
+
+    cprintf(BOTTOM_SCREEN, "Loading NATIVE_FIRM\n");
+    if (load_firm(firm_loc, PATH_NATIVE_F, PATH_NATIVE_FIRMKEY, PATH_NATIVE_CETK, &firm_size, NATIVE_FIRM_TITLEID) != 0)
+        return 1;
+
+    cprintf(BOTTOM_SCREEN, "Loading TWL_FIRM\n");
+    if(load_firm(twl_firm_loc, PATH_TWL_F, PATH_TWL_FIRMKEY, PATH_TWL_CETK, &twl_firm_size, TWL_FIRM_TITLEID))
+        cprintf(BOTTOM_SCREEN, "TWL_FIRM failed to load.\n");
+
+    cprintf(BOTTOM_SCREEN, "Loading AGB_FIRM\n");
+    if(load_firm(agb_firm_loc, PATH_AGB_F, PATH_AGB_FIRMKEY, PATH_AGB_CETK, &agb_firm_size, AGB_FIRM_TITLEID))
+        cprintf(BOTTOM_SCREEN, "AGB_FIRM failed to load.\n");
+
+    return 0;
+}
+
+void boot_cfw() {
+    cprintf(TOP_SCREEN, "[Patching]");
+//    if (patch_firm_all() != 0)
+//        return;
+
+    // Only save the firm if that option is required (or it's needed for autoboot),
+    //   and either the patches have been modified, or the file doesn't exist.
+    if ((save_firm || config.options[OPTION_AUTOBOOT]) &&
+            f_stat(PATH_NATIVE_P, NULL) != 0) {
+        cprintf(BOTTOM_SCREEN, "Saving patched NATIVE_FIRM\n");
+        if (write_file(firm_loc, PATH_NATIVE_P, firm_size) != firm_size) {
+            cprintf(BOTTOM_SCREEN, "%pFailed to save patched FIRM.\nWriting SD failed.\nThis is fatal.\n", COLOR(RED, BLACK));
+            return;
+        }
+    }
+
+    if ((save_firm || config.options[OPTION_AUTOBOOT]) &&
+            f_stat(PATH_MEMBIN, NULL) != 0) {
+        cprintf(BOTTOM_SCREEN, "Saving patched memory\n");
+        if (write_file(memory_loc, PATH_MEMBIN, *memory_loc) != *memory_loc) {
+            cprintf(BOTTOM_SCREEN, "%pFailed to save the patched FIRM\nWriting SD failed.\n", COLOR(RED, BLACK));
+            return;
+        }
+    }
+
+    if (f_stat(PATH_TWL_P, NULL) != 0) {
+        cprintf(BOTTOM_SCREEN, "Saving patched TWL_FIRM\n");
+        if (write_file(twl_firm_loc, PATH_TWL_P, twl_firm_size) != twl_firm_size) {
+            cprintf(BOTTOM_SCREEN, "%pFailed to save the patched FIRM\nWriting SD failed.\n", COLOR(RED, BLACK));
+            return;
+        }
+    }
+
+    if (f_stat(PATH_AGB_P, NULL) != 0) {
+        cprintf(BOTTOM_SCREEN, "Saving patched AGB_FIRM\n");
+        if (write_file(agb_firm_loc, PATH_AGB_P, agb_firm_size) != agb_firm_size) {
+            cprintf(BOTTOM_SCREEN, "%pFailed to save the patched FIRM\nWriting SD failed.\n", COLOR(RED, BLACK));
+            return;
+        }
+    }
+
+//    boot_firm();
+}
diff --git a/source/firm/firm.h b/source/firm/firm.h
new file mode 100644 (file)
index 0000000..20eb89b
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __FIRM_H
+
+#include <stdint.h>
+#include "headers.h"
+
+extern firm_h *firm_loc;
+extern struct firm_signature *current_firm;
+
+extern firm_h *twl_firm_loc;
+extern struct firm_signature *current_twl_firm;
+
+extern firm_h *agb_firm_loc;
+extern struct firm_signature *current_agb_firm;
+
+struct firm_signature *get_firm_info(firm_h *firm);
+void slot0x11key96_init();
+
+int  load_firms();
+void boot_firm();
+void boot_cfw();
+
+#endif
similarity index 98%
rename from source/headers.h
rename to source/firm/headers.h
index 5110cdc8411c21ed9cd42e61fde1461e3fb34ebb..8ea3556d389768f5aa5593494fc08f10e0b606f6 100644 (file)
 #define ARM9BIN_MAGIC           (0x47704770)
 #define LGY_ARM9BIN_MAGIC       (0xB0862000)
 
+struct memory_header {
+    uint32_t location;
+    uint32_t size;
+} memory_header_t;
+
 typedef struct firm_section_h {
     uint32_t offset;
     uint32_t address;
index 42053ce9b6546ee3c113cb2626e97a153f4a4dc3..099f7bda444220789b1a7d4c4fa63dfc02078eb1 100644 (file)
@@ -1,12 +1,70 @@
 #include "common.h"
 
-void load_options() {
-       FILE config;
-}
-
 void init_system() {}
 
+#define MENU_BOOTME  -1
+#define MENU_MAIN     1
+#define MENU_OPTIONS  2
+#define MENU_PATCHES  3
+#define MENU_INFO     4
+#define MENU_RESET    5
+#define MENU_POWER    6
+
+static int cursor_y = 0;
+static int which_menu = 1;
+
+int menu_options() { return MENU_MAIN; }
+int menu_patches() { return MENU_MAIN; }
+int menu_info()    { return MENU_MAIN; }
+
+int menu_main() {
+    set_cursor(TOP_SCREEN, 0, 0);
+
+    const char *list[] = {
+        "Options",
+        "Patches",
+        "Info",
+        "Boot firmware",
+        "Reset",
+        "Power off"
+    };
+
+    cprintf(TOP_SCREEN, "%p[Corbenik - The Rebirth]\n", COLOR(CYAN, BLACK));
+
+    for(int i=0; i < 6; i++) {
+        if (cursor_y == i)
+            cprintf(TOP_SCREEN, "%p-> ", COLOR(GREEN, BLACK));
+        else
+            cprintf(TOP_SCREEN, "   ");
+        cprintf(TOP_SCREEN, "%s\n", list[i]);
+    }
+
+    return 0;
+}
+
 int menu_handler() {
+    int to_menu = 0;
+    switch(which_menu) {
+        case MENU_MAIN:
+            to_menu = menu_main();
+            break;
+        case MENU_OPTIONS:
+            to_menu = menu_options();
+            break;
+        case MENU_PATCHES:
+            to_menu = menu_patches();
+            break;
+        case MENU_INFO:
+            to_menu = menu_info();
+            break;
+        case MENU_BOOTME:
+        default:
+            return 0;
+    }
+
+    if (to_menu != 0)
+        which_menu = to_menu;
+
     return 1;
 }
 
@@ -18,13 +76,9 @@ void main() {
         cprintf(BOTTOM_SCREEN, "Mounted SD card.\n");
     }
 
-    for (int i = 0; i < 200; i++) {
-        cprintf(TOP_SCREEN, "%d\n", i);
-    }
-
-    cprintf(TOP_SCREEN, "Done printing.");
+    load_config(); // Load configuration.
 
-    load_options(); // Load configuration.
+    load_firms();
 
     int in_menu = 1;
 
index 3b7ff95908495f7f9f6ebf72a9d0f6ad010cedb3..38879af549fd570b9afbb20432bf940136333a09 100644 (file)
 
 #define LOADER_TITLEID           0x0004013000001302llu // Loader is handled specially.
 
+#define PATCH_MANDATORY  (1 << 0) // Patch must be applied for successful boot.
+#define PATCH_FAIL_ABORT (1 << 1) // If patch fails to apply, abort and show an error.
+#define PATCH_DISABLED   (1 << 2) // Do not allow changing this patch's status. With PATCH_MANDATORY, this prevents disabling it.
+
+#define PATH_CFW        "/corbenik"                // CFW root directory.
+#define PATH_CONFIG     PATH_CFW "/main.conf"      // Config file.
+#define PATH_LOCEMU     PATH_CFW "/locale.conf"    // Locale emulation config
+#define PATH_CPU_CFG    PATH_CFW "/cpu.conf"       // CPU settings config
+
+#define PATH_FIRMWARES  PATH_CFW "/firmware"       // Firmware folder.
+#define PATH_PATCHES    PATH_CFW "/patches"        // Patches folder.
+#define PATH_TEMP       PATH_CFW "/temp"           // Files that are transient (user can delete them and they will be regenerated)
+#define PATH_KEYS       PATH_CFW "/keys"           // Keyfiles will be loaded from this dir, and additionally the root if not found.
+#define PATH_EXEFS      PATH_CFW "/exefs"          // ExeFS overrides, named like '<titleid>.exefs'
+
+#define PATH_NATIVE_F   PATH_FIRMWARES "/native"
+#define PATH_AGB_F      PATH_FIRMWARES "/agb"
+#define PATH_TWL_F      PATH_FIRMWARES "/twl"
+
+#define PATH_NATIVE_CETK       PATH_KEYS "/native.cetk"
+#define PATH_NATIVE_FIRMKEY    PATH_KEYS "/native.key"
+
+#define PATH_TWL_CETK       PATH_KEYS "/twl.cetk"
+#define PATH_TWL_FIRMKEY    PATH_KEYS "/twl.key"
+
+#define PATH_AGB_CETK       PATH_KEYS "/agb.cetk"
+#define PATH_AGB_FIRMKEY    PATH_KEYS "/agb.key"
+
+#define PATH_SLOT0X11KEY96  PATH_KEYS "/0x11.key"
+
+#define PATH_ALT_SLOT0X11KEY96 "/slot0x11key96.bin" // Hey, your perrogative, buddy. I like cleaned up paths.
+
+#define PATH_MEMBIN     PATH_TEMP "/memory_p"        // Memory binary
+#define PATH_NATIVE_P   PATH_TEMP "/native_p"   // Native FIRM patched
+#define PATH_AGB_P      PATH_TEMP "/agb_firm_p"      // AGB FIRM patched
+#define PATH_TWL_P      PATH_TEMP "/twl_firm_p"      // TWL FIRM patched
+
 // Structure of a patch file.
 struct system_patch {
        char magic[4];            // "AIDA" for shits and giggles and because we like .hack.
@@ -24,11 +61,29 @@ struct system_patch {
     uint64_t patch_id;        // Unique ID for patch. Each unique patch should provide a unique ID.
 
        uint64_t tid;             // What title this patch is intended for. Certain values are specially handled.
-    uint64_t depends[64];     // What patches need to be applied for this patch to be applied; as unique IDs
+
+    uint8_t extra_flags;      // Extra flags for patch.
+
+    uint64_t depends[16];     // What patches need to be applied for this patch to be applied; as unique IDs
 
     uint32_t patch_size;      // Size of the following patch data.
     uint8_t patch_data[];     // The data for the patch. This is a sort of interpreted code...see below.
 } __attribute__((packed));
 
+/*
+[PATCH]
+version=1
+cfw_version=1
+
+name=Signature Check
+desc=Disables firmware signature checking.
+uuid=1
+title_id=0004013800000002
+[DEPENDS]
+none
+[DATA]
+<BYTECODE AS HEX>
+*/
+
 #endif
 
index 0a0148181ea44aac91fb77821186b9ff585ad669..e722559dc95d3824d70dd0dbd8faf6ce272d5d82 100644 (file)
@@ -17,20 +17,20 @@ static char color_buffer_bottom [TEXT_BOTTOM_SIZE];
 
 static uint32_t colors[16] = {
        0x000000, // Black
-       0x0000aa, // Blue
+       0xaa0000, // Blue
        0x00aa00, // Green
-       0x00aaaa, // Cyan
-       0xaa0000, // Red
+       0xaaaa00, // Cyan
+       0x0000aa, // Red
        0xaa00aa, // Magenta
-       0xaa5500, // Brown
+       0x0055aa, // Brown
        0xaaaaaa, // Gray
        0x555555, // Dark gray
-       0x5555ff, // Bright blue
+       0xff5555, // Bright blue
        0x55ff55, // Bright green
-       0x55ffff, // Bright cyan
-       0xff5555, // Bright red
+       0xffff55, // Bright cyan
+       0x5555ff, // Bright red
        0xff55ff, // Bright megenta
-       0xffff55, // Yellow
+       0x55ffff, // Yellow
        0xffffff  // White
 };
 
@@ -43,10 +43,14 @@ void clear_screen(uint8_t* screen) {
                size = SCREEN_TOP_SIZE;
                buffer = text_buffer_top;
                buffer_size = TEXT_TOP_SIZE;
+               top_cursor_x = 0;
+               top_cursor_y = 0;
        } else if(screen == framebuffers->bottom) {
                size = SCREEN_BOTTOM_SIZE;
                buffer = text_buffer_bottom;
                buffer_size = TEXT_BOTTOM_SIZE;
+               bottom_cursor_x = 0;
+               bottom_cursor_y = 0;
        } else {
                return; // Invalid buffer.
        }
@@ -55,13 +59,22 @@ void clear_screen(uint8_t* screen) {
        memset(buffer, 0, buffer_size);
 }
 
+void set_cursor(int channel, unsigned int x, unsigned int y) {
+       switch(channel) {
+               case TOP_SCREEN:
+            top_cursor_x = x;
+            top_cursor_y = y;
+            break;
+               case BOTTOM_SCREEN:
+            bottom_cursor_x = x;
+            bottom_cursor_y = y;
+            break;
+       }
+}
+
 void clear_screens() {
     clear_screen(framebuffers->top_left);
     clear_screen(framebuffers->bottom);
-       top_cursor_x = 0;
-       top_cursor_y = 0;
-       bottom_cursor_x = 0;
-       bottom_cursor_y = 0;
 }
 
 void draw_character(uint8_t* screen, const char character, const unsigned int buf_x, const unsigned int buf_y, const uint32_t color_fg, const uint32_t color_bg) {
@@ -103,7 +116,7 @@ void draw_character(uint8_t* screen, const char character, const unsigned int bu
     }
 }
 
-void putc(int buf, unsigned char color, const char c) {
+void putc(int buf, unsigned char color, const int c) {
        unsigned int width  = 0;
        unsigned int height = 0;
        unsigned int size = 0;
index 26b5831fe8c1567a25c671e64767732bed21df82..a79eb0bec3d1d9aab7b6982eb8127b83504c1e12 100644 (file)
@@ -51,13 +51,15 @@ void draw_character(uint8_t* screen, const char character, const unsigned int po
 #define TOP_SCREEN    0
 #define BOTTOM_SCREEN 1
 
-void putc(int buf, unsigned char color, const char c);
+void putc(int buf, unsigned char color, const int c);
 void puts(int buf, unsigned char color, const char *string);
 void cflush(int channel);
 
 void put_int(int channel, unsigned char color, int n);
 void put_uint(int channel, unsigned char color, unsigned int n);
 
+void set_cursor(int channel, unsigned int x, unsigned int y);
+
 // Like printf. Supports the following format specifiers:
 //   %s %c %d %u
 // The following non-standard formats are also supported (but are subject to replacement)
index f22291383e1a38c94d3a39f5aebbe1fee87e9f68..e25a7a3ad4c2414f7d9ea605c9b505d1b4183828 100644 (file)
@@ -21,9 +21,7 @@ int fopen(FILE* fp, const char *filename, const char *mode) {
 
        fp->mode = (*mode == 'r' ? FA_READ : (FA_WRITE | FA_OPEN_ALWAYS));
 
-    f_open(&(fp->handle), filename, fp->mode);
-
-    return 0;
+    return f_open(&(fp->handle), filename, fp->mode);
 }
 
 void fclose(FILE* fp) {
@@ -61,16 +59,38 @@ size_t fsize(FILE* fp) {
     return f_size(&(fp->handle));
 }
 
-size_t fwrite(const char *buffer, size_t elementSize, size_t elementCnt, FILE* fp) {
-    uint32_t br;
+size_t fwrite(const void *buffer, size_t elementSize, size_t elementCnt, FILE* fp) {
+    UINT br;
     if(f_write(&(fp->handle), buffer, elementSize*elementCnt, &br)) return 0;
     if (br == elementSize*elementCnt) br /= elementSize; else return 0;
     return br;
 }
 
-size_t fread(char *buffer, size_t elementSize, size_t elementCnt, FILE* fp) {
-    uint32_t br;
-    if(f_read(&(fp->handle), buffer, elementSize*elementCnt, &br)) return 0;
-    if (br == elementSize*elementCnt) br /= elementSize; else return 0;
+size_t fread(void *buffer, size_t elementSize, size_t elementCnt, FILE* fp) {
+    UINT br;
+    if(f_read(&(fp->handle), buffer, elementSize*elementCnt, &br))
+        return 0;
+    if (br == elementSize*elementCnt)
+        br /= elementSize;
+    else
+        return 0;
     return br;
 }
+
+size_t write_file(void* data, char* path, size_t size) {
+    FILE temp;
+    fopen(&temp, path, "w");
+    size_t written = fwrite(data, 1, size, &temp);
+    fclose(&temp);
+    return written;
+}
+
+size_t read_file(void* data, char* path, size_t size) {
+    FILE temp;
+    fopen(&temp, path, "r");
+
+    size_t read = fread(data, 1, size, &temp);
+    fclose(&temp);
+
+    return read;
+}
index 53f97618b517dbe81fa31c1ac787e4f8c2c989c2..16f6f4779a39342efe77ba7fb474c956dcc085ba 100644 (file)
@@ -31,7 +31,11 @@ int    feof      (FILE* fp);
 
 size_t fsize     (FILE* fp);
 
-size_t fwrite    (const char *buffer, size_t elementSize, size_t elementCnt, FILE* fp);
-size_t fread     (char *buffer,       size_t elementSize, size_t elementCnt, FILE* fp);
+size_t fwrite    (const void *buffer, size_t elementSize, size_t elementCnt, FILE* fp);
+size_t fread     (void *buffer,       size_t elementSize, size_t elementCnt, FILE* fp);
+
+
+size_t write_file(void* data, char* path, size_t size);
+size_t read_file(void* data, char* path, size_t size);
 
 #endif