mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
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:
parent
de49cfefac
commit
f41aaccaa2
12 changed files with 105 additions and 25 deletions
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
8
exosphere/src/bpmpfw_debug.h
Normal file
8
exosphere/src/bpmpfw_debug.h
Normal 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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue