diff --git a/exosphere/src/coldboot_main.c b/exosphere/src/coldboot_main.c index d1951baff..4840dc3fc 100644 --- a/exosphere/src/coldboot_main.c +++ b/exosphere/src/coldboot_main.c @@ -7,24 +7,14 @@ extern uint8_t __pk2ldr_start__[], __pk2ldr_end__[]; -/* start.s */ -void __attribute__((noreturn)) __jump_to_lower_el(uint64_t arg, uintptr_t ep, unsigned int el); - void coldboot_main(void) { uintptr_t *mmu_l3_table = (uintptr_t *)TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGMENT_ID_L3_TRANSLATION_TABLE); uintptr_t pk2ldr = TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGMENT_ID_PK2LDR); - uintptr_t ep; - uint64_t arg; /* Clear and unmap pk2ldr (which is reused as exception entry stacks) */ memset((void *)pk2ldr, 0, __pk2ldr_end__ - __pk2ldr_start__); mmu_unmap_range(3, mmu_l3_table, pk2ldr, __pk2ldr_end__ - __pk2ldr_start__); tlb_invalidate_all_inner_shareable(); - use_core_entrypoint_and_argument(get_core_id(), &ep, &arg); - - /* Nintendo jumps to EL1, we jump to EL2. Both are supported with all current packages2. */ - /* TODO: Remove this panic() when we're ready to test Kernel handoff. */ - panic(0x7A700001); - __jump_to_lower_el(arg, ep, 2); + core_jump_to_lower_el(); } diff --git a/exosphere/src/cpu_context.c b/exosphere/src/cpu_context.c index ad3ff1d82..e78ac7a6f 100644 --- a/exosphere/src/cpu_context.c +++ b/exosphere/src/cpu_context.c @@ -7,6 +7,7 @@ #include "timers.h" #include "smc_api.h" #include "utils.h" +#include "synchronization.h" #include "preprocessor.h" #define SAVE_SYSREG64(reg) do { __asm__ __volatile__ ("mrs %0, " #reg : "=r"(temp_reg) :: "memory"); g_cpu_contexts[current_core].reg = temp_reg; } while(false) @@ -19,6 +20,12 @@ #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); +/* start.s */ +void __attribute__((noreturn)) __jump_to_lower_el(uint64_t arg, uintptr_t ep, unsigned int el); + +/* See notes in start.s */ +critical_section_t g_boot_critical_section = {{{.ticket_number = 1}}}; + static saved_cpu_context_t g_cpu_contexts[NUM_CPU_CORES] = {0}; void use_core_entrypoint_and_argument(uint32_t core, uintptr_t *entrypoint_addr, uint64_t *argument) { @@ -40,6 +47,22 @@ void set_core_entrypoint_and_argument(uint32_t core, uintptr_t entrypoint_addr, g_cpu_contexts[core].argument = argument; } +void core_jump_to_lower_el(void) { + uintptr_t ep; + uint64_t arg; + unsigned int core_id = get_core_id(); + + use_core_entrypoint_and_argument(core_id, &ep, &arg); + critical_section_leave(&g_boot_critical_section); + flush_dcache_range(&g_boot_critical_section, (uint8_t *)&g_boot_critical_section + sizeof(g_boot_critical_section)); /* already does a dsb sy */ + __sev(); + + /* Nintendo jumps to EL1, we jump to EL2. Both are supported with all current packages2. */ + /* TODO: Remove this panic() when we're ready to test Kernel handoff. */ + panic(0x7A700001); + __jump_to_lower_el(arg, ep, 2); +} + uint32_t cpu_on(uint32_t core, uintptr_t entrypoint_addr, uint64_t argument) { /* Is core valid? */ if (core >= NUM_CPU_CORES) { diff --git a/exosphere/src/cpu_context.h b/exosphere/src/cpu_context.h index 2b4f6b6d6..dcbe0e9dd 100644 --- a/exosphere/src/cpu_context.h +++ b/exosphere/src/cpu_context.h @@ -1,11 +1,13 @@ #ifndef EXOSPHERE_CPU_CTX_H #define EXOSPHERE_CPU_CTX_H -#include -#include +#include "utils.h" +#include "synchronization.h" /* Exosphere CPU Management functionality. */ +extern critical_section_t g_boot_critical_section; + typedef struct { uint64_t argument; uint64_t ELR_EL3; @@ -54,6 +56,7 @@ void set_current_core_inactive(void); void use_core_entrypoint_and_argument(uint32_t core, uintptr_t *entrypoint_addr, uint64_t *argument); void set_core_entrypoint_and_argument(uint32_t core, uintptr_t entrypoint_addr, uint64_t argument); +void core_jump_to_lower_el(void); uint32_t cpu_on(uint32_t core, uintptr_t entrypoint_addr, uint64_t argument); uint32_t cpu_off(void); diff --git a/exosphere/src/start.s b/exosphere/src/start.s index d09929b41..13536c1e0 100644 --- a/exosphere/src/start.s +++ b/exosphere/src/start.s @@ -76,6 +76,11 @@ __start_cold: ERRATUM_INVALIDATE_BTB_AT_BOOT + /* + This coldboot crt0 doesn't enter the boot critical section in the official monitor. + However we'll initialize g_boot_critical_section so that it acts like core0 has entered it, + for it to be in .data and for safety. + */ msr spsel, #0 bl get_coldboot_crt0_stack_address mov sp, x0 @@ -96,8 +101,22 @@ __start_cold: __start_warm: ERRATUM_INVALIDATE_BTB_AT_BOOT - /* For some reasons, Nintendo uses spsel, #1 here, causing issues if an exception occurs */ + /* For some reasons, Nintendo uses spsel, #1 around here, causing issues if an exception occurs */ msr spsel, #0 + + /* Nintendo doesn't use anything like the following two lines, but their critical section algo is borked */ + /* FWIW this function doesn't use a stack atm, with latest GCC, but that might change. */ + bl get_warmboot_crt0_stack_address_critsec_enter + mov sp, x0 + + /* PA(__main_start__) = __warmboot_crt0_start__ + 0x800 (refer to the linker script) */ + ldr x0, =g_boot_critical_section + ldr x1, =__main_start__ + sub x0, x0, x1 + ldr x1, =(__start_warm + 0x800) + add x0, x0, x1 + bl warmboot_crt0_critical_section_enter + bl get_warmboot_crt0_stack_address mov sp, x0 mov fp, #0 diff --git a/exosphere/src/warmboot_init.c b/exosphere/src/warmboot_init.c index f8116e360..d3bd83a19 100644 --- a/exosphere/src/warmboot_init.c +++ b/exosphere/src/warmboot_init.c @@ -2,6 +2,8 @@ #include "memory_map.h" #include "arm.h" +#include "synchronization.h" + /* start.s */ void __set_memory_registers(uintptr_t ttbr0, uintptr_t vbar, uint64_t cpuectlr, uint32_t scr, uint32_t tcr, uint32_t cptr, uint64_t mair, uint32_t sctlr); @@ -10,6 +12,21 @@ uintptr_t get_warmboot_crt0_stack_address(void) { return TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_CORE012_STACK) + 0x800; } +uintptr_t get_warmboot_crt0_stack_address_critsec_enter(void) { + unsigned int core_id = get_core_id(); + + if (core_id) { + return TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_CORE3_STACK) + 0x1000; + } + else { + return TZRAM_GET_SEGMENT_PA(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x80 * (core_id + 1); + } +} + +void warmboot_crt0_critical_section_enter(volatile critical_section_t *critical_section) { + critical_section_enter(critical_section); +} + void set_memory_registers_enable_mmu(void) { static const uintptr_t vbar = TZRAM_GET_SEGMENT_PA(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x800; static const uintptr_t ttbr0 = vbar - 64; diff --git a/exosphere/src/warmboot_main.c b/exosphere/src/warmboot_main.c index 8442f6065..4d0eb1f59 100644 --- a/exosphere/src/warmboot_main.c +++ b/exosphere/src/warmboot_main.c @@ -1,10 +1,9 @@ #include "utils.h" #include "mmu.h" #include "memory_map.h" - -/* start.s */ -void __jump_to_lower_el(uint64_t arg, uintptr_t ep, unsigned int el); +#include "cpu_context.h" void warmboot_main(void) { - /* TODO */ + /* TODO: lots of stuff */ + core_jump_to_lower_el(); }