From be6b67669fbd523002f321e14f42a8fc31fc6901 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Sat, 3 Mar 2018 16:58:23 +0100 Subject: [PATCH] Finish writing warmboot _crt0_ --- exosphere/src/coldboot_init.c | 46 +++++----------------- exosphere/src/start.s | 3 +- exosphere/src/utils.h | 3 +- exosphere/src/warmboot_init.c | 74 +++++++++++++++++++++++++++++++++-- 4 files changed, 85 insertions(+), 41 deletions(-) diff --git a/exosphere/src/coldboot_init.c b/exosphere/src/coldboot_init.c index e7ea268e5..f0915d0cd 100644 --- a/exosphere/src/coldboot_init.c +++ b/exosphere/src/coldboot_init.c @@ -122,39 +122,6 @@ uintptr_t get_coldboot_crt0_stack_address(void) { return TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_CORE3_STACK) + 0x800; } -void coldboot_init_dma_controllers(void) { - /* SYSCTR0_CNTCR_0 = ENABLE | HALT_ON_DEBUG (write-once init) */ - (*((volatile uint32_t *)(0x700F0000))) = 3; - - /* Set some unknown registers in HOST1X. */ - (*((volatile uint32_t *)(0x500038F8))) &= 0xFFFFFFFE; - (*((volatile uint32_t *)(0x50003300))) = 0; - - /* AHB_MASTER_SWID_0 */ - (*((volatile uint32_t *)(0x6000C018))) = 0; - - /* AHB_MASTER_SWID_1 - Makes USB1/USB2 use SWID[1] */ - (*((volatile uint32_t *)(0x6000C038))) = 0x40040; - - /* APBDMA_CHANNEL_SWID_0 = ~0 (SWID = 1 for all APB-DMA channels) */ - (*((volatile uint32_t *)(0x6002003C))) = 0xFFFFFFFF; - - /* APBDMA_CHANNEL_SWID1_0 = 0 (See above) */ - (*((volatile uint32_t *)(0x60020054))) = 0; - - /* APBDMA_SECURITY_REG_0 = 0 (All APB-DMA channels non-secure) */ - (*((volatile uint32_t *)(0x60020038))) = 0; - - /* MSELECT_CONFIG_0 |= WRAP_TO_INCR_SLAVE0(APC) | WRAP_TO_INCR_SLAVE1(PCIe) | WRAP_TO_INCR_SLAVE2(GPU) */ - (*((volatile uint32_t *)(0x50060000))) |= 0x38000000; - - /* AHB_ARBITRATION_PRIORITY_CTRL_0 - Select high prio group with prio 7 */ - (*((volatile uint32_t *)(0x6000C008))) = 0xE0000001; - - /* AHB_GIZMO_TZRAM_0 |= DONT_SPLIT_AHB_WR */ - (*((volatile uint32_t *)(0x6000C054))) = 0x80; -} - void coldboot_init(coldboot_crt0_reloc_list_t *reloc_list, boot_func_list_t *func_list, boot_func_list_t *func_list_warmboot) { /* Custom approach */ reloc_list->reloc_base = (uintptr_t)__start_cold; @@ -168,8 +135,16 @@ void coldboot_init(coldboot_crt0_reloc_list_t *reloc_list, boot_func_list_t *fun /* At this point, we can (and will) access functions located in .warm_crt0 */ translate_warmboot_func_list(reloc_list, func_list); - /* TODO: 4.x does slightly different init. How should we handle this? We can't detect master key revision yet. */ - coldboot_init_dma_controllers(); + /* + From https://events.static.linuxfound.org/sites/events/files/slides/slides_17.pdf : + Caches may write back dirty lines at any time: + - To make space for new allocations + - Even if MMU is off + - Even if Cacheable accesses are disabled (caches are never 'off') + */ + func_list->funcs.flush_dcache_all(); + func_list->funcs.invalidate_icache_all(); + func_list->funcs.init_dma_controllers(); configure_ttbls(); func_list->funcs.set_memory_registers_enable_mmu(); @@ -179,7 +154,6 @@ void coldboot_init(coldboot_crt0_reloc_list_t *reloc_list, boot_func_list_t *fun do_relocation(reloc_list, reloc_list->nb_relocs_pre_mmu_init + i); } - func_list->funcs.flush_dcache_all(); func_list->funcs.invalidate_icache_all(); /* At this point we can access all the mapped segments (all other functions, data...) normally */ diff --git a/exosphere/src/start.s b/exosphere/src/start.s index 441433681..456862906 100644 --- a/exosphere/src/start.s +++ b/exosphere/src/start.s @@ -242,8 +242,9 @@ g_coldboot_crt0_relocation_list: .align 3 .global g_coldboot_crt0_main_func_list g_coldboot_crt0_main_func_list: - .quad 3 /* Number of functions */ + .quad 4 /* Number of functions */ /* Functions */ + .quad init_dma_controllers .quad set_memory_registers_enable_mmu .quad flush_dcache_all .quad invalidate_icache_all diff --git a/exosphere/src/utils.h b/exosphere/src/utils.h index 0aadc1172..ce5c290f6 100644 --- a/exosphere/src/utils.h +++ b/exosphere/src/utils.h @@ -24,11 +24,12 @@ typedef struct { size_t nb_funcs; union { struct { + void (*init_dma_controllers)(void); void (*set_memory_registers_enable_mmu)(void); void (*flush_dcache_all)(void); void (*invalidate_icache_all)(void); } funcs; - uintptr_t addrs[3]; + uintptr_t addrs[4]; }; } boot_func_list_t; diff --git a/exosphere/src/warmboot_init.c b/exosphere/src/warmboot_init.c index b5eb125da..e1937c8f2 100644 --- a/exosphere/src/warmboot_init.c +++ b/exosphere/src/warmboot_init.c @@ -1,9 +1,12 @@ #include "utils.h" #include "memory_map.h" +#include "mc.h" #include "arm.h" - #include "synchronization.h" +#undef MC_BASE +#define MC_BASE (MMIO_GET_DEVICE_PA(MMIO_DEVID_MC)) + /* 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); @@ -27,6 +30,41 @@ void warmboot_crt0_critical_section_enter(volatile critical_section_t *critical_ critical_section_enter(critical_section); } +void init_dma_controllers(void) { + /* TODO: 4.x does slightly different init. How should we handle this? We can't detect master key revision yet. */ + + /* SYSCTR0_CNTCR_0 = ENABLE | HALT_ON_DEBUG (write-once init) */ + (*((volatile uint32_t *)(0x700F0000))) = 3; + + /* Set some unknown registers in HOST1X. */ + (*((volatile uint32_t *)(0x500038F8))) &= 0xFFFFFFFE; + (*((volatile uint32_t *)(0x50003300))) = 0; + + /* AHB_MASTER_SWID_0 */ + (*((volatile uint32_t *)(0x6000C018))) = 0; + + /* AHB_MASTER_SWID_1 - Makes USB1/USB2 use SWID[1] */ + (*((volatile uint32_t *)(0x6000C038))) = 0x40040; + + /* APBDMA_CHANNEL_SWID_0 = ~0 (SWID = 1 for all APB-DMA channels) */ + (*((volatile uint32_t *)(0x6002003C))) = 0xFFFFFFFF; + + /* APBDMA_CHANNEL_SWID1_0 = 0 (See above) */ + (*((volatile uint32_t *)(0x60020054))) = 0; + + /* APBDMA_SECURITY_REG_0 = 0 (All APB-DMA channels non-secure) */ + (*((volatile uint32_t *)(0x60020038))) = 0; + + /* MSELECT_CONFIG_0 |= WRAP_TO_INCR_SLAVE0(APC) | WRAP_TO_INCR_SLAVE1(PCIe) | WRAP_TO_INCR_SLAVE2(GPU) */ + (*((volatile uint32_t *)(0x50060000))) |= 0x38000000; + + /* AHB_ARBITRATION_PRIORITY_CTRL_0 - Select high prio group with prio 7 */ + (*((volatile uint32_t *)(0x6000C008))) = 0xE0000001; + + /* AHB_GIZMO_TZRAM_0 |= DONT_SPLIT_AHB_WR */ + (*((volatile uint32_t *)(0x6000C054))) = 0x80; +} + void set_memory_registers_enable_mmu(void) { static const uintptr_t vbar = TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x800; static const uintptr_t ttbr0 = TZRAM_GET_SEGMENT_PA(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x800 - 64; @@ -80,6 +118,36 @@ void set_memory_registers_enable_mmu(void) { __set_memory_registers(ttbr0, vbar, cpuectlr, scr, tcr, cptr, mair, sctlr); } -void warmboot_init(boot_func_list_t *func_list) { - (void)func_list; +static void identity_remap_tzram(void) { + /* See also: configure_ttbls (in coldboot_init.c). */ + uintptr_t *mmu_l1_tbl = (uintptr_t *)(TZRAM_GET_SEGMENT_PA(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x800 - 64); + uintptr_t *mmu_l2_tbl = (uintptr_t *)TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_L2_TRANSLATION_TABLE); + uintptr_t *mmu_l3_tbl = (uintptr_t *)TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_L3_TRANSLATION_TABLE); + + mmu_map_table(1, mmu_l1_tbl, 0x40000000, mmu_l2_tbl, 0); + mmu_map_table(2, mmu_l2_tbl, 0x7C000000, mmu_l3_tbl, 0); + + identity_map_mapping(mmu_l1_tbl, mmu_l3_tbl, IDENTITY_GET_MAPPING_ADDRESS(IDENTITY_MAPPING_TZRAM), + IDENTITY_GET_MAPPING_SIZE(IDENTITY_MAPPING_TZRAM), IDENTITY_GET_MAPPING_ATTRIBS(IDENTITY_MAPPING_TZRAM), + IDENTITY_IS_MAPPING_BLOCK_RANGE(IDENTITY_MAPPING_TZRAM)); +} + +void warmboot_init(boot_func_list_t *func_list) { + /* + From https://events.static.linuxfound.org/sites/events/files/slides/slides_17.pdf : + Caches may write back dirty lines at any time: + - To make space for new allocations + - Even if MMU is off + - Even if Cacheable accesses are disabled (caches are never 'off') + */ + func_list->funcs.flush_dcache_all(); + func_list->funcs.invalidate_icache_all(); + + if(MC_SECURITY_CFG0_0 != 0) { + init_dma_controllers(); + } + + identity_remap_tzram(); + /* Nintendo pointlessly fully invalidate the TLB & invalidate the data cache on the modified ranges here */ + set_memory_registers_enable_mmu(); }