diff --git a/exosphere/src/bootup.c b/exosphere/src/bootup.c index 29bad2497..7015a9085 100644 --- a/exosphere/src/bootup.c +++ b/exosphere/src/bootup.c @@ -3,12 +3,83 @@ #include "utils.h" #include "bootup.h" +#include "fuse.h" +#include "flow.h" +#include "pmc.h" +#include "mc.h" +#include "se.h" +#include "masterkey.h" +#include "configitem.h" +#include "misc.h" + void bootup_misc_mmio(void) { + /* Initialize Fuse registers. */ + fuse_init(); + + /* Verify Security Engine sanity. */ + se_set_in_context_save_mode(false); + /* TODO: se_verify_keys_unreadable(); */ + se_validate_stored_vector(); + + for (unsigned int i = 0; i < KEYSLOT_SWITCH_SESSIONKEY; i++) { + clear_aes_keyslot(i); + } + + for (unsigned int i = 0; i < KEYSLOT_RSA_MAX; i++) { + clear_rsa_keyslot(i); + } + se_initialize_rng(KEYSLOT_SWITCH_RNGKEY); + se_generate_random_key(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY); + se_generate_srk(KEYSLOT_SWITCH_SRKGENKEY); + + FLOW_CTLR_BPMP_CLUSTER_CONTROL_0 = 4; /* ACTIVE_CLUSTER_LOCK. */ + FLOW_CTLR_FLOW_DBG_QUAL_0 = 0x10000000; /* Enable FIQ2CCPLEX */ + + /* Disable Deep Power Down. */ + APBDEV_PMC_DPD_ENABLE_0 = 0; + + /* Setup MC. */ + /* TODO: What are these MC reg writes? */ + MAKE_MC_REG(0x984) = 1; + MAKE_MC_REG(0x648) = 0; + MAKE_MC_REG(0x64C) = 0; + MAKE_MC_REG(0x650) = 1; + MAKE_MC_REG(0x670) = 0; + MAKE_MC_REG(0x674) = 0; + MAKE_MC_REG(0x678) = 1; + MAKE_MC_REG(0x9A0) = 0; + MAKE_MC_REG(0x9A4) = 0; + MAKE_MC_REG(0x9A8) = 0; + MAKE_MC_REG(0x9AC) = 1; + MC_SECURITY_CFG0_0 = 0; + MC_SECURITY_CFG1_0 = 0; + MC_SECURITY_CFG3_0 = 3; + configure_default_carveouts(); + + /* Mark registers secure world only. */ + /* Mark SATA_AUX, DTV, QSPI, SE, SATA, LA secure only. */ + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 = 0x504244; + + /* By default, mark SPI1, SPI2, SPI3, SPI5, SPI6, I2C6 secure only. */ + uint32_t sec_disable_1 = 0x83700000; + /* By default, mark SDMMC3, DDS, DP2 secure only. */ + uint32_t sec_disable_2 = 0x304; + uint64_t hardware_type = configitem_get_hardware_type(); + if (hardware_type != 1) { + /* Also mark I2C5 secure only, */ + sec_disable_1 |= 0x20000000; + } + if (hardware_type != 0 && mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) { + /* Starting on 4.x on non-dev units, mark UARTB, UARTC, SPI4, I2C3 secure only. */ + sec_disable_1 |= 0x10806000; + /* Starting on 4.x on non-dev units, mark SDMMC1 secure only. */ + sec_disable_2 |= 1; + } + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 = sec_disable_1; + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 = sec_disable_2; + + /* TODO */ - /* 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. */ } diff --git a/exosphere/src/configitem.c b/exosphere/src/configitem.c index fc9af2b88..e97c8ed22 100644 --- a/exosphere/src/configitem.c +++ b/exosphere/src/configitem.c @@ -41,6 +41,14 @@ bool configitem_should_profile_battery(void) { return g_battery_profile; } +uint64_t configitem_get_hardware_type(void) { + uint64_t hardware_type; + if (configitem_get(CONFIGITEM_HARDWARETYPE, &hardware_type) != 0) { + generic_panic(); + } + return hardware_type; +} + uint32_t configitem_get(enum ConfigItem item, uint64_t *p_outvalue) { uint32_t result = 0; switch (item) { diff --git a/exosphere/src/configitem.h b/exosphere/src/configitem.h index 465ae4740..edc505325 100644 --- a/exosphere/src/configitem.h +++ b/exosphere/src/configitem.h @@ -27,4 +27,6 @@ bool configitem_is_recovery_boot(void); bool configitem_is_retail(void); bool configitem_should_profile_battery(void); +uint64_t configitem_get_hardware_type(void); + #endif diff --git a/exosphere/src/flow.h b/exosphere/src/flow.h index 9716aa546..4d7066c69 100644 --- a/exosphere/src/flow.h +++ b/exosphere/src/flow.h @@ -16,7 +16,9 @@ static inline uintptr_t get_flow_base(void) { #define MAKE_FLOW_REG(ofs) (*((volatile uint32_t *)(FLOW_BASE + ofs))) #define FLOW_CTLR_HALT_COP_EVENTS_0 MAKE_FLOW_REG(0x004) +#define FLOW_CTLR_FLOW_DBG_QUAL_0 MAKE_FLOW_REG(0x050) #define FLOW_CTLR_L2FLUSH_CONTROL_0 MAKE_FLOW_REG(0x094) +#define FLOW_CTLR_BPMP_CLUSTER_CONTROL_0 MAKE_FLOW_REG(0x098) static const struct { diff --git a/exosphere/src/fuse.c b/exosphere/src/fuse.c index de65e4847..a88b13490 100644 --- a/exosphere/src/fuse.c +++ b/exosphere/src/fuse.c @@ -16,6 +16,8 @@ void fuse_wait_idle(void); void fuse_init(void) { fuse_make_regs_visible(); + fuse_secondary_private_key_disable(); + fuse_disable_programming(); /* TODO: Overrides (iROM patches) and various reads happen here */ } diff --git a/exosphere/src/mc.h b/exosphere/src/mc.h index 5c5b613b4..f7291f2f4 100644 --- a/exosphere/src/mc.h +++ b/exosphere/src/mc.h @@ -12,6 +12,13 @@ static inline uintptr_t get_mc_base(void) { #define MC_BASE (get_mc_base()) +#define MAKE_MC_REG(n) (*((volatile uint32_t *)(MC_BASE + n))) + +#define MC_SECURITY_CFG0_0 MAKE_MC_REG(0x070) +#define MC_SECURITY_CFG1_0 MAKE_MC_REG(0x074) +#define MC_SECURITY_CFG3_0 MAKE_MC_REG(0x9BC) + + #define CARVEOUT_ID_MIN 1 #define CARVEOUT_ID_MAX 5 diff --git a/exosphere/src/misc.h b/exosphere/src/misc.h new file mode 100644 index 000000000..68016ea76 --- /dev/null +++ b/exosphere/src/misc.h @@ -0,0 +1,19 @@ +#ifndef EXOSPHERE_MISC_H +#define EXOSPHERE_MISC_H + +#include + +#include "memory_map.h" + +/* Exosphere driver for the Tegra X1 MISC Registers. */ + +#define MISC_BASE (MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MISC)) + +#define MAKE_MISC_REG(n) (*((volatile uint32_t *)(MISC_BASE + n))) + + +#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 MAKE_MISC_REG(0x0C00) +#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 MAKE_MISC_REG(0x0C04) +#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 MAKE_MISC_REG(0x0C08) + +#endif \ No newline at end of file diff --git a/exosphere/src/se.c b/exosphere/src/se.c index e14933d57..b912e7f9d 100644 --- a/exosphere/src/se.c +++ b/exosphere/src/se.c @@ -16,6 +16,9 @@ static unsigned int (*g_se_callback)(void); static unsigned int g_se_modulus_sizes[KEYSLOT_RSA_MAX]; static unsigned int g_se_exp_sizes[KEYSLOT_RSA_MAX]; +static bool g_se_generated_vector = false; +static uint8_t g_se_stored_test_vector[0x10]; + /* Initialize a SE linked list. */ void ll_init(se_ll_t *ll, void *buffer, size_t size) { @@ -71,6 +74,35 @@ void se_verify_flags_cleared(void) { } } + +void se_generate_test_vector(void *vector) { + /* TODO: Implement real test vector generation. */ + memset(vector, 0, 0x10); +} + +void se_validate_stored_vector(void) { + if (!g_se_generated_vector) { + generic_panic(); + } + + uint8_t calc_vector[0x10]; + se_generate_test_vector(calc_vector); + + /* Ensure nobody's messed with the security engine while we slept. */ + if (memcmp(calc_vector, g_se_stored_test_vector, 0x10) != 0) { + generic_panic(); + } +} + +void se_generate_stored_vector(void) { + if (g_se_generated_vector) { + generic_panic(); + } + + se_generate_test_vector(g_se_stored_test_vector); + g_se_generated_vector = true; +} + /* Set the flags for an AES keyslot. */ void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) { if (keyslot >= KEYSLOT_AES_MAX) { diff --git a/exosphere/src/se.h b/exosphere/src/se.h index 279106ae5..fa5feff36 100644 --- a/exosphere/src/se.h +++ b/exosphere/src/se.h @@ -173,6 +173,9 @@ void se_check_error_status_reg(void); void se_check_for_error(void); void se_trigger_interrupt(void); +void se_validate_stored_vector(void); +void se_generate_stored_vector(void); + void se_verify_flags_cleared(void); void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags); @@ -215,6 +218,7 @@ void se_initialize_rng(unsigned int keyslot); void se_generate_random(unsigned int keyslot, void *dst, size_t size); /* SE context save API. */ +void se_generate_srk(unsigned int srkgen_keyslot); void se_set_in_context_save_mode(bool is_context_save_mode); void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot); void se_save_context(unsigned int srk_keyslot, unsigned int rng_keyslot, void *dst);