diff --git a/fusee/fusee-primary/src/main.c b/fusee/fusee-primary/src/main.c index 04470fa3d..10a69c881 100644 --- a/fusee/fusee-primary/src/main.c +++ b/fusee/fusee-primary/src/main.c @@ -1,4 +1,5 @@ #include "utils.h" +#include "panic.h" #include "hwinit.h" #include "fuse.h" #include "se.h" @@ -67,6 +68,9 @@ static void setup_env(void) { /* TODO: What can be stripped out to make this minimal? */ nx_hwinit(); + /* Check for panics. */ + check_and_display_panic(); + /* Try to load the SBK into the security engine, if possible. */ /* TODO: Should this be done later? */ load_sbk(); diff --git a/fusee/fusee-primary/src/panic.c b/fusee/fusee-primary/src/panic.c new file mode 100644 index 000000000..918b23a66 --- /dev/null +++ b/fusee/fusee-primary/src/panic.c @@ -0,0 +1,82 @@ +#include "panic.h" +#include "pmc.h" +#include "fuse.h" +#include "utils.h" +#include "hwinit.h" + +static uint32_t g_panic_code = 0; + +void check_and_display_panic(void) { + /* We also handle our own panics. */ + /* In the case of our own panics, we assume that the display has already been initialized. */ + bool has_panic = APBDEV_PMC_RST_STATUS_0 != 0 || g_panic_code != 0; + uint32_t code = g_panic_code == 0 ? APBDEV_PMC_SCRATCH200_0 : g_panic_code; + + has_panic = has_panic && !(APBDEV_PMC_RST_STATUS_0 != 1 && code == PANIC_CODE_SAFEMODE); + + if (has_panic) { + uint32_t color; + + /* Check for predefined codes: */ + switch (code & MASK(20)) { + case 0x01: /* Package2 signature verification failed. */ + case 0x02: /* Package2 meta verification failed. */ + case 0x03: /* Package2 version check failed. */ + case 0x04: /* Package2 payload verification failed. */ + color = PANIC_COLOR_KERNEL; + break; + case 0x05: /* Unknown SMC. */ + case 0x06: /* Unknown Abort. */ + color = PANIC_COLOR_SECMON_GENERIC; + break; + case 0x07: /* Invalid CPU context. */ + case 0x08: /* Invalid SE state. */ + case 0x09: /* CPU is already awake (2.0.0+). */ + color = PANIC_COLOR_SECMON_DEEPSLEEP; + break; + case 0x10: /* Unknown exception. */ + color = PANIC_COLOR_SECMON_EXCEPTION; + break; + case 0x30: /* General bootloader error. */ + case 0x31: /* Invalid DRAM ID. */ + case 0x32: /* Invalid size. */ + case 0x33: /* Invalid arguement. */ + case 0x34: /* Bad GPT. */ + case 0x35: /* Failed to boot SafeMode. */ + case 0x36: /* Activity monitor fired (4.0.0+). */ + color = PANIC_COLOR_BOOTLOADER_GENERIC; + break; + case 0x40: /* Kernel panic. */ + color = PANIC_COLOR_KERNEL; + break; + default: + color = code >> 20; + color |= color << 4; + break; + } + + if (g_panic_code == 0) { + display_init(); + } + + display_color_screen(color); + wait_for_button_and_pmc_reboot(); + } else { + g_panic_code = 0; + APBDEV_PMC_SCRATCH200_0 = 0; + } +} + +__attribute__ ((noreturn)) void panic(uint32_t code) { + /* Set panic code. */ + if (g_panic_code == 0) { + g_panic_code = code; + APBDEV_PMC_SCRATCH200_0 = code; + } + + fuse_disable_programming(); + APBDEV_PMC_CRYPTO_OP_0 = 1; /* Disable all SE operations. */ + + check_and_display_panic(); + while(true); +} diff --git a/fusee/fusee-primary/src/panic.h b/fusee/fusee-primary/src/panic.h new file mode 100644 index 000000000..0b29f7070 --- /dev/null +++ b/fusee/fusee-primary/src/panic.h @@ -0,0 +1,18 @@ +#ifndef FUSEE_PANIC_H +#define FUSEE_PANIC_H + +#include + +#define PANIC_COLOR_KERNEL 0x0000FF +#define PANIC_COLOR_SECMON_EXCEPTION 0xFF7700 +#define PANIC_COLOR_SECMON_GENERIC 0x00FFFF +#define PANIC_COLOR_SECMON_DEEPSLEEP 0xFF77FF /* 4.0+ color */ +#define PANIC_COLOR_BOOTLOADER_GENERIC 0xAA00FF +#define PANIC_COLOR_BOOTLOADER_SAFEMODE 0xFFFFAA /* Removed */ + +#define PANIC_CODE_SAFEMODE 0x00000020 + +void check_and_display_panic(void); +__attribute__ ((noreturn)) void panic(uint32_t code); + +#endif diff --git a/fusee/fusee-primary/src/pmc.h b/fusee/fusee-primary/src/pmc.h index d01f0d58c..1a1a8b30a 100644 --- a/fusee/fusee-primary/src/pmc.h +++ b/fusee/fusee-primary/src/pmc.h @@ -20,6 +20,7 @@ #define APBDEV_PM_0 MAKE_REG32(PMC_BASE + 0x14) #define APBDEV_PMC_WAKE2_STATUS_0 MAKE_REG32(PMC_BASE + 0x168) +#define APBDEV_PMC_RST_STATUS_0 MAKE_REG32(PMC_BASE + 0x1B4) #define APBDEV_PMC_CNTRL2_0 MAKE_REG32(PMC_BASE + 0x440) #define APBDEV_PMC_SCRATCH43_0 MAKE_REG32(PMC_BASE + 0x22C) @@ -28,6 +29,7 @@ /** * Definitions of the Tegra PMC. + * NOTE: Incomplete, do not use */ struct tegra_pmc { uint32_t cntrl; @@ -306,11 +308,11 @@ enum tegra_pmc_masks { /** - * Utility function that grabs the Tegra pinmux registers. + * Utility function that grabs the Tegra PMC registers. */ -static inline struct tegra_pmc *pmc_get_regs(void) +static inline volatile struct tegra_pmc *pmc_get_regs(void) { - return (struct tegra_pmc *)0x7000e400; + return (volatile struct tegra_pmc *)0x7000E400; } diff --git a/fusee/fusee-primary/src/sdmmc.c b/fusee/fusee-primary/src/sdmmc.c index c023f6a71..f77ab609b 100644 --- a/fusee/fusee-primary/src/sdmmc.c +++ b/fusee/fusee-primary/src/sdmmc.c @@ -2440,8 +2440,8 @@ static void sdmmc_apply_card_type(struct mmc *mmc, enum sdmmc_card_type type) // Switch-cart protocol cards case MMC_CARD_CART: - printk("BUG: trying to use an impossible code path!\n"); - panic(0); + printk("BUG: trying to use an impossible code path, hanging!\n"); + while(true); } } diff --git a/fusee/fusee-primary/src/utils.c b/fusee/fusee-primary/src/utils.c index 7d1b1fb81..884066c8b 100644 --- a/fusee/fusee-primary/src/utils.c +++ b/fusee/fusee-primary/src/utils.c @@ -3,41 +3,49 @@ #include "se.h" #include "fuse.h" #include "pmc.h" -#include "panic_color.h" #include "timers.h" #include "hwinit/btn.h" - -__attribute__ ((noreturn)) void panic(uint32_t code) { - /* Set Panic Code for NX_BOOTLOADER. */ - if (APBDEV_PMC_SCRATCH200_0 == 0) { - APBDEV_PMC_SCRATCH200_0 = code; +__attribute__((noreturn)) void watchdog_reboot(void) { + volatile watchdog_timers_t *wdt = GET_WDT(4); + wdt->PATTERN = WDT_REBOOT_PATTERN; + wdt->COMMAND = 2; /* Disable Counter. */ + GET_WDT_REBOOT_CFG_REG(4) = 0xC0000000; + wdt->CONFIG = 0x8019; /* Full System Reset after Fourth Counter expires, using TIMER(9). */ + wdt->COMMAND = 1; /* Enable Counter. */ + while (true) { + /* Wait for reboot. */ } +} - /* TODO: Custom Panic Driver, which displays to screen without rebooting. */ - /* For now, just use NX BOOTLOADER's panic. */ - fuse_disable_programming(); - APBDEV_PMC_CRYPTO_OP_0 = 1; /* Disable all SE operations. */ - - /* FIXME: clean up and use this instead of replacing things */ - while(btn_read() != BTN_POWER); - - /* Ensure we boot back into RCM, for development. */ - APBDEV_PMC_SCRATCH0_0 = (1 << 1); +__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0) { + APBDEV_PMC_SCRATCH0_0 = scratch0; /* Reset the processor. */ - APBDEV_PMC_CONTROL = (1 << 4); - while(1); + APBDEV_PMC_CONTROL = BIT(4); + + while (true) { + /* Wait for reboot. */ + } +} + +__attribute__((noreturn)) void wait_for_button_and_pmc_reboot(void) { + uint32_t button; + while (true) { + button = btn_read(); + if (button & BTN_POWER) { + /* Reboot into RCM. */ + pmc_reboot(BIT(1) | 0); + } else if (button & (BTN_VOL_UP | BTN_VOL_DOWN)) { + /* Reboot normally. */ + pmc_reboot(0); + } + } } __attribute__ ((noreturn)) void generic_panic(void) { - panic(0xFF000006); -} - -__attribute__ ((noreturn)) void panic_predefined(uint32_t which) { - static const uint32_t codes[0x10] = {COLOR_0, COLOR_1, COLOR_2, COLOR_3, COLOR_4, COLOR_5, COLOR_6, COLOR_7, COLOR_8, COLOR_9, COLOR_A, COLOR_B, COLOR_C, COLOR_D, COLOR_E, COLOR_F}; - panic(codes[which & 0xF]); + while(true);//panic(0xFF000006); } __attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be) diff --git a/fusee/fusee-primary/src/utils.h b/fusee/fusee-primary/src/utils.h index 924989766..f5b6e26ed 100644 --- a/fusee/fusee-primary/src/utils.h +++ b/fusee/fusee-primary/src/utils.h @@ -101,8 +101,11 @@ static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t s overlaps_a(start, end, __start__, __end__); } -void panic(uint32_t code); +__attribute__((noreturn)) void watchdog_reboot(void); +__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0); +__attribute__((noreturn)) void wait_for_button_and_pmc_reboot(void); + + void generic_panic(void); -void panic_predefined(uint32_t which); #endif diff --git a/fusee/fusee-secondary/src/main.c b/fusee/fusee-secondary/src/main.c index afeab6b51..890c73ddf 100644 --- a/fusee/fusee-secondary/src/main.c +++ b/fusee/fusee-secondary/src/main.c @@ -4,6 +4,7 @@ #include #include #include "utils.h" +#include "panic.h" #include "loader.h" #include "chainloader.h" #include "stage2.h" @@ -20,6 +21,9 @@ static stage2_args_t *g_stage2_args; static bool g_do_nxboot; static void setup_env(void) { + /* Check for panics. */ + check_and_display_panic(); + /* Set the console up. */ if (console_init() == -1) { generic_panic(); diff --git a/fusee/fusee-secondary/src/panic.c b/fusee/fusee-secondary/src/panic.c new file mode 100644 index 000000000..918b23a66 --- /dev/null +++ b/fusee/fusee-secondary/src/panic.c @@ -0,0 +1,82 @@ +#include "panic.h" +#include "pmc.h" +#include "fuse.h" +#include "utils.h" +#include "hwinit.h" + +static uint32_t g_panic_code = 0; + +void check_and_display_panic(void) { + /* We also handle our own panics. */ + /* In the case of our own panics, we assume that the display has already been initialized. */ + bool has_panic = APBDEV_PMC_RST_STATUS_0 != 0 || g_panic_code != 0; + uint32_t code = g_panic_code == 0 ? APBDEV_PMC_SCRATCH200_0 : g_panic_code; + + has_panic = has_panic && !(APBDEV_PMC_RST_STATUS_0 != 1 && code == PANIC_CODE_SAFEMODE); + + if (has_panic) { + uint32_t color; + + /* Check for predefined codes: */ + switch (code & MASK(20)) { + case 0x01: /* Package2 signature verification failed. */ + case 0x02: /* Package2 meta verification failed. */ + case 0x03: /* Package2 version check failed. */ + case 0x04: /* Package2 payload verification failed. */ + color = PANIC_COLOR_KERNEL; + break; + case 0x05: /* Unknown SMC. */ + case 0x06: /* Unknown Abort. */ + color = PANIC_COLOR_SECMON_GENERIC; + break; + case 0x07: /* Invalid CPU context. */ + case 0x08: /* Invalid SE state. */ + case 0x09: /* CPU is already awake (2.0.0+). */ + color = PANIC_COLOR_SECMON_DEEPSLEEP; + break; + case 0x10: /* Unknown exception. */ + color = PANIC_COLOR_SECMON_EXCEPTION; + break; + case 0x30: /* General bootloader error. */ + case 0x31: /* Invalid DRAM ID. */ + case 0x32: /* Invalid size. */ + case 0x33: /* Invalid arguement. */ + case 0x34: /* Bad GPT. */ + case 0x35: /* Failed to boot SafeMode. */ + case 0x36: /* Activity monitor fired (4.0.0+). */ + color = PANIC_COLOR_BOOTLOADER_GENERIC; + break; + case 0x40: /* Kernel panic. */ + color = PANIC_COLOR_KERNEL; + break; + default: + color = code >> 20; + color |= color << 4; + break; + } + + if (g_panic_code == 0) { + display_init(); + } + + display_color_screen(color); + wait_for_button_and_pmc_reboot(); + } else { + g_panic_code = 0; + APBDEV_PMC_SCRATCH200_0 = 0; + } +} + +__attribute__ ((noreturn)) void panic(uint32_t code) { + /* Set panic code. */ + if (g_panic_code == 0) { + g_panic_code = code; + APBDEV_PMC_SCRATCH200_0 = code; + } + + fuse_disable_programming(); + APBDEV_PMC_CRYPTO_OP_0 = 1; /* Disable all SE operations. */ + + check_and_display_panic(); + while(true); +} diff --git a/fusee/fusee-secondary/src/panic.h b/fusee/fusee-secondary/src/panic.h new file mode 100644 index 000000000..0b29f7070 --- /dev/null +++ b/fusee/fusee-secondary/src/panic.h @@ -0,0 +1,18 @@ +#ifndef FUSEE_PANIC_H +#define FUSEE_PANIC_H + +#include + +#define PANIC_COLOR_KERNEL 0x0000FF +#define PANIC_COLOR_SECMON_EXCEPTION 0xFF7700 +#define PANIC_COLOR_SECMON_GENERIC 0x00FFFF +#define PANIC_COLOR_SECMON_DEEPSLEEP 0xFF77FF /* 4.0+ color */ +#define PANIC_COLOR_BOOTLOADER_GENERIC 0xAA00FF +#define PANIC_COLOR_BOOTLOADER_SAFEMODE 0xFFFFAA /* Removed */ + +#define PANIC_CODE_SAFEMODE 0x00000020 + +void check_and_display_panic(void); +__attribute__ ((noreturn)) void panic(uint32_t code); + +#endif diff --git a/fusee/fusee-secondary/src/pmc.h b/fusee/fusee-secondary/src/pmc.h index d01f0d58c..1a1a8b30a 100644 --- a/fusee/fusee-secondary/src/pmc.h +++ b/fusee/fusee-secondary/src/pmc.h @@ -20,6 +20,7 @@ #define APBDEV_PM_0 MAKE_REG32(PMC_BASE + 0x14) #define APBDEV_PMC_WAKE2_STATUS_0 MAKE_REG32(PMC_BASE + 0x168) +#define APBDEV_PMC_RST_STATUS_0 MAKE_REG32(PMC_BASE + 0x1B4) #define APBDEV_PMC_CNTRL2_0 MAKE_REG32(PMC_BASE + 0x440) #define APBDEV_PMC_SCRATCH43_0 MAKE_REG32(PMC_BASE + 0x22C) @@ -28,6 +29,7 @@ /** * Definitions of the Tegra PMC. + * NOTE: Incomplete, do not use */ struct tegra_pmc { uint32_t cntrl; @@ -306,11 +308,11 @@ enum tegra_pmc_masks { /** - * Utility function that grabs the Tegra pinmux registers. + * Utility function that grabs the Tegra PMC registers. */ -static inline struct tegra_pmc *pmc_get_regs(void) +static inline volatile struct tegra_pmc *pmc_get_regs(void) { - return (struct tegra_pmc *)0x7000e400; + return (volatile struct tegra_pmc *)0x7000E400; } diff --git a/fusee/fusee-secondary/src/sdmmc.c b/fusee/fusee-secondary/src/sdmmc.c index c023f6a71..f77ab609b 100644 --- a/fusee/fusee-secondary/src/sdmmc.c +++ b/fusee/fusee-secondary/src/sdmmc.c @@ -2440,8 +2440,8 @@ static void sdmmc_apply_card_type(struct mmc *mmc, enum sdmmc_card_type type) // Switch-cart protocol cards case MMC_CARD_CART: - printk("BUG: trying to use an impossible code path!\n"); - panic(0); + printk("BUG: trying to use an impossible code path, hanging!\n"); + while(true); } } diff --git a/fusee/fusee-secondary/src/utils.c b/fusee/fusee-secondary/src/utils.c index 7ea22d803..d1420afa5 100644 --- a/fusee/fusee-secondary/src/utils.c +++ b/fusee/fusee-secondary/src/utils.c @@ -3,35 +3,51 @@ #include "se.h" #include "fuse.h" #include "pmc.h" -#include "panic_color.h" #include "timers.h" +#include "hwinit/btn.h" #include #include -__attribute__ ((noreturn)) void panic(uint32_t code) { - /* Set Panic Code for NX_BOOTLOADER. */ - if (APBDEV_PMC_SCRATCH200_0 == 0) { - APBDEV_PMC_SCRATCH200_0 = code; +__attribute__((noreturn)) void watchdog_reboot(void) { + volatile watchdog_timers_t *wdt = GET_WDT(4); + wdt->PATTERN = WDT_REBOOT_PATTERN; + wdt->COMMAND = 2; /* Disable Counter. */ + GET_WDT_REBOOT_CFG_REG(4) = 0xC0000000; + wdt->CONFIG = 0x8019; /* Full System Reset after Fourth Counter expires, using TIMER(9). */ + wdt->COMMAND = 1; /* Enable Counter. */ + while (true) { + /* Wait for reboot. */ } +} - /* TODO: Custom Panic Driver, which displays to screen without rebooting. */ - /* For now, just use NX BOOTLOADER's panic. */ - fuse_disable_programming(); - APBDEV_PMC_CRYPTO_OP_0 = 1; /* Disable all SE operations. */ - /* TODO: watchdog_reboot(); */ - while (1) { } +__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0) { + APBDEV_PMC_SCRATCH0_0 = scratch0; + + /* Reset the processor. */ + APBDEV_PMC_CONTROL = BIT(4); + while (true) { + /* Wait for reboot. */ + } +} + +__attribute__((noreturn)) void wait_for_button_and_pmc_reboot(void) { + uint32_t button; + while (true) { + button = btn_read(); + if (button & BTN_POWER) { + /* Reboot into RCM. */ + pmc_reboot(BIT(1) | 0); + } else if (button & (BTN_VOL_UP | BTN_VOL_DOWN)) { + /* Reboot normally. */ + pmc_reboot(0); + } + } } __attribute__ ((noreturn)) void generic_panic(void) { - panic(0xFF000006); + while(true);//panic(0xFF000006); } - -__attribute__ ((noreturn)) void panic_predefined(uint32_t which) { - static const uint32_t codes[0x10] = {COLOR_0, COLOR_1, COLOR_2, COLOR_3, COLOR_4, COLOR_5, COLOR_6, COLOR_7, COLOR_8, COLOR_9, COLOR_A, COLOR_B, COLOR_C, COLOR_D, COLOR_E, COLOR_F}; - panic(codes[which & 0xF]); -} - __attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be) { if(as <= bs && bs <= ae) diff --git a/fusee/fusee-secondary/src/utils.h b/fusee/fusee-secondary/src/utils.h index 687f32f8a..5708d23ab 100644 --- a/fusee/fusee-secondary/src/utils.h +++ b/fusee/fusee-secondary/src/utils.h @@ -104,8 +104,10 @@ static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t s void hexdump(const void* data, size_t size, uintptr_t addrbase); -__attribute__ ((noreturn)) void panic(uint32_t code); -__attribute__ ((noreturn)) void generic_panic(void); -__attribute__ ((noreturn)) void panic_predefined(uint32_t which); +__attribute__((noreturn)) void watchdog_reboot(void); +__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0); +__attribute__((noreturn)) void wait_for_button_and_pmc_reboot(void); + +void generic_panic(void); #endif