mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-01 02:37:27 +01:00
Introduce fatal_error
This commit is contained in:
parent
add03d5774
commit
f45bc83bc4
@ -13,7 +13,7 @@
|
|||||||
* TODO: This should print via UART, console framebuffer, and to a ring for
|
* TODO: This should print via UART, console framebuffer, and to a ring for
|
||||||
* consumption by Horizon
|
* consumption by Horizon
|
||||||
*/
|
*/
|
||||||
void printk(char *fmt, ...)
|
void printk(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
@ -22,7 +22,7 @@ void printk(char *fmt, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void vprintk(char *fmt, va_list args)
|
void vprintk(const char *fmt, va_list args)
|
||||||
{
|
{
|
||||||
char buf[512];
|
char buf[512];
|
||||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
void printk(char *fmt, ...);
|
void printk(const char *fmt, ...);
|
||||||
void vprintk(char *fmt, va_list args);
|
void vprintk(const char *fmt, va_list args);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -34,8 +34,7 @@ static const char *load_config(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(g_bct0_buffer, "BCT0", 4) != 0) {
|
if (memcmp(g_bct0_buffer, "BCT0", 4) != 0) {
|
||||||
printk("Error: Unexpected magic in BCT.ini!\n");
|
fatal_error("Unexpected magic in BCT.ini!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
/* Return pointer to first line of the ini. */
|
/* Return pointer to first line of the ini. */
|
||||||
const char *bct0 = g_bct0_buffer;
|
const char *bct0 = g_bct0_buffer;
|
||||||
@ -43,8 +42,7 @@ static const char *load_config(void) {
|
|||||||
bct0++;
|
bct0++;
|
||||||
}
|
}
|
||||||
if (!bct0) {
|
if (!bct0) {
|
||||||
printk("Error: BCT.ini has no newline!\n");
|
fatal_error("BCT.ini has no newline!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
return bct0;
|
return bct0;
|
||||||
}
|
}
|
||||||
@ -116,9 +114,8 @@ int main(void) {
|
|||||||
#ifndef I_KNOW_WHAT_I_AM_DOING
|
#ifndef I_KNOW_WHAT_I_AM_DOING
|
||||||
#error "Fusee is a work-in-progress bootloader, and is not ready for usage yet. If you want to play with it anyway, please #define I_KNOW_WHAT_I_AM_DOING -- and recognize that we will be unable to provide support until it is ready for general usage :)"
|
#error "Fusee is a work-in-progress bootloader, and is not ready for usage yet. If you want to play with it anyway, please #define I_KNOW_WHAT_I_AM_DOING -- and recognize that we will be unable to provide support until it is ready for general usage :)"
|
||||||
|
|
||||||
printk("Warning: Fus\e9e is not yet completed, and not ready for general testing!\n");
|
printk("Warning: Fus\xe9" "e is not yet completed, and not ready for general testing!\n");
|
||||||
printk("Please do not seek support for it until it is done.\n");
|
fatal_error("Please do not seek support for it until it is done.\n");
|
||||||
generic_panic();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Load the BCT0 configuration ini off of the SD. */
|
/* Load the BCT0 configuration ini off of the SD. */
|
||||||
|
@ -49,13 +49,11 @@ void load_stage2(const char *bct0) {
|
|||||||
uintptr_t tmp_addr;
|
uintptr_t tmp_addr;
|
||||||
|
|
||||||
if (ini_parse_string(bct0, stage2_ini_handler, &config) < 0) {
|
if (ini_parse_string(bct0, stage2_ini_handler, &config) < 0) {
|
||||||
printk("Error: Failed to parse BCT.ini!\n");
|
fatal_error("Failed to parse BCT.ini!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.load_address == 0 || config.path[0] == '\x00') {
|
if (config.load_address == 0 || config.path[0] == '\x00') {
|
||||||
printk("Error: Failed to determine where to load stage2!\n");
|
fatal_error("Failed to determine where to load stage2!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(config.path) + 1 + sizeof(stage2_args_t) > CHAINLOADER_ARG_DATA_MAX_SIZE) {
|
if (strlen(config.path) + 1 + sizeof(stage2_args_t) > CHAINLOADER_ARG_DATA_MAX_SIZE) {
|
||||||
@ -63,13 +61,11 @@ void load_stage2(const char *bct0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!check_32bit_address_loadable(config.entrypoint)) {
|
if (!check_32bit_address_loadable(config.entrypoint)) {
|
||||||
printk("Error: Stage2's entrypoint is invalid!\n");
|
fatal_error("Stage2's entrypoint is invalid!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!check_32bit_address_loadable(config.load_address)) {
|
if (!check_32bit_address_loadable(config.load_address)) {
|
||||||
printk("Error: Stage2's load address is invalid!\n");
|
fatal_error("Stage2's load address is invalid!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printk("[DEBUG] Stage 2 Config:\n");
|
printk("[DEBUG] Stage 2 Config:\n");
|
||||||
@ -78,26 +74,22 @@ void load_stage2(const char *bct0) {
|
|||||||
printk(" Entrypoint: 0x%p\n", config.entrypoint);
|
printk(" Entrypoint: 0x%p\n", config.entrypoint);
|
||||||
|
|
||||||
if (f_stat(config.path, &info) != FR_OK) {
|
if (f_stat(config.path, &info) != FR_OK) {
|
||||||
printk("Error: Failed to stat stage2 (%s)!\n", config.path);
|
fatal_error("Failed to stat stage2 (%s)!\n", config.path);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size = (size_t)info.fsize;
|
size = (size_t)info.fsize;
|
||||||
|
|
||||||
/* the LFB is located at 0xC0000000 atm */
|
/* the LFB is located at 0xC0000000 atm */
|
||||||
if (size > 0xC0000000u - 0x80000000u) {
|
if (size > 0xC0000000u - 0x80000000u) {
|
||||||
printk("Error: Stage2 is way too big!\n");
|
fatal_error("Stage2 is way too big!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!check_32bit_address_range_loadable(config.load_address, size)) {
|
if (!check_32bit_address_range_loadable(config.load_address, size)) {
|
||||||
printk("Error: Stage2 has an invalid load address & size combination (0x%08x 0x%08x)!\n", config.load_address, size);
|
fatal_error("Stage2 has an invalid load address & size combination (0x%08x 0x%08x)!\n", config.load_address, size);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.entrypoint < config.load_address || config.entrypoint >= config.load_address + size) {
|
if (config.entrypoint < config.load_address || config.entrypoint >= config.load_address + size) {
|
||||||
printk("Error: Stage2's entrypoint is outside Stage2!\n");
|
fatal_error("Stage2's entrypoint is outside Stage2!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_32bit_address_range_in_program(config.load_address, size)) {
|
if (check_32bit_address_range_in_program(config.load_address, size)) {
|
||||||
@ -107,8 +99,7 @@ void load_stage2(const char *bct0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (read_from_file((void *)tmp_addr, size, config.path) != size) {
|
if (read_from_file((void *)tmp_addr, size, config.path) != size) {
|
||||||
printk("Error: Failed to read stage2 (%s)!\n", config.path);
|
fatal_error("Failed to read stage2 (%s)!\n", config.path);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_chainloader_num_entries = 1;
|
g_chainloader_num_entries = 1;
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "se.h"
|
#include "se.h"
|
||||||
#include "fuse.h"
|
#include "fuse.h"
|
||||||
#include "pmc.h"
|
#include "pmc.h"
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
|
#include "panic.h"
|
||||||
|
|
||||||
|
#include "lib/printk.h"
|
||||||
#include "hwinit/btn.h"
|
#include "hwinit/btn.h"
|
||||||
|
|
||||||
__attribute__((noreturn)) void watchdog_reboot(void) {
|
__attribute__((noreturn)) void watchdog_reboot(void) {
|
||||||
@ -45,7 +48,17 @@ __attribute__((noreturn)) void wait_for_button_and_pmc_reboot(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
__attribute__ ((noreturn)) void generic_panic(void) {
|
__attribute__ ((noreturn)) void generic_panic(void) {
|
||||||
while(true);//panic(0xFF000006);
|
panic(0xFF000006);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
printk("Fatal error: ");
|
||||||
|
va_start(args, fmt);
|
||||||
|
vprintk(fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
printk("\nPress POWER to reboot into RCM, VOL+/VOL- to reboot normally.\n");
|
||||||
|
wait_for_button_and_pmc_reboot();
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be)
|
__attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be)
|
||||||
|
@ -105,7 +105,8 @@ __attribute__((noreturn)) void watchdog_reboot(void);
|
|||||||
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0);
|
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0);
|
||||||
__attribute__((noreturn)) void wait_for_button_and_pmc_reboot(void);
|
__attribute__((noreturn)) void wait_for_button_and_pmc_reboot(void);
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void generic_panic(void);
|
||||||
|
|
||||||
void generic_panic(void);
|
__attribute__((noreturn)) void fatal_error(const char *fmt, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -52,34 +52,28 @@ static void load_list_entry(const char *key) {
|
|||||||
load_file_ctx.key = key;
|
load_file_ctx.key = key;
|
||||||
|
|
||||||
if (ini_parse_string(get_loader_ctx()->bct0, loadlist_entry_ini_handler, &load_file_ctx) < 0) {
|
if (ini_parse_string(get_loader_ctx()->bct0, loadlist_entry_ini_handler, &load_file_ctx) < 0) {
|
||||||
printf("Error: Failed to parse BCT.ini!\n");
|
fatal_error("Failed to parse BCT.ini!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (load_file_ctx.load_address == 0 || load_file_ctx.path[0] == '\x00') {
|
if (load_file_ctx.load_address == 0 || load_file_ctx.path[0] == '\x00') {
|
||||||
printf("Error: Failed to determine where to load %s from!\n", key);
|
fatal_error("Failed to determine where to load %s from!\n", key);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(load_file_ctx.path) > LOADER_MAX_PATH_SIZE) {
|
if (strlen(load_file_ctx.path) > LOADER_MAX_PATH_SIZE) {
|
||||||
printf("Error: The filename for %s is too long!\n", key);
|
fatal_error("The filename for %s is too long!\n", key);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!check_32bit_address_loadable(load_file_ctx.load_address)) {
|
if (!check_32bit_address_loadable(load_file_ctx.load_address)) {
|
||||||
printf("Error: Load address 0x%08x is invalid (%s)!\n", load_file_ctx.load_address, key);
|
fatal_error("Load address 0x%08x is invalid (%s)!\n", load_file_ctx.load_address, key);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stat(load_file_ctx.path, &st) == -1) {
|
if (stat(load_file_ctx.path, &st) == -1) {
|
||||||
printf("Error: Failed to stat file %s: %s!\n", load_file_ctx.path, strerror(errno));
|
fatal_error("Failed to stat file %s: %s!\n", load_file_ctx.path, strerror(errno));
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size = (size_t)st.st_size;
|
size = (size_t)st.st_size;
|
||||||
if (!check_32bit_address_range_loadable(load_file_ctx.load_address, size)) {
|
if (!check_32bit_address_range_loadable(load_file_ctx.load_address, size)) {
|
||||||
printf("Error: %s has an invalid load address & size combination!\n", key);
|
fatal_error("%s has an invalid load address & size combination!\n", key);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entry_num = g_chainloader_num_entries++;
|
entry_num = g_chainloader_num_entries++;
|
||||||
@ -114,8 +108,7 @@ static void parse_loadlist(const char *ll) {
|
|||||||
/* Skip to the next delimiter. */
|
/* Skip to the next delimiter. */
|
||||||
for (; *p == ' ' || *p == '\t' || *p == '\x00'; p++) { }
|
for (; *p == ' ' || *p == '\t' || *p == '\x00'; p++) { }
|
||||||
if (*p != '|') {
|
if (*p != '|') {
|
||||||
printf("Error: Load list is malformed!\n");
|
fatal_error("Load list is malformed!\n");
|
||||||
generic_panic();
|
|
||||||
} else {
|
} else {
|
||||||
/* Skip to the next entry. */
|
/* Skip to the next entry. */
|
||||||
for (; *p == ' ' || *p == '\t' || *p == '|'; p++) { }
|
for (; *p == ' ' || *p == '\t' || *p == '|'; p++) { }
|
||||||
@ -216,13 +209,11 @@ void load_payload(const char *bct0) {
|
|||||||
ctx->bct0 = bct0;
|
ctx->bct0 = bct0;
|
||||||
|
|
||||||
if (ini_parse_string(ctx->bct0, loadlist_ini_handler, ctx) < 0) {
|
if (ini_parse_string(ctx->bct0, loadlist_ini_handler, ctx) < 0) {
|
||||||
printf("Error: Failed to parse BCT.ini!\n");
|
fatal_error("Failed to parse BCT.ini!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->chainload_entrypoint != 0 || ctx->nb_files_to_load > 0) {
|
if (ctx->chainload_entrypoint != 0 || ctx->nb_files_to_load > 0) {
|
||||||
printf("Error: loadlist must be empty when booting Horizon!\n");
|
fatal_error("loadlist must be empty when booting Horizon!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sort the entries by ascending load addresses */
|
/* Sort the entries by ascending load addresses */
|
||||||
@ -239,8 +230,8 @@ void load_payload(const char *bct0) {
|
|||||||
g_chainloader_entries[i + 1].load_address + g_chainloader_entries[i + 1].size
|
g_chainloader_entries[i + 1].load_address + g_chainloader_entries[i + 1].size
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
printf(
|
fatal_error(
|
||||||
"Error: Loading ranges for files %s and %s overlap!\n",
|
"Loading ranges for files %s and %s overlap!\n",
|
||||||
ctx->file_paths_to_load[g_chainloader_entries[i].num],
|
ctx->file_paths_to_load[g_chainloader_entries[i].num],
|
||||||
ctx->file_paths_to_load[g_chainloader_entries[i + 1].num]
|
ctx->file_paths_to_load[g_chainloader_entries[i + 1].num]
|
||||||
);
|
);
|
||||||
@ -260,8 +251,7 @@ void load_payload(const char *bct0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->chainload_entrypoint != 0 && ctx->file_id_of_entrypoint >= ctx->nb_files_to_load) {
|
if (ctx->chainload_entrypoint != 0 && ctx->file_id_of_entrypoint >= ctx->nb_files_to_load) {
|
||||||
printf("Error: Entrypoint not in range of any of the files!\n");
|
fatal_error("Entrypoint not in range of any of the files!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (can_load_in_place) {
|
if (can_load_in_place) {
|
||||||
@ -269,8 +259,7 @@ void load_payload(const char *bct0) {
|
|||||||
chainloader_entry_t *entry = &g_chainloader_entries[i];
|
chainloader_entry_t *entry = &g_chainloader_entries[i];
|
||||||
entry->src_address = entry->load_address;
|
entry->src_address = entry->load_address;
|
||||||
if (read_from_file((void *)entry->src_address, entry->size, ctx->file_paths_to_load[entry->num]) != entry->size) {
|
if (read_from_file((void *)entry->src_address, entry->size, ctx->file_paths_to_load[entry->num]) != entry->size) {
|
||||||
printf("Error: Failed to read file %s: %s!\n", ctx->file_paths_to_load[entry->num], strerror(errno));
|
fatal_error("Failed to read file %s: %s!\n", ctx->file_paths_to_load[entry->num], strerror(errno));
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -296,8 +285,7 @@ void load_payload(const char *bct0) {
|
|||||||
carveout = find_carveout(g_chainloader_entries, g_chainloader_num_entries, total_size);
|
carveout = find_carveout(g_chainloader_entries, g_chainloader_num_entries, total_size);
|
||||||
}
|
}
|
||||||
if (carveout == 0) {
|
if (carveout == 0) {
|
||||||
printf("Error: Failed to find a carveout!\n");
|
fatal_error("Failed to find a carveout!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finally, read the files into the carveout */
|
/* Finally, read the files into the carveout */
|
||||||
@ -306,8 +294,7 @@ void load_payload(const char *bct0) {
|
|||||||
chainloader_entry_t *entry = &g_chainloader_entries[i];
|
chainloader_entry_t *entry = &g_chainloader_entries[i];
|
||||||
entry->src_address = pos;
|
entry->src_address = pos;
|
||||||
if (read_from_file((void *)entry->src_address, entry->size, ctx->file_paths_to_load[entry->num]) != entry->size) {
|
if (read_from_file((void *)entry->src_address, entry->size, ctx->file_paths_to_load[entry->num]) != entry->size) {
|
||||||
printf("Error: Failed to read file %s: %s!\n", ctx->file_paths_to_load[entry->num], strerror(errno));
|
fatal_error("Failed to read file %s: %s!\n", ctx->file_paths_to_load[entry->num], strerror(errno));
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
pos += entry->size;
|
pos += entry->size;
|
||||||
}
|
}
|
||||||
|
@ -62,14 +62,12 @@ int main(int argc, void **argv) {
|
|||||||
setup_env();
|
setup_env();
|
||||||
|
|
||||||
if (argc != STAGE2_ARGC) {
|
if (argc != STAGE2_ARGC) {
|
||||||
printf("Error: Invalid argc (expected %d, got %d)!\n", STAGE2_ARGC, argc);
|
fatal_error("Invalid argc (expected %d, got %d)!\n", STAGE2_ARGC, argc);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
g_stage2_args = (stage2_args_t *)argv[STAGE2_ARGV_ARGUMENT_STRUCT];
|
g_stage2_args = (stage2_args_t *)argv[STAGE2_ARGV_ARGUMENT_STRUCT];
|
||||||
|
|
||||||
if(g_stage2_args->version != 0) {
|
if(g_stage2_args->version != 0) {
|
||||||
printf("Error: Incorrect Stage2 args version (expected %lu, got %lu)!\n", 0ul, g_stage2_args->version);
|
fatal_error("Incorrect Stage2 args version (expected %lu, got %lu)!\n", 0ul, g_stage2_args->version);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(u8"Welcome to Atmosphère Fusée Stage 2!\n");
|
printf(u8"Welcome to Atmosphère Fusée Stage 2!\n");
|
||||||
|
@ -44,13 +44,11 @@ static void nxboot_configure_exosphere(void) {
|
|||||||
exo_cfg.target_firmware = EXOSPHERE_TARGET_FIRMWARE_MAX;
|
exo_cfg.target_firmware = EXOSPHERE_TARGET_FIRMWARE_MAX;
|
||||||
|
|
||||||
if (ini_parse_string(get_loader_ctx()->bct0, exosphere_ini_handler, &exo_cfg) < 0) {
|
if (ini_parse_string(get_loader_ctx()->bct0, exosphere_ini_handler, &exo_cfg) < 0) {
|
||||||
printf("Error: Failed to parse BCT.ini!\n");
|
fatal_error("Failed to parse BCT.ini!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exo_cfg.target_firmware < EXOSPHERE_TARGET_FIRMWARE_MIN || exo_cfg.target_firmware > EXOSPHERE_TARGET_FIRMWARE_MAX) {
|
if (exo_cfg.target_firmware < EXOSPHERE_TARGET_FIRMWARE_MIN || exo_cfg.target_firmware > EXOSPHERE_TARGET_FIRMWARE_MAX) {
|
||||||
printf("Error: Invalid Exosphere target firmware!\n");
|
fatal_error("Invalid Exosphere target firmware!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*(MAILBOX_EXOSPHERE_CONFIGURATION) = exo_cfg;
|
*(MAILBOX_EXOSPHERE_CONFIGURATION) = exo_cfg;
|
||||||
@ -78,16 +76,14 @@ void nxboot_main(void) {
|
|||||||
/* TODO: How should we deal with bootconfig? */
|
/* TODO: How should we deal with bootconfig? */
|
||||||
package2 = memalign(4096, PACKAGE2_SIZE_MAX);
|
package2 = memalign(4096, PACKAGE2_SIZE_MAX);
|
||||||
if (package2 == NULL) {
|
if (package2 == NULL) {
|
||||||
printf("Error: nxboot: out of memory!\n");
|
fatal_error("nxboot: out of memory!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read Package2 from a file, otherwise from its partition(s). */
|
/* Read Package2 from a file, otherwise from its partition(s). */
|
||||||
if (loader_ctx->package2_path[0] != '\0') {
|
if (loader_ctx->package2_path[0] != '\0') {
|
||||||
pk2file = fopen(loader_ctx->package2_path, "rb");
|
pk2file = fopen(loader_ctx->package2_path, "rb");
|
||||||
if (pk2file == NULL) {
|
if (pk2file == NULL) {
|
||||||
printf("Error: Failed to open Package2 from %s: %s!\n", loader_ctx->package2_path, strerror(errno));
|
fatal_error("Failed to open Package2 from %s: %s!\n", loader_ctx->package2_path, strerror(errno));
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifndef I_KNOW_WHAT_IM_DOING_2
|
#ifndef I_KNOW_WHAT_IM_DOING_2
|
||||||
@ -98,26 +94,22 @@ void nxboot_main(void) {
|
|||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
printf("Error: Package2 must be loaded from the SD card, unless you know what you are doing!\n");
|
fatal_error("Package2 must be loaded from the SD card, unless you know what you are doing!\n");
|
||||||
generic_panic();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
setvbuf(pk2file, NULL, _IONBF, 0); /* Workaround. */
|
setvbuf(pk2file, NULL, _IONBF, 0); /* Workaround. */
|
||||||
if (fread(package2, sizeof(package2_header_t), 1, pk2file) < 1) {
|
if (fread(package2, sizeof(package2_header_t), 1, pk2file) < 1) {
|
||||||
printf("Error: Failed to read Package2!\n");
|
fatal_error("Failed to read Package2!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
package2_size = package2_meta_get_size(&package2->metadata);
|
package2_size = package2_meta_get_size(&package2->metadata);
|
||||||
if (package2_size > PACKAGE2_SIZE_MAX || package2_size <= sizeof(package2_header_t)) {
|
if (package2_size > PACKAGE2_SIZE_MAX || package2_size <= sizeof(package2_header_t)) {
|
||||||
printf("Error: Package2 is too big or too small!\n");
|
fatal_error("Package2 is too big or too small!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fread(package2->data, package2_size - sizeof(package2_header_t), 1, pk2file) < 1) {
|
if (fread(package2->data, package2_size - sizeof(package2_header_t), 1, pk2file) < 1) {
|
||||||
printf("Error: Failed to read Package2!\n");
|
fatal_error("Failed to read Package2!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(pk2file);
|
fclose(pk2file);
|
||||||
@ -129,8 +121,7 @@ void nxboot_main(void) {
|
|||||||
printf("Reading boot0...\n");
|
printf("Reading boot0...\n");
|
||||||
boot0 = fopen("boot0:/", "rb");
|
boot0 = fopen("boot0:/", "rb");
|
||||||
if (boot0 == NULL || package1_read_and_parse_boot0(&package1loader, &package1loader_size, g_keyblobs, &available_revision, boot0) == -1) {
|
if (boot0 == NULL || package1_read_and_parse_boot0(&package1loader, &package1loader_size, g_keyblobs, &available_revision, boot0) == -1) {
|
||||||
printf("Error: Couldn't parse boot0: %s!\n", strerror(errno));
|
fatal_error("Couldn't parse boot0: %s!\n", strerror(errno));
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
fclose(boot0);
|
fclose(boot0);
|
||||||
|
|
||||||
@ -138,27 +129,22 @@ void nxboot_main(void) {
|
|||||||
if (loader_ctx->tsecfw_path[0] != '\0') {
|
if (loader_ctx->tsecfw_path[0] != '\0') {
|
||||||
tsec_fw_size = get_file_size(loader_ctx->tsecfw_path);
|
tsec_fw_size = get_file_size(loader_ctx->tsecfw_path);
|
||||||
if (tsec_fw_size != 0 && tsec_fw_size != 0xF00) {
|
if (tsec_fw_size != 0 && tsec_fw_size != 0xF00) {
|
||||||
printf("Error: TSEC firmware from %s has a wrong size!\n", loader_ctx->tsecfw_path);
|
fatal_error("TSEC firmware from %s has a wrong size!\n", loader_ctx->tsecfw_path);
|
||||||
generic_panic();
|
|
||||||
} else if (tsec_fw_size == 0) {
|
} else if (tsec_fw_size == 0) {
|
||||||
printf("Error: Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
|
fatal_error("Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tsec_fw = memalign(0x100, tsec_fw_size);
|
tsec_fw = memalign(0x100, tsec_fw_size);
|
||||||
if (tsec_fw == NULL) {
|
if (tsec_fw == NULL) {
|
||||||
printf("Error: nxboot_main: out of memory!\n");
|
fatal_error("nxboot_main: out of memory!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
if (read_from_file(tsec_fw, tsec_fw_size, loader_ctx->tsecfw_path) != tsec_fw_size) {
|
if (read_from_file(tsec_fw, tsec_fw_size, loader_ctx->tsecfw_path) != tsec_fw_size) {
|
||||||
printf("Error: Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
|
fatal_error("Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tsec_fw_size = package1_get_tsec_fw(&tsec_fw, package1loader, package1loader_size);
|
tsec_fw_size = package1_get_tsec_fw(&tsec_fw, package1loader, package1loader_size);
|
||||||
if (tsec_fw_size == 0) {
|
if (tsec_fw_size == 0) {
|
||||||
printf("Error: Failed to read the TSEC firmware from Package1loader!\n");
|
fatal_error("Failed to read the TSEC firmware from Package1loader!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,26 +154,22 @@ void nxboot_main(void) {
|
|||||||
|
|
||||||
/* Derive keydata. */
|
/* Derive keydata. */
|
||||||
if (derive_nx_keydata(MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware, g_keyblobs, available_revision, tsec_fw, tsec_fw_size) != 0) {
|
if (derive_nx_keydata(MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware, g_keyblobs, available_revision, tsec_fw, tsec_fw_size) != 0) {
|
||||||
printf("Error: Key derivation failed!\n");
|
fatal_error("Key derivation failed!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the warmboot firmware from a file, otherwise from PK1. */
|
/* Read the warmboot firmware from a file, otherwise from PK1. */
|
||||||
if (loader_ctx->warmboot_path[0] != '\0') {
|
if (loader_ctx->warmboot_path[0] != '\0') {
|
||||||
warmboot_fw_size = get_file_size(loader_ctx->warmboot_path);
|
warmboot_fw_size = get_file_size(loader_ctx->warmboot_path);
|
||||||
if (warmboot_fw_size == 0) {
|
if (warmboot_fw_size == 0) {
|
||||||
printf("Error: Could not read the warmboot firmware from %s!\n", loader_ctx->warmboot_path);
|
fatal_error("Could not read the warmboot firmware from %s!\n", loader_ctx->warmboot_path);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
warmboot_fw = malloc(warmboot_fw_size);
|
warmboot_fw = malloc(warmboot_fw_size);
|
||||||
if (warmboot_fw == NULL) {
|
if (warmboot_fw == NULL) {
|
||||||
printf("Error: nxboot_main: out of memory!\n");
|
fatal_error("nxboot_main: out of memory!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
if (read_from_file(warmboot_fw, warmboot_fw_size, loader_ctx->warmboot_path) != warmboot_fw_size) {
|
if (read_from_file(warmboot_fw, warmboot_fw_size, loader_ctx->warmboot_path) != warmboot_fw_size) {
|
||||||
printf("Error: Could not read the warmboot firmware from %s!\n", loader_ctx->warmboot_path);
|
fatal_error("Could not read the warmboot firmware from %s!\n", loader_ctx->warmboot_path);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uint8_t ctr[16];
|
uint8_t ctr[16];
|
||||||
@ -201,8 +183,7 @@ void nxboot_main(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (warmboot_fw_size == 0) {
|
if (warmboot_fw_size == 0) {
|
||||||
printf("Error: Could not read the warmboot firmware from Package1!\n");
|
fatal_error("Could not read the warmboot firmware from Package1!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,17 +202,14 @@ void nxboot_main(void) {
|
|||||||
if (loader_ctx->exosphere_path[0] != '\0') {
|
if (loader_ctx->exosphere_path[0] != '\0') {
|
||||||
size_t exosphere_size = get_file_size(loader_ctx->exosphere_path);
|
size_t exosphere_size = get_file_size(loader_ctx->exosphere_path);
|
||||||
if (exosphere_size == 0) {
|
if (exosphere_size == 0) {
|
||||||
printf(u8"Error: Could not read Exosphère from %s!\n", loader_ctx->exosphere_path);
|
fatal_error(u8"Error: Could not read Exosphère from %s!\n", loader_ctx->exosphere_path);
|
||||||
generic_panic();
|
|
||||||
} else if (exosphere_size > 0x10000) {
|
} else if (exosphere_size > 0x10000) {
|
||||||
/* The maximum is actually a bit less than that. */
|
/* The maximum is actually a bit less than that. */
|
||||||
printf(u8"Error: Exosphère from %s is too big!\n", loader_ctx->exosphere_path);
|
fatal_error(u8"Error: Exosphère from %s is too big!\n", loader_ctx->exosphere_path);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_from_file(exosphere_memaddr, exosphere_size, loader_ctx->exosphere_path) != exosphere_size) {
|
if (read_from_file(exosphere_memaddr, exosphere_size, loader_ctx->exosphere_path) != exosphere_size) {
|
||||||
printf(u8"Error: Could not read Exosphère from %s!\n", loader_ctx->exosphere_path);
|
fatal_error(u8"Error: Could not read Exosphère from %s!\n", loader_ctx->exosphere_path);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memcpy(exosphere_memaddr, exosphere_bin, exosphere_bin_size);
|
memcpy(exosphere_memaddr, exosphere_bin, exosphere_bin_size);
|
||||||
|
@ -39,8 +39,7 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
|
|||||||
thermosphere_size = package2_get_thermosphere(&thermosphere);
|
thermosphere_size = package2_get_thermosphere(&thermosphere);
|
||||||
|
|
||||||
if (thermosphere_size != 0 && package2->metadata.section_sizes[PACKAGE2_SECTION_UNUSED] != 0) {
|
if (thermosphere_size != 0 && package2->metadata.section_sizes[PACKAGE2_SECTION_UNUSED] != 0) {
|
||||||
printf(u8"Error: Package2 has no unused section for Thermosphère!\n");
|
fatal_error(u8"Error: Package2 has no unused section for Thermosphère!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform any patches we want to the NX kernel. */
|
/* Perform any patches we want to the NX kernel. */
|
||||||
@ -56,14 +55,12 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
|
|||||||
rebuilt_package2_size += package2->metadata.section_sizes[PACKAGE2_SECTION_KERNEL] + thermosphere_size + rebuilt_ini1->size;
|
rebuilt_package2_size += package2->metadata.section_sizes[PACKAGE2_SECTION_KERNEL] + thermosphere_size + rebuilt_ini1->size;
|
||||||
|
|
||||||
if (rebuilt_package2_size > PACKAGE2_SIZE_MAX) {
|
if (rebuilt_package2_size > PACKAGE2_SIZE_MAX) {
|
||||||
printf("Error: rebuilt package2 is too big!\n");
|
fatal_error("rebuilt package2 is too big!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rebuilt_package2 = (package2_header_t *)malloc(rebuilt_package2_size);
|
rebuilt_package2 = (package2_header_t *)malloc(rebuilt_package2_size);
|
||||||
if (rebuilt_package2 == NULL) {
|
if (rebuilt_package2 == NULL) {
|
||||||
printf("Error: package2_rebuild: out of memory!\n");
|
fatal_error("package2_rebuild: out of memory!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rebuild package2. */
|
/* Rebuild package2. */
|
||||||
@ -205,12 +202,10 @@ static uint32_t package2_decrypt_and_validate_header(package2_header_t *header,
|
|||||||
|
|
||||||
/* Ensure we successfully decrypted the header. */
|
/* Ensure we successfully decrypted the header. */
|
||||||
if (mkey_rev > mkey_get_revision()) {
|
if (mkey_rev > mkey_get_revision()) {
|
||||||
printf("Error: failed to decrypt the Package2 header (master key revision %u)!\n", mkey_get_revision());
|
fatal_error("failed to decrypt the Package2 header (master key revision %u)!\n", mkey_get_revision());
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
} else if (!package2_validate_metadata(&header->metadata)) {
|
} else if (!package2_validate_metadata(&header->metadata)) {
|
||||||
printf("Error: Failed to validate the Package2 header!\n");
|
fatal_error("Failed to validate the Package2 header!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,7 @@ void display_splash_screen_bmp(const char *custom_splash_path) {
|
|||||||
uint8_t *splash_screen = g_default_splash_screen;
|
uint8_t *splash_screen = g_default_splash_screen;
|
||||||
if (custom_splash_path != NULL && custom_splash_path[0] != '\x00') {
|
if (custom_splash_path != NULL && custom_splash_path[0] != '\x00') {
|
||||||
if (!read_from_file(splash_screen, sizeof(g_default_splash_screen), custom_splash_path)) {
|
if (!read_from_file(splash_screen, sizeof(g_default_splash_screen), custom_splash_path)) {
|
||||||
printf("Error: Failed to read custom splash screen from %s!\n", custom_splash_path);
|
fatal_error("Failed to read custom splash screen from %s!\n", custom_splash_path);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,8 +47,7 @@ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) {
|
|||||||
g_stratosphere_ini1 = (ini1_header_t *)malloc(size);
|
g_stratosphere_ini1 = (ini1_header_t *)malloc(size);
|
||||||
|
|
||||||
if (g_stratosphere_ini1 != NULL) {
|
if (g_stratosphere_ini1 != NULL) {
|
||||||
printf("Error: stratosphere_get_ini1: out of memory!\n");
|
fatal_error("stratosphere_get_ini1: out of memory!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_stratosphere_ini1->magic = MAGIC_INI1;
|
g_stratosphere_ini1->magic = MAGIC_INI1;
|
||||||
@ -87,24 +86,21 @@ ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) {
|
|||||||
/* Validate all ini headers. */
|
/* Validate all ini headers. */
|
||||||
for (size_t i = 0; i < num_inis; i++) {
|
for (size_t i = 0; i < num_inis; i++) {
|
||||||
if (inis[i] == NULL || inis[i]->magic != MAGIC_INI1 || inis[i]->num_processes > INI1_MAX_KIPS) {
|
if (inis[i] == NULL || inis[i]->magic != MAGIC_INI1 || inis[i]->num_processes > INI1_MAX_KIPS) {
|
||||||
printf("Error: INI1s[%d] section appears to not contain an INI1!\n", i);
|
fatal_error("INI1s[%d] section appears to not contain an INI1!\n", i);
|
||||||
generic_panic();
|
|
||||||
} else {
|
} else {
|
||||||
total_num_processes += inis[i]->num_processes;
|
total_num_processes += inis[i]->num_processes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (total_num_processes > INI1_MAX_KIPS) {
|
if (total_num_processes > INI1_MAX_KIPS) {
|
||||||
printf("Error: The resulting INI1 would have too many KIPs!\n");
|
fatal_error("The resulting INI1 would have too many KIPs!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t process_list[INI1_MAX_KIPS] = {0};
|
uint64_t process_list[INI1_MAX_KIPS] = {0};
|
||||||
ini1_header_t *merged = (ini1_header_t *)malloc(PACKAGE2_SIZE_MAX); /* because of SD file overrides */
|
ini1_header_t *merged = (ini1_header_t *)malloc(PACKAGE2_SIZE_MAX); /* because of SD file overrides */
|
||||||
|
|
||||||
if (merged == NULL) {
|
if (merged == NULL) {
|
||||||
printf("Error: stratosphere_merge_inis: out of memory!\n");
|
fatal_error("stratosphere_merge_inis: out of memory!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
merged->magic = MAGIC_INI1;
|
merged->magic = MAGIC_INI1;
|
||||||
@ -121,8 +117,7 @@ ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) {
|
|||||||
for (size_t p = 0; p < (size_t)inis[i]->num_processes; p++) {
|
for (size_t p = 0; p < (size_t)inis[i]->num_processes; p++) {
|
||||||
kip1_header_t *current_kip = (kip1_header_t *)(inis[i]->kip_data + offset);
|
kip1_header_t *current_kip = (kip1_header_t *)(inis[i]->kip_data + offset);
|
||||||
if (current_kip->magic != MAGIC_KIP1) {
|
if (current_kip->magic != MAGIC_KIP1) {
|
||||||
printf("Error: INI1s[%zu][%zu] appears not to be a KIP1!\n", i, p);
|
fatal_error("INI1s[%zu][%zu] appears not to be a KIP1!\n", i, p);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool already_loaded = false;
|
bool already_loaded = false;
|
||||||
@ -144,11 +139,9 @@ ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) {
|
|||||||
if (read_size != 0) {
|
if (read_size != 0) {
|
||||||
kip1_header_t *sd_kip = (kip1_header_t *)(current_dst_kip);
|
kip1_header_t *sd_kip = (kip1_header_t *)(current_dst_kip);
|
||||||
if (read_size < sizeof(kip1_header_t) || sd_kip->magic != MAGIC_KIP1) {
|
if (read_size < sizeof(kip1_header_t) || sd_kip->magic != MAGIC_KIP1) {
|
||||||
printf("Error: %s is not a KIP1?\n", sd_path);
|
fatal_error("%s is not a KIP1?\n", sd_path);
|
||||||
generic_panic();
|
|
||||||
} else if (sd_kip->title_id != current_kip->title_id) {
|
} else if (sd_kip->title_id != current_kip->title_id) {
|
||||||
printf("Error: %s has wrong Title ID!\n", sd_path);
|
fatal_error("%s has wrong Title ID!\n", sd_path);
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
size_t expected_sd_kip_size = kip1_get_size_from_header(sd_kip);
|
size_t expected_sd_kip_size = kip1_get_size_from_header(sd_kip);
|
||||||
if (expected_sd_kip_size != read_size) {
|
if (expected_sd_kip_size != read_size) {
|
||||||
@ -161,8 +154,7 @@ ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) {
|
|||||||
} else {
|
} else {
|
||||||
size_t current_kip_size = kip1_get_size_from_header(current_kip);
|
size_t current_kip_size = kip1_get_size_from_header(current_kip);
|
||||||
if (current_kip_size > remaining_size) {
|
if (current_kip_size > remaining_size) {
|
||||||
printf("Error: Not enough space for all the KIP1s!\n");
|
fatal_error("Not enough space for all the KIP1s!\n");
|
||||||
generic_panic();
|
|
||||||
}
|
}
|
||||||
memcpy(current_dst_kip, current_kip, current_kip_size);
|
memcpy(current_dst_kip, current_kip, current_kip_size);
|
||||||
remaining_size -= current_kip_size;
|
remaining_size -= current_kip_size;
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "se.h"
|
#include "se.h"
|
||||||
#include "fuse.h"
|
#include "fuse.h"
|
||||||
#include "pmc.h"
|
#include "pmc.h"
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
#include "hwinit/btn.h"
|
#include "hwinit/btn.h"
|
||||||
|
#include "panic.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
@ -46,8 +48,19 @@ __attribute__((noreturn)) void wait_for_button_and_pmc_reboot(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
__attribute__ ((noreturn)) void generic_panic(void) {
|
__attribute__ ((noreturn)) void generic_panic(void) {
|
||||||
while(true);//panic(0xFF000006);
|
panic(0xFF000006);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
printf("Fatal error: ");
|
||||||
|
va_start(args, fmt);
|
||||||
|
vprintf(fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
printf("\n Press POWER to reboot into RCM, VOL+/VOL- to reboot normally.\n");
|
||||||
|
wait_for_button_and_pmc_reboot();
|
||||||
|
}
|
||||||
|
|
||||||
__attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be)
|
__attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be)
|
||||||
{
|
{
|
||||||
if(as <= bs && bs <= ae)
|
if(as <= bs && bs <= ae)
|
||||||
|
@ -108,6 +108,9 @@ __attribute__((noreturn)) void watchdog_reboot(void);
|
|||||||
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0);
|
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0);
|
||||||
__attribute__((noreturn)) void wait_for_button_and_pmc_reboot(void);
|
__attribute__((noreturn)) void wait_for_button_and_pmc_reboot(void);
|
||||||
|
|
||||||
void generic_panic(void);
|
__attribute__((noreturn)) void generic_panic(void);
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void fatal_error(const char *fmt, ...);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user