diff --git a/fusee/fusee-primary/src/fastboot/fastboot.cpp b/fusee/fusee-primary/src/fastboot/fastboot.cpp index 4795452be..c89ee74e9 100644 --- a/fusee/fusee-primary/src/fastboot/fastboot.cpp +++ b/fusee/fusee-primary/src/fastboot/fastboot.cpp @@ -26,16 +26,19 @@ extern "C" { static ams::fastboot::FastbootGadget fastboot_gadget((uint8_t*) 0xf0000000, 1024 * 1024 * 256); // 256 MiB download buffer reaches end of address space -extern "C" fastboot_return fastboot_enter(const bct0_t *bct0) { - bool should_enter = bct0->fastboot_force_enable; +extern "C" fastboot_return fastboot_enter(const bct0_t *bct0, bool force) { + bool should_enter = force || bct0->fastboot_force_enable; - log_setup_display(); - - if (!should_enter) { + if(should_enter) { + log_setup_display(); + } else { if (bct0->fastboot_button_timeout > 0) { + log_setup_display(); + uint32_t timeout = bct0->fastboot_button_timeout; uint32_t start_time = get_time_ms(); uint32_t last_message_secs = 0; + while (get_time_ms() - start_time < timeout) { uint32_t seconds_remaining = (start_time + timeout - get_time_ms() + 999) / 1000; if (seconds_remaining != last_message_secs) { @@ -48,20 +51,25 @@ extern "C" fastboot_return fastboot_enter(const bct0_t *bct0) { break; } } + print((ScreenLogLevel) (SCREEN_LOG_LEVEL_NONE | SCREEN_LOG_LEVEL_NO_PREFIX), "\n\n"); + + if (!should_enter) { + log_cleanup_display(); + return FASTBOOT_SKIPPED; + } + } else { + /* We did not initialize the display, so don't need to clean it up here. */ + + return FASTBOOT_SKIPPED; } } - if (!should_enter) { - log_cleanup_display(); - return FASTBOOT_SKIPPED; - } - - print(SCREEN_LOG_LEVEL_DEBUG, "Entering fastboot.\n"); + print(SCREEN_LOG_LEVEL_DEBUG, "Entering fastboot. (forced = %d)\n", force); ams::xusb::Initialize(); print(SCREEN_LOG_LEVEL_DEBUG, "Finished initializing USB hardware.\n"); ams::xusb::EnableDevice(fastboot_gadget); - + print((ScreenLogLevel) (SCREEN_LOG_LEVEL_NONE | SCREEN_LOG_LEVEL_NO_PREFIX), "Fastboot mode:\n"); print((ScreenLogLevel) (SCREEN_LOG_LEVEL_NONE | SCREEN_LOG_LEVEL_NO_PREFIX), "-------------------------------\n"); print((ScreenLogLevel) (SCREEN_LOG_LEVEL_NONE | SCREEN_LOG_LEVEL_NO_PREFIX), "Volume up: Reboot to RCM.\n"); @@ -71,6 +79,6 @@ extern "C" fastboot_return fastboot_enter(const bct0_t *bct0) { fastboot_return r = fastboot_gadget.Run(); log_cleanup_display(); - + return r; } diff --git a/fusee/fusee-primary/src/fastboot/fastboot.h b/fusee/fusee-primary/src/fastboot/fastboot.h index 5c79444e1..2c3792e19 100644 --- a/fusee/fusee-primary/src/fastboot/fastboot.h +++ b/fusee/fusee-primary/src/fastboot/fastboot.h @@ -29,7 +29,7 @@ enum fastboot_return { FASTBOOT_CHAINLOAD, }; -enum fastboot_return fastboot_enter(const bct0_t *bct0); +enum fastboot_return fastboot_enter(const bct0_t *bct0, bool force); #ifdef __cplusplus } diff --git a/fusee/fusee-primary/src/main.c b/fusee/fusee-primary/src/main.c index 1c8cf169d..5d6fd7f86 100644 --- a/fusee/fusee-primary/src/main.c +++ b/fusee/fusee-primary/src/main.c @@ -28,6 +28,7 @@ #include "lib/vsprintf.h" #include "display/video_fb.h" #include "fastboot/fastboot.h" +#include "btn.h" extern void (*__program_exit_callback)(int rc); @@ -79,16 +80,6 @@ static void setup_env(void) { /* Set up the exception handlers. */ setup_exception_handlers(); - - /* Mount the SD card. */ - if (!mount_sd()) { - fatal_error("Failed to mount SD card!\n"); - } -} - -static void cleanup_env(void) { - /* Unmount the SD card. */ - unmount_sd(); } static void exit_callback(int rc) { @@ -96,8 +87,8 @@ static void exit_callback(int rc) { relocate_and_chainload(); } -int main(void) { - const char *bct0_string; +int main(void) { + const char *bct0_string = DEFAULT_BCT0; stage2_args_t *stage2_args; uint32_t stage2_version = 0; bct0_t bct0; @@ -108,46 +99,126 @@ int main(void) { /* Check for panics. */ check_and_display_panic(); - /* Load the BCT0 configuration ini off of the SD. */ - bct0_string = load_config(); + bool should_greet = true; + bool skip_fastboot = false; + bool stage2_loaded = false; + bool has_sd_card = false; - /* Parse the BCT0 configuration ini. */ - if (bct0_parse(bct0_string, &bct0) < 0) { - fatal_error("Failed to parse BCT.ini!\n"); + while (!stage2_loaded) { + + /* Try to mount the SD card and load configuration. */ + if (has_sd_card || mount_sd()) { + /* Load the BCT0 configuration ini off of the SD. */ + bct0_string = load_config(); + + /* Parse the BCT0 configuration ini. */ + if (bct0_parse(bct0_string, &bct0) < 0) { + fatal_error("Failed to parse BCT.ini!\n"); + } + + /* Override the global logging level. */ + log_set_log_level(bct0.log_level); + + if (should_greet && bct0.log_level != SCREEN_LOG_LEVEL_NONE) { + /* Initialize the display for debugging. */ + log_setup_display(); + + /* Say hello. */ + print(SCREEN_LOG_LEVEL_DEBUG | SCREEN_LOG_LEVEL_NO_PREFIX, "Welcome to Atmosph\xe8re Fus\xe9" "e!\n"); + print(SCREEN_LOG_LEVEL_DEBUG, "Using color linear framebuffer at 0x%p!\n", log_get_display_framebuffer()); + + should_greet = false; + } + + /* Run the MTC binary, if it hasn't already been run. */ + if (!stage2_run_mtc(&bct0)) { + print(SCREEN_LOG_LEVEL_WARNING, "DRAM training failed! Continuing with untrained DRAM.\n"); + } + + /* Assert that our configuration is sane. */ + stage2_validate_config(&bct0); + + has_sd_card = true; + } else { + /* Initialize the display to show messages. */ + log_setup_display(); + + /* Override logging level. */ + log_set_log_level(SCREEN_LOG_LEVEL_INFO); + + /* Prompt user for action. */ + print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "Failed to mount SD card!\n"); + print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, " Press Volume Up to retry.\n"); + print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, " Press Volume Down to enter fastboot mode.\n"); + print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\n Press POWER to reboot.\n"); + + /* Wait for user action. */ + uint32_t last_button = btn_read(); + while (true) { + uint32_t button = btn_read(); + + if (button & BTN_VOL_UP && !(last_button & BTN_VOL_UP)) { + /* Skip the rest of the loop and return to beginning. If we + * succeed, don't offer to enter fastboot. */ + skip_fastboot = true; + break; + } + + if (button & BTN_VOL_DOWN && !(last_button & BTN_VOL_DOWN)) { + /* Do not skip entering fastboot mode, even if we were previously requested to. */ + skip_fastboot = false; + break; + } + + if (button & BTN_POWER) { + /* Reboot. */ + reboot_to_self(); + } + + last_button = button; + } + + log_cleanup_display(); + } + + if (!skip_fastboot) { + /* Try to enter fastboot if we are configured to, or force it if SD mount failed and we reached this point. */ + switch(fastboot_enter(&bct0, !has_sd_card)) { + case FASTBOOT_INVALID: + case FASTBOOT_SKIPPED: + break; + case FASTBOOT_LOAD_STAGE2: + /* Return to start of loop to reload configuration and try again. Do + not attempt to enter fastboot again if config loads correctly, + but do offer to enter fastboot again if SD mount still fails. */ + skip_fastboot = true; + + continue; + case FASTBOOT_CHAINLOAD: + print(SCREEN_LOG_LEVEL_DEBUG, "fastboot: chainloading\n"); + + /* Break out of outer loop. Note that it is possible to reach + * this codepath with no SD card, in which case we forward the + * default BCT0 string to stage2.. */ + stage2_loaded = true; + + continue; + } + } + + /* Load stage2 if the SD card mounted successfully and fastboot didn't continue out of the loop. */ + if (has_sd_card) { + print(SCREEN_LOG_LEVEL_DEBUG, "Loading stage2 from sd card...\n"); + + stage2_load(&bct0); + + print(SCREEN_LOG_LEVEL_DEBUG, "Finished loading stage2.\n"); + + stage2_loaded = true; + } } - /* Override the global logging level. */ - log_set_log_level(bct0.log_level); - - if (bct0.log_level != SCREEN_LOG_LEVEL_NONE) { - /* Initialize the display for debugging. */ - log_setup_display(); - } - - /* Say hello. */ - print(SCREEN_LOG_LEVEL_DEBUG | SCREEN_LOG_LEVEL_NO_PREFIX, "Welcome to Atmosph\xe8re Fus\xe9" "e!\n"); - print(SCREEN_LOG_LEVEL_DEBUG, "Using color linear framebuffer at 0x%p!\n", log_get_display_framebuffer()); - - /* Run the MTC binary. */ - if (!stage2_run_mtc(&bct0)) { - print(SCREEN_LOG_LEVEL_WARNING, "DRAM training failed! Continuing with untrained DRAM.\n"); - } - - /* Assert that our configuration is sane. */ - stage2_validate_config(&bct0); - - /* Try to enter fastboot, if we are configured to. */ - switch(fastboot_enter(&bct0)) { - case FASTBOOT_INVALID: - case FASTBOOT_SKIPPED: - case FASTBOOT_LOAD_STAGE2: - /* Load the loader payload into DRAM. */ - stage2_load(&bct0); - break; - case FASTBOOT_CHAINLOAD: - print(SCREEN_LOG_LEVEL_DEBUG, "fastboot: chainloading\n"); - break; - } + print(SCREEN_LOG_LEVEL_DEBUG, "Continuing to stage2...\n"); /* Setup argument data. */ strcpy(g_chainloader_arg_data, bct0.stage2_path); @@ -157,8 +228,10 @@ int main(void) { strcpy(stage2_args->bct0, bct0_string); g_chainloader_argc = 2; - /* Terminate the boot environment. */ - cleanup_env(); + /* Cleanup environment. */ + if (has_sd_card) { + unmount_sd(); + } if (bct0.log_level != SCREEN_LOG_LEVEL_NONE) { /* Wait a while for debugging. */ @@ -168,6 +241,8 @@ int main(void) { log_cleanup_display(); } + print(SCREEN_LOG_LEVEL_DEBUG, "Exiting...\n"); + /* Finally, after the cleanup routines (__libc_fini_array, etc.) are called, jump to Stage2. */ __program_exit_callback = exit_callback; return 0; diff --git a/fusee/fusee-primary/src/panic.c b/fusee/fusee-primary/src/panic.c index e4cd19e06..0906ede83 100644 --- a/fusee/fusee-primary/src/panic.c +++ b/fusee/fusee-primary/src/panic.c @@ -148,7 +148,7 @@ static void _check_and_display_atmosphere_fatal_error(void) { print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "Error Desc: %s (0x%x)\n", get_error_desc_str(ctx.error_desc), ctx.error_desc); /* Save context to the SD card. */ - { + if (mount_sd()) { char filepath[0x40]; snprintf(filepath, sizeof(filepath) - 1, "/atmosphere/fatal_errors/report_%016llx.bin", ctx.report_identifier); filepath[sizeof(filepath)-1] = 0; @@ -157,6 +157,10 @@ static void _check_and_display_atmosphere_fatal_error(void) { } else { print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "Report saved to %s\n", filepath); } + + unmount_sd(); + } else { + print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "Failed to mount SD card to save report!\n"); } /* Try to print a fix suggestion via automatic error detection. */ diff --git a/fusee/fusee-primary/src/stage2.c b/fusee/fusee-primary/src/stage2.c index b0cfa85cc..97d09809e 100644 --- a/fusee/fusee-primary/src/stage2.c +++ b/fusee/fusee-primary/src/stage2.c @@ -20,8 +20,13 @@ #include "utils.h" bool stage2_run_mtc(const bct0_t *bct0) { + static bool has_run_mtc = false; FILINFO info; size_t size; + + if (has_run_mtc) { + return true; + } /* Check if the MTC binary is present. */ if (f_stat(bct0->stage2_mtc_path, &info) != FR_OK) { @@ -51,6 +56,8 @@ bool stage2_run_mtc(const bct0_t *bct0) { /* Cleanup right away. */ memset((void *)bct0->stage2_load_address, 0, size); + + has_run_mtc = true; return mtc_res; }