exosphere: commit WIP warmboot progress

-15+ bugs fixed
-We now receive ~0x400 SMCs from user processes
 (including from psm) on wake-from-sleep
This commit is contained in:
Michael Scire 2018-08-16 18:45:38 -07:00
parent de49cfefac
commit f41aaccaa2
12 changed files with 105 additions and 25 deletions

View file

@ -26,7 +26,6 @@ typedef struct {
bootconfig_unsigned_config_t unsigned_config;
uint8_t signature[0x100];
bootconfig_signed_config_t signed_config;
uint8_t unused_space[0x240]; /* remaining space in the evt page */
} bootconfig_t;
static inline bootconfig_t *get_loaded_bootconfig(void) {

View file

@ -268,7 +268,7 @@ void setup_current_core_state(void) {
uint64_t temp_reg;
/* Setup system registers. */
SET_SYSREG(spsr_el3, 0b1111 << 6 | 0b1001); /* use EL2h+DAIF set initially, may be overwritten later. Not in official code */
SET_SYSREG(spsr_el3, 0b1111 << 6 | 0b0101); /* use EL2h+DAIF set initially, may be overwritten later. Not in official code */
SET_SYSREG(actlr_el3, 0x73ull);
SET_SYSREG(actlr_el2, 0x73ull);

View file

@ -0,0 +1,8 @@
#ifndef EXOSPHERE_BPMPFW_DEBUG_H
#define EXOSPHERE_BPMPFW_DEBUG_H
static const unsigned char g_bpmpfw_for_debug[0x584] = {
/* ... */
};
#endif

View file

@ -14,6 +14,8 @@
#define CLK_RST_CONTROLLER_MISC_CLK_ENB_0 MAKE_CAR_REG(0x048)
#define CLK_RST_CONTROLLER_RST_DEVICES_H_0 MAKE_CAR_REG(0x008)
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD_0 MAKE_CAR_REG(0x3A4)
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET_0 MAKE_CAR_REG(0x450)
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR_0 MAKE_CAR_REG(0x454)
#define NUM_CAR_BANKS 7

View file

@ -2,6 +2,8 @@
#include <stdint.h>
#include "arm.h"
#include "cpu_context.h"
#include "car.h"
#include "exocfg.h"
#include "flow.h"
#include "pmc.h"
#include "timers.h"
@ -18,7 +20,7 @@
#define RESTORE_SYSREG64(reg) do { temp_reg = g_cpu_contexts[current_core].reg; __asm__ __volatile__ ("msr " #reg ", %0" :: "r"(temp_reg) : "memory"); } while(false)
#define RESTORE_SYSREG32(reg) RESTORE_SYSREG64(reg)
#define RESTORE_BP_REG(i, _) RESTORE_SYSREG64(DBGBVR##i##_EL1); RESTORE_SYSREG64(DBGBCR##i##_EL1);
#define RESTORE_WP_REG(i, _) RESTORE_SYSREG64(DBGBVR##i##_EL1); RESTORE_SYSREG64(DBGBCR##i##_EL1);
#define RESTORE_WP_REG(i, _) RESTORE_SYSREG64(DBGWVR##i##_EL1); RESTORE_SYSREG64(DBGWCR##i##_EL1);
/* start.s */
void __attribute__((noreturn)) __jump_to_lower_el(uint64_t arg, uintptr_t ep, uint32_t spsr);
@ -79,8 +81,13 @@ uint32_t cpu_on(uint32_t core, uintptr_t entrypoint_addr, uint64_t argument) {
set_core_entrypoint_and_argument(core, entrypoint_addr, argument);
const uint32_t status_masks[NUM_CPU_CORES] = {0x4000, 0x200, 0x400, 0x800};
const uint32_t toggle_vals[NUM_CPU_CORES] = {0xE, 0x9, 0xA, 0xB};
static const uint32_t status_masks[NUM_CPU_CORES] = {0x4000, 0x200, 0x400, 0x800};
static const uint32_t toggle_vals[NUM_CPU_CORES] = {0xE, 0x9, 0xA, 0xB};
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {
/* Reset the core */
CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET_0 = (1 << (core + 0x10)) | (1 << core);
}
/* Check if we're already in the correct state. */
if ((APBDEV_PMC_PWRGATE_STATUS_0 & status_masks[core]) != status_masks[core]) {
@ -91,7 +98,7 @@ uint32_t cpu_on(uint32_t core, uintptr_t entrypoint_addr, uint64_t argument) {
wait(1);
counter--;
if (counter < 1) {
return 0;
goto CPU_ON_SUCCESS;
}
}
@ -108,6 +115,13 @@ uint32_t cpu_on(uint32_t core, uintptr_t entrypoint_addr, uint64_t argument) {
counter--;
}
}
CPU_ON_SUCCESS:
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {
/* Start the core */
CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR_0 = (1 << (core + 0x10)) | (1 << core);
}
return 0;
}
@ -145,6 +159,7 @@ void save_current_core_context(void) {
/* Save system registers. */
SAVE_SYSREG32(OSDTRRX_EL1);
SAVE_SYSREG32(OSDTRTX_EL1);
SAVE_SYSREG32(MDSCR_EL1);
SAVE_SYSREG32(OSECCR_EL1);
SAVE_SYSREG32(MDCCINT_EL1);
@ -168,6 +183,7 @@ void restore_current_core_context(void) {
if (g_cpu_contexts[current_core].is_saved) {
RESTORE_SYSREG32(OSDTRRX_EL1);
RESTORE_SYSREG32(OSDTRTX_EL1);
RESTORE_SYSREG32(MDSCR_EL1);
RESTORE_SYSREG32(OSECCR_EL1);
RESTORE_SYSREG32(MDCCINT_EL1);

View file

@ -23,16 +23,21 @@
#define u8 uint8_t
#define u32 uint32_t
#include "bpmpfw_bin.h"
#include "bpmpfw_debug.h"
#undef u8
#undef u32
/* Save security engine, and go to sleep. */
void save_se_and_power_down_cpu(void) {
/* TODO: Remove set suspend call once exo warmboots fully */
set_suspend_for_debug();
uint32_t tzram_cmac[0x4] = {0};
uint8_t *tzram_encryption_dst = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_ENCRYPTED_TZRAM));
uint8_t *tzram_encryption_src = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM));
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) {
tzram_encryption_src += 0x2000ull;
}
uint8_t *tzram_store_address = (uint8_t *)(WARMBOOT_GET_RAM_SEGMENT_ADDRESS(WARMBOOT_RAM_SEGMENT_ID_TZRAM));
clear_priv_smc_in_progress();
@ -45,17 +50,20 @@ void save_se_and_power_down_cpu(void) {
flush_dcache_range(tzram_encryption_dst, tzram_encryption_dst + LP0_TZRAM_SAVE_SIZE);
flush_dcache_range(tzram_encryption_src, tzram_encryption_src + LP0_TZRAM_SAVE_SIZE);
/* Use the all-zero cmac buffer as an IV. */
/* Use the all-zero cmac buffer as an IV. */
se_aes_256_cbc_encrypt(KEYSLOT_SWITCH_LP0TZRAMKEY, tzram_encryption_dst, LP0_TZRAM_SAVE_SIZE, tzram_encryption_src, LP0_TZRAM_SAVE_SIZE, tzram_cmac);
flush_dcache_range(tzram_encryption_dst, tzram_encryption_dst + LP0_TZRAM_SAVE_SIZE);
/* Copy encrypted TZRAM from IRAM to DRAM. */
memcpy(tzram_store_address, tzram_encryption_dst, LP0_TZRAM_SAVE_SIZE);
for (unsigned int i = 0; i < LP0_TZRAM_SAVE_SIZE; i += 4) {
write32le(tzram_store_address, i, read32le(tzram_encryption_dst, i));
}
flush_dcache_range(tzram_store_address, tzram_store_address + LP0_TZRAM_SAVE_SIZE);
/* Compute CMAC. */
se_compute_aes_256_cmac(KEYSLOT_SWITCH_LP0TZRAMKEY, tzram_cmac, sizeof(tzram_cmac), tzram_encryption_src, LP0_TZRAM_SAVE_SIZE);
/* Write CMAC, lock registers. */
APBDEV_PMC_SECURE_SCRATCH112_0 = tzram_cmac[0];
APBDEV_PMC_SECURE_SCRATCH113_0 = tzram_cmac[1];
@ -76,6 +84,8 @@ void save_se_and_power_down_cpu(void) {
if (!configitem_is_retail()) {
/* TODO: uart_log("OYASUMI"); */
}
__dsb_sy();
finalize_powerdown();
}
@ -85,6 +95,7 @@ uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argumen
if ((power_state & 0x17FFF) != 0x1001B) {
return 0xFFFFFFFD;
}
unsigned int current_core = get_core_id();
@ -169,14 +180,17 @@ uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argumen
BPMP_VECTOR_UNK = 0x40003004; /* Reboot. */
BPMP_VECTOR_IRQ = 0x40003004; /* Reboot. */
BPMP_VECTOR_FIQ = 0x40003004; /* Reboot. */
/* Hold the BPMP in reset. */
MAKE_CAR_REG(0x300) = 2;
/* Copy BPMP firmware. */
uint8_t *lp0_entry_code = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_LP0_ENTRY_CODE));
memcpy(lp0_entry_code, bpmpfw_bin, bpmpfw_bin_size);
flush_dcache_range(lp0_entry_code, lp0_entry_code + bpmpfw_bin_size);
for (unsigned int i = 0; i < sizeof(g_bpmpfw_for_debug); i += 4) {
write32le(lp0_entry_code, i, read32le(g_bpmpfw_for_debug, i));
}
flush_dcache_range(lp0_entry_code, lp0_entry_code + sizeof(g_bpmpfw_for_debug));
/* Take the BPMP out of reset. */
MAKE_CAR_REG(0x304) = 2;
@ -188,11 +202,13 @@ uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argumen
flow_set_halt_events(current_core, false);
FLOW_CTLR_L2FLUSH_CONTROL_0 = 0;
flow_set_csr(current_core, 2);
/* Save core context. */
set_core_entrypoint_and_argument(current_core, entrypoint, argument);
save_current_core_context();
set_current_core_inactive();
call_with_stack_pointer(get_smc_core012_stack_address(), save_se_and_power_down_cpu);
generic_panic();

View file

@ -382,13 +382,32 @@ static void load_package2_sections(package2_meta_t *metadata, uint32_t master_ke
memset(load_buf, 0, PACKAGE2_SIZE_MAX);
}
static void copy_warmboot_bin_to_dram() {
uint8_t *warmboot_src = (uint8_t *)0x4003B000;
uint8_t *warmboot_dst = (uint8_t *)0x8000D000;
const size_t warmboot_size = 0x2000;
/* Flush cache, to ensure warmboot is where we need it to be. */
flush_dcache_range(warmboot_src, warmboot_src + warmboot_size);
__dsb_sy();
/* Copy warmboot. */
for (size_t i = 0; i < warmboot_size; i += sizeof(uint32_t)) {
write32le(warmboot_dst, i, read32le(warmboot_src, i));
}
/* Flush cache, to ensure warmboot is where we need it to be. */
flush_dcache_range(warmboot_dst, warmboot_dst + warmboot_size);
__dsb_sy();
}
static void sync_with_nx_bootloader(int state) {
while (MAILBOX_NX_BOOTLOADER_SETUP_STATE < state) {
wait(100);
}
}
static void indentity_unmap_dram(void) {
static void identity_unmap_dram(void) {
uintptr_t *mmu_l1_tbl = (uintptr_t *)(TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x800 - 64);
mmu_unmap_range(1, mmu_l1_tbl, IDENTITY_GET_MAPPING_ADDRESS(IDENTITY_MAPPING_DRAM), IDENTITY_GET_MAPPING_SIZE(IDENTITY_MAPPING_DRAM));
@ -410,6 +429,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Perform initial PMC register writes, if relevant. */
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {
MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000;
MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF;
MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE;
MAKE_REG32(PMC_BASE + 0x334) |= 0x10;
@ -453,7 +473,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Synchronize with NX BOOTLOADER. */
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X);
/* TODO: copy_warmboot_bin_to_dram(); */
copy_warmboot_bin_to_dram();
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_LOADED_PACKAGE2_4X);
} else {
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_LOADED_PACKAGE2);
@ -461,7 +481,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Make PMC (2.x+), MC (4.x+) registers secure-only */
secure_additional_devices();
/* Remove the identity mapping for iRAM-C+D & TZRAM */
/* For our crt0 to work, this doesn't actually unmap TZRAM */
identity_unmap_iram_cd_tzram();
@ -499,7 +519,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
set_core_entrypoint_and_argument(0, DRAM_BASE_PHYSICAL + header.metadata.entrypoint, 0);
/* Remove the DRAM identity mapping. */
indentity_unmap_dram();
if (0) {
identity_unmap_dram();
}
/* Synchronize with NX BOOTLOADER. */
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {

View file

@ -121,6 +121,11 @@ static atomic_flag g_is_priv_smc_in_progress = ATOMIC_FLAG_INIT;
/* Global for smc_configure_carveout. */
static bool g_configured_carveouts[2] = {false, false};
static bool g_has_suspended = false;
void set_suspend_for_debug(void) {
g_has_suspended = true;
}
void set_version_specific_smcs(void) {
switch (exosphere_get_target_firmware()) {
case EXOSPHERE_TARGET_FIRMWARE_100:
@ -207,7 +212,7 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) {
unsigned char smc_id;
unsigned int result;
unsigned int (*smc_handler)(smc_args_t *args);
/* Validate top-level handler. */
if (handler_id != SMC_HANDLER_USER && handler_id != SMC_HANDLER_PRIV) {
generic_panic();

View file

@ -22,6 +22,9 @@ uintptr_t get_exception_entry_stack_address(unsigned int core_id);
void set_version_specific_smcs(void);
void set_suspend_for_debug(void);
void call_smc_handler(unsigned int handler_id, smc_args_t *args);
#endif

View file

@ -223,8 +223,8 @@ __jump_to_main_warm:
bl __set_exception_entry_stack_pointer
mov w0, #0 /* use core0,1,2 stack bottom + 0x800 (VA of warmboot crt0 sp) temporarily */
bl get_exception_entry_stack_address
add sp, x0, #0x800
bl get_warmboot_main_stack_address
mov sp, x0
bl warmboot_main
.section .text.__set_exception_entry_stack, "ax", %progbits
@ -248,12 +248,14 @@ __set_exception_entry_stack_pointer:
.type __jump_to_lower_el, %function
__jump_to_lower_el:
/* x0: arg (context ID), x1: entrypoint, w2: spsr */
mov x19, x0
mov w2, w2
msr elr_el3, x1
msr spsr_el3, x2
bl __set_exception_entry_stack_pointer
mov x0, x19
isb
eret

View file

@ -4,6 +4,7 @@
#include "arm.h"
#include "synchronization.h"
#include "exocfg.h"
#include "pmc.h"
#undef MC_BASE
#define MC_BASE (MMIO_GET_DEVICE_PA(MMIO_DEVID_MC))
@ -24,7 +25,7 @@ uintptr_t get_warmboot_crt0_stack_address(void) {
uintptr_t get_warmboot_crt0_stack_address_critsec_enter(void) {
unsigned int core_id = get_core_id();
if (core_id) {
if (core_id == 3) {
return WARMBOOT_GET_TZRAM_SEGMENT_PA(TZRAM_SEGMENT_ID_CORE3_STACK) + 0x1000;
} else {
return WARMBOOT_GET_TZRAM_SEGMENT_PA(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x80 * (core_id + 1);
@ -180,12 +181,12 @@ void warmboot_init(void) {
*/
flush_dcache_all();
invalidate_icache_all();
/* On warmboot (not cpu_on) only */
if (MC_SECURITY_CFG3_0 == 0) {
init_dma_controllers(g_exosphere_target_firmware_for_init);
}
/*identity_remap_tzram();*/
/* Nintendo pointlessly fully invalidate the TLB & invalidate the data cache on the modified ranges here */
if (g_exosphere_target_firmware_for_init < EXOSPHERE_TARGET_FIRMWARE_500) {

View file

@ -16,6 +16,12 @@
#include "misc.h"
#include "interrupt.h"
#include "pmc.h"
uintptr_t get_warmboot_main_stack_address(void) {
return TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x780;
}
void __attribute__((noreturn)) warmboot_main(void) {
/*
This function and its callers are reached in either of the following events, under normal conditions:
@ -53,7 +59,7 @@ void __attribute__((noreturn)) warmboot_main(void) {
PINMUX_AUX_GEN1_I2C_SCL_0 = 0x40;
PINMUX_AUX_GEN1_I2C_SDA_0 = 0x40;
clkrst_enable(CARDEVICE_I2C1);
clkrst_reboot(CARDEVICE_I2C1);
i2c_init(0);
i2c_clear_ti_charger_bit_7();
clkrst_disable(CARDEVICE_I2C1);