2018-05-05 21:55:40 +00:00
|
|
|
#include <stdio.h>
|
2018-05-10 21:48:41 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include "sdmmc.h"
|
|
|
|
#include "raw_mmc_dev.h"
|
2018-04-09 21:34:23 +00:00
|
|
|
#include "utils.h"
|
|
|
|
#include "nxboot.h"
|
2018-04-10 22:37:58 +00:00
|
|
|
#include "key_derivation.h"
|
2018-05-10 21:48:41 +00:00
|
|
|
#include "gpt.h"
|
|
|
|
#include "package1.h"
|
2018-04-12 00:19:01 +00:00
|
|
|
#include "package2.h"
|
2018-04-10 22:09:00 +00:00
|
|
|
#include "loader.h"
|
|
|
|
#include "splash_screen.h"
|
2018-04-10 22:37:58 +00:00
|
|
|
#include "exocfg.h"
|
|
|
|
#include "display/video_fb.h"
|
|
|
|
#include "lib/ini.h"
|
|
|
|
#include "hwinit/cluster.h"
|
|
|
|
|
|
|
|
static int exosphere_ini_handler(void *user, const char *section, const char *name, const char *value) {
|
|
|
|
exosphere_config_t *exo_cfg = (exosphere_config_t *)user;
|
|
|
|
if (strcmp(section, "exosphere") == 0) {
|
|
|
|
if (strcmp(name, EXOSPHERE_TARGETFW_KEY) == 0) {
|
|
|
|
sscanf(value, "%d", &exo_cfg->target_firmware);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nxboot_configure_exosphere(void) {
|
|
|
|
exosphere_config_t exo_cfg = {0};
|
2018-05-05 21:55:40 +00:00
|
|
|
|
2018-04-10 22:37:58 +00:00
|
|
|
exo_cfg.magic = MAGIC_EXOSPHERE_BOOTCONFIG;
|
|
|
|
exo_cfg.target_firmware = EXOSPHERE_TARGET_FIRMWARE_MAX;
|
2018-05-05 21:55:40 +00:00
|
|
|
|
2018-04-10 22:37:58 +00:00
|
|
|
if (ini_parse_string(get_loader_ctx()->bct0, exosphere_ini_handler, &exo_cfg) < 0) {
|
2018-05-05 21:55:40 +00:00
|
|
|
printf("Error: Failed to parse BCT.ini!\n");
|
2018-04-10 22:37:58 +00:00
|
|
|
generic_panic();
|
|
|
|
}
|
2018-05-05 21:55:40 +00:00
|
|
|
|
2018-04-10 22:37:58 +00:00
|
|
|
if (exo_cfg.target_firmware < EXOSPHERE_TARGET_FIRMWARE_MIN || exo_cfg.target_firmware > EXOSPHERE_TARGET_FIRMWARE_MAX) {
|
2018-05-05 21:55:40 +00:00
|
|
|
printf("Error: Invalid Exosphere target firmware!\n");
|
2018-04-10 22:37:58 +00:00
|
|
|
generic_panic();
|
|
|
|
}
|
2018-05-05 21:55:40 +00:00
|
|
|
|
2018-04-10 22:37:58 +00:00
|
|
|
*(MAILBOX_EXOSPHERE_CONFIGURATION) = exo_cfg;
|
|
|
|
}
|
2018-04-09 21:34:23 +00:00
|
|
|
|
2018-05-10 21:48:41 +00:00
|
|
|
static struct mmc nand_mmc; /* TODO: Remove, move it elsewhere and actually initalize the controller!! */
|
|
|
|
|
|
|
|
static int init_rawnand_and_boot0_devices(void) {
|
|
|
|
if (rawmmcdev_mount_unencrypted_device("rawnand", &nand_mmc, SDMMC_PARTITION_USER, 0, 32ull<<30) == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (rawmmcdev_mount_unencrypted_device("boot0", &nand_mmc, SDMMC_PARTITION_BOOT0, 0, 0x184000) == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool g_bcpkg2_initialized = false;
|
|
|
|
static int bcpkg2_finder_callback(const efi_entry_t *entry, size_t entry_offset, FILE *disk) {
|
|
|
|
/* TODO: what about backup partitions? */
|
|
|
|
static const uint16_t part_name[] = u"BCPKG2-1-Normal-Main";
|
|
|
|
if (memcmp(entry->name, part_name, sizeof(part_name)) == 0) {
|
|
|
|
uint64_t part_offset = 512 * entry->first_lba;
|
|
|
|
uint64_t part_size = 512 * (entry->last_lba - entry->first_lba);
|
|
|
|
|
|
|
|
int rc = rawmmcdev_mount_unencrypted_device("bcpkg2", &nand_mmc, SDMMC_PARTITION_USER, part_offset, part_size);
|
|
|
|
|
|
|
|
g_bcpkg2_initialized = rc == 0;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find BCPKG2-1-Normal-Main using the GPT, then register it. */
|
|
|
|
static int init_bcpkg2_device(void) {
|
|
|
|
FILE *rawnand = fopen("rawnand:/", "rb");
|
|
|
|
int rc;
|
|
|
|
if (rawnand == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = gpt_iterate_through_entries(rawnand, bcpkg2_finder_callback);
|
|
|
|
fclose(rawnand);
|
|
|
|
|
|
|
|
if (rc == 0 && !g_bcpkg2_initialized) {
|
|
|
|
errno = ENOENT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-04-09 21:34:23 +00:00
|
|
|
/* This is the main function responsible for booting Horizon. */
|
|
|
|
void nxboot_main(void) {
|
2018-04-10 22:09:00 +00:00
|
|
|
loader_ctx_t *loader_ctx = get_loader_ctx();
|
2018-05-05 21:55:40 +00:00
|
|
|
|
2018-05-10 21:48:41 +00:00
|
|
|
/* TODO: this is not always necessary */
|
|
|
|
if (init_rawnand_and_boot0_devices()) {
|
|
|
|
printf("Error: Failed to mount rawnand and/or boot0: %s!\n", strerror(errno));
|
|
|
|
generic_panic();
|
|
|
|
}
|
2018-04-10 22:37:58 +00:00
|
|
|
/* TODO: Validate that we're capable of booting. */
|
2018-05-05 21:55:40 +00:00
|
|
|
|
2018-04-10 22:37:58 +00:00
|
|
|
/* TODO: Initialize Boot Reason. */
|
2018-05-05 21:55:40 +00:00
|
|
|
|
2018-04-10 22:37:58 +00:00
|
|
|
/* TODO: How should we deal with bootconfig? */
|
2018-05-05 21:55:40 +00:00
|
|
|
|
2018-04-10 22:37:58 +00:00
|
|
|
/* Setup boot configuration for Exosphere. */
|
|
|
|
nxboot_configure_exosphere();
|
2018-05-05 21:55:40 +00:00
|
|
|
|
2018-04-10 22:37:58 +00:00
|
|
|
/* Derive keydata. */
|
|
|
|
derive_nx_keydata(MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware);
|
2018-05-05 21:55:40 +00:00
|
|
|
|
2018-05-10 21:48:41 +00:00
|
|
|
if (loader_ctx->package2_loadfile.load_address == 0) {
|
|
|
|
if (init_bcpkg2_device() == -1) {
|
|
|
|
printf("Error: Failed to mount BCPKG2-1-Normal-Main: %s!\n", strerror(errno));
|
|
|
|
generic_panic();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: read package2 somewhere. */
|
|
|
|
}
|
|
|
|
|
2018-04-12 00:19:01 +00:00
|
|
|
/* Patch package2, adding thermosphere + custom KIPs. */
|
2018-05-08 22:19:51 +00:00
|
|
|
package2_rebuild_and_copy((void *)loader_ctx->package2_loadfile.load_address);
|
2018-05-05 21:55:40 +00:00
|
|
|
|
2018-04-10 22:37:58 +00:00
|
|
|
/* Boot up Exosphere. */
|
|
|
|
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE = 0;
|
2018-05-05 21:55:40 +00:00
|
|
|
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware <= EXOSPHERE_TARGET_FIRMWARE_400) {
|
2018-04-10 22:37:58 +00:00
|
|
|
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_LOADED_PACKAGE2;
|
|
|
|
} else {
|
|
|
|
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_LOADED_PACKAGE2_4X;
|
|
|
|
}
|
2018-05-04 17:47:05 +00:00
|
|
|
cluster_enable_cpu0(loader_ctx->exosphere_loadfile.load_address, 1);
|
2018-04-10 22:37:58 +00:00
|
|
|
while (MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE == 0) {
|
|
|
|
/* Wait for Exosphere to wake up. */
|
|
|
|
}
|
2018-05-05 21:55:40 +00:00
|
|
|
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware <= EXOSPHERE_TARGET_FIRMWARE_400) {
|
2018-04-10 22:37:58 +00:00
|
|
|
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_FINISHED;
|
|
|
|
} else {
|
|
|
|
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_FINISHED_4X;
|
|
|
|
}
|
2018-05-05 21:55:40 +00:00
|
|
|
|
2018-04-10 22:09:00 +00:00
|
|
|
/* Display splash screen. */
|
|
|
|
display_splash_screen_bmp(loader_ctx->custom_splash_path);
|
2018-05-05 21:55:40 +00:00
|
|
|
|
2018-05-10 21:48:41 +00:00
|
|
|
rawmmcdev_unmount_all();
|
|
|
|
|
2018-04-10 22:37:58 +00:00
|
|
|
/* TODO: Halt ourselves. */
|
2018-05-05 21:55:40 +00:00
|
|
|
}
|