mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
sept: update to support 8.1.0
This commit is contained in:
parent
c96ae0148e
commit
befd912a88
20 changed files with 218 additions and 140 deletions
|
@ -13,7 +13,7 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ATMOSPHERE_TARGET_FIRMWARE_H
|
#ifndef ATMOSPHERE_TARGET_FIRMWARE_H
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_H
|
#define ATMOSPHERE_TARGET_FIRMWARE_H
|
||||||
|
|
||||||
|
@ -26,11 +26,12 @@
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_620 7
|
#define ATMOSPHERE_TARGET_FIRMWARE_620 7
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_700 8
|
#define ATMOSPHERE_TARGET_FIRMWARE_700 8
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_800 9
|
#define ATMOSPHERE_TARGET_FIRMWARE_800 9
|
||||||
|
#define ATMOSPHERE_TARGET_FIRMWARE_810 10
|
||||||
|
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_800
|
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_810
|
||||||
|
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100
|
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_800
|
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_810
|
||||||
|
|
||||||
/* TODO: What should this be, for release? */
|
/* TODO: What should this be, for release? */
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG ATMOSPHERE_TARGET_FIRMWARE_CURRENT
|
#define ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG ATMOSPHERE_TARGET_FIRMWARE_CURRENT
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
@ -34,13 +34,13 @@ unsigned int exosphere_load_config(void) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
g_has_loaded_config = true;
|
g_has_loaded_config = true;
|
||||||
|
|
||||||
const unsigned int magic = MAILBOX_EXOSPHERE_CONFIG.magic;
|
const unsigned int magic = MAILBOX_EXOSPHERE_CONFIG.magic;
|
||||||
|
|
||||||
if (magic == MAGIC_EXOSPHERE_CONFIG) {
|
if (magic == MAGIC_EXOSPHERE_CONFIG) {
|
||||||
g_exosphere_cfg = MAILBOX_EXOSPHERE_CONFIG;
|
g_exosphere_cfg = MAILBOX_EXOSPHERE_CONFIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_exosphere_cfg.target_firmware;
|
return g_exosphere_cfg.target_firmware;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ unsigned int exosphere_get_target_firmware(void) {
|
||||||
if (!g_has_loaded_config) {
|
if (!g_has_loaded_config) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_exosphere_cfg.target_firmware;
|
return g_exosphere_cfg.target_firmware;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,15 +56,15 @@ unsigned int exosphere_should_perform_620_keygen(void) {
|
||||||
if (!g_has_loaded_config) {
|
if (!g_has_loaded_config) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_exosphere_cfg.target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_620 && EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_PERFORM_620_KEYGEN);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int exosphere_should_override_debugmode_priv(void) {
|
unsigned int exosphere_should_override_debugmode_priv(void) {
|
||||||
if (!g_has_loaded_config) {
|
if (!g_has_loaded_config) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV);
|
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ unsigned int exosphere_should_override_debugmode_user(void) {
|
||||||
if (!g_has_loaded_config) {
|
if (!g_has_loaded_config) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_USER);
|
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_USER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ unsigned int exosphere_should_disable_usermode_exception_handlers(void) {
|
||||||
if (!g_has_loaded_config) {
|
if (!g_has_loaded_config) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS);
|
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef EXOSPHERE_EXOSPHERE_CONFIG_H
|
#ifndef EXOSPHERE_EXOSPHERE_CONFIG_H
|
||||||
#define EXOSPHERE_EXOSPHERE_CONFIG_H
|
#define EXOSPHERE_EXOSPHERE_CONFIG_H
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
/* Exosphere config in DRAM shares physical/virtual mapping. */
|
/* Exosphere config in DRAM shares physical/virtual mapping. */
|
||||||
#define MAILBOX_EXOSPHERE_CONFIG_PHYS MAILBOX_EXOSPHERE_CONFIG
|
#define MAILBOX_EXOSPHERE_CONFIG_PHYS MAILBOX_EXOSPHERE_CONFIG
|
||||||
|
|
||||||
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN (1 << 0u)
|
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN_DEPRECATED (1 << 0u)
|
||||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
|
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
|
||||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
|
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
|
||||||
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
|
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
|
||||||
|
|
|
@ -99,7 +99,7 @@ SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
KIPFILES := loader.kip pm.kip sm.kip ams_mitm.kip spl.kip boot.kip
|
KIPFILES := loader.kip pm.kip sm.kip ams_mitm.kip spl.kip boot.kip
|
||||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee-primary.bin \
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee-primary.bin \
|
||||||
exosphere.bin lp0fw.bin rebootstub.bin thermosphere.bin splash_screen.bmp \
|
exosphere.bin lp0fw.bin rebootstub.bin thermosphere.bin splash_screen.bmp \
|
||||||
sept-primary.bin sept-secondary.enc emummc.kip \
|
sept-primary.bin sept-secondary_00.enc sept-secondary_01.enc emummc.kip \
|
||||||
$(KIPFILES)
|
$(KIPFILES)
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
|
@ -198,22 +198,27 @@ fusee_primary.bin.o fusee_primary_bin.h: fusee-primary.bin
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
@echo $(notdir $<)
|
@echo $(notdir $<)
|
||||||
@$(_bin2o)
|
@$(_bin2o)
|
||||||
|
|
||||||
sept_primary.bin.o sept_primary_bin.h: sept-primary.bin
|
sept_primary.bin.o sept_primary_bin.h: sept-primary.bin
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
@echo $(notdir $<)
|
@echo $(notdir $<)
|
||||||
@$(_bin2o)
|
@$(_bin2o)
|
||||||
|
|
||||||
sept_secondary.enc.o sept_secondary_enc.h: sept-secondary.enc
|
sept_secondary_00.enc.o sept_secondary_00.h: sept-secondary_00.enc
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
@echo $(notdir $<)
|
@echo $(notdir $<)
|
||||||
@$(_bin2o)
|
@$(_bin2o)
|
||||||
|
|
||||||
|
sept_secondary_01.enc.o sept_secondary_01_enc.h: sept-secondary_01.enc
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(_bin2o)
|
||||||
|
|
||||||
%.bin.o %_bin.h: %.bin
|
%.bin.o %_bin.h: %.bin
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
@echo $(notdir $<)
|
@echo $(notdir $<)
|
||||||
@$(bin2o)
|
@$(bin2o)
|
||||||
|
|
||||||
%.bmp.o %_bmp.h: %.bmp
|
%.bmp.o %_bmp.h: %.bmp
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
@echo $(notdir $<)
|
@echo $(notdir $<)
|
||||||
|
|
|
@ -55,7 +55,7 @@ SECTIONS
|
||||||
. = ALIGN(32);
|
. = ALIGN(32);
|
||||||
PROVIDE (__chainloader_end__ = ABSOLUTE(.));
|
PROVIDE (__chainloader_end__ = ABSOLUTE(.));
|
||||||
} >low_iram :NONE
|
} >low_iram :NONE
|
||||||
|
|
||||||
.nxboot_loadable :
|
.nxboot_loadable :
|
||||||
{
|
{
|
||||||
. = ALIGN(32);
|
. = ALIGN(32);
|
||||||
|
@ -157,7 +157,7 @@ SECTIONS
|
||||||
CONSTRUCTORS
|
CONSTRUCTORS
|
||||||
. = ALIGN(32);
|
. = ALIGN(32);
|
||||||
} >main
|
} >main
|
||||||
|
|
||||||
__data_end__ = ABSOLUTE(.);
|
__data_end__ = ABSOLUTE(.);
|
||||||
PROVIDE (__total_size__ = (__data_end__ - __start__));
|
PROVIDE (__total_size__ = (__data_end__ - __start__));
|
||||||
|
|
||||||
|
@ -236,8 +236,10 @@ SECTIONS
|
||||||
PROVIDE(__rebootstub_bin_size__ = rebootstub_bin_end - rebootstub_bin);
|
PROVIDE(__rebootstub_bin_size__ = rebootstub_bin_end - rebootstub_bin);
|
||||||
PROVIDE(__sept_primary_bin_start__ = sept_primary_bin - __start__);
|
PROVIDE(__sept_primary_bin_start__ = sept_primary_bin - __start__);
|
||||||
PROVIDE(__sept_primary_bin_size__ = sept_primary_bin_end - sept_primary_bin);
|
PROVIDE(__sept_primary_bin_size__ = sept_primary_bin_end - sept_primary_bin);
|
||||||
PROVIDE(__sept_secondary_enc_start__ = sept_secondary_enc - __start__);
|
PROVIDE(__sept_secondary_00_enc_start__ = sept_secondary_00_enc - __start__);
|
||||||
PROVIDE(__sept_secondary_enc_size__ = sept_secondary_enc_end - sept_secondary_enc);
|
PROVIDE(__sept_secondary_00_enc_size__ = sept_secondary_00_enc_end - sept_secondary_00_enc);
|
||||||
|
PROVIDE(__sept_secondary_01_enc_start__ = sept_secondary_01_enc - __start__);
|
||||||
|
PROVIDE(__sept_secondary_01_enc_size__ = sept_secondary_01_enc_end - sept_secondary_01_enc);
|
||||||
PROVIDE(__sm_kip_start__ = sm_kip - __start__);
|
PROVIDE(__sm_kip_start__ = sm_kip - __start__);
|
||||||
PROVIDE(__sm_kip_size__ = sm_kip_end - sm_kip);
|
PROVIDE(__sm_kip_size__ = sm_kip_end - sm_kip);
|
||||||
PROVIDE(__spl_kip_start__ = spl_kip - __start__);
|
PROVIDE(__spl_kip_start__ = spl_kip - __start__);
|
||||||
|
|
|
@ -54,7 +54,8 @@ static const uint8_t AL16 masterkey_4x_seed[0x10] = {
|
||||||
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
|
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t AL16 new_master_kek_seeds[MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_600_610][0x10] = {
|
/* TODO: Bother adding 8.1.0 here? We'll never call into here... */
|
||||||
|
static const uint8_t AL16 new_master_kek_seeds[MASTERKEY_REVISION_700_800 - MASTERKEY_REVISION_600_610][0x10] = {
|
||||||
{0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, /* MasterKek seed 06. */
|
{0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, /* MasterKek seed 06. */
|
||||||
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, /* MasterKek seed 07. */
|
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, /* MasterKek seed 07. */
|
||||||
};
|
};
|
||||||
|
@ -93,17 +94,17 @@ static int decrypt_keyblob(const nx_keyblob_t *keyblobs, uint32_t revision, uint
|
||||||
if (get_keyblob(&keyblob, revision, keyblobs, available_revision) != 0) {
|
if (get_keyblob(&keyblob, revision, keyblobs, available_revision) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seeds[revision], 0x10);
|
se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seeds[revision], 0x10);
|
||||||
decrypt_data_into_keyslot(keyslot, 0xE, work_buffer, 0x10);
|
decrypt_data_into_keyslot(keyslot, 0xE, work_buffer, 0x10);
|
||||||
decrypt_data_into_keyslot(0xB, keyslot, keyblob_mac_seed, 0x10);
|
decrypt_data_into_keyslot(0xB, keyslot, keyblob_mac_seed, 0x10);
|
||||||
|
|
||||||
/* Validate keyblob. */
|
/* Validate keyblob. */
|
||||||
se_compute_aes_128_cmac(0xB, work_buffer, 0x10, keyblob.mac + sizeof(keyblob.mac), sizeof(keyblob) - sizeof(keyblob.mac));
|
se_compute_aes_128_cmac(0xB, work_buffer, 0x10, keyblob.mac + sizeof(keyblob.mac), sizeof(keyblob) - sizeof(keyblob.mac));
|
||||||
if (safe_memcmp(keyblob.mac, work_buffer, 0x10)) {
|
if (safe_memcmp(keyblob.mac, work_buffer, 0x10)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decrypt keyblob. */
|
/* Decrypt keyblob. */
|
||||||
se_aes_ctr_crypt(keyslot, &g_dec_keyblobs[revision], sizeof(g_dec_keyblobs[revision]), keyblob.data, sizeof(keyblob.data), keyblob.ctr, sizeof(keyblob.ctr));
|
se_aes_ctr_crypt(keyslot, &g_dec_keyblobs[revision], sizeof(g_dec_keyblobs[revision]), keyblob.data, sizeof(keyblob.data), keyblob.ctr, sizeof(keyblob.ctr));
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -113,7 +114,7 @@ int load_package1_key(uint32_t revision) {
|
||||||
if (revision > MASTERKEY_REVISION_600_610) {
|
if (revision > MASTERKEY_REVISION_600_610) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_aes_keyslot(0xB, g_dec_keyblobs[revision].package1_key, 0x10);
|
set_aes_keyslot(0xB, g_dec_keyblobs[revision].package1_key, 0x10);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -122,17 +123,17 @@ int load_package1_key(uint32_t revision) {
|
||||||
int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_key, void *tsec_root_keys, unsigned int *out_keygen_type) {
|
int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_key, void *tsec_root_keys, unsigned int *out_keygen_type) {
|
||||||
uint8_t AL16 work_buffer[0x10];
|
uint8_t AL16 work_buffer[0x10];
|
||||||
uint8_t AL16 zeroes[0x10] = {0};
|
uint8_t AL16 zeroes[0x10] = {0};
|
||||||
|
|
||||||
/* Initialize keygen type. */
|
/* Initialize keygen type. */
|
||||||
*out_keygen_type = 0;
|
*out_keygen_type = 0;
|
||||||
|
|
||||||
/* TODO: Set keyslot flags properly in preparation of derivation. */
|
/* TODO: Set keyslot flags properly in preparation of derivation. */
|
||||||
set_aes_keyslot_flags(0xE, 0x15);
|
set_aes_keyslot_flags(0xE, 0x15);
|
||||||
set_aes_keyslot_flags(0xD, 0x15);
|
set_aes_keyslot_flags(0xD, 0x15);
|
||||||
|
|
||||||
/* Set the TSEC key. */
|
/* Set the TSEC key. */
|
||||||
set_aes_keyslot(0xD, tsec_key, 0x10);
|
set_aes_keyslot(0xD, tsec_key, 0x10);
|
||||||
|
|
||||||
/* Decrypt all keyblobs, setting keyslot 0xF correctly. */
|
/* Decrypt all keyblobs, setting keyslot 0xF correctly. */
|
||||||
for (unsigned int rev = 0; rev <= MASTERKEY_REVISION_600_610; rev++) {
|
for (unsigned int rev = 0; rev <= MASTERKEY_REVISION_600_610; rev++) {
|
||||||
int ret = decrypt_keyblob(keyblobs, rev, available_revision);
|
int ret = decrypt_keyblob(keyblobs, rev, available_revision);
|
||||||
|
@ -150,13 +151,16 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
|
||||||
break;
|
break;
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||||
desired_keyblob = MASTERKEY_REVISION_700_CURRENT;
|
desired_keyblob = MASTERKEY_REVISION_700_800;
|
||||||
|
break;
|
||||||
|
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
||||||
|
desired_keyblob = MASTERKEY_REVISION_810_CURRENT;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fatal_error("Unknown target firmware: %02x!", target_firmware);
|
fatal_error("Unknown target firmware: %02x!", target_firmware);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try emulation result. */
|
/* Try emulation result. */
|
||||||
for (unsigned int rev = MASTERKEY_REVISION_620; rev < MASTERKEY_REVISION_MAX; rev++) {
|
for (unsigned int rev = MASTERKEY_REVISION_620; rev < MASTERKEY_REVISION_MAX; rev++) {
|
||||||
void *tsec_root_key = (void *)((uintptr_t)tsec_root_keys + 0x10 * (rev - MASTERKEY_REVISION_620));
|
void *tsec_root_key = (void *)((uintptr_t)tsec_root_keys + 0x10 * (rev - MASTERKEY_REVISION_620));
|
||||||
|
@ -167,7 +171,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
|
||||||
memcpy(g_dec_keyblobs[rev].master_kek, work_buffer, 0x10);
|
memcpy(g_dec_keyblobs[rev].master_kek, work_buffer, 0x10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(g_dec_keyblobs[desired_keyblob].master_kek, zeroes, 0x10) == 0) {
|
if (memcmp(g_dec_keyblobs[desired_keyblob].master_kek, zeroes, 0x10) == 0) {
|
||||||
/* Try reading the keys from a file. */
|
/* Try reading the keys from a file. */
|
||||||
const char *keyfile = fuse_get_retail_type() != 0 ? "atmosphere/prod.keys" : "atmosphere/dev.keys";
|
const char *keyfile = fuse_get_retail_type() != 0 ? "atmosphere/prod.keys" : "atmosphere/dev.keys";
|
||||||
|
@ -188,13 +192,13 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (memcmp(g_dec_keyblobs[available_revision].master_kek, zeroes, 0x10) == 0) {
|
if (memcmp(g_dec_keyblobs[available_revision].master_kek, zeroes, 0x10) == 0) {
|
||||||
fatal_error("Error: failed to derive master_kek_%02x!", available_revision);
|
fatal_error("Error: failed to derive master_kek_%02x!", available_revision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the SBK. */
|
/* Clear the SBK. */
|
||||||
clear_aes_keyslot(0xE);
|
clear_aes_keyslot(0xE);
|
||||||
|
|
||||||
|
@ -225,6 +229,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_620:
|
case ATMOSPHERE_TARGET_FIRMWARE_620:
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||||
|
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
||||||
decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
|
decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
|
||||||
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
|
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
|
||||||
decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10);
|
decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10);
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -39,6 +39,7 @@ static const uint8_t mkey_vectors_dev[MASTERKEY_REVISION_MAX][0x10] =
|
||||||
{0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */
|
{0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */
|
||||||
{0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */
|
{0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */
|
||||||
{0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */
|
{0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */
|
||||||
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: Master key 07 encrypted with Master key 08. */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Retail unit keys. */
|
/* Retail unit keys. */
|
||||||
|
@ -52,6 +53,7 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] =
|
||||||
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
|
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
|
||||||
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
|
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
|
||||||
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
|
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
|
||||||
|
{0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool check_mkey_revision(unsigned int revision, bool is_retail) {
|
static bool check_mkey_revision(unsigned int revision, bool is_retail) {
|
||||||
|
@ -80,7 +82,7 @@ int mkey_detect_revision(bool is_retail) {
|
||||||
if (g_determined_mkey_revision) {
|
if (g_determined_mkey_revision) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int rev = 0; rev < MASTERKEY_REVISION_MAX; rev++) {
|
for (unsigned int rev = 0; rev < MASTERKEY_REVISION_MAX; rev++) {
|
||||||
if (check_mkey_revision(rev, is_retail)) {
|
if (check_mkey_revision(rev, is_retail)) {
|
||||||
g_determined_mkey_revision = true;
|
g_determined_mkey_revision = true;
|
||||||
|
@ -88,7 +90,7 @@ int mkey_detect_revision(bool is_retail) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We must have determined the master key, or we're not running on a Switch. */
|
/* We must have determined the master key, or we're not running on a Switch. */
|
||||||
if (!g_determined_mkey_revision) {
|
if (!g_determined_mkey_revision) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -13,14 +13,14 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FUSEE_MASTERKEY_H
|
#ifndef FUSEE_MASTERKEY_H
|
||||||
#define FUSEE_MASTERKEY_H
|
#define FUSEE_MASTERKEY_H
|
||||||
|
|
||||||
/* This is glue code to enable master key support across versions. */
|
/* This is glue code to enable master key support across versions. */
|
||||||
|
|
||||||
/* TODO: Update to 0x8 on release of new master key. */
|
/* TODO: Update to 0xA on release of new master key. */
|
||||||
#define MASTERKEY_REVISION_MAX 0x8
|
#define MASTERKEY_REVISION_MAX 0x9
|
||||||
|
|
||||||
#define MASTERKEY_REVISION_100_230 0x00
|
#define MASTERKEY_REVISION_100_230 0x00
|
||||||
#define MASTERKEY_REVISION_300 0x01
|
#define MASTERKEY_REVISION_300 0x01
|
||||||
|
@ -29,7 +29,8 @@
|
||||||
#define MASTERKEY_REVISION_500_510 0x04
|
#define MASTERKEY_REVISION_500_510 0x04
|
||||||
#define MASTERKEY_REVISION_600_610 0x05
|
#define MASTERKEY_REVISION_600_610 0x05
|
||||||
#define MASTERKEY_REVISION_620 0x06
|
#define MASTERKEY_REVISION_620 0x06
|
||||||
#define MASTERKEY_REVISION_700_CURRENT 0x07
|
#define MASTERKEY_REVISION_700_800 0x07
|
||||||
|
#define MASTERKEY_REVISION_810_CURRENT 0x08
|
||||||
|
|
||||||
#define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410)
|
#define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410)
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -53,7 +53,8 @@
|
||||||
#define u8 uint8_t
|
#define u8 uint8_t
|
||||||
#define u32 uint32_t
|
#define u32 uint32_t
|
||||||
#include "exosphere_bin.h"
|
#include "exosphere_bin.h"
|
||||||
#include "sept_secondary_enc.h"
|
#include "sept_secondary_00_enc.h"
|
||||||
|
#include "sept_secondary_01_enc.h"
|
||||||
#include "lp0fw_bin.h"
|
#include "lp0fw_bin.h"
|
||||||
#include "emummc_kip.h"
|
#include "emummc_kip.h"
|
||||||
#include "lib/log.h"
|
#include "lib/log.h"
|
||||||
|
@ -207,8 +208,15 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
|
||||||
}
|
}
|
||||||
case 0x0F: /* 7.0.0 - 7.0.1 */
|
case 0x0F: /* 7.0.0 - 7.0.1 */
|
||||||
return ATMOSPHERE_TARGET_FIRMWARE_700;
|
return ATMOSPHERE_TARGET_FIRMWARE_700;
|
||||||
case 0x10: /* 8.0.0 */
|
case 0x10: { /* 8.0.0 - 8.1.0 */
|
||||||
return ATMOSPHERE_TARGET_FIRMWARE_800;
|
if (memcmp(package1loader_header->build_timestamp, "20190314", 8) == 0) {
|
||||||
|
return ATMOSPHERE_TARGET_FIRMWARE_800;
|
||||||
|
} else if (memcmp(package1loader_header->build_timestamp, "20190531", 8) == 0) {
|
||||||
|
return ATMOSPHERE_TARGET_FIRMWARE_810;
|
||||||
|
} else {
|
||||||
|
fatal_error("[NXBOOT] Unable to identify package1!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
fatal_error("[NXBOOT] Unable to identify package1!\n");
|
fatal_error("[NXBOOT] Unable to identify package1!\n");
|
||||||
}
|
}
|
||||||
|
@ -216,7 +224,7 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
|
||||||
|
|
||||||
static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
||||||
emummc_config_t emummc_cfg = {.enabled = false, .id = 0, .sector = -1, .path = "", .nintendo_path = ""};
|
emummc_config_t emummc_cfg = {.enabled = false, .id = 0, .sector = -1, .path = "", .nintendo_path = ""};
|
||||||
|
|
||||||
char *emummc_ini = calloc(1, 0x10000);
|
char *emummc_ini = calloc(1, 0x10000);
|
||||||
if (!read_from_file(emummc_ini, 0xFFFF, "emummc/emummc.ini")) {
|
if (!read_from_file(emummc_ini, 0xFFFF, "emummc/emummc.ini")) {
|
||||||
free(emummc_ini);
|
free(emummc_ini);
|
||||||
|
@ -237,12 +245,12 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
||||||
exo_emummc_config->base_cfg.fs_version = FS_VER_1_0_0; /* Will be filled out later. */
|
exo_emummc_config->base_cfg.fs_version = FS_VER_1_0_0; /* Will be filled out later. */
|
||||||
strncpy(exo_emummc_config->emu_dir_path, emummc_cfg.nintendo_path, sizeof(exo_emummc_config->emu_dir_path));
|
strncpy(exo_emummc_config->emu_dir_path, emummc_cfg.nintendo_path, sizeof(exo_emummc_config->emu_dir_path));
|
||||||
exo_emummc_config->emu_dir_path[sizeof(exo_emummc_config->emu_dir_path) - 1] = '\0';
|
exo_emummc_config->emu_dir_path[sizeof(exo_emummc_config->emu_dir_path) - 1] = '\0';
|
||||||
|
|
||||||
if (emummc_cfg.enabled) {
|
if (emummc_cfg.enabled) {
|
||||||
if (emummc_cfg.sector != -1) {
|
if (emummc_cfg.sector != -1) {
|
||||||
exo_emummc_config->base_cfg.type = EMUMMC_TYPE_PARTITION;
|
exo_emummc_config->base_cfg.type = EMUMMC_TYPE_PARTITION;
|
||||||
exo_emummc_config->partition_cfg.start_sector = emummc_cfg.sector;
|
exo_emummc_config->partition_cfg.start_sector = emummc_cfg.sector;
|
||||||
|
|
||||||
/* Mount emulated NAND from SD card partition. */
|
/* Mount emulated NAND from SD card partition. */
|
||||||
if (nxfs_mount_emummc_partition(emummc_cfg.sector) < 0) {
|
if (nxfs_mount_emummc_partition(emummc_cfg.sector) < 0) {
|
||||||
fatal_error("[NXBOOT] Failed to mount EmuMMC from SD card partition!\n");
|
fatal_error("[NXBOOT] Failed to mount EmuMMC from SD card partition!\n");
|
||||||
|
@ -258,24 +266,24 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
||||||
char emummc_boot0_path[0x300 + 1] = {0};
|
char emummc_boot0_path[0x300 + 1] = {0};
|
||||||
char emummc_boot1_path[0x300 + 1] = {0};
|
char emummc_boot1_path[0x300 + 1] = {0};
|
||||||
char emummc_rawnand_path[0x300 + 1] = {0};
|
char emummc_rawnand_path[0x300 + 1] = {0};
|
||||||
|
|
||||||
/* Prepare base folder path. */
|
/* Prepare base folder path. */
|
||||||
snprintf(emummc_path, sizeof(emummc_path) - 1, "%s/%s", emummc_cfg.path, "eMMC");
|
snprintf(emummc_path, sizeof(emummc_path) - 1, "%s/%s", emummc_cfg.path, "eMMC");
|
||||||
|
|
||||||
/* Check if eMMC folder is present. */
|
/* Check if eMMC folder is present. */
|
||||||
if (!is_valid_folder(emummc_path)) {
|
if (!is_valid_folder(emummc_path)) {
|
||||||
fatal_error("[NXBOOT] Failed to find EmuMMC eMMC folder!\n");
|
fatal_error("[NXBOOT] Failed to find EmuMMC eMMC folder!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare expected file paths. */
|
/* Prepare expected file paths. */
|
||||||
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0");
|
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0");
|
||||||
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1");
|
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1");
|
||||||
|
|
||||||
/* Check if boot0 and boot1 image files are present. */
|
/* Check if boot0 and boot1 image files are present. */
|
||||||
if (!is_valid_file(emummc_boot0_path) || !is_valid_file(emummc_boot1_path)) {
|
if (!is_valid_file(emummc_boot0_path) || !is_valid_file(emummc_boot1_path)) {
|
||||||
fatal_error("[NXBOOT] Failed to find EmuMMC boot0/boot1 image files!\n");
|
fatal_error("[NXBOOT] Failed to find EmuMMC boot0/boot1 image files!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find raw image files (single or multi part). */
|
/* Find raw image files (single or multi part). */
|
||||||
for (int i = 0; i < 64; i++) {
|
for (int i = 0; i < 64; i++) {
|
||||||
snprintf(emummc_rawnand_path, sizeof(emummc_rawnand_path) - 1, "%s/%02d", emummc_path, i);
|
snprintf(emummc_rawnand_path, sizeof(emummc_rawnand_path) - 1, "%s/%02d", emummc_path, i);
|
||||||
|
@ -295,7 +303,7 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
||||||
if ((num_parts == 0) || (part_limit == 0)) {
|
if ((num_parts == 0) || (part_limit == 0)) {
|
||||||
fatal_error("[NXBOOT] Failed to find EmuMMC raw image files!\n");
|
fatal_error("[NXBOOT] Failed to find EmuMMC raw image files!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mount emulated NAND from files. */
|
/* Mount emulated NAND from files. */
|
||||||
if (nxfs_mount_emummc_file(emummc_path, num_parts, part_limit) < 0) {
|
if (nxfs_mount_emummc_file(emummc_path, num_parts, part_limit) < 0) {
|
||||||
fatal_error("[NXBOOT] Failed to mount EmuMMC from files!\n");
|
fatal_error("[NXBOOT] Failed to mount EmuMMC from files!\n");
|
||||||
|
@ -304,7 +312,7 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
||||||
fatal_error("[NXBOOT] Invalid EmuMMC setting!\n");
|
fatal_error("[NXBOOT] Invalid EmuMMC setting!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return emummc_cfg.enabled;
|
return emummc_cfg.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,7 +345,7 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) {
|
||||||
if (ini_parse_string(get_loader_ctx()->bct0, stratosphere_ini_handler, &strat_cfg) < 0) {
|
if (ini_parse_string(get_loader_ctx()->bct0, stratosphere_ini_handler, &strat_cfg) < 0) {
|
||||||
fatal_error("[NXBOOT] Failed to parse BCT.ini!\n");
|
fatal_error("[NXBOOT] Failed to parse BCT.ini!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable NOGC patches if the user requested it, or if the user is booting into 4.0.0+ with 3.0.2- fuses. */
|
/* Enable NOGC patches if the user requested it, or if the user is booting into 4.0.0+ with 3.0.2- fuses. */
|
||||||
if (strat_cfg.has_nogc_config) {
|
if (strat_cfg.has_nogc_config) {
|
||||||
if (strat_cfg.enable_nogc) {
|
if (strat_cfg.enable_nogc) {
|
||||||
|
@ -353,7 +361,7 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) {
|
||||||
|
|
||||||
static void nxboot_set_bootreason(void *bootreason_base) {
|
static void nxboot_set_bootreason(void *bootreason_base) {
|
||||||
boot_reason_t boot_reason = {0};
|
boot_reason_t boot_reason = {0};
|
||||||
FILE *boot0;
|
FILE *boot0;
|
||||||
nvboot_config_table *bct;
|
nvboot_config_table *bct;
|
||||||
nv_bootloader_info *bootloader_info;
|
nv_bootloader_info *bootloader_info;
|
||||||
|
|
||||||
|
@ -362,7 +370,7 @@ static void nxboot_set_bootreason(void *bootreason_base) {
|
||||||
if (bct == NULL) {
|
if (bct == NULL) {
|
||||||
fatal_error("[NXBOOT] Out of memory!\n");
|
fatal_error("[NXBOOT] Out of memory!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open boot0. */
|
/* Open boot0. */
|
||||||
boot0 = fopen("boot0:/", "rb");
|
boot0 = fopen("boot0:/", "rb");
|
||||||
if (boot0 == NULL) {
|
if (boot0 == NULL) {
|
||||||
|
@ -373,25 +381,25 @@ static void nxboot_set_bootreason(void *bootreason_base) {
|
||||||
if (fread(bct, sizeof(nvboot_config_table), 1, boot0) == 0) {
|
if (fread(bct, sizeof(nvboot_config_table), 1, boot0) == 0) {
|
||||||
fatal_error("[NXBOOT] Failed to read the BCT!\n");
|
fatal_error("[NXBOOT] Failed to read the BCT!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close boot0. */
|
/* Close boot0. */
|
||||||
fclose(boot0);
|
fclose(boot0);
|
||||||
|
|
||||||
/* Populate bootloader parameters. */
|
/* Populate bootloader parameters. */
|
||||||
bootloader_info = &bct->bootloader[0];
|
bootloader_info = &bct->bootloader[0];
|
||||||
boot_reason.bootloader_version = bootloader_info->version;
|
boot_reason.bootloader_version = bootloader_info->version;
|
||||||
boot_reason.bootloader_start_block = bootloader_info->start_blk;
|
boot_reason.bootloader_start_block = bootloader_info->start_blk;
|
||||||
boot_reason.bootloader_start_page = bootloader_info->start_page;
|
boot_reason.bootloader_start_page = bootloader_info->start_page;
|
||||||
boot_reason.bootloader_attribute = bootloader_info->attribute;
|
boot_reason.bootloader_attribute = bootloader_info->attribute;
|
||||||
|
|
||||||
uint8_t power_key_intr = 0;
|
uint8_t power_key_intr = 0;
|
||||||
uint8_t rtc_intr = 0;
|
uint8_t rtc_intr = 0;
|
||||||
i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_ONOFFIRQ, &power_key_intr, 1);
|
i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_ONOFFIRQ, &power_key_intr, 1);
|
||||||
i2c_query(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_REG_RTCINT, &rtc_intr, 1);
|
i2c_query(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_REG_RTCINT, &rtc_intr, 1);
|
||||||
|
|
||||||
/* Set PMIC value. */
|
/* Set PMIC value. */
|
||||||
boot_reason.boot_reason_value = ((rtc_intr << 0x08) | power_key_intr);
|
boot_reason.boot_reason_value = ((rtc_intr << 0x08) | power_key_intr);
|
||||||
|
|
||||||
/* TODO: Find out what these mean. */
|
/* TODO: Find out what these mean. */
|
||||||
if (power_key_intr & 0x80)
|
if (power_key_intr & 0x80)
|
||||||
boot_reason.boot_reason_state = 0x01;
|
boot_reason.boot_reason_state = 0x01;
|
||||||
|
@ -401,10 +409,10 @@ static void nxboot_set_bootreason(void *bootreason_base) {
|
||||||
boot_reason.boot_reason_state = 0x03;
|
boot_reason.boot_reason_state = 0x03;
|
||||||
else if (rtc_intr & 0x04)
|
else if (rtc_intr & 0x04)
|
||||||
boot_reason.boot_reason_state = 0x04;
|
boot_reason.boot_reason_state = 0x04;
|
||||||
|
|
||||||
/* Set in memory. */
|
/* Set in memory. */
|
||||||
memcpy(bootreason_base, &boot_reason, sizeof(boot_reason));
|
memcpy(bootreason_base, &boot_reason, sizeof(boot_reason));
|
||||||
|
|
||||||
/* Clean up. */
|
/* Clean up. */
|
||||||
free(bct);
|
free(bct);
|
||||||
}
|
}
|
||||||
|
@ -414,13 +422,13 @@ static void nxboot_move_bootconfig() {
|
||||||
void *bootconfig;
|
void *bootconfig;
|
||||||
uint32_t bootconfig_addr;
|
uint32_t bootconfig_addr;
|
||||||
uint32_t bootconfig_size;
|
uint32_t bootconfig_size;
|
||||||
|
|
||||||
/* Allocate memory for reading BootConfig. */
|
/* Allocate memory for reading BootConfig. */
|
||||||
bootconfig = memalign(0x1000, 0x4000);
|
bootconfig = memalign(0x1000, 0x4000);
|
||||||
if (bootconfig == NULL) {
|
if (bootconfig == NULL) {
|
||||||
fatal_error("[NXBOOT] Out of memory!\n");
|
fatal_error("[NXBOOT] Out of memory!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get BootConfig from the Package2 partition. */
|
/* Get BootConfig from the Package2 partition. */
|
||||||
bcfile = fopen("bcpkg21:/", "rb");
|
bcfile = fopen("bcpkg21:/", "rb");
|
||||||
if (bcfile == NULL) {
|
if (bcfile == NULL) {
|
||||||
|
@ -431,15 +439,15 @@ static void nxboot_move_bootconfig() {
|
||||||
fatal_error("[NXBOOT] Failed to read BootConfig!\n");
|
fatal_error("[NXBOOT] Failed to read BootConfig!\n");
|
||||||
}
|
}
|
||||||
fclose(bcfile);
|
fclose(bcfile);
|
||||||
|
|
||||||
/* Select the actual BootConfig size and destination address. */
|
/* Select the actual BootConfig size and destination address. */
|
||||||
bootconfig_addr = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_600) ? 0x4003D000 : 0x4003F800;
|
bootconfig_addr = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_600) ? 0x4003D000 : 0x4003F800;
|
||||||
bootconfig_size = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) ? 0x3000 : 0x1000;
|
bootconfig_size = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) ? 0x3000 : 0x1000;
|
||||||
|
|
||||||
/* Copy the BootConfig into IRAM. */
|
/* Copy the BootConfig into IRAM. */
|
||||||
memset((void *)bootconfig_addr, 0, bootconfig_size);
|
memset((void *)bootconfig_addr, 0, bootconfig_size);
|
||||||
memcpy((void *)bootconfig_addr, bootconfig, bootconfig_size);
|
memcpy((void *)bootconfig_addr, bootconfig, bootconfig_size);
|
||||||
|
|
||||||
/* Clean up. */
|
/* Clean up. */
|
||||||
free(bootconfig);
|
free(bootconfig);
|
||||||
}
|
}
|
||||||
|
@ -459,6 +467,8 @@ uint32_t nxboot_main(void) {
|
||||||
size_t package2_size;
|
size_t package2_size;
|
||||||
void *tsec_fw;
|
void *tsec_fw;
|
||||||
size_t tsec_fw_size;
|
size_t tsec_fw_size;
|
||||||
|
const void *sept_secondary_enc = NULL;
|
||||||
|
size_t sept_secondary_enc_size = 0;
|
||||||
void *warmboot_fw;
|
void *warmboot_fw;
|
||||||
size_t warmboot_fw_size;
|
size_t warmboot_fw_size;
|
||||||
void *warmboot_memaddr;
|
void *warmboot_memaddr;
|
||||||
|
@ -470,7 +480,7 @@ uint32_t nxboot_main(void) {
|
||||||
FILE *boot0, *pk2file;
|
FILE *boot0, *pk2file;
|
||||||
void *exosphere_memaddr;
|
void *exosphere_memaddr;
|
||||||
exo_emummc_config_t exo_emummc_cfg;
|
exo_emummc_config_t exo_emummc_cfg;
|
||||||
|
|
||||||
/* Configure emummc or mount the real NAND. */
|
/* Configure emummc or mount the real NAND. */
|
||||||
if (!nxboot_configure_emummc(&exo_emummc_cfg)) {
|
if (!nxboot_configure_emummc(&exo_emummc_cfg)) {
|
||||||
emummc = NULL;
|
emummc = NULL;
|
||||||
|
@ -542,7 +552,7 @@ uint32_t nxboot_main(void) {
|
||||||
fatal_error("[NXBOOT] Failed to read Package2!\n");
|
fatal_error("[NXBOOT] Failed to read Package2!\n");
|
||||||
}
|
}
|
||||||
fclose(pk2file);
|
fclose(pk2file);
|
||||||
|
|
||||||
/* Read and parse boot0. */
|
/* Read and parse boot0. */
|
||||||
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Reading boot0...\n");
|
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Reading boot0...\n");
|
||||||
boot0 = fopen("boot0:/", "rb");
|
boot0 = fopen("boot0:/", "rb");
|
||||||
|
@ -550,7 +560,7 @@ uint32_t nxboot_main(void) {
|
||||||
fatal_error("[NXBOOT] Couldn't parse boot0: %s!\n", strerror(errno));
|
fatal_error("[NXBOOT] Couldn't parse boot0: %s!\n", strerror(errno));
|
||||||
}
|
}
|
||||||
fclose(boot0);
|
fclose(boot0);
|
||||||
|
|
||||||
/* Find the system's target firmware. */
|
/* Find the system's target firmware. */
|
||||||
uint32_t target_firmware = nxboot_get_target_firmware(package1loader);
|
uint32_t target_firmware = nxboot_get_target_firmware(package1loader);
|
||||||
if (!target_firmware)
|
if (!target_firmware)
|
||||||
|
@ -561,26 +571,42 @@ uint32_t nxboot_main(void) {
|
||||||
/* Read the TSEC firmware from a file, otherwise from PK1L. */
|
/* Read the TSEC firmware from a file, otherwise from PK1L. */
|
||||||
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 && tsec_fw_size != 0x2900 && tsec_fw_size != 0x3000)) {
|
if ((tsec_fw_size != 0) && (tsec_fw_size != 0xF00 && tsec_fw_size != 0x2900 && tsec_fw_size != 0x3000 && tsec_fw_size != 0x3300)) {
|
||||||
fatal_error("[NXBOOT] TSEC firmware from %s has a wrong size!\n", loader_ctx->tsecfw_path);
|
fatal_error("[NXBOOT] TSEC firmware from %s has a wrong size!\n", loader_ctx->tsecfw_path);
|
||||||
} else if (tsec_fw_size == 0) {
|
} else if (tsec_fw_size == 0) {
|
||||||
fatal_error("[NXBOOT] Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
|
fatal_error("[NXBOOT] Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate memory for the TSEC firmware. */
|
/* Allocate memory for the TSEC firmware. */
|
||||||
tsec_fw = memalign(0x100, tsec_fw_size);
|
tsec_fw = memalign(0x100, tsec_fw_size);
|
||||||
|
|
||||||
if (tsec_fw == NULL) {
|
if (tsec_fw == NULL) {
|
||||||
fatal_error("[NXBOOT] Out of memory!\n");
|
fatal_error("[NXBOOT] Out of memory!\n");
|
||||||
}
|
}
|
||||||
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) {
|
||||||
fatal_error("[NXBOOT] Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
|
fatal_error("[NXBOOT] Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tsec_fw_size == 0x3000) {
|
||||||
|
sept_secondary_enc = sept_secondary_00_enc;
|
||||||
|
sept_secondary_enc_size = sept_secondary_00_enc_size;
|
||||||
|
} else if (tsec_fw_size == 0x3300) {
|
||||||
|
sept_secondary_enc = sept_secondary_01_enc;
|
||||||
|
sept_secondary_enc_size = sept_secondary_01_enc_size;
|
||||||
|
} else {
|
||||||
|
fatal_error("[NXBOOT] Unable to identify sept revision to run.");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!package1_get_tsec_fw(&tsec_fw, package1loader, package1loader_size)) {
|
if (!package1_get_tsec_fw(&tsec_fw, package1loader, package1loader_size)) {
|
||||||
fatal_error("[NXBOOT] Failed to read the TSEC firmware from Package1loader!\n");
|
fatal_error("[NXBOOT] Failed to read the TSEC firmware from Package1loader!\n");
|
||||||
}
|
}
|
||||||
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) {
|
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_810) {
|
||||||
|
sept_secondary_enc = sept_secondary_01_enc;
|
||||||
|
sept_secondary_enc_size = sept_secondary_01_enc_size;
|
||||||
|
tsec_fw_size = 0x3300;
|
||||||
|
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) {
|
||||||
|
sept_secondary_enc = sept_secondary_00_enc;
|
||||||
|
sept_secondary_enc_size = sept_secondary_00_enc_size;
|
||||||
tsec_fw_size = 0x3000;
|
tsec_fw_size = 0x3000;
|
||||||
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
|
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
|
||||||
tsec_fw_size = 0x2900;
|
tsec_fw_size = 0x2900;
|
||||||
|
@ -606,10 +632,10 @@ uint32_t nxboot_main(void) {
|
||||||
get_and_clear_has_run_sept();
|
get_and_clear_has_run_sept();
|
||||||
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
|
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
|
||||||
uint8_t tsec_keys[0x20] = {0};
|
uint8_t tsec_keys[0x20] = {0};
|
||||||
|
|
||||||
/* Emulate the TSEC payload on 6.2.0+. */
|
/* Emulate the TSEC payload on 6.2.0+. */
|
||||||
smmu_emulate_tsec((void *)tsec_keys, package1loader, package1loader_size, package1loader);
|
smmu_emulate_tsec((void *)tsec_keys, package1loader, package1loader_size, package1loader);
|
||||||
|
|
||||||
/* Copy back the keys. */
|
/* Copy back the keys. */
|
||||||
memcpy((void *)tsec_key, (void *)tsec_keys, 0x10);
|
memcpy((void *)tsec_key, (void *)tsec_keys, 0x10);
|
||||||
memcpy((void *)tsec_root_keys, (void *)tsec_keys + 0x10, 0x10);
|
memcpy((void *)tsec_root_keys, (void *)tsec_keys + 0x10, 0x10);
|
||||||
|
@ -619,11 +645,11 @@ uint32_t nxboot_main(void) {
|
||||||
fatal_error("[NXBOOT] Failed to get TSEC key!\n");
|
fatal_error("[NXBOOT] Failed to get TSEC key!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//fatal_error("Ran sept!");
|
//fatal_error("Ran sept!");
|
||||||
/* Display splash screen. */
|
/* Display splash screen. */
|
||||||
display_splash_screen_bmp(loader_ctx->custom_splash_path, (void *)0xC0000000);
|
display_splash_screen_bmp(loader_ctx->custom_splash_path, (void *)0xC0000000);
|
||||||
|
|
||||||
/* Derive keydata. If on 7.0.0+, sept has already derived keys for us. */
|
/* Derive keydata. If on 7.0.0+, sept has already derived keys for us. */
|
||||||
unsigned int keygen_type = 0;
|
unsigned int keygen_type = 0;
|
||||||
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) {
|
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) {
|
||||||
|
@ -665,27 +691,27 @@ uint32_t nxboot_main(void) {
|
||||||
if (warmboot_fw == NULL) {
|
if (warmboot_fw == NULL) {
|
||||||
fatal_error("[NXBOOT] Out of memory!\n");
|
fatal_error("[NXBOOT] Out of memory!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(warmboot_fw, lp0fw_bin, warmboot_fw_size);
|
memcpy(warmboot_fw, lp0fw_bin, warmboot_fw_size);
|
||||||
|
|
||||||
if (warmboot_fw_size == 0) {
|
if (warmboot_fw_size == 0) {
|
||||||
fatal_error("[NXBOOT] Could not read the warmboot firmware from Package1!\n");
|
fatal_error("[NXBOOT] Could not read the warmboot firmware from Package1!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Patch warmboot firmware for atmosphere. */
|
/* Patch warmboot firmware for atmosphere. */
|
||||||
if (warmboot_fw != NULL && warmboot_fw_size >= sizeof(warmboot_ams_header_t)) {
|
if (warmboot_fw != NULL && warmboot_fw_size >= sizeof(warmboot_ams_header_t)) {
|
||||||
warmboot_ams_header_t *ams_header = (warmboot_ams_header_t *)warmboot_fw;
|
warmboot_ams_header_t *ams_header = (warmboot_ams_header_t *)warmboot_fw;
|
||||||
if (ams_header->ams_metadata.magic == WARMBOOT_MAGIC) {
|
if (ams_header->ams_metadata.magic == WARMBOOT_MAGIC) {
|
||||||
/* Set target firmware */
|
/* Set target firmware */
|
||||||
ams_header->ams_metadata.target_firmware = target_firmware;
|
ams_header->ams_metadata.target_firmware = target_firmware;
|
||||||
|
|
||||||
/* Set RSA modulus */
|
/* Set RSA modulus */
|
||||||
const uint8_t *pkc_modulus = fuse_get_retail_type() != 0 ? retail_pkc_modulus : dev_pkc_modulus;
|
const uint8_t *pkc_modulus = fuse_get_retail_type() != 0 ? retail_pkc_modulus : dev_pkc_modulus;
|
||||||
memcpy(ams_header->rsa_modulus, pkc_modulus, sizeof(ams_header->rsa_modulus));
|
memcpy(ams_header->rsa_modulus, pkc_modulus, sizeof(ams_header->rsa_modulus));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Select the right address for the warmboot firmware. */
|
/* Select the right address for the warmboot firmware. */
|
||||||
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
|
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
|
||||||
|
@ -708,7 +734,7 @@ uint32_t nxboot_main(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Rebuilding package2...\n");
|
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Rebuilding package2...\n");
|
||||||
|
|
||||||
/* Parse stratosphere config. */
|
/* Parse stratosphere config. */
|
||||||
nxboot_configure_stratosphere(MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware);
|
nxboot_configure_stratosphere(MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware);
|
||||||
|
|
||||||
|
@ -770,10 +796,10 @@ uint32_t nxboot_main(void) {
|
||||||
free(package2);
|
free(package2);
|
||||||
|
|
||||||
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Powering on the CCPLEX...\n");
|
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Powering on the CCPLEX...\n");
|
||||||
|
|
||||||
/* Unmount everything. */
|
/* Unmount everything. */
|
||||||
nxfs_end();
|
nxfs_end();
|
||||||
|
|
||||||
/* Return the memory address for booting CPU0. */
|
/* Return the memory address for booting CPU0. */
|
||||||
return (uint32_t)exosphere_memaddr;
|
return (uint32_t)exosphere_memaddr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <atmosphere.h>
|
#include <atmosphere.h>
|
||||||
|
@ -66,7 +66,7 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
|
||||||
if (thermosphere_size != 0 && package2->metadata.section_sizes[PACKAGE2_SECTION_UNUSED] != 0) {
|
if (thermosphere_size != 0 && package2->metadata.section_sizes[PACKAGE2_SECTION_UNUSED] != 0) {
|
||||||
fatal_error(u8"Error: Package2 has no unused section for Thermosphère!\n");
|
fatal_error(u8"Error: Package2 has no unused section for Thermosphère!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load Kernel from SD, if possible. */
|
/* Load Kernel from SD, if possible. */
|
||||||
{
|
{
|
||||||
size_t sd_kernel_size = get_file_size("atmosphere/kernel.bin");
|
size_t sd_kernel_size = get_file_size("atmosphere/kernel.bin");
|
||||||
|
@ -88,13 +88,13 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
|
||||||
|
|
||||||
/* Perform any patches we want to the NX kernel. */
|
/* Perform any patches we want to the NX kernel. */
|
||||||
package2_patch_kernel(kernel, kernel_size, is_sd_kernel, (void *)&orig_ini1);
|
package2_patch_kernel(kernel, kernel_size, is_sd_kernel, (void *)&orig_ini1);
|
||||||
|
|
||||||
/* Ensure we know where embedded INI is if present, and we don't if not. */
|
/* Ensure we know where embedded INI is if present, and we don't if not. */
|
||||||
if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 != NULL) ||
|
if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 != NULL) ||
|
||||||
(target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 == NULL)) {
|
(target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 == NULL)) {
|
||||||
fatal_error("Error: inappropriate kernel embedded ini context");
|
fatal_error("Error: inappropriate kernel embedded ini context");
|
||||||
}
|
}
|
||||||
|
|
||||||
print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilding the INI1 section...\n");
|
print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilding the INI1 section...\n");
|
||||||
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800) {
|
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800) {
|
||||||
package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1);
|
package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1);
|
||||||
|
@ -232,7 +232,7 @@ static bool package2_validate_metadata(package2_meta_t *metadata, uint8_t data[]
|
||||||
|
|
||||||
/* Perform version checks. */
|
/* Perform version checks. */
|
||||||
/* We will be compatible with all package2s released before current, but not newer ones. */
|
/* We will be compatible with all package2s released before current, but not newer ones. */
|
||||||
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_700_CURRENT) {
|
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_810_CURRENT) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FUSEE_PACKAGE2_H
|
#ifndef FUSEE_PACKAGE2_H
|
||||||
#define FUSEE_PACKAGE2_H
|
#define FUSEE_PACKAGE2_H
|
||||||
|
|
||||||
|
@ -36,7 +36,8 @@
|
||||||
#define PACKAGE2_MAXVER_500_510 0x7
|
#define PACKAGE2_MAXVER_500_510 0x7
|
||||||
#define PACKAGE2_MAXVER_600_610 0x8
|
#define PACKAGE2_MAXVER_600_610 0x8
|
||||||
#define PACKAGE2_MAXVER_620 0x9
|
#define PACKAGE2_MAXVER_620 0x9
|
||||||
#define PACKAGE2_MAXVER_700_CURRENT 0xA
|
#define PACKAGE2_MAXVER_700_800 0xA
|
||||||
|
#define PACKAGE2_MAXVER_810_CURRENT 0xB
|
||||||
|
|
||||||
#define PACKAGE2_MINVER_100 0x3
|
#define PACKAGE2_MINVER_100 0x3
|
||||||
#define PACKAGE2_MINVER_200 0x4
|
#define PACKAGE2_MINVER_200 0x4
|
||||||
|
@ -46,7 +47,8 @@
|
||||||
#define PACKAGE2_MINVER_500_510 0x8
|
#define PACKAGE2_MINVER_500_510 0x8
|
||||||
#define PACKAGE2_MINVER_600_610 0x9
|
#define PACKAGE2_MINVER_600_610 0x9
|
||||||
#define PACKAGE2_MINVER_620 0xA
|
#define PACKAGE2_MINVER_620 0xA
|
||||||
#define PACKAGE2_MINVER_700_CURRENT 0xB
|
#define PACKAGE2_MINVER_700_800 0xB
|
||||||
|
#define PACKAGE2_MINVER_810_CURRENT 0xC
|
||||||
|
|
||||||
#define NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS ((void *)(0xA9800000ull))
|
#define NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS ((void *)(0xA9800000ull))
|
||||||
|
|
||||||
|
@ -79,7 +81,7 @@ typedef struct {
|
||||||
/* Package2 can be encrypted or unencrypted for these functions: */
|
/* Package2 can be encrypted or unencrypted for these functions: */
|
||||||
|
|
||||||
static inline size_t package2_meta_get_size(const package2_meta_t *metadata) {
|
static inline size_t package2_meta_get_size(const package2_meta_t *metadata) {
|
||||||
return metadata->ctr_dwords[0] ^ metadata->ctr_dwords[2] ^ metadata->ctr_dwords[3];
|
return metadata->ctr_dwords[0] ^ metadata->ctr_dwords[2] ^ metadata->ctr_dwords[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t package2_meta_get_header_version(const package2_meta_t *metadata) {
|
static inline uint8_t package2_meta_get_header_version(const package2_meta_t *metadata) {
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <atmosphere/version.h>
|
#include <atmosphere/version.h>
|
||||||
|
|
||||||
.macro CLEAR_GPR_REG_ITER
|
.macro CLEAR_GPR_REG_ITER
|
||||||
mov r\@, #0
|
mov r\@, #0
|
||||||
.endm
|
.endm
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
.type _start, %function
|
.type _start, %function
|
||||||
_start:
|
_start:
|
||||||
b _crt0
|
b _crt0
|
||||||
|
|
||||||
.word (_metadata - _start)
|
.word (_metadata - _start)
|
||||||
|
|
||||||
_crt0:
|
_crt0:
|
||||||
|
@ -67,7 +67,7 @@ _crt0:
|
||||||
ldr r0, [r0]
|
ldr r0, [r0]
|
||||||
ldr r1, [r1]
|
ldr r1, [r1]
|
||||||
b main
|
b main
|
||||||
|
|
||||||
/* Fusee-secondary header. */
|
/* Fusee-secondary header. */
|
||||||
.align 5
|
.align 5
|
||||||
_metadata:
|
_metadata:
|
||||||
|
@ -168,12 +168,20 @@ _content_headers:
|
||||||
.asciz "sept_primary"
|
.asciz "sept_primary"
|
||||||
.align 5
|
.align 5
|
||||||
|
|
||||||
/* sept_secondary content header */
|
/* sept_secondary 00 content header */
|
||||||
.word __sept_secondary_enc_start__
|
.word __sept_secondary_00_enc_start__
|
||||||
.word __sept_secondary_enc_size__
|
.word __sept_secondary_00_enc_size__
|
||||||
.word CONTENT_TYPE_SP2
|
.word CONTENT_TYPE_SP2
|
||||||
.word 0xCCCCCCCC
|
.word 0xCCCCCCCC
|
||||||
.asciz "sept_secondary"
|
.asciz "sept_secondary_00"
|
||||||
|
.align 5
|
||||||
|
|
||||||
|
/* sept_secondary 01 content header */
|
||||||
|
.word __sept_secondary_01_enc_start__
|
||||||
|
.word __sept_secondary_01_enc_size__
|
||||||
|
.word CONTENT_TYPE_SP2
|
||||||
|
.word 0xCCCCCCCC
|
||||||
|
.asciz "sept_secondary_01"
|
||||||
.align 5
|
.align 5
|
||||||
|
|
||||||
/* sm content header */
|
/* sm content header */
|
||||||
|
|
|
@ -1,7 +1,19 @@
|
||||||
HOVI_ENC_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000')
|
NUM_KEYS = 2
|
||||||
HOVI_ENC_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000')
|
|
||||||
HOVI_SIG_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000')
|
HOVI_ENC_KEY_PRD = [
|
||||||
HOVI_SIG_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000')
|
bytearray.fromhex('00000000000000000000000000000000'),
|
||||||
HOVI_KEK_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000')
|
bytearray.fromhex('00000000000000000000000000000000'),
|
||||||
HOVI_KEK_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000')
|
]
|
||||||
IV = bytearray.fromhex('00000000000000000000000000000000')
|
HOVI_SIG_KEY_PRD = [
|
||||||
|
bytearray.fromhex('00000000000000000000000000000000'),
|
||||||
|
bytearray.fromhex('00000000000000000000000000000000'),
|
||||||
|
]
|
||||||
|
|
||||||
|
IV = [
|
||||||
|
bytearray.fromhex('00000000000000000000000000000000'),
|
||||||
|
bytearray.fromhex('00000000000000000000000000000000'),
|
||||||
|
]
|
||||||
|
|
||||||
|
assert len(HOVI_ENC_KEY_PRD) == NUM_KEYS
|
||||||
|
assert len(HOVI_SIG_KEY_PRD) == NUM_KEYS
|
||||||
|
assert len(IV) == NUM_KEYS
|
|
@ -137,12 +137,12 @@ clean:
|
||||||
@echo clean ...
|
@echo clean ...
|
||||||
@$(MAKE) -C $(AMS)/exosphere/rebootstub clean
|
@$(MAKE) -C $(AMS)/exosphere/rebootstub clean
|
||||||
@$(MAKE) -C key_derivation clean
|
@$(MAKE) -C key_derivation clean
|
||||||
@rm -fr $(BUILD) $(TARGET).bin $(TARGET).enc $(TARGET).elf
|
@rm -fr $(BUILD) $(TARGET).bin $(TARGET)_*.enc $(TARGET).elf
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
else
|
else
|
||||||
.PHONY: all
|
.PHONY: all $(OUTPUT).bin
|
||||||
|
|
||||||
DEPENDS := $(OFILES:.o=.d)
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
#define AL16 __attribute__((aligned(16)))
|
#define AL16 __attribute__((aligned(16)))
|
||||||
|
|
||||||
#define DERIVATION_ID_MAX 1
|
#define DERIVATION_ID_MAX 2
|
||||||
|
|
||||||
static const uint8_t AL16 keyblob_seed_00[0x10] = {
|
static const uint8_t AL16 keyblob_seed_00[0x10] = {
|
||||||
0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3
|
0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3
|
||||||
|
@ -44,10 +44,12 @@ static const uint8_t AL16 masterkey_4x_seed[0x10] = {
|
||||||
|
|
||||||
static const uint8_t AL16 master_kek_seeds[DERIVATION_ID_MAX][0x10] = {
|
static const uint8_t AL16 master_kek_seeds[DERIVATION_ID_MAX][0x10] = {
|
||||||
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C},
|
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C},
|
||||||
|
{0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t AL16 master_devkey_seeds[DERIVATION_ID_MAX][0x10] = {
|
static const uint8_t AL16 master_devkey_seeds[DERIVATION_ID_MAX][0x10] = {
|
||||||
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D},
|
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D},
|
||||||
|
{0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE},
|
||||||
};
|
};
|
||||||
|
|
||||||
void derive_keys(void) {
|
void derive_keys(void) {
|
||||||
|
@ -101,7 +103,7 @@ void derive_keys(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Derive master kek. */
|
/* Derive master kek. */
|
||||||
decrypt_data_into_keyslot(0xE, 0xE, master_kek_seeds[0], 0x10);
|
decrypt_data_into_keyslot(0xE, 0xE, master_kek_seeds[derivation_id], 0x10);
|
||||||
|
|
||||||
/* Derive master key, device master key. */
|
/* Derive master key, device master key. */
|
||||||
decrypt_data_into_keyslot(0xC, 0xE, masterkey_seed, 0x10);
|
decrypt_data_into_keyslot(0xC, 0xE, masterkey_seed, 0x10);
|
||||||
|
@ -123,7 +125,7 @@ void derive_keys(void) {
|
||||||
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
|
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
|
||||||
|
|
||||||
/* Derive firmware specific device key. */
|
/* Derive firmware specific device key. */
|
||||||
se_aes_ecb_decrypt_block(0xA, work_buffer, 0x10, master_devkey_seeds[0], 0x10);
|
se_aes_ecb_decrypt_block(0xA, work_buffer, 0x10, master_devkey_seeds[derivation_id], 0x10);
|
||||||
decrypt_data_into_keyslot(0xE, 0xE, work_buffer, 0x10);
|
decrypt_data_into_keyslot(0xE, 0xE, work_buffer, 0x10);
|
||||||
|
|
||||||
/* Clear work buffer. */
|
/* Clear work buffer. */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
import sys
|
import sys, os
|
||||||
from struct import pack as pk, unpack as up
|
from struct import pack as pk, unpack as up
|
||||||
from Crypto.Cipher import AES
|
from Crypto.Cipher import AES
|
||||||
from Crypto.Hash import CMAC
|
from Crypto.Hash import CMAC
|
||||||
|
@ -41,7 +41,7 @@ def get_last_block_for_desired_mac(key, data, desired_mac):
|
||||||
return last_block
|
return last_block
|
||||||
|
|
||||||
|
|
||||||
def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac):
|
def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac, version):
|
||||||
# Pad with 0x20 of zeroes.
|
# Pad with 0x20 of zeroes.
|
||||||
code = code + bytearray(0x20)
|
code = code + bytearray(0x20)
|
||||||
code_len = len(code)
|
code_len = len(code)
|
||||||
|
@ -49,6 +49,9 @@ def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac):
|
||||||
code_len &= ~0xFFF
|
code_len &= ~0xFFF
|
||||||
code = code + bytearray(code_len - len(code))
|
code = code + bytearray(code_len - len(code))
|
||||||
|
|
||||||
|
# Insert version
|
||||||
|
code = code[:8] + pk('<I', version) + code[12:]
|
||||||
|
|
||||||
# Add empty trustzone, warmboot segments.
|
# Add empty trustzone, warmboot segments.
|
||||||
code = code + bytearray(0x1FE0 - 0x10)
|
code = code + bytearray(0x1FE0 - 0x10)
|
||||||
pk11_hdr = b'PK11' + pk('<IIIIIII', 0x1000, 0, 0, code_len - 0x20, 0, 0x1000, 0)
|
pk11_hdr = b'PK11' + pk('<IIIIIII', 0x1000, 0, 0, code_len - 0x20, 0, 0x1000, 0)
|
||||||
|
@ -69,8 +72,10 @@ def main(argc, argv):
|
||||||
if len(code) & 0xF:
|
if len(code) & 0xF:
|
||||||
code = code + bytearray(0x10 - (len(code) & 0xF))
|
code = code + bytearray(0x10 - (len(code) & 0xF))
|
||||||
# TODO: Support dev unit crypto
|
# TODO: Support dev unit crypto
|
||||||
with open(argv[2], 'wb') as f:
|
fn, fext = os.path.splitext(argv[2])
|
||||||
f.write(sign_encrypt_code(code, KEYS.HOVI_SIG_KEY_PRD, KEYS.HOVI_ENC_KEY_PRD, KEYS.IV, b'THANKS_NVIDIA_<3'))
|
for key in range(KEYS.NUM_KEYS):
|
||||||
|
with open(fn + ('_%02X' % key) + fext, 'wb') as f:
|
||||||
|
f.write(sign_encrypt_code(code, KEYS.HOVI_SIG_KEY_PRD[key], KEYS.HOVI_ENC_KEY_PRD[key], KEYS.IV[key], b'THANKS_NVIDIA_<3', key))
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#undef u32
|
#undef u32
|
||||||
|
|
||||||
|
|
||||||
void derive_keys(void) {
|
void derive_keys(uint32_t version) {
|
||||||
/* Clear mailbox. */
|
/* Clear mailbox. */
|
||||||
volatile uint32_t *mailbox = (volatile uint32_t *)0x4003FF00;
|
volatile uint32_t *mailbox = (volatile uint32_t *)0x4003FF00;
|
||||||
while (*mailbox != 0) {
|
while (*mailbox != 0) {
|
||||||
|
@ -37,7 +37,7 @@ void derive_keys(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set derivation id. */
|
/* Set derivation id. */
|
||||||
*((volatile uint32_t *)0x4003E800) = 0x0;
|
*((volatile uint32_t *)0x4003E800) = version;
|
||||||
|
|
||||||
/* Copy key derivation stub into IRAM high. */
|
/* Copy key derivation stub into IRAM high. */
|
||||||
for (size_t i = 0; i < key_derivation_bin_size; i += sizeof(uint32_t)) {
|
for (size_t i = 0; i < key_derivation_bin_size; i += sizeof(uint32_t)) {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void derive_keys(void);
|
void derive_keys(uint32_t version);
|
||||||
void load_keys(const uint8_t *se_state);
|
void load_keys(const uint8_t *se_state);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -48,7 +48,7 @@ static void set_has_rebooted(bool rebooted) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void exfiltrate_keys_and_reboot_if_needed(void) {
|
static void exfiltrate_keys_and_reboot_if_needed(uint32_t version) {
|
||||||
volatile tegra_pmc_t *pmc = pmc_get_regs();
|
volatile tegra_pmc_t *pmc = pmc_get_regs();
|
||||||
uint8_t *enc_se_state = (uint8_t *)0x4003E000;
|
uint8_t *enc_se_state = (uint8_t *)0x4003E000;
|
||||||
uint8_t *dec_se_state = (uint8_t *)0x4003F000;
|
uint8_t *dec_se_state = (uint8_t *)0x4003F000;
|
||||||
|
@ -59,7 +59,7 @@ static void exfiltrate_keys_and_reboot_if_needed(void) {
|
||||||
set_has_rebooted(true);
|
set_has_rebooted(true);
|
||||||
|
|
||||||
/* Derive keys. */
|
/* Derive keys. */
|
||||||
derive_keys();
|
derive_keys(version);
|
||||||
|
|
||||||
reboot_to_self();
|
reboot_to_self();
|
||||||
} else {
|
} else {
|
||||||
|
@ -135,14 +135,14 @@ static void exit_callback(int rc) {
|
||||||
relocate_and_chainload();
|
relocate_and_chainload();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int sept_main(uint32_t version) {
|
||||||
const char *stage2_path;
|
const char *stage2_path;
|
||||||
stage2_args_t *stage2_args;
|
stage2_args_t *stage2_args;
|
||||||
uint32_t stage2_version = 0;
|
uint32_t stage2_version = 0;
|
||||||
ScreenLogLevel log_level = SCREEN_LOG_LEVEL_NONE;
|
ScreenLogLevel log_level = SCREEN_LOG_LEVEL_NONE;
|
||||||
|
|
||||||
/* Extract keys from the security engine, which TSEC FW locked down. */
|
/* Extract keys from the security engine, which TSEC FW locked down. */
|
||||||
exfiltrate_keys_and_reboot_if_needed();
|
exfiltrate_keys_and_reboot_if_needed(version);
|
||||||
|
|
||||||
/* Override the global logging level. */
|
/* Override the global logging level. */
|
||||||
log_set_log_level(log_level);
|
log_set_log_level(log_level);
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.macro CLEAR_GPR_REG_ITER
|
.macro CLEAR_GPR_REG_ITER
|
||||||
mov r\@, #0
|
mov r\@, #0
|
||||||
.endm
|
.endm
|
||||||
|
@ -26,13 +26,18 @@
|
||||||
_start:
|
_start:
|
||||||
/* Switch to system mode, mask all interrupts, clear all flags */
|
/* Switch to system mode, mask all interrupts, clear all flags */
|
||||||
msr cpsr_cxsf, #0xDF
|
msr cpsr_cxsf, #0xDF
|
||||||
|
b begin_relocation_loop
|
||||||
|
_version:
|
||||||
|
.word 0x00000000 /* Version. */
|
||||||
|
.word 0x00000000 /* Reserved. */
|
||||||
|
|
||||||
|
begin_relocation_loop:
|
||||||
/* Relocate ourselves if necessary */
|
/* Relocate ourselves if necessary */
|
||||||
ldr r2, =__start__
|
ldr r2, =__start__
|
||||||
adr r3, _start
|
adr r3, _start
|
||||||
cmp r2, r3
|
cmp r2, r3
|
||||||
beq _relocation_loop_end
|
beq _relocation_loop_end
|
||||||
|
|
||||||
/* If we are relocating, we are not rebooting to ourselves. Note that. */
|
/* If we are relocating, we are not rebooting to ourselves. Note that. */
|
||||||
ldr r0, =0x4003FFFC
|
ldr r0, =0x4003FFFC
|
||||||
mov r1, #0x0
|
mov r1, #0x0
|
||||||
|
@ -50,12 +55,12 @@ _start:
|
||||||
|
|
||||||
ldr r12, =_second_relocation_start
|
ldr r12, =_second_relocation_start
|
||||||
bx r12
|
bx r12
|
||||||
|
|
||||||
_second_relocation_start:
|
_second_relocation_start:
|
||||||
ldr r4, =__bss_start__
|
ldr r4, =__bss_start__
|
||||||
sub r4, r4, r2
|
sub r4, r4, r2
|
||||||
mov r1, #0x0
|
mov r1, #0x0
|
||||||
|
|
||||||
_second_relocation_loop:
|
_second_relocation_loop:
|
||||||
ldmia r3!, {r5-r12}
|
ldmia r3!, {r5-r12}
|
||||||
stmia r2!, {r5-r12}
|
stmia r2!, {r5-r12}
|
||||||
|
@ -67,7 +72,7 @@ _start:
|
||||||
bx r12
|
bx r12
|
||||||
|
|
||||||
_relocation_loop_end:
|
_relocation_loop_end:
|
||||||
|
|
||||||
/* Set the stack pointer */
|
/* Set the stack pointer */
|
||||||
ldr sp, =__stack_top__
|
ldr sp, =__stack_top__
|
||||||
mov fp, #0
|
mov fp, #0
|
||||||
|
@ -78,7 +83,9 @@ _start:
|
||||||
CLEAR_GPR_REG_ITER
|
CLEAR_GPR_REG_ITER
|
||||||
.endr
|
.endr
|
||||||
ldr lr, =__program_exit
|
ldr lr, =__program_exit
|
||||||
b main
|
ldr r0, =_version
|
||||||
|
ldr r0, [r0]
|
||||||
|
b sept_main
|
||||||
|
|
||||||
/* No need to include this in normal programs: */
|
/* No need to include this in normal programs: */
|
||||||
.section .chainloader.text.start, "ax", %progbits
|
.section .chainloader.text.start, "ax", %progbits
|
||||||
|
|
Loading…
Reference in a new issue