From 7512aaaf3133b012c6aaa93e708a214442288d32 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 12 Aug 2022 13:50:32 -0500 Subject: [PATCH 01/10] add scan_all_buttons_held function - Condense 2 instances of scanning and assigning `all_buttons_held` into a single function. --- source/main.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/source/main.c b/source/main.c index 53e782f..7ca1b16 100644 --- a/source/main.c +++ b/source/main.c @@ -20,7 +20,6 @@ u8 *dol = NULL; int dol_argc = 0; #define MAX_NUM_ARGV 1024 char *dol_argv[MAX_NUM_ARGV]; -u16 all_buttons_held; char *default_path = "/ipl.dol"; struct shortcut { @@ -38,6 +37,15 @@ struct shortcut { }; int num_shortcuts = sizeof(shortcuts) / sizeof(shortcuts[0]); +u16 all_buttons_held; +void +scan_all_buttons_held() { + PAD_ScanPads(); + all_buttons_held = + (PAD_ButtonsHeld(PAD_CHAN0) | PAD_ButtonsHeld(PAD_CHAN1) + | PAD_ButtonsHeld(PAD_CHAN2) | PAD_ButtonsHeld(PAD_CHAN3)); +} + void dol_alloc(int size) { int mram_size = (SYS_GetArenaHi() - SYS_GetArenaLo()); @@ -297,10 +305,7 @@ delay_exit() { while (all_buttons_held & PAD_BUTTON_DOWN || SYS_ResetButtonDown()) { VIDEO_WaitVSync(); - PAD_ScanPads(); - all_buttons_held = - (PAD_ButtonsHeld(PAD_CHAN0) | PAD_ButtonsHeld(PAD_CHAN1) - | PAD_ButtonsHeld(PAD_CHAN2) | PAD_ButtonsHeld(PAD_CHAN3)); + scan_all_buttons_held(); } } @@ -347,11 +352,7 @@ main() { EXI_Deselect(EXI_CHANNEL_0); EXI_Unlock(EXI_CHANNEL_0); - PAD_ScanPads(); - - all_buttons_held = - (PAD_ButtonsHeld(PAD_CHAN0) | PAD_ButtonsHeld(PAD_CHAN1) - | PAD_ButtonsHeld(PAD_CHAN2) | PAD_ButtonsHeld(PAD_CHAN3)); + scan_all_buttons_held(); if (all_buttons_held & PAD_BUTTON_LEFT || SYS_ResetButtonDown()) { // Since we've disabled the Qoob, we wil reboot to the Nintendo IPL From 7790c7404206e707aeeecc9e274c950f18a56b10 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 12 Aug 2022 14:27:02 -0500 Subject: [PATCH 02/10] move shortcuts to file - Move shortcut definitions to its own file. --- meson.build | 1 + source/main.c | 17 ++--------------- source/shortcut.c | 13 +++++++++++++ source/shortcut.h | 14 ++++++++++++++ 4 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 source/shortcut.c create mode 100644 source/shortcut.h diff --git a/meson.build b/meson.build index 3a12cab..da6447a 100644 --- a/meson.build +++ b/meson.build @@ -53,6 +53,7 @@ gekkoboot = executable( 'gekkoboot', 'source/main.c', 'source/utils.c', + 'source/shortcut.c', 'source/fatfs/ff.c', 'source/fatfs/ffsystem.c', 'source/fatfs/ffunicode.c', diff --git a/source/main.c b/source/main.c index 7ca1b16..bc0ec89 100644 --- a/source/main.c +++ b/source/main.c @@ -1,5 +1,6 @@ #include "fatfs/ff.h" #include "ffshim.h" +#include "shortcut.h" #include "utils.h" #include "version.h" #include @@ -22,20 +23,6 @@ int dol_argc = 0; char *dol_argv[MAX_NUM_ARGV]; char *default_path = "/ipl.dol"; -struct shortcut { - u16 pad_buttons; - char *path; -} shortcuts[] = { - {PAD_BUTTON_A, "/a.dol"}, - {PAD_BUTTON_B, "/b.dol"}, - {PAD_BUTTON_X, "/x.dol"}, - {PAD_BUTTON_Y, "/y.dol"}, - {PAD_TRIGGER_Z, "/z.dol"}, - {PAD_BUTTON_START, "/start.dol"}, - // NOTE: Shouldn't use L, R or Joysticks as analog inputs are calibrated on boot. - // Should also avoid D-Pad as it is used for special functionality. -}; -int num_shortcuts = sizeof(shortcuts) / sizeof(shortcuts[0]); u16 all_buttons_held; void @@ -364,7 +351,7 @@ main() { char *paths[2]; int num_paths = 0; - for (int i = 0; i < num_shortcuts; i++) { + for (int i = 0; i < NUM_SHORTCUTS; i++) { if (all_buttons_held & shortcuts[i].pad_buttons) { paths[num_paths++] = shortcuts[i].path; break; diff --git a/source/shortcut.c b/source/shortcut.c new file mode 100644 index 0000000..d3f206e --- /dev/null +++ b/source/shortcut.c @@ -0,0 +1,13 @@ +#include "shortcut.h" +#include + +SHORTCUT shortcuts[NUM_SHORTCUTS] = { + {PAD_BUTTON_A, "/a.dol"}, + {PAD_BUTTON_B, "/b.dol"}, + {PAD_BUTTON_X, "/x.dol"}, + {PAD_BUTTON_Y, "/y.dol"}, + {PAD_TRIGGER_Z, "/z.dol"}, + {PAD_BUTTON_START, "/start.dol"}, + // NOTE: Shouldn't use L, R or Joysticks as analog inputs are calibrated on boot. + // Should also avoid D-Pad as it is used for special functionality. +}; diff --git a/source/shortcut.h b/source/shortcut.h new file mode 100644 index 0000000..fb26bf6 --- /dev/null +++ b/source/shortcut.h @@ -0,0 +1,14 @@ +#ifndef INC_SHORTCUT_H +#define INC_SHORTCUT_H +#include + +#define NUM_SHORTCUTS 6 + +typedef struct { + u16 pad_buttons; + char *path; +} SHORTCUT; + +extern SHORTCUT shortcuts[NUM_SHORTCUTS]; + +#endif From fc572ad0ace098983c253e5cdc0cb7f75100b623 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 12 Aug 2022 16:39:30 -0500 Subject: [PATCH 03/10] use shortcut for default - Add a special shortcut definition for default `ipl.dol`. - This prepares for future in which shortcuts are referenced rather than just paths and prevents requiring explicit handling of the special no-shortcut/default case. --- source/main.c | 6 ++---- source/shortcut.c | 1 + source/shortcut.h | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/source/main.c b/source/main.c index bc0ec89..11ca83a 100644 --- a/source/main.c +++ b/source/main.c @@ -22,8 +22,6 @@ int dol_argc = 0; #define MAX_NUM_ARGV 1024 char *dol_argv[MAX_NUM_ARGV]; -char *default_path = "/ipl.dol"; - u16 all_buttons_held; void scan_all_buttons_held() { @@ -351,14 +349,14 @@ main() { char *paths[2]; int num_paths = 0; - for (int i = 0; i < NUM_SHORTCUTS; i++) { + for (int i = 1; i < NUM_SHORTCUTS; i++) { if (all_buttons_held & shortcuts[i].pad_buttons) { paths[num_paths++] = shortcuts[i].path; break; } } - paths[num_paths++] = default_path; + paths[num_paths++] = shortcuts[0].path; if (load_usb('B')) { goto load; diff --git a/source/shortcut.c b/source/shortcut.c index d3f206e..28803e8 100644 --- a/source/shortcut.c +++ b/source/shortcut.c @@ -2,6 +2,7 @@ #include SHORTCUT shortcuts[NUM_SHORTCUTS] = { + {0, "/ipl.dol"}, {PAD_BUTTON_A, "/a.dol"}, {PAD_BUTTON_B, "/b.dol"}, {PAD_BUTTON_X, "/x.dol"}, diff --git a/source/shortcut.h b/source/shortcut.h index fb26bf6..57fb752 100644 --- a/source/shortcut.h +++ b/source/shortcut.h @@ -2,7 +2,7 @@ #define INC_SHORTCUT_H #include -#define NUM_SHORTCUTS 6 +#define NUM_SHORTCUTS 7 typedef struct { u16 pad_buttons; From 1634ea883c0d2fc954150bd97161f11ee7b4ca7e Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 7 Sep 2022 22:30:11 -0500 Subject: [PATCH 04/10] use BOOT_PAYLOAD struct - Defines the `BOOT_PAYLOAD` struct for containerizing boot data (`dol` and `dol_argc`). - Removes boot data from global scope. --- source/main.c | 82 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/source/main.c b/source/main.c index 11ca83a..4308099 100644 --- a/source/main.c +++ b/source/main.c @@ -17,10 +17,13 @@ #define VERBOSE_LOGGING 0 -u8 *dol = NULL; -int dol_argc = 0; #define MAX_NUM_ARGV 1024 -char *dol_argv[MAX_NUM_ARGV]; + +typedef struct { + u8 *dol; + int dol_argc; + char *dol_argv[MAX_NUM_ARGV]; +} BOOT_PAYLOAD; u16 all_buttons_held; void @@ -32,7 +35,7 @@ scan_all_buttons_held() { } void -dol_alloc(int size) { +dol_alloc(u8 **_dol, int size) { int mram_size = (SYS_GetArenaHi() - SYS_GetArenaLo()); kprintf("Memory available: %iB\n", mram_size); @@ -43,15 +46,17 @@ dol_alloc(int size) { return; } - dol = (u8 *) memalign(32, size); + u8 *dol = (u8 *) memalign(32, size); if (!dol) { kprintf("Couldn't allocate memory\n"); } + + *_dol = dol; } void -load_parse_cli(char *path) { +load_parse_cli(char **_dol_argv, int *_dol_argc, char *path) { int path_length = strlen(path); path[path_length - 3] = 'c'; path[path_length - 2] = 'l'; @@ -95,6 +100,9 @@ load_parse_cli(char *path) { // Parse CLI file // https://github.com/emukidid/swiss-gc/blob/a0fa06d81360ad6d173acd42e4dd5495e268de42/cube/swiss/source/swiss.c#L1236 + char **dol_argv = _dol_argv; + int dol_argc = 0; + dol_argv[dol_argc] = path; dol_argc++; @@ -125,10 +133,18 @@ load_parse_cli(char *path) { kprintf("arg%i: %s\n", i, dol_argv[i]); } #endif + + *_dol_argc = dol_argc; } int -load_fat(const char *slot_name, const DISC_INTERFACE *iface_, char **paths, int num_paths) { +load_fat( + BOOT_PAYLOAD *payload, + const char *slot_name, + const DISC_INTERFACE *iface_, + char **paths, + int num_paths +) { int res = 0; kprintf("Trying %s\n", slot_name); @@ -156,16 +172,16 @@ load_fat(const char *slot_name, const DISC_INTERFACE *iface_, char **paths, int } size_t size = f_size(&file); - dol_alloc(size); - if (!dol) { + dol_alloc(&payload->dol, size); + if (!payload->dol) { continue; } UINT _; - f_read(&file, dol, size, &_); + f_read(&file, payload->dol, size, &_); f_close(&file); // Attempt to load and parse CLI file - load_parse_cli(path); + load_parse_cli(payload->dol_argv, &payload->dol_argc, path); res = 1; break; @@ -197,7 +213,7 @@ convert_int(unsigned int in) { #define GC_OK 0x89 int -load_usb(char slot) { +load_usb(BOOT_PAYLOAD *payload, char slot) { kprintf("Trying USB Gecko in slot %c\n", slot); int channel, res = 1; @@ -254,10 +270,10 @@ load_usb(char slot) { usb_recvbuffer_safe(channel, &size, 4); size = convert_int(size); - dol_alloc(size); - unsigned char *pointer = dol; + dol_alloc(&payload->dol, size); + unsigned char *pointer = payload->dol; - if (!dol) { + if (!payload->dol) { res = 0; goto end; } @@ -358,28 +374,34 @@ main() { paths[num_paths++] = shortcuts[0].path; - if (load_usb('B')) { + // Init payload. + BOOT_PAYLOAD payload; + payload.dol = NULL; + payload.dol_argc = 0; + + // Attempt to load from each device. + if (load_usb(&payload, 'B')) { goto load; } - if (load_fat("sdb", &__io_gcsdb, paths, num_paths)) { + if (load_fat(&payload, "sdb", &__io_gcsdb, paths, num_paths)) { goto load; } - if (load_usb('A')) { + if (load_usb(&payload, 'A')) { goto load; } - if (load_fat("sda", &__io_gcsda, paths, num_paths)) { + if (load_fat(&payload, "sda", &__io_gcsda, paths, num_paths)) { goto load; } - if (load_fat("sd2", &__io_gcsd2, paths, num_paths)) { + if (load_fat(&payload, "sd2", &__io_gcsd2, paths, num_paths)) { goto load; } load: - if (!dol) { + if (!payload.dol) { kprintf("No DOL found! Halting."); while (true) { VIDEO_WaitVSync(); @@ -391,13 +413,13 @@ main() { dolargs.length = 0; // https://github.com/emukidid/swiss-gc/blob/f5319aab248287c847cb9468325ebcf54c993fb1/cube/swiss/source/aram/sidestep.c#L350 - if (dol_argc) { + if (payload.dol_argc) { dolargs.argvMagic = ARGV_MAGIC; - dolargs.argc = dol_argc; + dolargs.argc = payload.dol_argc; dolargs.length = 1; - for (int i = 0; i < dol_argc; i++) { - size_t arg_length = strlen(dol_argv[i]) + 1; + for (int i = 0; i < payload.dol_argc; i++) { + size_t arg_length = strlen(payload.dol_argv[i]) + 1; dolargs.length += arg_length; } @@ -409,9 +431,11 @@ main() { dolargs.length = 0; } else { unsigned int position = 0; - for (int i = 0; i < dol_argc; i++) { - size_t arg_length = strlen(dol_argv[i]) + 1; - memcpy(dolargs.commandLine + position, dol_argv[i], arg_length); + for (int i = 0; i < payload.dol_argc; i++) { + size_t arg_length = strlen(payload.dol_argv[i]) + 1; + memcpy(dolargs.commandLine + position, + payload.dol_argv[i], + arg_length); position += arg_length; } dolargs.commandLine[dolargs.length - 1] = '\0'; @@ -426,7 +450,7 @@ main() { SYS_ResetSystem(SYS_SHUTDOWN, 0, FALSE); SYS_SwitchFiber( - (intptr_t) dol, + (intptr_t) payload.dol, 0, (intptr_t) dolargs.commandLine, dolargs.length, From 501009e3916b05f48dd2247b845e4758a4b25620 Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 7 Sep 2022 23:10:58 -0500 Subject: [PATCH 05/10] split reading and parsing of files - Splits `load_parse_cli` into `read_cli_file` and `parse_cli_file`. - Moves DOL file reading to `read_dol_file`. --- source/main.c | 62 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/source/main.c b/source/main.c index 4308099..9ebfb27 100644 --- a/source/main.c +++ b/source/main.c @@ -56,7 +56,35 @@ dol_alloc(u8 **_dol, int size) { } void -load_parse_cli(char **_dol_argv, int *_dol_argc, char *path) { +read_dol_file(u8 **_dol, char *path) { + *_dol = NULL; + + kprintf("Reading %s\n", path); + FIL file; + FRESULT open_result = f_open(&file, path, FA_READ); + if (open_result != FR_OK) { + kprintf("Failed to open file: %s\n", get_fresult_message(open_result)); + return; + } + + size_t size = f_size(&file); + u8 *dol; + dol_alloc(&dol, size); + if (!dol) { + return; + } + UINT _; + f_read(&file, dol, size, &_); + f_close(&file); + + *_dol = dol; +} + +void +read_cli_file(char **_cli, int *_size, char *path) { + *_cli = NULL; + *_size = 0; + int path_length = strlen(path); path[path_length - 3] = 'c'; path[path_length - 2] = 'l'; @@ -98,14 +126,17 @@ load_parse_cli(char **_dol_argv, int *_dol_argc, char *path) { size++; } + *_cli = cli; + *_size = size; +} + +void +parse_cli_file(char **_dol_argv, int *_dol_argc, char *cli, int size) { // Parse CLI file // https://github.com/emukidid/swiss-gc/blob/a0fa06d81360ad6d173acd42e4dd5495e268de42/cube/swiss/source/swiss.c#L1236 char **dol_argv = _dol_argv; int dol_argc = 0; - dol_argv[dol_argc] = path; - dol_argc++; - // First argument is at the beginning of the file if (cli[0] != '\r' && cli[0] != '\n') { dol_argv[dol_argc] = cli; @@ -163,25 +194,20 @@ load_fat( for (int i = 0; i < num_paths; ++i) { char *path = paths[i]; - kprintf("Reading %s\n", path); - FIL file; - FRESULT open_result = f_open(&file, path, FA_READ); - if (open_result != FR_OK) { - kprintf("Failed to open file: %s\n", get_fresult_message(open_result)); - continue; - } - - size_t size = f_size(&file); - dol_alloc(&payload->dol, size); + read_dol_file(&payload->dol, path); if (!payload->dol) { continue; } - UINT _; - f_read(&file, payload->dol, size, &_); - f_close(&file); // Attempt to load and parse CLI file - load_parse_cli(payload->dol_argv, &payload->dol_argc, path); + char *cli; + int cli_size; + read_cli_file(&cli, &cli_size, path); + + // Parse CLI file. + if (cli) { + parse_cli_file(payload->dol_argv, &payload->dol_argc, cli, cli_size); + } res = 1; break; From 3e3746187af5b3593a215fd6a1a3b98ff240f1e5 Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 7 Sep 2022 23:21:02 -0500 Subject: [PATCH 06/10] pass shortcut index instead of paths array - Reference shortcuts rather just the shortcut's paths. - Prepares for future in which shortcuts define more than just a path. --- meson.build | 1 + source/main.c | 51 ++++++++++++++++++++++++--------------------------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/meson.build b/meson.build index da6447a..64c979d 100644 --- a/meson.build +++ b/meson.build @@ -54,6 +54,7 @@ gekkoboot = executable( 'source/main.c', 'source/utils.c', 'source/shortcut.c', + 'source/cli_args.c', 'source/fatfs/ff.c', 'source/fatfs/ffsystem.c', 'source/fatfs/ffunicode.c', diff --git a/source/main.c b/source/main.c index 9ebfb27..d7bff1b 100644 --- a/source/main.c +++ b/source/main.c @@ -173,8 +173,7 @@ load_fat( BOOT_PAYLOAD *payload, const char *slot_name, const DISC_INTERFACE *iface_, - char **paths, - int num_paths + int shortcut_index ) { int res = 0; @@ -192,27 +191,28 @@ load_fat( f_getlabel(slot_name, name, NULL); kprintf("Mounted %s as %s\n", name, slot_name); - for (int i = 0; i < num_paths; ++i) { - char *path = paths[i]; + char *path = shortcuts[shortcut_index].path; + read_dol_file(&payload->dol, path); + if (!payload->dol && shortcut_index != 0) { + shortcut_index = 0; + path = shortcuts[shortcut_index].path; read_dol_file(&payload->dol, path); - if (!payload->dol) { - continue; - } + } + if (!payload->dol) { + goto unmount; + } - // Attempt to load and parse CLI file - char *cli; - int cli_size; - read_cli_file(&cli, &cli_size, path); + // Attempt to load and parse CLI file + char *cli; + int cli_size; + read_cli_file(&cli, &cli_size, path); - // Parse CLI file. - if (cli) { - parse_cli_file(payload->dol_argv, &payload->dol_argc, cli, cli_size); - } - - res = 1; - break; + // Parse CLI file. + if (cli) { + parse_cli_file(payload->dol_argv, &payload->dol_argc, cli, cli_size); } +unmount: kprintf("Unmounting %s\n", slot_name); iface->shutdown(); iface = NULL; @@ -388,18 +388,15 @@ main() { return 0; } - char *paths[2]; - int num_paths = 0; - + // Detect selected shortcut. + int shortcut_index = 0; for (int i = 1; i < NUM_SHORTCUTS; i++) { if (all_buttons_held & shortcuts[i].pad_buttons) { - paths[num_paths++] = shortcuts[i].path; + shortcut_index = i; break; } } - paths[num_paths++] = shortcuts[0].path; - // Init payload. BOOT_PAYLOAD payload; payload.dol = NULL; @@ -410,7 +407,7 @@ main() { goto load; } - if (load_fat(&payload, "sdb", &__io_gcsdb, paths, num_paths)) { + if (load_fat(&payload, "sdb", &__io_gcsdb, shortcut_index)) { goto load; } @@ -418,11 +415,11 @@ main() { goto load; } - if (load_fat(&payload, "sda", &__io_gcsda, paths, num_paths)) { + if (load_fat(&payload, "sda", &__io_gcsda, shortcut_index)) { goto load; } - if (load_fat(&payload, "sd2", &__io_gcsd2, paths, num_paths)) { + if (load_fat(&payload, "sd2", &__io_gcsd2, shortcut_index)) { goto load; } From d990442fb1cf77800ba953813bf75e781284ba1c Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 7 Sep 2022 23:30:09 -0500 Subject: [PATCH 07/10] split load_shortcut_files function - Moves finding and reading of shortcut DOL and CLI files to `load_shortcut_files`. --- source/main.c | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/source/main.c b/source/main.c index d7bff1b..34067b4 100644 --- a/source/main.c +++ b/source/main.c @@ -168,6 +168,32 @@ parse_cli_file(char **_dol_argv, int *_dol_argc, char *cli, int size) { *_dol_argc = dol_argc; } +int +load_shortcut_files(BOOT_PAYLOAD *payload, int shortcut_index) { + char *path = shortcuts[shortcut_index].path; + read_dol_file(&payload->dol, path); + if (!payload->dol && shortcut_index != 0) { + shortcut_index = 0; + path = shortcuts[shortcut_index].path; + read_dol_file(&payload->dol, path); + } + if (!payload->dol) { + return 0; + } + + // Attempt to load and parse CLI file + char *cli; + int cli_size; + read_cli_file(&cli, &cli_size, path); + + // Parse CLI file. + if (cli) { + parse_cli_file(payload->dol_argv, &payload->dol_argc, cli, cli_size); + } + + return 1; +} + int load_fat( BOOT_PAYLOAD *payload, @@ -191,28 +217,8 @@ load_fat( f_getlabel(slot_name, name, NULL); kprintf("Mounted %s as %s\n", name, slot_name); - char *path = shortcuts[shortcut_index].path; - read_dol_file(&payload->dol, path); - if (!payload->dol && shortcut_index != 0) { - shortcut_index = 0; - path = shortcuts[shortcut_index].path; - read_dol_file(&payload->dol, path); - } - if (!payload->dol) { - goto unmount; - } - - // Attempt to load and parse CLI file - char *cli; - int cli_size; - read_cli_file(&cli, &cli_size, path); - - // Parse CLI file. - if (cli) { - parse_cli_file(payload->dol_argv, &payload->dol_argc, cli, cli_size); - } + res = load_shortcut_files(payload, shortcut_index); -unmount: kprintf("Unmounting %s\n", slot_name); iface->shutdown(); iface = NULL; From dfc3fd6b85a8211abbe3388beb4e42ba8c2c647f Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 7 Sep 2022 23:55:39 -0500 Subject: [PATCH 08/10] move file handeling to filesystem - Moves all filesystem reading and handling code to its own `filesystem.c` file. - `FS_RESULT` enum extends and replaces `FRESULT` enum. - Colapses `utils.c` into `filesystem.c`. - `dol_alloc` function removed. Filesystem and USB geko routines handle malloc independently. - Dropped `_size` param from `read_cli_file` in favor of `strenlen` --- meson.build | 2 +- source/filesystem.c | 115 +++++++++++++++++++++++++++++++++++++++++ source/filesystem.h | 45 ++++++++++++++++ source/main.c | 121 ++++++++++---------------------------------- source/utils.c | 36 ------------- source/utils.h | 9 ---- 6 files changed, 187 insertions(+), 141 deletions(-) create mode 100644 source/filesystem.c create mode 100644 source/filesystem.h delete mode 100644 source/utils.c delete mode 100644 source/utils.h diff --git a/meson.build b/meson.build index 64c979d..e9944b4 100644 --- a/meson.build +++ b/meson.build @@ -52,7 +52,7 @@ font = custom_target( gekkoboot = executable( 'gekkoboot', 'source/main.c', - 'source/utils.c', + 'source/filesystem.c', 'source/shortcut.c', 'source/cli_args.c', 'source/fatfs/ff.c', diff --git a/source/filesystem.c b/source/filesystem.c new file mode 100644 index 0000000..afb69ee --- /dev/null +++ b/source/filesystem.c @@ -0,0 +1,115 @@ +#include "filesystem.h" +#include "fatfs/ff.h" +#include "ffshim.h" +#include +#include + +FATFS fs; +FS_RESULT +fs_mount(const DISC_INTERFACE *iface_) { + iface = iface_; + return f_mount(&fs, "", 1); +} + +void +fs_unmount() { + f_unmount(""); + iface->shutdown(); + iface = NULL; +} + +void +fs_get_volume_label(const char *path, char *label) { + FRESULT res = f_getlabel(path, label, NULL); + if (res != FR_OK) { + *label = '\0'; + } +} + +FS_RESULT +_fs_read_file(void **contents_, const char *path, int is_string) { + FIL file; + FRESULT result = f_open(&file, path, FA_READ); + if (result != FR_OK) { + kprintf("Failed to open file: %s\n", get_fs_result_message(result)); + return result; + } + + size_t size = f_size(&file); + if (size <= 0) { + kprintf("File is empty\n"); + return FS_FILE_EMPTY; + } + kprintf("File size: %iB\n", size); + + // Malloc an extra byte if we are reading as a string incase we need to add NUL character. + void *contents = malloc(size + (is_string ? 1 : 0)); + if (!contents) { + kprintf("Couldn't allocate memory for file\n"); + return FS_NOT_ENOUGH_MEMORY; + } + + kprintf("Reading file...\n"); + UINT _; + result = f_read(&file, contents, size, &_); + if (result != FR_OK) { + kprintf("Failed to read file: %s\n", get_fs_result_message(result)); + return result; + } + + f_close(&file); + + // Ensure files read as strings end with NUL character. + if (is_string) { + // This is safe because we malloc an extra byte above if reading as string. + ((char *) contents)[size] = '\0'; + } + + *contents_ = contents; + return FS_OK; +} + +FS_RESULT +fs_read_file(void **contents, const char *path) { + return _fs_read_file(contents, path, false); +} +FS_RESULT +fs_read_file_string(const char **contents, const char *path) { + return _fs_read_file((void **) contents, path, true); +} + +#define NUM_FS_RESULT_MSGS 22 +const char *fs_result_msgs[NUM_FS_RESULT_MSGS] = { + /*FS_OK ( 0)*/ "Succeeded", + /*FS_DISK_ERR ( 1)*/ "A hard error occurred in the low level disk I/O layer", + /*FS_INT_ERR ( 2)*/ "Assertion failed", + /*FS_NOT_READY ( 3)*/ "Device not ready", + /*FS_NO_FILE ( 4)*/ "Could not find the file", + /*FS_NO_PATH ( 5)*/ "Could not find the path", + /*FS_INVALID_NAME ( 6)*/ "The path name format is invalid", + /*FS_DENIED ( 7)*/ "Access denied due to prohibited access or directory full", + /*FS_EXIST ( 8)*/ "Access denied due to prohibited access", + /*FS_INVALID_OBJECT ( 9)*/ "The file/directory object is invalid", + /*FS_WRITE_PROTECTED (10)*/ "The physical drive is write protected", + /*FS_INVALID_DRIVE (11)*/ "The logical drive number is invalid", + /*FS_NOT_ENABLED (12)*/ "The volume has no work area", + /*FS_NO_FILESYSTEM (13)*/ "There is no valid FAT volume", + /*FS_MKFS_ABORTED (14)*/ "The f_mkfs() aborted due to any problem", + /*FS_TIMEOUT (15)*/ + "Could not get a grant to access the volume within defined period", + /*FS_LOCKED (16)*/ + "The operation is rejected according to the file sharing policy", + /*FS_NOT_ENOUGH_CORE (17)*/ "LFN working buffer could not be allocated", + /*FS_TOO_MANY_OPEN_FILES (18)*/ "Number of open files > FF_FS_LOCK", + /*FS_INVALID_PARAMETER (19)*/ "Given parameter is invalid", + /*FS_FILE_EMPTY (20)*/ "File is empty", + /*FS_NOT_ENOUGH_MEMORY (21)*/ "Not enough memory", +}; + +const char * +get_fs_result_message(FS_RESULT result) { + if (result < 0 || result >= NUM_FS_RESULT_MSGS) { + return "Unknown"; + } + return fs_result_msgs[result]; +} diff --git a/source/filesystem.h b/source/filesystem.h new file mode 100644 index 0000000..4ae983e --- /dev/null +++ b/source/filesystem.h @@ -0,0 +1,45 @@ +#ifndef INC_FILESYSTEM_H +#define INC_FILESYSTEM_H +#include + +// See ./fatfs/ff.h:276 +typedef enum { + FS_OK = 0, /* ( 0) Succeeded */ + FS_DISK_ERR, /* ( 1) A hard error occurred in the low level disk I/O layer */ + FS_INT_ERR, /* ( 2) Assertion failed */ + FS_NOT_READY, /* ( 3) The physical drive cannot work */ + FS_NO_FILE, /* ( 4) Could not find the file */ + FS_NO_PATH, /* ( 5) Could not find the path */ + FS_INVALID_NAME, /* ( 6) The path name format is invalid */ + FS_DENIED, /* ( 7) Access denied due to prohibited access or directory full */ + FS_EXIST, /* ( 8) Access denied due to prohibited access */ + FS_INVALID_OBJECT, /* ( 9) The file/directory object is invalid */ + FS_WRITE_PROTECTED, /* (10) The physical drive is write protected */ + FS_INVALID_DRIVE, /* (11) The logical drive number is invalid */ + FS_NOT_ENABLED, /* (12) The volume has no work area */ + FS_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ + FS_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ + FS_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ + FS_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ + FS_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ + FS_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ + FS_INVALID_PARAMETER, /* (19) Given parameter is invalid */ + FS_FILE_EMPTY, /* (20) File is empty */ + FS_NOT_ENOUGH_MEMORY, /* (21) Not enough memory to malloc file */ +} FS_RESULT; +// Changes to this enum should also be made to fs_result_msgs in filesystem.c + +FS_RESULT +fs_mount(const DISC_INTERFACE *iface_); +void +fs_unmount(); +void +fs_get_volume_label(const char *path, char *label); +FS_RESULT +fs_read_file(void **contents, const char *path); +FS_RESULT +fs_read_file_string(const char **contents, const char *path); +const char * +get_fs_result_message(FS_RESULT result); + +#endif diff --git a/source/main.c b/source/main.c index 34067b4..8ea5e01 100644 --- a/source/main.c +++ b/source/main.c @@ -1,9 +1,8 @@ -#include "fatfs/ff.h" -#include "ffshim.h" +#include "filesystem.h" #include "shortcut.h" -#include "utils.h" #include "version.h" #include +#include #include #include #include @@ -34,56 +33,17 @@ scan_all_buttons_held() { | PAD_ButtonsHeld(PAD_CHAN2) | PAD_ButtonsHeld(PAD_CHAN3)); } -void -dol_alloc(u8 **_dol, int size) { - int mram_size = (SYS_GetArenaHi() - SYS_GetArenaLo()); - kprintf("Memory available: %iB\n", mram_size); - - kprintf("DOL size is %iB\n", size); - - if (size <= 0) { - kprintf("Empty DOL\n"); - return; - } - - u8 *dol = (u8 *) memalign(32, size); - - if (!dol) { - kprintf("Couldn't allocate memory\n"); - } - - *_dol = dol; -} - void read_dol_file(u8 **_dol, char *path) { *_dol = NULL; kprintf("Reading %s\n", path); - FIL file; - FRESULT open_result = f_open(&file, path, FA_READ); - if (open_result != FR_OK) { - kprintf("Failed to open file: %s\n", get_fresult_message(open_result)); - return; - } - - size_t size = f_size(&file); - u8 *dol; - dol_alloc(&dol, size); - if (!dol) { - return; - } - UINT _; - f_read(&file, dol, size, &_); - f_close(&file); - - *_dol = dol; + fs_read_file((void **) _dol, path); } void -read_cli_file(char **_cli, int *_size, char *path) { +read_cli_file(char **_cli, char *path) { *_cli = NULL; - *_size = 0; int path_length = strlen(path); path[path_length - 3] = 'c'; @@ -91,43 +51,7 @@ read_cli_file(char **_cli, int *_size, char *path) { path[path_length - 1] = 'i'; kprintf("Reading %s\n", path); - FIL file; - FRESULT result = f_open(&file, path, FA_READ); - if (result != FR_OK) { - if (result == FR_NO_FILE) { - kprintf("CLI file not found\n"); - } else { - kprintf("Failed to open CLI file: %s\n", get_fresult_message(result)); - } - return; - } - - size_t size = f_size(&file); - kprintf("CLI file size is %iB\n", size); - - if (size <= 0) { - kprintf("Empty CLI file\n"); - return; - } - - char *cli = (char *) malloc(size + 1); - - if (!cli) { - kprintf("Couldn't allocate memory for CLI file\n"); - return; - } - - UINT _; - f_read(&file, cli, size, &_); - f_close(&file); - - if (cli[size - 1] != '\0') { - cli[size] = '\0'; - size++; - } - - *_cli = cli; - *_size = size; + fs_read_file_string((const char **) _cli, path); } void @@ -183,12 +107,11 @@ load_shortcut_files(BOOT_PAYLOAD *payload, int shortcut_index) { // Attempt to load and parse CLI file char *cli; - int cli_size; - read_cli_file(&cli, &cli_size, path); + read_cli_file(&cli, path); // Parse CLI file. if (cli) { - parse_cli_file(payload->dol_argv, &payload->dol_argc, cli, cli_size); + parse_cli_file(payload->dol_argv, &payload->dol_argc, cli, strlen(cli)); } return 1; @@ -205,23 +128,20 @@ load_fat( kprintf("Trying %s\n", slot_name); - FATFS fs; - iface = iface_; - FRESULT mount_result = f_mount(&fs, "", 1); - if (mount_result != FR_OK) { - kprintf("Couldn't mount %s: %s\n", slot_name, get_fresult_message(mount_result)); + FS_RESULT mount_result = fs_mount(iface_); + if (mount_result != FS_OK) { + kprintf("Couldn't mount %s: %s\n", slot_name, get_fs_result_message(mount_result)); goto end; } char name[256]; - f_getlabel(slot_name, name, NULL); + fs_get_volume_label(slot_name, name); kprintf("Mounted %s as %s\n", name, slot_name); res = load_shortcut_files(payload, shortcut_index); kprintf("Unmounting %s\n", slot_name); - iface->shutdown(); - iface = NULL; + fs_unmount(); end: return res; @@ -302,15 +222,21 @@ load_usb(BOOT_PAYLOAD *payload, char slot) { usb_recvbuffer_safe(channel, &size, 4); size = convert_int(size); - dol_alloc(&payload->dol, size); - unsigned char *pointer = payload->dol; + if (size <= 0) { + kprintf("DOL is empty\n"); + return res; + } + kprintf("DOL size is %iB\n", size); - if (!payload->dol) { + u8 *dol = (u8 *) malloc(size); + + if (!dol) { res = 0; goto end; } kprintf("Receiving file...\n"); + unsigned char *pointer = dol; while (size > 0xF7D8) { usb_recvbuffer_safe(channel, (void *) pointer, 0xF7D8); size -= 0xF7D8; @@ -320,6 +246,8 @@ load_usb(BOOT_PAYLOAD *payload, char slot) { usb_recvbuffer_safe(channel, (void *) pointer, size); } + payload->dol = dol; + end: return res; } @@ -394,6 +322,9 @@ main() { return 0; } + int mram_size = SYS_GetArenaHi() - SYS_GetArenaLo(); + kprintf("Memory available: %iB\n", mram_size); + // Detect selected shortcut. int shortcut_index = 0; for (int i = 1; i < NUM_SHORTCUTS; i++) { diff --git a/source/utils.c b/source/utils.c deleted file mode 100644 index c52e4c7..0000000 --- a/source/utils.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "fatfs/ff.h" - -// See ./fatfs/ff.h:276 -char *fresult_msgs[] = { - /*FR_OK ( 0)*/ "Succeeded", - /*FR_DISK_ERR ( 1)*/ "A hard error occurred in the low level disk I/O layer", - /*FR_INT_ERR ( 2)*/ "Assertion failed", - /*FR_NOT_READY ( 3)*/ "Device not ready", - /*FR_NO_FILE ( 4)*/ "Could not find the file", - /*FR_NO_PATH ( 5)*/ "Could not find the path", - /*FR_INVALID_NAME ( 6)*/ "The path name format is invalid", - /*FR_DENIED ( 7)*/ "Access denied due to prohibited access or directory full", - /*FR_EXIST ( 8)*/ "Access denied due to prohibited access", - /*FR_INVALID_OBJECT ( 9)*/ "The file/directory object is invalid", - /*FR_WRITE_PROTECTED (10)*/ "The physical drive is write protected", - /*FR_INVALID_DRIVE (11)*/ "The logical drive number is invalid", - /*FR_NOT_ENABLED (12)*/ "The volume has no work area", - /*FR_NO_FILESYSTEM (13)*/ "There is no valid FAT volume", - /*FR_MKFS_ABORTED (14)*/ "The f_mkfs() aborted due to any problem", - /*FR_TIMEOUT (15)*/ - "Could not get a grant to access the volume within defined period", - /*FR_LOCKED (16)*/ - "The operation is rejected according to the file sharing policy", - /*FR_NOT_ENOUGH_CORE (17)*/ "LFN working buffer could not be allocated", - /*FR_TOO_MANY_OPEN_FILES (18)*/ "Number of open files > FF_FS_LOCK", - /*FR_INVALID_PARAMETER (19)*/ "Given parameter is invalid", -}; -int num_fresult_msgs = sizeof(fresult_msgs) / sizeof(fresult_msgs[0]); - -char * -get_fresult_message(FRESULT result) { - if (result < 0 || result >= num_fresult_msgs) { - return "Unknown"; - } - return fresult_msgs[result]; -} diff --git a/source/utils.h b/source/utils.h deleted file mode 100644 index 9fda394..0000000 --- a/source/utils.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef INC_UTILS_H -#define INC_UTILS_H - -#include "fatfs/ff.h" - -extern char * -get_fresult_message(FRESULT result); - -#endif From 91e86cc42e354c81845815cd58b7feef38b51bd7 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 8 Sep 2022 01:39:57 -0500 Subject: [PATCH 09/10] pass argv struct instead of arg array - Rather than track `argc` and `argv` array and combine into `__argv` struct later, create `__argv` struct immediately. - Moves CLI parsing to its own file. - Renames `parse_cli_file` to `parse_cli_args` as it is source agnostic. --- source/cli_args.c | 78 +++++++++++++++++++++++++++++++++++ source/cli_args.h | 8 ++++ source/main.c | 103 ++++++++++++---------------------------------- 3 files changed, 112 insertions(+), 77 deletions(-) create mode 100644 source/cli_args.c create mode 100644 source/cli_args.h diff --git a/source/cli_args.c b/source/cli_args.c new file mode 100644 index 0000000..fd30424 --- /dev/null +++ b/source/cli_args.c @@ -0,0 +1,78 @@ +#include "cli_args.h" +#include +#include +#include + +#define MAX_NUM_ARGV 1024 + +// 0 - Failure +// 1 - OK/Empty +int +parse_cli_args(struct __argv *argv, char *cli_option_str) { + kprintf("Parsing CLI args...\n"); + + argv->argc = 0; + argv->length = 0; + argv->commandLine = NULL; + + char *cli = cli_option_str; + char *dol_argv[MAX_NUM_ARGV]; + int dol_argc = 0; + int size = strlen(cli_option_str); + + // Parse CLI file + // https://github.com/emukidid/swiss-gc/blob/a0fa06d81360ad6d173acd42e4dd5495e268de42/cube/swiss/source/swiss.c#L1236 + // First argument is at the beginning of the file + if (cli[0] != '\r' && cli[0] != '\n') { + dol_argv[dol_argc] = cli; + dol_argc++; + } + + // Search for the others after each newline + for (int i = 0; i < size; i++) { + if (cli[i] == '\r' || cli[i] == '\n') { + cli[i] = '\0'; + } else if (cli[i - 1] == '\0') { + dol_argv[dol_argc] = cli + i; + dol_argc++; + if (dol_argc >= MAX_NUM_ARGV) { + kprintf("Reached max of %i args.\n", MAX_NUM_ARGV); + break; + } + } + } + + kprintf("Found %i CLI args\n", dol_argc); + + if (!dol_argc) { + return 0; + } + + // https://github.com/emukidid/swiss-gc/blob/f5319aab248287c847cb9468325ebcf54c993fb1/cube/swiss/source/aram/sidestep.c#L350 + argv->argc = dol_argc; + argv->length = 1; + + for (int i = 0; i < dol_argc; i++) { + size_t arg_length = strlen(dol_argv[i]) + 1; + argv->length += arg_length; + } + + kprintf("CLI argv size is %iB\n", argv->length); + argv->commandLine = (char *) malloc(argv->length); + + if (!argv->commandLine) { + kprintf("Couldn't allocate memory for CLI argv\n"); + argv->length = 0; + return 0; + } + + unsigned int position = 0; + for (int i = 0; i < dol_argc; i++) { + size_t arg_length = strlen(dol_argv[i]) + 1; + memcpy(argv->commandLine + position, dol_argv[i], arg_length); + position += arg_length; + } + argv->commandLine[argv->length - 1] = '\0'; + + return 1; +} \ No newline at end of file diff --git a/source/cli_args.h b/source/cli_args.h new file mode 100644 index 0000000..fc97273 --- /dev/null +++ b/source/cli_args.h @@ -0,0 +1,8 @@ +#ifndef INC_CLI_ARGS_H +#define INC_CLI_ARGS_H +#include + +int +parse_cli_args(struct __argv *argv, char *cli_option_str); + +#endif diff --git a/source/main.c b/source/main.c index 8ea5e01..4e066c4 100644 --- a/source/main.c +++ b/source/main.c @@ -1,3 +1,4 @@ +#include "cli_args.h" #include "filesystem.h" #include "shortcut.h" #include "version.h" @@ -16,12 +17,9 @@ #define VERBOSE_LOGGING 0 -#define MAX_NUM_ARGV 1024 - typedef struct { u8 *dol; - int dol_argc; - char *dol_argv[MAX_NUM_ARGV]; + struct __argv argv; } BOOT_PAYLOAD; u16 all_buttons_held; @@ -54,44 +52,6 @@ read_cli_file(char **_cli, char *path) { fs_read_file_string((const char **) _cli, path); } -void -parse_cli_file(char **_dol_argv, int *_dol_argc, char *cli, int size) { - // Parse CLI file - // https://github.com/emukidid/swiss-gc/blob/a0fa06d81360ad6d173acd42e4dd5495e268de42/cube/swiss/source/swiss.c#L1236 - char **dol_argv = _dol_argv; - int dol_argc = 0; - - // First argument is at the beginning of the file - if (cli[0] != '\r' && cli[0] != '\n') { - dol_argv[dol_argc] = cli; - dol_argc++; - } - - // Search for the others after each newline - for (int i = 0; i < size; i++) { - if (cli[i] == '\r' || cli[i] == '\n') { - cli[i] = '\0'; - } else if (cli[i - 1] == '\0') { - dol_argv[dol_argc] = cli + i; - dol_argc++; - if (dol_argc >= MAX_NUM_ARGV) { - kprintf("Reached max of %i args.\n", MAX_NUM_ARGV); - break; - } - } - } - - kprintf("Found %i CLI args\n", dol_argc); - -#if VERBOSE_LOGGING - for (int i = 0; i < dol_argc; ++i) { - kprintf("arg%i: %s\n", i, dol_argv[i]); - } -#endif - - *_dol_argc = dol_argc; -} - int load_shortcut_files(BOOT_PAYLOAD *payload, int shortcut_index) { char *path = shortcuts[shortcut_index].path; @@ -111,7 +71,8 @@ load_shortcut_files(BOOT_PAYLOAD *payload, int shortcut_index) { // Parse CLI file. if (cli) { - parse_cli_file(payload->dol_argv, &payload->dol_argc, cli, strlen(cli)); + parse_cli_args(&payload->argv, cli); + free((void *) cli); } return 1; @@ -337,7 +298,10 @@ main() { // Init payload. BOOT_PAYLOAD payload; payload.dol = NULL; - payload.dol_argc = 0; + payload.argv.argc = 0; + payload.argv.length = 0; + payload.argv.commandLine = NULL; + payload.argv.argvMagic = ARGV_MAGIC; // Attempt to load from each device. if (load_usb(&payload, 'B')) { @@ -368,39 +332,24 @@ main() { } } - struct __argv dolargs; - dolargs.commandLine = (char *) NULL; - dolargs.length = 0; - - // https://github.com/emukidid/swiss-gc/blob/f5319aab248287c847cb9468325ebcf54c993fb1/cube/swiss/source/aram/sidestep.c#L350 - if (payload.dol_argc) { - dolargs.argvMagic = ARGV_MAGIC; - dolargs.argc = payload.dol_argc; - dolargs.length = 1; - - for (int i = 0; i < payload.dol_argc; i++) { - size_t arg_length = strlen(payload.dol_argv[i]) + 1; - dolargs.length += arg_length; + // Print DOL args. +#if VERBOSE_LOGGING + if (payload.argv.length > 0) { + kprintf("----------\n"); + size_t position = 0; + for (int i = 0; i < payload.argv.argc; ++i) { + kprintf("arg%i: %s\n", i, payload.argv.commandLine + position); + position += strlen(payload.argv.commandLine + position) + 1; } + kprintf("----------\n\n"); + } else { + kprintf("No CLI args\n"); + } +#endif - kprintf("CLI argv size is %iB\n", dolargs.length); - dolargs.commandLine = (char *) malloc(dolargs.length); - - if (!dolargs.commandLine) { - kprintf("Couldn't allocate memory for CLI argv\n"); - dolargs.length = 0; - } else { - unsigned int position = 0; - for (int i = 0; i < payload.dol_argc; i++) { - size_t arg_length = strlen(payload.dol_argv[i]) + 1; - memcpy(dolargs.commandLine + position, - payload.dol_argv[i], - arg_length); - position += arg_length; - } - dolargs.commandLine[dolargs.length - 1] = '\0'; - DCStoreRange(dolargs.commandLine, dolargs.length); - } + // Prepare DOL argv. + if (payload.argv.length > 0) { + DCStoreRange(payload.argv.commandLine, payload.argv.length); } memcpy((void *) STUB_ADDR, stub, (size_t) stub_size); @@ -412,8 +361,8 @@ main() { SYS_SwitchFiber( (intptr_t) payload.dol, 0, - (intptr_t) dolargs.commandLine, - dolargs.length, + (intptr_t) payload.argv.commandLine, + payload.argv.length, STUB_ADDR, STUB_STACK ); From 87fd89a0695ff297553e9a94bf98671be30ec2f9 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 8 Sep 2022 00:34:02 -0500 Subject: [PATCH 10/10] code cleanup - Silence erroneous `TB_BUS_CLOCK` undefined error in some IDEs. - Group global state to top of `main.c`. - Copy and modify rather than overwriting DOL path for CLI path in `read_cli_file`. - `dol` -> `dol_file`, `cli` -> `cli_file`, and other variable name clarifications. - Add comments to describe function return codes. - Add various comments. - Various stylistic changes and delinting for consistency. --- source/main.c | 157 ++++++++++++++++++++++------------------------ source/shortcut.h | 4 +- 2 files changed, 77 insertions(+), 84 deletions(-) diff --git a/source/main.c b/source/main.c index 4e066c4..174f551 100644 --- a/source/main.c +++ b/source/main.c @@ -17,12 +17,17 @@ #define VERBOSE_LOGGING 0 +// Global State +// -------------------- +u16 all_buttons_held; +extern u8 __xfb[]; +// -------------------- + typedef struct { - u8 *dol; + u8 *dol_file; struct __argv argv; } BOOT_PAYLOAD; -u16 all_buttons_held; void scan_all_buttons_held() { PAD_ScanPads(); @@ -32,73 +37,84 @@ scan_all_buttons_held() { } void -read_dol_file(u8 **_dol, char *path) { - *_dol = NULL; +read_dol_file(u8 **dol_file, const char *path) { + *dol_file = NULL; kprintf("Reading %s\n", path); - fs_read_file((void **) _dol, path); + fs_read_file((void **) dol_file, path); } void -read_cli_file(char **_cli, char *path) { - *_cli = NULL; +read_cli_file(char **cli_file, const char *dol_path) { + *cli_file = NULL; - int path_length = strlen(path); + int path_length = strlen(dol_path); + char path[path_length + 1]; + strcpy(path, dol_path); path[path_length - 3] = 'c'; path[path_length - 2] = 'l'; path[path_length - 1] = 'i'; kprintf("Reading %s\n", path); - fs_read_file_string((const char **) _cli, path); + fs_read_file_string((const char **) cli_file, path); } +// 0 - Device should not be used. +// 1 - Device should be used. int load_shortcut_files(BOOT_PAYLOAD *payload, int shortcut_index) { - char *path = shortcuts[shortcut_index].path; - read_dol_file(&payload->dol, path); - if (!payload->dol && shortcut_index != 0) { + // Attempt to read shortcut paths from from mounted FAT device. + u8 *dol_file = NULL; + const char *dol_path = shortcuts[shortcut_index].path; + read_dol_file(&dol_file, dol_path); + if (!dol_file && shortcut_index != 0) { shortcut_index = 0; - path = shortcuts[shortcut_index].path; - read_dol_file(&payload->dol, path); + dol_path = shortcuts[shortcut_index].path; + read_dol_file(&dol_file, dol_path); } - if (!payload->dol) { + if (!dol_file) { return 0; } - // Attempt to load and parse CLI file - char *cli; - read_cli_file(&cli, path); + // Attempt to read CLI file. + char *cli_file; + read_cli_file(&cli_file, dol_path); // Parse CLI file. - if (cli) { - parse_cli_args(&payload->argv, cli); - free((void *) cli); + if (cli_file) { + parse_cli_args(&payload->argv, cli_file); + free((void *) cli_file); } + payload->dol_file = dol_file; return 1; } +// 0 - Device should not be used. +// 1 - Device should be used. int load_fat( BOOT_PAYLOAD *payload, const char *slot_name, - const DISC_INTERFACE *iface_, + const DISC_INTERFACE *iface, int shortcut_index ) { int res = 0; kprintf("Trying %s\n", slot_name); - FS_RESULT mount_result = fs_mount(iface_); - if (mount_result != FS_OK) { - kprintf("Couldn't mount %s: %s\n", slot_name, get_fs_result_message(mount_result)); + // Mount device. + FS_RESULT result = fs_mount(iface); + if (result != FS_OK) { + kprintf("Couldn't mount %s: %s\n", slot_name, get_fs_result_message(result)); goto end; } - char name[256]; - fs_get_volume_label(slot_name, name); - kprintf("Mounted %s as %s\n", name, slot_name); + char volume_label[256]; + fs_get_volume_label(slot_name, volume_label); + kprintf("Mounted %s as %s\n", volume_label, slot_name); + // Attempt to load shortcut files. res = load_shortcut_files(payload, shortcut_index); kprintf("Unmounting %s\n", slot_name); @@ -125,27 +141,18 @@ convert_int(unsigned int in) { #define GC_READY 0x88 #define GC_OK 0x89 +// 0 - Device should not be used. +// 1 - Device should be used. int load_usb(BOOT_PAYLOAD *payload, char slot) { - kprintf("Trying USB Gecko in slot %c\n", slot); - - int channel, res = 1; - - switch (slot) { - case 'B': - channel = 1; - break; + int res = 0; + int channel = slot == 'B' ? 1 : 0; - case 'A': - default: - channel = 0; - break; - } + kprintf("Trying USB Gecko in slot %c\n", slot); if (!usb_isgeckoalive(channel)) { kprintf("Not present\n"); - res = 0; - goto end; + return res; } usb_flush(channel); @@ -163,13 +170,14 @@ load_usb(BOOT_PAYLOAD *payload, char slot) { current_time = gettime(); if (diff_sec(start_time, current_time) >= 5) { kprintf("PC did not respond in time\n"); - res = 0; - goto end; + return res; } usb_recvbuffer_safe_ex(channel, &data, 1, 10); // 10 retries } + res = 1; + if (data == PC_READY) { kprintf("Respond with OK\n"); // Sometimes the PC can fail to receive the byte, this helps @@ -189,15 +197,14 @@ load_usb(BOOT_PAYLOAD *payload, char slot) { } kprintf("DOL size is %iB\n", size); - u8 *dol = (u8 *) malloc(size); - - if (!dol) { - res = 0; - goto end; + u8 *dol_file = (u8 *) malloc(size); + if (!dol_file) { + kprintf("Couldn't allocate memory for DOL file\n"); + return res; } kprintf("Receiving file...\n"); - unsigned char *pointer = dol; + unsigned char *pointer = dol_file; while (size > 0xF7D8) { usb_recvbuffer_safe(channel, (void *) pointer, 0xF7D8); size -= 0xF7D8; @@ -207,14 +214,10 @@ load_usb(BOOT_PAYLOAD *payload, char slot) { usb_recvbuffer_safe(channel, (void *) pointer, size); } - payload->dol = dol; - -end: + payload->dol_file = dol_file; return res; } -extern u8 __xfb[]; - void delay_exit() { // Wait while the d-pad down direction or reset button is held. @@ -273,11 +276,11 @@ main() { EXI_Sync(EXI_CHANNEL_0); EXI_Deselect(EXI_CHANNEL_0); EXI_Unlock(EXI_CHANNEL_0); + // Since we've disabled the Qoob, we wil reboot to the Nintendo IPL scan_all_buttons_held(); if (all_buttons_held & PAD_BUTTON_LEFT || SYS_ResetButtonDown()) { - // Since we've disabled the Qoob, we wil reboot to the Nintendo IPL kprintf("Skipped. Rebooting into original IPL...\n"); delay_exit(); return 0; @@ -297,36 +300,22 @@ main() { // Init payload. BOOT_PAYLOAD payload; - payload.dol = NULL; + payload.dol_file = NULL; payload.argv.argc = 0; payload.argv.length = 0; payload.argv.commandLine = NULL; payload.argv.argvMagic = ARGV_MAGIC; // Attempt to load from each device. - if (load_usb(&payload, 'B')) { - goto load; - } - - if (load_fat(&payload, "sdb", &__io_gcsdb, shortcut_index)) { - goto load; - } - - if (load_usb(&payload, 'A')) { - goto load; - } - - if (load_fat(&payload, "sda", &__io_gcsda, shortcut_index)) { - goto load; - } - - if (load_fat(&payload, "sd2", &__io_gcsd2, shortcut_index)) { - goto load; - } - -load: - if (!payload.dol) { - kprintf("No DOL found! Halting."); + int res = + (load_usb(&payload, 'B') || load_fat(&payload, "sdb", &__io_gcsdb, shortcut_index) + || load_usb(&payload, 'A') + || load_fat(&payload, "sda", &__io_gcsda, shortcut_index) + || load_fat(&payload, "sd2", &__io_gcsd2, shortcut_index)); + + if (!res || !payload.dol_file) { + // If we reach here, all attempts to load a DOL failed + kprintf("No DOL loaded! Halting."); while (true) { VIDEO_WaitVSync(); } @@ -352,19 +341,23 @@ main() { DCStoreRange(payload.argv.commandLine, payload.argv.length); } + // Load stub. memcpy((void *) STUB_ADDR, stub, (size_t) stub_size); DCStoreRange((void *) STUB_ADDR, (u32) stub_size); delay_exit(); + // Boot DOL. SYS_ResetSystem(SYS_SHUTDOWN, 0, FALSE); SYS_SwitchFiber( - (intptr_t) payload.dol, + (intptr_t) payload.dol_file, 0, (intptr_t) payload.argv.commandLine, payload.argv.length, STUB_ADDR, STUB_STACK ); + + // Will never reach here. return 0; } diff --git a/source/shortcut.h b/source/shortcut.h index 57fb752..a56b34b 100644 --- a/source/shortcut.h +++ b/source/shortcut.h @@ -5,8 +5,8 @@ #define NUM_SHORTCUTS 7 typedef struct { - u16 pad_buttons; - char *path; + const u16 pad_buttons; + const char *path; } SHORTCUT; extern SHORTCUT shortcuts[NUM_SHORTCUTS];