out
-CakeHax
-CakeBrah
build
*.bin
*.3dsx
*.o
*.d
*.elf
-*.bat
\ No newline at end of file
+*.bat
+input
cp out/arm9loaderhax.bin /media/cd/anim/boot/r.bin || exit 0
cp out/arm9loaderhax.bin /media/cd/anim/boot/l.bin || exit 0
cp -r out/corbenik /media/cd/ || exit 0
+cp -r input/corbenik /media/cd/ || exit 0
umount /media/cd || exit 0
eject /dev/sdb || exit 0
.PHONY: all copyout
all: loader
- mkdir -p ../out/corbenik/module
- cp loader/loader.cxi ../out/corbenik/module/loader.cxi
+ mkdir -p ../out/corbenik/lib/module
+ cp loader/loader.cxi ../out/corbenik/lib/module/loader.cxi
.PHONY: clean
clean: clean_loader
- rm -rf ../out/corbenik/module
+ rm -rf ../out/corbenik/bin
.PHONY: loader
loader:
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
+ERROR := -Werror
CFLAGS := -flto -Wall -Os -mword-relocations \
-fomit-frame-pointer -ffunction-sections -fdata-sections -fshort-wchar \
$(ARCH)
-#pragma once
+#ifndef __CONFIG_H
+#define __CONFIG_H
-#include <stdint.h>
+static unsigned int config_version = 1;
+#define CONFIG_MAGIC "OVAN"
+
+// Structure of config file
struct config_file {
- unsigned int config_ver;
- unsigned int firm_ver;
- uint8_t firm_console;
- uint32_t emunand_location;
+ 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));
+
+/*
+extern struct config_file config;
+
+enum type {
+ boolean_val, // Toggle
+ ranged_val // N1 - N2, left and right to pick.
+ mask_val // Bitmask allowed values.
+};
+
+struct range_str {
+ int a, b;
+};
+
+struct option {
+ int config_index;
+ char name_text[64];
+ enum type allowed;
+ uint32_t a, b;
+}__attribute__((packed));
+
+
+static struct options[] = {
+ { 0, "Signature Patch", boolean_val, 0 },
+ { 1, "FIRM Protection", boolean_val, 0 },
+ { 2, "SysModule Replacement", boolean_val, 0 },
+ { 3, "Service Replacement", boolean_val, 0 },
+ { 4, "ARM9 Thread", boolean_val, 0 },
+
+ { 5, "Autoboot", boolean_val, 0 },
+ { 6, "Silence w/ Autoboot", boolean_val, 0 },
+ { 7, "Step through with button", boolean_val, 0 },
+
+ { 8, "Don't draw background color", boolean_val, 0 },
+ { 9, "Preserve framebuffer data", boolean_val, 0 },
+
+ { 10, "Hide Help from menu", boolean_val, 0 },
+
+ { 11, "Loader: CPU L2 enable", boolean_val, 0 },
+ { 12, "Loader: CPU 800Mhz mode", boolean_val, 0 },
+ { 13, "Loader: Language Emulation", boolean_val, 0 },
+
+ { 14, "No dependency tracking", boolean_val, 0 },
+ { 15, "Allow unsafe options", boolean_val, 0 },
+}
+*/
+#define OPTION_SIGPATCH 0 // Use builtin signature patch.
+#define OPTION_FIRMPROT 1 // Protect firmware from writes.
+#define OPTION_LOADER 2 // Use builtin loader module replacer.
+#define OPTION_SERVICES 3 // Inject services (including backdoor for 11)
+#define OPTION_ARM9THREAD 4 // Use builtin ARM9 thread injector.
+
+#define OPTION_AUTOBOOT 5 // Skip menu unless L is held.
+#define OPTION_SILENCE 6 // Don't print debug information.
+#define OPTION_TRACE 7 // Pause for A key on each step.
+
+#define OPTION_TRANSP_BG 8 // Background color is not drawn under text.
+#define OPTION_NO_CLEAR_BG 9 // Framebuffer is preserved from whatever ran before us.
+#define OPTION_READ_ME 10 // Remove Help/Readme from menu.
+
+#define OPTION_LOADER_CPU_L2 11 // Enable L2 cache.
+#define OPTION_LOADER_CPU_800MHZ 12 // Enable 800Mhz mode.
+#define OPTION_LOADER_LANGEMU 13 // Enable 800Mhz mode.
- unsigned int autoboot_enabled: 1;
- unsigned int n3ds_clock: 1;
- unsigned int n3ds_l2: 1;
- unsigned int language_emu: 1;
+#define IGNORE_PATCH_DEPS 14 // Ignore patch UUID dependencies. Not recommended.
+#define IGNORE_BROKEN_SHIT 15 // Allow enabling patches which are marked as 'incompatible'. Chances are there's a reason.
- /* The cakes_count and cakes data
- is excluded because loader has
- no use for it. */
-} __attribute__((packed));
+//#define HEADER_COLOR 12 // Color of header text.
+//#define BG_COLOR 13 // Color of background.
+//#define TEXT_COLOR 14 // Color of most text.
+//#define ARROW_COLOR 15 // Color of Arrow.
+#endif
-#pragma once
+#ifndef __MEMORY_H__
+#define __MEMORY_H__
#include <3ds/types.h>
void memcpy(void *dest, const void *src, u32 size);
+
+#endif
#define _MAX_LFN 255
#endif
#include "config.h"
+#include "../../../source/patch_format.h"
static int memcmp(const void *buf1, const void *buf2, u32 size)
{
if(found == NULL) break;
+ // FIXME - This is throwing on Werror.
memcpy(found + offset, replace, repSize);
u32 at = (u32)(found - start);
return secureInfoExists;
}
-static unsigned int config_ver = 4;
-static struct config_file config;
-static int failed_load_config = 1;
-void load_config() {
- // Make sure we don't get random values if the config file doesn't load
- for(int i=0;i<sizeof(struct config_file);i++) ((char*)&config)[i]=0;
+struct config_file config;
+int failed_load_config = 1;
+
+void clear_config() {
+ // Basically; memset.
+ for(int i=0;i<sizeof(struct config_file);i++)
+ ((char*)&config)[i]=0;
+}
+void load_config() {
IFile file;
u64 total;
// Open file.
- if (!fileOpen(&file, ARCHIVE_SDMC, "/corbenik/config.dat", FS_OPEN_READ)) {
+ if (!fileOpen(&file, ARCHIVE_SDMC, PATH_CONFIG, FS_OPEN_READ)) {
// Failed to open.
failed_load_config = 1;
- return;
+ goto ret_fail;
}
// Read file.
if(!IFile_Read(&file, &total, &config, sizeof(struct config_file))) {
// Failed to read.
- failed_load_config = 1;
- for(int i=0;i<sizeof(struct config_file);i++) ((char*)&config)[i]=0;
- return;
+ goto ret_fail;
+ }
+
+ IFile_Close(&file); // Read to memory.
+
+ if (config.magic[0] != 'O' || config.magic[1] != 'V' || config.magic[2] != 'A' || config.magic[3] != 'N') {
+ // Incorrect magic.
+ // Failed to read.
+ goto ret_fail;
}
- if (config.config_ver != config_ver) {
+ if (config.config_ver != config_version) {
// Invalid version.
- failed_load_config = 1;
- for(int i=0;i<sizeof(struct config_file);i++) ((char*)&config)[i]=0;
- return;
+ goto ret_fail;
}
- IFile_Close(&file);
- // Loaded okay.
+ failed_load_config = 0;
+
+ return;
+
+ret_fail:
+ clear_config();
+
+ return;
}
static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
{
- /* Here we look for "/cfw/locale/[u64 titleID in hex, uppercase].txt"
+ // FIXME - Rewrite this function to use a single line-based config
+ // Directory seeks have severe issues on FAT and
+ // dumping configs based on 3dsdb (more than 1000) causes things
+ // to kind a choke.
+
+ /* Here we look for "/corbenik/locale/[u64 titleID in hex, uppercase].txt"
If it exists it should contain, for example, "EUR IT" */
char path[] = "/corbenik/locales/0000000000000000.txt";
- u32 i = strlen(path) - 21;
+ u32 i = 0, j = 0;
+ while(path[j] != 0) {
+ if (path[j] == '/')
+ i = j;
+ j++;
+ }
+ i += 1;
while(progId > 0)
{
for(u32 i = 0; i < 7; ++i)
{
+ // TODO - Permit alternative names. They're using fixed strings for ease of use;
+ // we need to permit names like 'Japan', 'Europe', etc
+ // Maybe read locale data from the FS? http://cldr.unicode.org/
static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
if(memcmp(buf, regions[i], 3) == 0)
for(u32 i = 0; i < 12; ++i)
{
+ // TODO - Same as above.
static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"};
if(memcmp(buf + 4, languages[i], 2) == 0)
}
}
+void region_patch(u64 progId, u8 *code, u32 size) {
+ static const u8 regionFreePattern[] = {0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3};
+ static const u8 regionFreePatch[] = {0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1};
+
+ //Patch SMDH region checks
+ patchMemory(code, size,
+ regionFreePattern,
+ sizeof(regionFreePattern), -16,
+ regionFreePatch,
+ sizeof(regionFreePatch), 1
+ );
+}
+
+void disable_nim_updates(u64 progId, u8 *code, u32 size) {
+ static const u8 blockAutoUpdatesPattern[] = {0x25, 0x79, 0x0B, 0x99};
+ static const u8 blockAutoUpdatesPatch[] = {0xE3, 0xA0};
+
+ //Block silent auto-updates
+ patchMemory(code, size,
+ blockAutoUpdatesPattern,
+ sizeof(blockAutoUpdatesPattern), 0,
+ blockAutoUpdatesPatch,
+ sizeof(blockAutoUpdatesPatch), 1
+ );
+}
+
+void disable_eshop_updates(u64 progId, u8 *code, u32 size) {
+ static const u8 skipEshopUpdateCheckPattern[] = {0x30, 0xB5, 0xF1, 0xB0};
+ static const u8 skipEshopUpdateCheckPatch[] = {0x00, 0x20, 0x08, 0x60, 0x70, 0x47};
+
+ //Skip update checks to access the EShop
+ patchMemory(code, size,
+ skipEshopUpdateCheckPattern,
+ sizeof(skipEshopUpdateCheckPattern), 0,
+ skipEshopUpdateCheckPatch,
+ sizeof(skipEshopUpdateCheckPatch), 1
+ );
+}
+
+void fake_friends_version(u64 progId, u8 *code, u32 size) {
+ static const u8 fpdVerPattern[] = {0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01};
+ static const u8 fpdVerPatch = 0x06; // Latest version.
+
+ //Allow online access to work with old friends modules
+ patchMemory(code, size,
+ fpdVerPattern,
+ sizeof(fpdVerPattern), 9,
+ &fpdVerPatch,
+ sizeof(fpdVerPatch), 1
+ );
+}
+
+void settings_string(u64 progId, u8 *code, u32 size) {
+ static const u16 verPattern[] = u"Ver.";
+ static const u16 verPatch[] = u".hax";
+
+ //Patch Ver. string
+ patchMemory(code, size,
+ verPattern,
+ sizeof(verPattern) - sizeof(u16), 0,
+ verPatch,
+ sizeof(verPatch) - sizeof(u16), 1
+ );
+}
+
+void disable_cart_updates(u64 progId, u8 *code, u32 size) {
+ static const u8 stopCartUpdatesPattern[] = {0x0C, 0x18, 0xE1, 0xD8};
+ static const u8 stopCartUpdatesPatch[] = {0x0B, 0x18, 0x21, 0xC8};
+
+ //Disable updates from foreign carts (makes carts region-free)
+ patchMemory(code, size,
+ stopCartUpdatesPattern,
+ sizeof(stopCartUpdatesPattern), 0,
+ stopCartUpdatesPatch,
+ sizeof(stopCartUpdatesPatch), 2
+ );
+}
+
+void adjust_cpu_settings(u64 progId, u8 *code, u32 size) {
+ if (!failed_load_config) {
+ u32 cpuSetting = 0;
+ // L2
+ cpuSetting |= config.options[OPTION_LOADER_CPU_L2];
+ // Speed
+ cpuSetting |= config.options[OPTION_LOADER_CPU_800MHZ] << 1;
+
+ if(cpuSetting) {
+ static const u8 cfgN3dsCpuPattern[] = {0x00, 0x40, 0xA0, 0xE1, 0x07, 0x00};
+
+ u32 *cfgN3dsCpuLoc = (u32 *)memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern));
+
+ //Patch N3DS CPU Clock and L2 cache setting
+ if(cfgN3dsCpuLoc != NULL) {
+ *(cfgN3dsCpuLoc + 1) = 0xE1A00000;
+ *(cfgN3dsCpuLoc + 8) = 0xE3A00000 | cpuSetting;
+ }
+ }
+ }
+}
+
+void secureinfo_sigpatch(u64 progId, u8 *code, u32 size) {
+ static const u8 secureinfoSigCheckPattern[] = {0x06, 0x46, 0x10, 0x48, 0xFC};
+ static const u8 secureinfoSigCheckPatch[] = {0x00, 0x26};
+
+ //Disable SecureInfo signature check
+ patchMemory(code, size,
+ secureinfoSigCheckPattern,
+ sizeof(secureinfoSigCheckPattern), 0,
+ secureinfoSigCheckPatch,
+ sizeof(secureinfoSigCheckPatch), 1
+ );
+}
+
void patchCode(u64 progId, u8 *code, u32 size)
{
- load_config(); // Load cakes.dat
+ // FIXME - Config loading breaks loader. WTF is this?
+ // Maybe the memcpy?
+ // load_config();
switch(progId)
{
case 0x000400300000A902LL: // KOR Menu
case 0x000400300000B102LL: // TWN Menu
{
- static const u8 regionFreePattern[] = {
- 0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3
- };
- static const u8 regionFreePatch[] = {
- 0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
- };
-
- //Patch SMDH region checks
- patchMemory(code, size,
- regionFreePattern,
- sizeof(regionFreePattern), -16,
- regionFreePatch,
- sizeof(regionFreePatch), 1
- );
-
+ region_patch(progId, code, size);
break;
}
case 0x0004013000002C02LL: // NIM
{
- static const u8 blockAutoUpdatesPattern[] = {
- 0x25, 0x79, 0x0B, 0x99
- };
- static const u8 blockAutoUpdatesPatch[] = {
- 0xE3, 0xA0
- };
- static const u8 skipEshopUpdateCheckPattern[] = {
- 0x30, 0xB5, 0xF1, 0xB0
- };
- static const u8 skipEshopUpdateCheckPatch[] = {
- 0x00, 0x20, 0x08, 0x60, 0x70, 0x47
- };
-
- //Block silent auto-updates
- patchMemory(code, size,
- blockAutoUpdatesPattern,
- sizeof(blockAutoUpdatesPattern), 0,
- blockAutoUpdatesPatch,
- sizeof(blockAutoUpdatesPatch), 1
- );
-
- //Skip update checks to access the EShop
- patchMemory(code, size,
- skipEshopUpdateCheckPattern,
- sizeof(skipEshopUpdateCheckPattern), 0,
- skipEshopUpdateCheckPatch,
- sizeof(skipEshopUpdateCheckPatch), 1
- );
-
+ disable_nim_updates(progId, code, size);
+ disable_eshop_updates(progId, code, size);
break;
}
case 0x0004013000003202LL: // FRIENDS
{
- static const u8 fpdVerPattern[] = {
- 0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01
- };
-
- static const u8 fpdVerPatch = 0x05;
-
- //Allow online access to work with old friends modules
- patchMemory(code, size,
- fpdVerPattern,
- sizeof(fpdVerPattern), 9,
- &fpdVerPatch,
- sizeof(fpdVerPatch), 1
- );
-
+ fake_friends_version(progId, code, size);
break;
}
case 0x0004001000027000LL: // KOR MSET
case 0x0004001000028000LL: // TWN MSET
{
- static const u16 verPattern[] = u"Ver.";
-
- //Patch Ver. string
- patchMemory(code, size,
- verPattern,
- sizeof(verPattern) - sizeof(u16), 0,
- u".hax",
- sizeof(verPattern) - sizeof(u16), 1
- );
+ settings_string(progId, code, size);
break;
}
-
case 0x0004013000008002LL: // NS
{
- static const u8 stopCartUpdatesPattern[] = {
- 0x0C, 0x18, 0xE1, 0xD8
- };
- static const u8 stopCartUpdatesPatch[] = {
- 0x0B, 0x18, 0x21, 0xC8
- };
-
- //Disable updates from foreign carts (makes carts region-free)
- patchMemory(code, size,
- stopCartUpdatesPattern,
- sizeof(stopCartUpdatesPattern), 0,
- stopCartUpdatesPatch,
- sizeof(stopCartUpdatesPatch), 2
- );
-
- if (!failed_load_config) {
- u32 cpuSetting = 0;
- cpuSetting += config.n3ds_clock ? 0x1 : 0x0;
- cpuSetting += config.n3ds_l2 ? 0x2 : 0x0;
-
- if(cpuSetting)
- {
- static const u8 cfgN3dsCpuPattern[] = {
- 0x00, 0x40, 0xA0, 0xE1, 0x07, 0x00
- };
-
- u32 *cfgN3dsCpuLoc = (u32 *)memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern));
-
- //Patch N3DS CPU Clock and L2 cache setting
- if(cfgN3dsCpuLoc != NULL)
- {
- *(cfgN3dsCpuLoc + 1) = 0xE1A00000;
- *(cfgN3dsCpuLoc + 8) = 0xE3A00000 | cpuSetting;
- }
- }
- }
+ disable_cart_updates(progId, code, size);
+ adjust_cpu_settings(progId, code, size);
break;
}
case 0x0004013000001702LL: // CFG
{
- static const u8 secureinfoSigCheckPattern[] = {
- 0x06, 0x46, 0x10, 0x48, 0xFC
- };
- static const u8 secureinfoSigCheckPatch[] = {
- 0x00, 0x26
- };
-
- //Disable SecureInfo signature check
- patchMemory(code, size,
- secureinfoSigCheckPattern,
- sizeof(secureinfoSigCheckPattern), 0,
- secureinfoSigCheckPatch,
- sizeof(secureinfoSigCheckPatch), 1
- );
-
- if(secureInfoExists())
- {
- static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
- static const u16 secureinfoFilenamePatch[] = u"C";
-
- //Use SecureInfo_C
- patchMemory(code, size,
- secureinfoFilenamePattern,
- sizeof(secureinfoFilenamePattern) - sizeof(u16),
- sizeof(secureinfoFilenamePattern) - sizeof(u16),
- secureinfoFilenamePatch,
- sizeof(secureinfoFilenamePatch) - sizeof(u16), 2
- );
- }
-
+ secureinfo_sigpatch(progId, code, size);
break;
}
- default:
+/* default:
{
- if(!failed_load_config && config.language_emu)
+ if(!failed_load_config && config.options[OPTION_LOADER_LANGEMU])
{
u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;
}
}
}
-
break;
- }
+ } */
}
}
void regenerate_config() {
f_mkdir(PATH_CFW);
+ f_mkdir(PATH_CFW "/lib");
f_mkdir(PATH_FIRMWARES);
f_mkdir(PATH_PATCHES);
- f_mkdir(PATH_LOCEMU);
f_mkdir(PATH_TEMP);
f_mkdir(PATH_KEYS);
f_mkdir(PATH_EXEFS);
extern struct config_file config;
+enum type {
+ boolean_val, // Toggle
+ ranged_val, // N1 - N2, left and right to pick.
+ mask_val // Bitmask allowed values.
+};
+
+struct range_str {
+ int a, b;
+};
+
+struct options_s {
+ int index;
+ char name[64];
+ enum type allowed;
+ uint32_t a, b;
+}__attribute__((packed));
+
#define OPTION_SIGPATCH 0 // Use builtin signature patch.
#define OPTION_FIRMPROT 1 // Protect firmware from writes.
#define OPTION_LOADER 2 // Use builtin loader module replacer.
#define OPTION_NO_CLEAR_BG 9 // Framebuffer is preserved from whatever ran before us.
#define OPTION_READ_ME 10 // Remove Help/Readme from menu.
-#define IGNORE_PATCH_DEPS 11 // Ignore patch UUID dependencies. Not recommended.
-#define IGNORE_BROKEN_SHIT 12 // Allow enabling patches which are marked as 'incompatible'. Chances are there's a reason.
+#define OPTION_LOADER_CPU_L2 11 // Enable L2 cache.
+#define OPTION_LOADER_CPU_800MHZ 12 // Enable 800Mhz mode.
+#define OPTION_LOADER_LANGEMU 13 // Enable 800Mhz mode.
+
+#define IGNORE_PATCH_DEPS 14 // Ignore patch UUID dependencies. Not recommended.
+#define IGNORE_BROKEN_SHIT 15 // Allow enabling patches which are marked as 'incompatible'. Chances are there's a reason.
//#define HEADER_COLOR 12 // Color of header text.
//#define BG_COLOR 13 // Color of background.
// patch.c
#define FCRAM_PATCHBIN_EXEC_LOC (FCRAM_START + FCRAM_SPACING * 4)
+// Throwaway temporary space. Don't expect it to stay sane.
+#define FCRAM_JUNK_LOCATION (FCRAM_START + FCRAM_SPACING * 5)
+
#endif
#include "common.h"
#include "firm/firm.h"
#include "firm/headers.h"
-#define MENU_BOOTME -1
#define MENU_MAIN 1
#define MENU_OPTIONS 2
#define MENU_HELP 5
#define MENU_RESET 6
#define MENU_POWER 7
+#define MENU_BOOTME 8
+
+static struct options_s options[] = {
+ { 0, "Signature Patch", boolean_val, 0, 0 },
+ { 1, "FIRM Protection", boolean_val, 0, 0 },
+ { 2, "SysModule Replacement", boolean_val, 0, 0 },
+ { 3, "Service Replacement", boolean_val, 0, 0 },
+ { 4, "ARM9 Thread", boolean_val, 0, 0 },
+
+ { 5, "Autoboot", boolean_val, 0, 0 },
+ { 6, "Silence w/ Autoboot", boolean_val, 0, 0 },
+ { 7, "Step through with button", boolean_val, 0, 0 },
+
+ { 8, "Don't draw background color", boolean_val, 0, 0 },
+ { 9, "Preserve framebuffer data", boolean_val, 0, 0 },
+
+ { 10, "Hide Help from menu", boolean_val, 0, 0 },
+
+ { 11, "Loader: CPU L2 enable", boolean_val, 0, 0 },
+ { 12, "Loader: CPU 800Mhz mode", boolean_val, 0, 0 },
+ { 13, "Loader: Language Emulation", boolean_val, 0, 0 },
+
+ { 14, "No dependency tracking", boolean_val, 0, 0 },
+ { 15, "Allow unsafe options", boolean_val, 0, 0 },
+ { -1, "", 0, 0, 0},
+};
static int cursor_y = 0;
static int which_menu = 1;
int menu_options() {
set_cursor(TOP_SCREEN, 0, 0);
- const char *list[] = {
- "Signature Patch",
- "FIRM Write Protection",
- "Inject Loader (NYI)",
- "Inject Services",
- "Enable ARM9 Thread",
-
- "Autoboot",
- "Silence debug w/ autoboot",
- "Pause for input on steps",
-
- "Don't draw background color (NYI)",
- "Preserve current framebuffer (NYI)",
- "Hide Readme/Help from menu",
-
- "Ignore dependencies (NYI)",
- "Allow enabling broken (NYI)",
- };
- const int menu_max = 12;
-
header();
- for(int i=0; i < menu_max; i++) {
+ int i = 0;
+ while(options[i].index != -1) { // -1 Sentinel.
if (cursor_y == i)
fprintf(TOP_SCREEN, "\x1b[32m>>\x1b[0m ");
else
fprintf(TOP_SCREEN, " ");
if (need_redraw)
- fprintf(TOP_SCREEN, "[%c] %s\n", (config.options[i] ? 'X' : ' '), list[i]);
+ fprintf(TOP_SCREEN, "[%c] %s\n", (config.options[options[i].index] ? 'X' : ' '), options[i].name);
else {
// Yes, this is weird. printf does a large number of extra things we don't
// want computed at the moment; this is faster.
putc(TOP_SCREEN, '[');
- putc(TOP_SCREEN, (config.options[i] ? 'X' : ' '));
+ putc(TOP_SCREEN, (config.options[options[i].index] ? 'X' : ' '));
putc(TOP_SCREEN, ']');
putc(TOP_SCREEN, '\n');
}
+ ++i;
}
need_redraw = 0;
switch(key) {
case BUTTON_UP:
cursor_y -= 1;
+ if (cursor_y < 0)
+ cursor_y = 0;
break;
case BUTTON_DOWN:
cursor_y += 1;
+ if (options[cursor_y].index == -1)
+ cursor_y -= 1;
break;
case BUTTON_A:
// TODO - Value options
- config.options[cursor_y] = !config.options[cursor_y];
+ config.options[options[cursor_y].index] = !config.options[options[cursor_y].index];
break;
case BUTTON_B:
need_redraw = 1;
break;
}
- // Loop around the cursor.
- if (cursor_y < 0)
- cursor_y = menu_max - 1;
- if (cursor_y > menu_max - 1)
- cursor_y = 0;
-
return 0;
}
case BUTTON_A:
need_redraw = 1;
cursor_y = 0;
- if (ret == menu_max + 2)
+ if (ret == MENU_BOOTME)
return MENU_BOOTME; // Boot meh, damnit!
return ret;
}
menu_reset();
case MENU_POWER:
menu_poweroff();
+ default:
+ fprintf(stderr, "Attempt to enter wrong menu!\n");
+ to_menu = MENU_MAIN;
}
if (to_menu != 0)
--- /dev/null
+#include <stdint.h>
+#include "../std/unused.h"
+#include "../std/memory.h"
+#include "../firm/firm.h"
+#include "../config.h"
+#include "../common.h"
+
+int patch_test() {
+ fprintf(stderr, "Testing, testing, 1, 2, 3, 4..\n");
+
+ return 0;
+}
+
--- /dev/null
+#include <stdint.h>
+#include "../std/unused.h"
+#include "../std/memory.h"
+#include "../firm/firm.h"
+#include "../firm/fcram.h"
+#include "../config.h"
+#include "../common.h"
+
+int patch_modules() {
+ // TODO - load module cxi here
+ FILE* f = fopen(PATH_MODULES "/loader.cxi", "r");
+ if (!f) {
+ fprintf(stderr, "Module: loader.cxi not found on FS\n");
+ return 2;
+ }
+
+ uint32_t size = fsize(f);
+ fread((uint8_t*)FCRAM_JUNK_LOCATION, 1, size, f);
+ fclose(f);
+
+ // Look for the section that holds all the sysmodules
+ firm_section_h *sysmodule_section = NULL;
+ for (firm_section_h *section = firm_loc->section; section < firm_loc->section + 4; section++) {
+ if (section->address == 0x1FF00000 && section->type == FIRM_TYPE_ARM11) {
+ sysmodule_section = section;
+ break;
+ }
+ }
+
+ if (!sysmodule_section) {
+ fprintf(stderr, "Module: sysmodule section not found\n");
+ return 1;
+ }
+
+ ncch_h *module = (ncch_h*)FCRAM_JUNK_LOCATION;
+ ncch_h *sysmodule = (ncch_h *)((uint32_t)firm_loc + sysmodule_section->offset);
+
+ // Check if we want to replace an existing sysmodule
+ while (sysmodule->magic == NCCH_MAGIC) {
+ if (memcmp(sysmodule->programID, module->programID, 8) == 0) {
+ // Expand firmware module size if needed to accomodate replacement.
+ if (module->contentSize > sysmodule->contentSize) {
+ // Location to shuffle to.
+ uint32_t need_units = (module->contentSize - sysmodule->contentSize);
+ uint8_t* move_to = ((uint8_t*)sysmodule + (module->contentSize + need_units) * 0x200);
+ uint8_t* move_from = ((uint8_t*)sysmodule + module->contentSize * 0x200);
+
+ uint32_t copy_size = 0x10000; // FIXME - Add a safe way to properly calculate the half of NCCH we need to copy. This is okay for now.
+
+ memmove(move_to, move_from, copy_size);
+ // TODO - This is hackish and possibly incorrect. It needs testing.
+ }
+
+ // Move the remaining modules closer
+ if (module->contentSize < sysmodule->contentSize) {
+ int remaining_size =
+ sysmodule_section->size -
+ (((uint32_t)sysmodule + sysmodule->contentSize * 0x200) -
+ ((uint32_t)firm_loc + sysmodule_section->offset));
+ // Sysmodule section size - (End location of this sysmodule - Sysmodule section) =>
+ memmove((uint8_t*)sysmodule + module->contentSize * 0x200, (uint8_t*)sysmodule + sysmodule->contentSize * 0x200, remaining_size);
+ // Move end of section to be adjacent
+ }
+
+ // Copy the module into the firm
+ memcpy(sysmodule, module, module->contentSize * 0x200);
+ break;
+ }
+ sysmodule = (ncch_h *)((uintptr_t)sysmodule + sysmodule->contentSize * 0x200);
+ }
+
+ fprintf(stderr, "Module: injected modules.\n");
+
+ return 0;
+}
+
#define __PATCH_FORMAT_H
// The following are titleids which are handled specially for one reason or another.
+// We use titleIDs to be generic; it ensures that patches can share the same format
+// regardless of whether they're intended for loader or not. Simple logistics.
#define NATIVE_FIRM_TITLEID 0x0004013800000002llu // NATIVE_FIRM
#define NATIVE_FIRM_N3DS_TITLEID 0x0004013820000002llu // NATIVE_FIRM, n3ds
#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
+// You can redefine this in the Makefile, if you'd like.
+// Recommended names for being silly:
+// Windows
+// system
+#ifndef PATH_CFW
+ #define PATH_CFW "/corbenik" // CFW root directory.
+#endif
+
+#define PATH_CONFIG_DIR PATH_CFW "/etc" // Config file directory.
+#define PATH_CONFIG PATH_CONFIG_DIR "/main.conf" // Config file.
+#define PATH_LOCEMU PATH_CONFIG_DIR "/locale.conf" // Locale emulation config
+#define PATH_CPU_CFG PATH_CONFIG_DIR "/cpu.conf" // CPU settings config
-#define PATH_FIRMWARES PATH_CFW "/firm" // Firmware folder.
#define PATH_PATCHES PATH_CFW "/bin" // Patch binary 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_FIRMWARES PATH_CFW "/lib/firmware" // Firmware folder.
+#define PATH_MODULES PATH_CFW "/lib/module" // Sysmodule location
+#define PATH_SERVICES PATH_CFW "/lib/svc" // Service code location.
+#define PATH_TEMP PATH_CFW "/tmp" // Files that are transient (user can delete them and they will be regenerated)
+#define PATH_KEYS PATH_CFW "/share/keys" // Keyfiles will be loaded from this dir, and additionally the root if not found.
+#define PATH_EXEFS PATH_CFW "/lib/exe" // 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_NATIVE_CETK PATH_FIRMWARES "/native.cetk"
+
+#define PATH_TWL_CETK PATH_FIRMWARES "/twl.cetk"
-#define PATH_TWL_CETK PATH_KEYS "/twl.cetk"
-#define PATH_TWL_FIRMKEY PATH_KEYS "/twl.key"
+#define PATH_AGB_CETK PATH_FIRMWARES "/agb.cetk"
-#define PATH_AGB_CETK PATH_KEYS "/agb.cetk"
-#define PATH_AGB_FIRMKEY PATH_KEYS "/agb.key"
+#define PATH_NATIVE_FIRMKEY PATH_KEYS "/native.key"
+#define PATH_TWL_FIRMKEY PATH_KEYS "/twl.key"
+#define PATH_AGB_FIRMKEY PATH_KEYS "/agb.key"
-#define PATH_SLOT0X11KEY96 PATH_KEYS "/11.key"
+// These are used with O3DS units. Keep in mind I have no way to test this.
+#define PATH_NATIVE_FIRMKEY_2 PATH_KEYS "/native_old.key"
+#define PATH_TWL_FIRMKEY_2 PATH_KEYS "/twl_old.key"
+#define PATH_AGB_FIRMKEY_2 PATH_KEYS "/agb_old.key"
-#define PATH_ALT_SLOT0X11KEY96 "/slot0x11key96.bin" // Hey, your perrogative, buddy. I like cleaned up paths.
+#define PATH_SLOT0X11KEY96 PATH_KEYS "/11.key"
-#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
+#define PATH_ALT_SLOT0X11KEY96 "/slot0x11key96.bin" // Hey, your perrogative, buddy. I like cleaned up paths.
// Structure of a patch file.
struct system_patch {
struct patch_opcode {
} __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
extern int patch_signatures();
extern int patch_firmprot();
extern int patch_services();
+extern int patch_modules();
// A portion of this file is inherited from Luma3DS.
/*u32 getLoader(u8 *pos, u32 *loaderSize) {
// Replace loader?
if (config.options[OPTION_LOADER]) {
- // Yes.
-
+ if(patch_modules()) {
+ abort("Fatal. Service patch has failed.");
+ }
// This requires OPTION_SIGPATCH.
}
- // Replace loader?
+ wait();
+
+ // Inject services?
if (config.options[OPTION_SERVICES]) {
if(patch_services()) {
abort("Fatal. Service patch has failed.");
// FIXME - NYI
}
+ wait();
+
return 0;
}