Push WIP NX_BOOTLOADER sync code (for coldboots)

This commit is contained in:
Michael Scire 2018-02-21 10:57:51 -08:00
parent 330f8a0f8b
commit f0d0ec0dca
9 changed files with 213 additions and 4 deletions

18
exosphere/bootconfig.h Normal file
View 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

View file

@ -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

View file

@ -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
View 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
View 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

View file

@ -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) {

View file

@ -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. */

View file

@ -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 {

View file

@ -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