mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
Push WIP NX_BOOTLOADER sync code (for coldboots)
This commit is contained in:
parent
330f8a0f8b
commit
f0d0ec0dca
9 changed files with 213 additions and 4 deletions
18
exosphere/bootconfig.h
Normal file
18
exosphere/bootconfig.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef EXOSPHERE_BOOTCONFIG_H
|
||||
#define EXOSPHERE_BOOTCONFIG_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* This provides management for Switch BootConfig. */
|
||||
|
||||
typedef struct {
|
||||
uint8_t unsigned_config[0x200];
|
||||
uint8_t signature[0x100];
|
||||
uint8_t header[0x100];
|
||||
uint8_t signed_config[0x24];
|
||||
} bootconfig_t;
|
||||
|
||||
void bootconfig_load_and_verify(const bootconfig_t *bootconfig)
|
||||
void bootconfig_clear(void);
|
||||
|
||||
#endif
|
|
@ -24,5 +24,6 @@ uint32_t configitem_set(enum ConfigItem item, uint64_t value);
|
|||
uint32_t configitem_get(enum ConfigItem item, uint64_t *p_outvalue);
|
||||
|
||||
uint64_t configitem_is_recovery_boot(void);
|
||||
uint64_t configitem_is_retail(void);
|
||||
|
||||
#endif
|
|
@ -6,6 +6,11 @@
|
|||
/* TODO: Update to 0x5 on release of new master key. */
|
||||
#define MASTERKEY_REVISION_MAX 0x4
|
||||
|
||||
#define MASTERKEY_REVISION_100_230 0x00
|
||||
#define MASTERKEY_REVISION_300 0x01
|
||||
#define MASTERKEY_REVISION_301_302 0x02
|
||||
#define MASTERKEY_REVISION_400_CURRENT 0x03
|
||||
|
||||
/* This should be called early on in initialization. */
|
||||
void mkey_detect_revision(void);
|
||||
|
||||
|
|
139
exosphere/package2.c
Normal file
139
exosphere/package2.c
Normal file
|
@ -0,0 +1,139 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include "package2.h"
|
||||
#include "configitem.h"
|
||||
#include "se.h"
|
||||
#include "masterkey.h"
|
||||
#include "cache.h"
|
||||
#include "randomcache.h"
|
||||
#include "timers.h"
|
||||
|
||||
void setup_mmio_virtual_addresses(void) {
|
||||
/* TODO: Set Timers address to 0x1F008B000. */
|
||||
/* TODO: Set Security Engine address to 0x1F008F000. */
|
||||
/* TODO: Set CAR address to 0x1F0087000. */
|
||||
/* TODO: Set PMC address to 0x1F0089400. */
|
||||
/* TODO: Set Fuse address to 0x1F0096800. */
|
||||
/* TODO: Set Interrupt addresses to 0x1F0080000, 0x1F0082000. */
|
||||
/* TODO: Set Flow Controller address to 0x1F009D000. */
|
||||
/* TODO: Set UART-A address to 0x1F0085000. */
|
||||
/* TODO: Set I2C-0 address to 0x1F00A5000. */
|
||||
/* TODO: Set I2C-4 address to 0x1F00A1000. */
|
||||
/* TODO: Set MISC address to 0x70000000. */
|
||||
/* TODO: Set GPIO-1 address to 0x6000D000. */
|
||||
}
|
||||
|
||||
/* Hardware init, sets up the RNG and SESSION keyslots, derives new DEVICE key. */
|
||||
void setup_se(void) {
|
||||
uint8_t work_buffer[0x10];
|
||||
|
||||
/* Sanity check the Security Engine. */
|
||||
se_verify_flags_cleared();
|
||||
se_clear_interrupts();
|
||||
|
||||
/* Perform some sanity initialization. */
|
||||
security_engine_t *p_security_engine = get_security_engine_address();
|
||||
p_security_engine->_0x4 = 0;
|
||||
p_security_engine->AES_KEY_READ_DISABLE_REG = 0;
|
||||
p_security_engine->RSA_KEY_READ_SAIBEL_REG = 0;
|
||||
p_security_engine->_0x0 &= 0xFFFFFFFB;
|
||||
|
||||
/* Currently unknown what each flag does. */
|
||||
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
||||
set_aes_keyslot_flags(i, 0x15);
|
||||
}
|
||||
|
||||
for (unsigned int i = 4; i < KEYSLOT_AES_MAX; i++) {
|
||||
set_aes_keyslot_flags(i, 0x40);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < KEYSLOT_RSA_MAX; i++) {
|
||||
set_rsa_keyslot_flags(i, 0x41);
|
||||
}
|
||||
|
||||
/* Detect Master Key revision. */
|
||||
mkey_detect_revision();
|
||||
|
||||
/* Setup new device key, if necessary. */
|
||||
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||
const uint8_t 4x_new_devicekey_source[0x10] = {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D};
|
||||
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY, work_buffer, 0x10, 4x_new_devicekey_source, 0x10);
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY, work_buffer, 0x10);
|
||||
clear_aes_keyslot(KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY);
|
||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
|
||||
}
|
||||
|
||||
se_initialize_rng(KEYSLOT_SWITCH_DEVICEKEY);
|
||||
|
||||
/* Generate random data, transform with device key to get RNG key. */
|
||||
se_generate_random(KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_RNGKEY, KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_RNGKEY, 0xFF);
|
||||
|
||||
/* Repeat for Session key. */
|
||||
se_generate_random(KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_SESSIONKEY, KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_SESSIONKEY, 0xFF);
|
||||
|
||||
/* TODO: Create Test Vector, to validate keyslot data is unchanged post warmboot. */
|
||||
}
|
||||
|
||||
void setup_boot_config(void) {
|
||||
/* Load boot config only if dev unit. */
|
||||
if (configitem_is_retail()) {
|
||||
bootconfig_clear();
|
||||
} else {
|
||||
flush_dcache_range((uint8_t *)NX_BOOTLOADER_BOOTCONFIG_POINTER, (uint8_t *)NX_BOOTLOADER_BOOTCONFIG_POINTER + sizeof(bootconfig_t));
|
||||
bootconfig_load_and_verify((bootconfig_t *)NX_BOOTLOADER_BOOTCONFIG_POINTER);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function is called during coldboot crt0, and validates a package2. */
|
||||
/* This package2 is read into memory by a concurrent BPMP bootloader. */
|
||||
void load_package2(void) {
|
||||
/* Setup MMIO virtual pointers. */
|
||||
setup_mmio_virtual_addresses();
|
||||
|
||||
/* Setup the Security Engine. */
|
||||
setup_se();
|
||||
|
||||
/* TODO: bootup_misc_mmio(). */
|
||||
/* This func will also be called on warmboot. */
|
||||
/* And will verify stored SE Test Vector, clear keyslots, */
|
||||
/* Generate an SRK, set the warmboot firmware location, */
|
||||
/* Configure the GPU uCode carveout, configure the Kernel default carveouts, */
|
||||
/* Initialize the PMC secure scratch registers, initialize MISC registers, */
|
||||
/* And assign "se_operation_completed" to Interrupt 0x5A. */
|
||||
|
||||
/* TODO: Read and save BOOTREASON stored by NX_BOOTLOADER at 0x1F009FE00 */
|
||||
|
||||
/* Initialize cache'd random bytes for kernel. */
|
||||
randomcache_init();
|
||||
|
||||
/* TODO: memclear the initial copy of Exosphere running in IRAM (relocated to TZRAM by earlier code). */
|
||||
|
||||
/* Let NX Bootloader know that we're running. */
|
||||
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE = 1;
|
||||
|
||||
/* Synchronize with NX BOOTLOADER. */
|
||||
if (MAILBOX_NX_BOOTLOADER_SETUP_STATE == NX_BOOTLOADER_STATE_INIT) {
|
||||
while (MAILBOX_NX_BOOTLOADER_SETUP_STATE < NX_BOOTLOADER_STATE_MOVED_BOOTCONFIG) {
|
||||
wait(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Load Boot Config into global. */
|
||||
setup_boot_config();
|
||||
|
||||
/* Synchronize with NX BOOTLOADER. */
|
||||
if (MAILBOX_NX_BOOTLOADER_SETUP_STATE == NX_BOOTLOADER_STATE_MOVED_BOOTCONFIG) {
|
||||
while (MAILBOX_NX_BOOTLOADER_SETUP_STATE < NX_BOOTLOADER_STATE_LOADED_PACKAGE2) {
|
||||
wait(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Parse/load Package2. */
|
||||
|
||||
}
|
24
exosphere/package2.h
Normal file
24
exosphere/package2.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef EXOSPHERE_PACKAGE2_H
|
||||
#define EXOSPHERE_PACKAGE2_H
|
||||
|
||||
/* This is code responsible for validating a package2. Actual file reading is done by bootloader. */
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bootconfig.h"
|
||||
|
||||
/* Physaddr 0x40002EF8 */
|
||||
#define MAILBOX_NX_BOOTLOADER_SETUP_STATE (*((volatile uint32_t *)(0x1F009FEF8ULL)))
|
||||
|
||||
#define NX_BOOTLOADER_STATE_INIT 0
|
||||
#define NX_BOOTLOADER_STATE_MOVED_BOOTCONFIG 1
|
||||
#define NX_BOOTLOADER_STATE_LOADED_PACKAGE2 2
|
||||
#define NX_BOOTLOADER_STATE_FINISHED 3
|
||||
|
||||
/* Physaddr 0x40002EFC */
|
||||
#define MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE (*((volatile uint32_t *)(0x1F009FEFCULL)))
|
||||
|
||||
#define NX_BOOTLOADER_BOOTCONFIG_POINTER ((void *)(0x4003D000ULL));
|
||||
|
||||
void load_package2(void);
|
||||
|
||||
#endif
|
|
@ -62,6 +62,17 @@ void se_operation_completed(void) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void se_verify_flags_cleared(void) {
|
||||
if (g_security_engine == NULL || g_security_engine->FLAGS_REG & 3) {
|
||||
panic();
|
||||
}
|
||||
}
|
||||
|
||||
void se_clear_interrupts(void) {
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
/* Set the flags for an AES keyslot. */
|
||||
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
||||
if (g_security_engine == NULL || keyslot >= KEYSLOT_AES_MAX) {
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#define KEYSLOT_SWITCH_DEVICEKEY 0xD
|
||||
|
||||
/* This keyslot was added in 4.0.0. */
|
||||
#define KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY 0xD
|
||||
#define KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY 0xE
|
||||
#define KEYSLOT_SWITCH_4XOLDDEVICEKEY 0xF
|
||||
|
||||
#define KEYSLOT_AES_MAX 0x10
|
||||
|
@ -75,7 +77,11 @@ typedef struct security_engine {
|
|||
unsigned int _0x328;
|
||||
unsigned int _0x32C;
|
||||
unsigned int CRYPTO_KEYTABLE_DST_REG;
|
||||
unsigned char _0x334[0xCC];
|
||||
unsigned char _0x334[0xC];
|
||||
unsigned int RNG_CONFIG_REG;
|
||||
unsigned int RNG_SRC_CONFIG_REG;
|
||||
unsigned int RNG_RESEED_INTERVAL_REG;
|
||||
unsigned char _0x34C[0xB4];
|
||||
unsigned int RSA_CONFIG;
|
||||
unsigned int RSA_KEY_SIZE_REG;
|
||||
unsigned int RSA_EXP_SIZE_REG;
|
||||
|
@ -123,6 +129,9 @@ security_engine_t *get_security_engine_address(void);
|
|||
void se_check_for_error(void);
|
||||
void se_trigger_interrupt(void);
|
||||
|
||||
void se_verify_flags_cleared(void);
|
||||
void se_clear_interrupts(void);
|
||||
|
||||
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags);
|
||||
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags);
|
||||
void clear_aes_keyslot(unsigned int keyslot);
|
||||
|
@ -154,6 +163,8 @@ void se_calculate_sha256(void *dst, const void *src, size_t src_size);
|
|||
void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*callback)(void));
|
||||
void se_get_exp_mod_output(void *buf, size_t size);
|
||||
|
||||
/* RNG API */
|
||||
void se_initialize_rng(unsigned int keyslot);
|
||||
void se_generate_random(unsigned int keyslot, void *dst, size_t size);
|
||||
|
||||
/* TODO: SE context save API, consider extending AES API for secure world vs non-secure world operations. */
|
||||
|
|
|
@ -158,7 +158,7 @@ uint32_t user_generate_aes_kek(smc_args_t *args) {
|
|||
unsigned int keyslot;
|
||||
if (is_personalized) {
|
||||
/* Behavior changed in 4.0.0. */
|
||||
if (mkey_get_revision() >= 4) {
|
||||
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||
if (master_key_rev >= 1) {
|
||||
keyslot = KEYSLOT_SWITCH_DEVICEKEY; /* New device key, 4.x. */
|
||||
} else {
|
||||
|
@ -288,7 +288,7 @@ uint32_t user_generate_specific_aes_key(smc_args_t *args) {
|
|||
unsigned int keyslot;
|
||||
|
||||
/* Behavior changed in 4.0.0. */
|
||||
if (mkey_get_revision() >= 4) {
|
||||
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||
if (master_key_rev >= 2) {
|
||||
keyslot = KEYSLOT_SWITCH_DEVICEKEY; /* New device key, 4.x. */
|
||||
} else {
|
||||
|
|
|
@ -82,7 +82,7 @@ __init_cold:
|
|||
msr spsel, #0
|
||||
ldr x20, =__pk2_load_stack_top__
|
||||
mov sp, x20
|
||||
bl loadPk2
|
||||
bl load_package2
|
||||
ldr x20, =__cold_init_stack_top__
|
||||
mov sp, x20
|
||||
b coldboot_main
|
||||
|
|
Loading…
Reference in a new issue