mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
Write a significant chunk of coldboot init...
...merge start.cold.s and start.warm.s, other changes, etc.
This commit is contained in:
parent
be67169390
commit
a00e68e94a
14 changed files with 394 additions and 291 deletions
|
@ -8,9 +8,9 @@ tlb_invalidate_all:
|
||||||
isb
|
isb
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.section .text.tlb_invalidate_inner_shareable, "ax", %progbits
|
.section .text.tlb_invalidate_all_inner_shareable, "ax", %progbits
|
||||||
.type tlb_invalidate_inner_shareable, %function
|
.type tlb_invalidate_all_inner_shareable, %function
|
||||||
.global tlb_invalidate_inner_shareable
|
.global tlb_invalidate_all_inner_shareable
|
||||||
tlb_invalidate_all_inner_shareable:
|
tlb_invalidate_all_inner_shareable:
|
||||||
dsb ish
|
dsb ish
|
||||||
tlbi alle3is
|
tlbi alle3is
|
||||||
|
|
85
exosphere/coldboot_init.c
Normal file
85
exosphere/coldboot_init.c
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
#include "utils.h"
|
||||||
|
#include "mmu.h"
|
||||||
|
#include "memory_map.h"
|
||||||
|
|
||||||
|
extern void (*__preinit_array_start[])(void);
|
||||||
|
extern void (*__preinit_array_end[])(void);
|
||||||
|
extern void (*__init_array_start[])(void);
|
||||||
|
extern void (*__init_array_end[])(void);
|
||||||
|
extern void _init(void);
|
||||||
|
|
||||||
|
extern uint8_t __warmboot_crt0_start__[], __warmboot_crt0_end__[], __warmboot_crt0_lma__[];
|
||||||
|
extern uint8_t __main_start__[], __main_end__[], __main_lma__[];
|
||||||
|
extern uint8_t __pk2ldr_start__[], __pk2ldr_end__[], __pk2ldr_lma__[];
|
||||||
|
extern uint8_t __vectors_start__[], __vectors_end__[], __vectors_lma__[];
|
||||||
|
extern void flush_dcache_all_tzram_pa(void);
|
||||||
|
extern void invalidate_icache_all_tzram_pa(void);
|
||||||
|
|
||||||
|
uintptr_t get_coldboot_crt0_stack_address(void);
|
||||||
|
|
||||||
|
static void configure_ttbls(void) {
|
||||||
|
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_init_table(mmu_l1_tbl, 64); /* 33-bit address space */
|
||||||
|
mmu_init_table(mmu_l2_tbl, 4096);
|
||||||
|
/*
|
||||||
|
Nintendo uses the same L3 table for everything, but they make sure
|
||||||
|
nothing clashes.
|
||||||
|
*/
|
||||||
|
mmu_init_table(mmu_l3_tbl, 4096);
|
||||||
|
|
||||||
|
mmu_map_table(1, mmu_l1_tbl, 0x40000000, mmu_l2_tbl, 0);
|
||||||
|
mmu_map_table(1, mmu_l1_tbl, 0x1C0000000, mmu_l2_tbl, 0);
|
||||||
|
|
||||||
|
mmu_map_table(2, mmu_l2_tbl, 0x40000000, mmu_l3_tbl, 0);
|
||||||
|
mmu_map_table(2, mmu_l2_tbl, 0x7C000000, mmu_l3_tbl, 0);
|
||||||
|
mmu_map_table(2, mmu_l2_tbl, 0x1F0000000ull, mmu_l3_tbl, 0);
|
||||||
|
|
||||||
|
identity_map_all_mappings(mmu_l1_tbl, mmu_l3_tbl);
|
||||||
|
mmio_map_all_devices(mmu_l3_tbl);
|
||||||
|
lp0_map_all_plaintext_ram_segments(mmu_l3_tbl);
|
||||||
|
lp0_map_all_ciphertext_ram_segments(mmu_l3_tbl);
|
||||||
|
tzram_map_all_segments(mmu_l3_tbl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copy_lma_to_vma(unsigned int segment_id, void *lma, size_t size, bool vma_is_pa) {
|
||||||
|
uintptr_t vma = vma_is_pa ? tzram_get_segment_pa(segment_id) : tzram_get_segment_address(segment_id);
|
||||||
|
uintptr_t vma_offset = (uintptr_t)lma & 0xFFF;
|
||||||
|
uint64_t *p_vma = (uint64_t *)vma;
|
||||||
|
uint64_t *p_lma = (uint64_t *)lma;
|
||||||
|
for (size_t i = 0; i < size / 8; i++) {
|
||||||
|
p_vma[vma_offset / 8 + i] = p_lma[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __libc_init_array(void) {
|
||||||
|
for (size_t i = 0; i < __preinit_array_end - __preinit_array_start; i++)
|
||||||
|
__preinit_array_start[i]();
|
||||||
|
_init(); /* FIXME: do we have this gcc-provided symbol if we build with -nostartfiles? */
|
||||||
|
for (size_t i = 0; i < __init_array_end - __init_array_start; i++)
|
||||||
|
__init_array_start[i]();
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t get_coldboot_crt0_stack_address(void) {
|
||||||
|
return tzram_get_segment_pa(TZRAM_SEGMENT_ID_CORE3_STACK) + 0x800;
|
||||||
|
}
|
||||||
|
|
||||||
|
void coldboot_init(void) {
|
||||||
|
/* TODO: Set NX BOOTLOADER clock time field */
|
||||||
|
copy_lma_to_vma(TZRAM_SEGMENT_ID_WARMBOOT_CRT0_AND_MAIN, __warmboot_crt0_lma__, __warmboot_crt0_end__ - __warmboot_crt0_start__, true);
|
||||||
|
/* TODO: set some mmio regs, etc. */
|
||||||
|
/* TODO: initialize DMA controllers */
|
||||||
|
configure_ttbls();
|
||||||
|
copy_lma_to_vma(TZRAM_SEGMENT_ID_WARMBOOT_CRT0_AND_MAIN, __main_lma__, __main_end__ - __main_start__, false);
|
||||||
|
copy_lma_to_vma(TZRAM_SEGMENT_ID_PK2LDR, __pk2ldr_lma__, __pk2ldr_end__ - __pk2ldr_start__, false);
|
||||||
|
copy_lma_to_vma(TZRAM_SEGEMENT_ID_SECMON_EVT, __vectors_lma__, __vectors_end__ - __vectors_start__, false);
|
||||||
|
/* TODO: set the MMU regs & tlbi & enable MMU */
|
||||||
|
|
||||||
|
flush_dcache_all_tzram_pa();
|
||||||
|
invalidate_icache_all_tzram_pa();
|
||||||
|
/* TODO: zero-initialize the cpu context */
|
||||||
|
/* Nintendo clears the (emtpy) pk2ldr's BSS section, but we embed it 0-filled in the binary */
|
||||||
|
__libc_init_array(); /* construct global objects */
|
||||||
|
}
|
22
exosphere/coldboot_main.c
Normal file
22
exosphere/coldboot_main.c
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#include "utils.h"
|
||||||
|
#include "mmu.h"
|
||||||
|
#include "memory_map.h"
|
||||||
|
|
||||||
|
extern void (*__fini_array_start[])(void);
|
||||||
|
extern void (*__fini_array_end[])(void);
|
||||||
|
extern void _fini(void);
|
||||||
|
|
||||||
|
extern void __jump_to_lower_el(uint64_t arg, uintptr_t ep, unsigned int el);
|
||||||
|
|
||||||
|
void coldboot_main(void);
|
||||||
|
|
||||||
|
/* Needs to be called for EL3->EL3 chainloading (and only in that case). TODO: use it */
|
||||||
|
static void __libc_fini_array(void) __attribute__((used)) {
|
||||||
|
for (size_t i = __fini_array_end - __fini_array_start; i > 0; i--)
|
||||||
|
__fini_array_start[i - 1]();
|
||||||
|
_fini(); /* FIXME: do we have this gcc-provided symbol if we build with -nostartfiles? */
|
||||||
|
}
|
||||||
|
|
||||||
|
void coldboot_main(void) {
|
||||||
|
/* TODO */
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "mmu.h"
|
#include "memory_map.h"
|
||||||
#include "mc.h"
|
#include "mc.h"
|
||||||
|
|
||||||
volatile security_carveout_t *get_carveout_by_id(unsigned int carveout) {
|
volatile security_carveout_t *get_carveout_by_id(unsigned int carveout) {
|
||||||
|
|
|
@ -46,8 +46,8 @@ static const struct {
|
||||||
uintptr_t pa;
|
uintptr_t pa;
|
||||||
size_t size;
|
size_t size;
|
||||||
uint64_t attributes;
|
uint64_t attributes;
|
||||||
} g_lp0_plaintext_ram_segments[] = {
|
} g_lp0_entry_ram_segments[] = {
|
||||||
{ 0x40020000, 0x10000, MMU_PTE_TABLE_NS | ATTRIB_MEMTYPE_DEVICE }, /* TZRAM decrypted by warmboot.bin */
|
{ 0x40020000, 0x10000, MMU_PTE_TABLE_NS | ATTRIB_MEMTYPE_DEVICE }, /* Encrypted TZRAM */
|
||||||
{ 0x40003000, 0x01000, MMU_PTE_TABLE_NS | ATTRIB_MEMTYPE_DEVICE }, /* LP0 entry code */
|
{ 0x40003000, 0x01000, MMU_PTE_TABLE_NS | ATTRIB_MEMTYPE_DEVICE }, /* LP0 entry code */
|
||||||
{ 0x7C010000, 0x10000, MMU_AP_PRIV_RO | ATTRIB_MEMTYPE_NORMAL }, /* TZRAM to encrypt */
|
{ 0x7C010000, 0x10000, MMU_AP_PRIV_RO | ATTRIB_MEMTYPE_NORMAL }, /* TZRAM to encrypt */
|
||||||
};
|
};
|
||||||
|
@ -56,9 +56,9 @@ static const struct {
|
||||||
uintptr_t pa;
|
uintptr_t pa;
|
||||||
size_t size;
|
size_t size;
|
||||||
uint64_t attributes;
|
uint64_t attributes;
|
||||||
} g_lp0_ciphertext_ram_segments[] = {
|
} g_warmboot_ram_segments[] = {
|
||||||
{ 0x8000F000, 0x01000, MMU_PTE_TABLE_NS | ATTRIB_MEMTYPE_DEVICE }, /* Encrypted SE state */
|
{ 0x8000F000, 0x01000, MMU_PTE_TABLE_NS | ATTRIB_MEMTYPE_DEVICE }, /* Encrypted SE state for bootROM */
|
||||||
{ 0x80010000, 0x10000, MMU_PTE_TABLE_NS | ATTRIB_MEMTYPE_DEVICE }, /* Encrypted TZRAM */
|
{ 0x80010000, 0x10000, MMU_PTE_TABLE_NS | ATTRIB_MEMTYPE_DEVICE }, /* Encrypted TZRAM for warmboot.bin */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
|
@ -78,8 +78,8 @@ static const struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MMIO_BASE 0x1F0080000ull
|
#define MMIO_BASE 0x1F0080000ull
|
||||||
#define LP0_PLAINTEXT_RAM_SEGMENT_BASE (MMIO_BASE + 0x000100000)
|
#define LP0_ENTRY_RAM_SEGMENT_BASE (MMIO_BASE + 0x000100000)
|
||||||
#define LP0_CIPHERTEXT_RAM_SEGMENT_BASE (LP0_PLAINTEXT_RAM_SEGMENT_BASE + 0x000047000) /* increment seems to be arbitrary ? */
|
#define WARMBOOT_RAM_SEGMENT_BASE (LP0_ENTRY_RAM_SEGMENT_BASE + 0x000047000) /* increment seems to be arbitrary ? */
|
||||||
#define TZRAM_SEGMENT_BASE (MMIO_BASE + 0x0001E0000)
|
#define TZRAM_SEGMENT_BASE (MMIO_BASE + 0x0001E0000)
|
||||||
|
|
||||||
#define MMIO_DEVID_GICD 0
|
#define MMIO_DEVID_GICD 0
|
||||||
|
@ -101,12 +101,12 @@ static const struct {
|
||||||
#define MMIO_DEVID_DTV_I2C234 16
|
#define MMIO_DEVID_DTV_I2C234 16
|
||||||
#define MMIO_DEVID_EXCEPTION_VECTORS 17
|
#define MMIO_DEVID_EXCEPTION_VECTORS 17
|
||||||
|
|
||||||
#define LP0_PLAINTEXT_RAM_SEGMENT_ID_DECRYPTED_TZRAM 0
|
#define LP0_ENTRY_RAM_SEGMENT_ID_DECRYPTED_TZRAM 0
|
||||||
#define LP0_PLAINTEXT_RAM_SEGMENT_ID_LP0_ENTRY_CODE 1
|
#define LP0_ENTRY_RAM_SEGMENT_ID_LP0_ENTRY_CODE 1
|
||||||
#define LP0_PLAINTEXT_RAM_SEGMENT_ID_CURRENT_TZRAM 2
|
#define LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM 2
|
||||||
|
|
||||||
#define LP0_CIPHERTEXT_RAM_SEGMENT_ID_SE_STATE 0
|
#define WARMBOOT_RAM_SEGMENT_ID_SE_STATE 0
|
||||||
#define LP0_CIPHERTEXT_RAM_SEGMENT_ID_TZRAM 1
|
#define WARMBOOT_RAM_SEGMENT_ID_TZRAM 1
|
||||||
|
|
||||||
#define TZRAM_SEGMENT_ID_WARMBOOT_CRT0_MAIN_CODE 0
|
#define TZRAM_SEGMENT_ID_WARMBOOT_CRT0_MAIN_CODE 0
|
||||||
#define TZRAM_SEGMENT_ID_PK2LDR 1
|
#define TZRAM_SEGMENT_ID_PK2LDR 1
|
||||||
|
@ -119,7 +119,7 @@ static const struct {
|
||||||
|
|
||||||
/**********************************************************************************************/
|
/**********************************************************************************************/
|
||||||
|
|
||||||
static inline uintptr_t identity_map_all(uintptr_t *mmu_l1_tbl, uintptr_t *mmu_l3_tbl) {
|
static inline uintptr_t identity_map_all_mappings(uintptr_t *mmu_l1_tbl, uintptr_t *mmu_l3_tbl) {
|
||||||
static uint64_t base_attributes = MMU_PTE_BLOCK_INNER_SHAREBLE | ATTRIB_MEMTYPE_NORMAL;
|
static uint64_t base_attributes = MMU_PTE_BLOCK_INNER_SHAREBLE | ATTRIB_MEMTYPE_NORMAL;
|
||||||
for(size_t i = 0; i < sizeof(g_identity_mappings) / sizeof(g_identity_mappings[0]); i++) {
|
for(size_t i = 0; i < sizeof(g_identity_mappings) / sizeof(g_identity_mappings[0]); i++) {
|
||||||
uint64_t attributes = base_attributes | g_identity_mappings[i].attributes;
|
uint64_t attributes = base_attributes | g_identity_mappings[i].attributes;
|
||||||
|
@ -134,7 +134,7 @@ static inline uintptr_t identity_map_all(uintptr_t *mmu_l1_tbl, uintptr_t *mmu_l
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uintptr_t identity_unmap_all(uintptr_t *mmu_l1_tbl, uintptr_t *mmu_l3_tbl) {
|
static inline uintptr_t identity_unmap_all_mappings(uintptr_t *mmu_l1_tbl, uintptr_t *mmu_l3_tbl) {
|
||||||
for(size_t i = 0; i < sizeof(g_identity_mappings) / sizeof(g_identity_mappings[0]); i++) {
|
for(size_t i = 0; i < sizeof(g_identity_mappings) / sizeof(g_identity_mappings[0]); i++) {
|
||||||
if(g_identity_mappings[i].is_block_range) {
|
if(g_identity_mappings[i].is_block_range) {
|
||||||
mmu_unmap_block_range(mmu_l1_tbl, g_identity_mappings[i].address, g_identity_mappings[i].size);
|
mmu_unmap_block_range(mmu_l1_tbl, g_identity_mappings[i].address, g_identity_mappings[i].size);
|
||||||
|
@ -193,7 +193,7 @@ static inline void mmio_unmap_all_devices(uintptr_t *mmu_l3_tbl) {
|
||||||
/**********************************************************************************************/
|
/**********************************************************************************************/
|
||||||
|
|
||||||
static inline uintptr_t lp0_get_plaintext_ram_segment_pa(unsigned int segment_id) {
|
static inline uintptr_t lp0_get_plaintext_ram_segment_pa(unsigned int segment_id) {
|
||||||
return g_lp0_plaintext_ram_segments[segment_id].pa;
|
return g_lp0_entry_ram_segments[segment_id].pa;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MEMORY_MAP_USE_IDENTIY_MAPPING
|
#ifndef MEMORY_MAP_USE_IDENTIY_MAPPING
|
||||||
|
@ -207,17 +207,17 @@ static inline uintptr_t lp0_get_plaintext_ram_segment_address(unsigned int segme
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void lp0_map_all_plaintext_ram_segments(uintptr_t *mmu_l3_tbl) {
|
static inline void lp0_map_all_plaintext_ram_segments(uintptr_t *mmu_l3_tbl) {
|
||||||
for(size_t i = 0, offset = 0; i < sizeof(g_lp0_plaintext_ram_segments) / sizeof(g_lp0_plaintext_ram_segments[0]); i++) {
|
for(size_t i = 0, offset = 0; i < sizeof(g_lp0_entry_ram_segments) / sizeof(g_lp0_entry_ram_segments[0]); i++) {
|
||||||
uint64_t attributes = MMU_PTE_BLOCK_XN | MMU_PTE_BLOCK_INNER_SHAREBLE | g_lp0_plaintext_ram_segments[i].attributes;
|
uint64_t attributes = MMU_PTE_BLOCK_XN | MMU_PTE_BLOCK_INNER_SHAREBLE | g_lp0_entry_ram_segments[i].attributes;
|
||||||
mmu_map_page_range(mmu_l3_tbl, LP0_PLAINTEXT_RAM_SEGMENT_BASE + offset, g_lp0_plaintext_ram_segments[i].pa,
|
mmu_map_page_range(mmu_l3_tbl, LP0_PLAINTEXT_RAM_SEGMENT_BASE + offset, g_lp0_entry_ram_segments[i].pa,
|
||||||
g_lp0_plaintext_ram_segments[i].size, attributes);
|
g_lp0_entry_ram_segments[i].size, attributes);
|
||||||
offset += 0x10000;
|
offset += 0x10000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void lp0_unmap_all_plaintext_ram_segments(uintptr_t *mmu_l3_tbl) {
|
static inline void lp0_unmap_all_plaintext_ram_segments(uintptr_t *mmu_l3_tbl) {
|
||||||
for(size_t i = 0, offset = 0; i < sizeof(g_lp0_plaintext_ram_segments) / sizeof(g_lp0_plaintext_ram_segments[0]); i++) {
|
for(size_t i = 0, offset = 0; i < sizeof(g_lp0_entry_ram_segments) / sizeof(g_lp0_entry_ram_segments[0]); i++) {
|
||||||
mmu_unmap_range(3, mmu_l3_tbl, LP0_PLAINTEXT_RAM_SEGMENT_BASE + offset, g_lp0_plaintext_ram_segments[i].size);
|
mmu_unmap_range(3, mmu_l3_tbl, LP0_PLAINTEXT_RAM_SEGMENT_BASE + offset, g_lp0_entry_ram_segments[i].size);
|
||||||
|
|
||||||
offset += 0x10000;
|
offset += 0x10000;
|
||||||
}
|
}
|
||||||
|
@ -226,14 +226,14 @@ static inline void lp0_unmap_all_plaintext_ram_segments(uintptr_t *mmu_l3_tbl) {
|
||||||
/**********************************************************************************************/
|
/**********************************************************************************************/
|
||||||
|
|
||||||
static inline uintptr_t lp0_get_ciphertext_ram_segment_pa(unsigned int segment_id) {
|
static inline uintptr_t lp0_get_ciphertext_ram_segment_pa(unsigned int segment_id) {
|
||||||
return g_lp0_ciphertext_ram_segments[segment_id].pa;
|
return g_warmboot_ram_segments[segment_id].pa;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MEMORY_MAP_USE_IDENTIY_MAPPING
|
#ifndef MEMORY_MAP_USE_IDENTIY_MAPPING
|
||||||
static inline uintptr_t lp0_get_ciphertext_ram_segment_address(unsigned int segment_id) {
|
static inline uintptr_t lp0_get_ciphertext_ram_segment_address(unsigned int segment_id) {
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
for(unsigned int i = 0; i < segment_id; i++) {
|
for(unsigned int i = 0; i < segment_id; i++) {
|
||||||
offset += g_lp0_ciphertext_ram_segments[i].size;
|
offset += g_warmboot_ram_segments[i].size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LP0_CIPHERTEXT_RAM_SEGMENT_BASE + offset;
|
return LP0_CIPHERTEXT_RAM_SEGMENT_BASE + offset;
|
||||||
|
@ -245,19 +245,19 @@ static inline uintptr_t lp0_get_ciphertext_ram_segment_address(unsigned int segm
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void lp0_map_all_ciphertext_ram_segments(uintptr_t *mmu_l3_tbl) {
|
static inline void lp0_map_all_ciphertext_ram_segments(uintptr_t *mmu_l3_tbl) {
|
||||||
for(size_t i = 0, offset = 0; i < sizeof(g_lp0_ciphertext_ram_segments) / sizeof(g_lp0_ciphertext_ram_segments[0]); i++) {
|
for(size_t i = 0, offset = 0; i < sizeof(g_warmboot_ram_segments) / sizeof(g_warmboot_ram_segments[0]); i++) {
|
||||||
uint64_t attributes = MMU_PTE_BLOCK_XN | MMU_PTE_BLOCK_INNER_SHAREBLE | g_lp0_ciphertext_ram_segments[i].attributes;
|
uint64_t attributes = MMU_PTE_BLOCK_XN | MMU_PTE_BLOCK_INNER_SHAREBLE | g_warmboot_ram_segments[i].attributes;
|
||||||
mmu_map_page_range(mmu_l3_tbl, LP0_CIPHERTEXT_RAM_SEGMENT_BASE + offset, g_lp0_ciphertext_ram_segments[i].pa,
|
mmu_map_page_range(mmu_l3_tbl, LP0_CIPHERTEXT_RAM_SEGMENT_BASE + offset, g_warmboot_ram_segments[i].pa,
|
||||||
g_lp0_ciphertext_ram_segments[i].size, attributes);
|
g_warmboot_ram_segments[i].size, attributes);
|
||||||
offset += g_lp0_ciphertext_ram_segments[i].size;
|
offset += g_warmboot_ram_segments[i].size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void lp0_unmap_all_ciphertext_ram_segments(uintptr_t *mmu_l3_tbl) {
|
static inline void lp0_unmap_all_ciphertext_ram_segments(uintptr_t *mmu_l3_tbl) {
|
||||||
for(size_t i = 0, offset = 0; i < sizeof(g_lp0_ciphertext_ram_segments) / sizeof(g_lp0_ciphertext_ram_segments[0]); i++) {
|
for(size_t i = 0, offset = 0; i < sizeof(g_warmboot_ram_segments) / sizeof(g_warmboot_ram_segments[0]); i++) {
|
||||||
mmu_unmap_range(3, mmu_l3_tbl, LP0_CIPHERTEXT_RAM_SEGMENT_BASE + offset, g_lp0_ciphertext_ram_segments[i].size);
|
mmu_unmap_range(3, mmu_l3_tbl, LP0_CIPHERTEXT_RAM_SEGMENT_BASE + offset, g_warmboot_ram_segments[i].size);
|
||||||
|
|
||||||
offset += g_lp0_ciphertext_ram_segments[i].size;
|
offset += g_warmboot_ram_segments[i].size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ static inline void tzram_map_all_segments(uintptr_t *mmu_l3_tbl) {
|
||||||
|
|
||||||
static inline void tzram_unmap_all_segments(uintptr_t *mmu_l3_tbl) {
|
static inline void tzram_unmap_all_segments(uintptr_t *mmu_l3_tbl) {
|
||||||
/* Except the SPL userpage */
|
/* Except the SPL userpage */
|
||||||
for(size_t i = 0, offset = 0; i < sizeof(g_lp0_ciphertext_ram_segments) / sizeof(g_lp0_ciphertext_ram_segments[0]); i++) {
|
for(size_t i = 0, offset = 0; i < sizeof(g_warmboot_ram_segments) / sizeof(g_warmboot_ram_segments[0]); i++) {
|
||||||
if(g_tzram_segments[i].map_size == 0) {
|
if(g_tzram_segments[i].map_size == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "memory_map.h"
|
||||||
|
|
||||||
#include "package2.h"
|
#include "package2.h"
|
||||||
#include "configitem.h"
|
#include "configitem.h"
|
||||||
|
@ -12,23 +13,8 @@
|
||||||
#include "randomcache.h"
|
#include "randomcache.h"
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
|
|
||||||
void setup_mmio_virtual_addresses(void) {
|
|
||||||
/* TODO: Set Timers address to 0x1F008B000. */
|
|
||||||
/* TODO: Set Security Engine address to 0x1F008F000. */
|
|
||||||
/* TODO: Set CAR address to 0x1F0087000. */
|
|
||||||
/* TODO: Set PMC address to 0x1F0089400. */
|
|
||||||
/* TODO: Set Fuse address to 0x1F0096800. */
|
|
||||||
/* TODO: Set Interrupt addresses to 0x1F0080000, 0x1F0082000. */
|
|
||||||
/* TODO: Set Flow Controller address to 0x1F009D000. */
|
|
||||||
/* TODO: Set UART-A address to 0x1F0085000. */
|
|
||||||
/* TODO: Set I2C-0 address to 0x1F00A5000. */
|
|
||||||
/* TODO: Set I2C-4 address to 0x1F00A1000. */
|
|
||||||
/* TODO: Set MISC address to 0x1F0098000. */
|
|
||||||
/* TODO: Set GPIO-1 address to 0x1F00A3000. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hardware init, sets up the RNG and SESSION keyslots, derives new DEVICE key. */
|
/* Hardware init, sets up the RNG and SESSION keyslots, derives new DEVICE key. */
|
||||||
void setup_se(void) {
|
static void setup_se(void) {
|
||||||
uint8_t work_buffer[0x10];
|
uint8_t work_buffer[0x10];
|
||||||
|
|
||||||
/* Sanity check the Security Engine. */
|
/* Sanity check the Security Engine. */
|
||||||
|
@ -82,7 +68,7 @@ void setup_se(void) {
|
||||||
/* TODO: Create Test Vector, to validate keyslot data is unchanged post warmboot. */
|
/* TODO: Create Test Vector, to validate keyslot data is unchanged post warmboot. */
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_boot_config(void) {
|
static void setup_boot_config(void) {
|
||||||
/* Load boot config only if dev unit. */
|
/* Load boot config only if dev unit. */
|
||||||
if (configitem_is_retail()) {
|
if (configitem_is_retail()) {
|
||||||
bootconfig_clear();
|
bootconfig_clear();
|
||||||
|
@ -92,7 +78,7 @@ void setup_boot_config(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size) {
|
static bool rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size) {
|
||||||
uint8_t message[RSA_2048_BYTES];
|
uint8_t message[RSA_2048_BYTES];
|
||||||
uint8_t h_buf[0x24];
|
uint8_t h_buf[0x24];
|
||||||
|
|
||||||
|
@ -101,7 +87,6 @@ bool rsa2048_pss_verify(const void *signature, size_t signature_size, const void
|
||||||
set_rsa_keyslot(0, modulus, modulus_size, public_exponent, sizeof(public_exponent));
|
set_rsa_keyslot(0, modulus, modulus_size, public_exponent, sizeof(public_exponent));
|
||||||
se_synchronous_exp_mod(0, message, sizeof(message), signature, signature_size);
|
se_synchronous_exp_mod(0, message, sizeof(message), signature, signature_size);
|
||||||
|
|
||||||
|
|
||||||
/* Validate sanity byte. */
|
/* Validate sanity byte. */
|
||||||
if (message[RSA_2048_BYTES - 1] != 0xBC) {
|
if (message[RSA_2048_BYTES - 1] != 0xBC) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -149,7 +134,7 @@ bool rsa2048_pss_verify(const void *signature, size_t signature_size, const void
|
||||||
return memcmp(h_buf, validate_hash, 0x20) == 0;
|
return memcmp(h_buf, validate_hash, 0x20) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void package2_crypt_ctr(unsigned int master_key_rev, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) {
|
static void package2_crypt_ctr(unsigned int master_key_rev, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) {
|
||||||
/* Derive package2 key. */
|
/* Derive package2 key. */
|
||||||
const uint8_t package2_key_source[0x10] = {0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7};
|
const uint8_t package2_key_source[0x10] = {0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7};
|
||||||
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + dst_size);
|
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + dst_size);
|
||||||
|
@ -162,7 +147,7 @@ void package2_crypt_ctr(unsigned int master_key_rev, void *dst, size_t dst_size,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void verify_header_signature(package2_header_t *header) {
|
static void verify_header_signature(package2_header_t *header) {
|
||||||
const uint8_t *modulus;
|
const uint8_t *modulus;
|
||||||
|
|
||||||
if (configitem_is_retail()) {
|
if (configitem_is_retail()) {
|
||||||
|
@ -213,7 +198,7 @@ void verify_header_signature(package2_header_t *header) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validate_package2_metadata(package2_meta_t *metadata) {
|
static bool validate_package2_metadata(package2_meta_t *metadata) {
|
||||||
if (metadata->magic != MAGIC_PK21) {
|
if (metadata->magic != MAGIC_PK21) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -295,7 +280,7 @@ bool validate_package2_metadata(package2_meta_t *metadata) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decrypts package2 header, and returns the master key revision required. */
|
/* Decrypts package2 header, and returns the master key revision required. */
|
||||||
uint32_t decrypt_and_validate_header(package2_header_t *header) {
|
static uint32_t decrypt_and_validate_header(package2_header_t *header) {
|
||||||
package2_meta_t metadata;
|
package2_meta_t metadata;
|
||||||
|
|
||||||
if (bootconfig_is_package2_plaintext() == 0) {
|
if (bootconfig_is_package2_plaintext() == 0) {
|
||||||
|
@ -319,7 +304,7 @@ uint32_t decrypt_and_validate_header(package2_header_t *header) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_package2_sections(package2_meta_t *metadata, uint32_t master_key_rev) {
|
static void load_package2_sections(package2_meta_t *metadata, uint32_t master_key_rev) {
|
||||||
/* By default, copy data directly from where NX_BOOTLOADER puts it. */
|
/* By default, copy data directly from where NX_BOOTLOADER puts it. */
|
||||||
void *load_buf = NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS;
|
void *load_buf = NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS;
|
||||||
|
|
||||||
|
@ -387,12 +372,13 @@ void load_package2_sections(package2_meta_t *metadata, uint32_t master_key_rev)
|
||||||
memset(load_buf, 0, PACKAGE2_SIZE_MAX);
|
memset(load_buf, 0, PACKAGE2_SIZE_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is called during coldboot crt0, and validates a package2. */
|
uintptr_t get_pk2ldr_stack_address(void) {
|
||||||
|
return tzram_get_segment_address(TZRAM_SEGMENT_ID_PK2LDR) + 0x2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is called during coldboot init, and validates a package2. */
|
||||||
/* This package2 is read into memory by a concurrent BPMP bootloader. */
|
/* This package2 is read into memory by a concurrent BPMP bootloader. */
|
||||||
void load_package2(void) {
|
void load_package2(void) {
|
||||||
/* Setup MMIO virtual pointers. */
|
|
||||||
setup_mmio_virtual_addresses();
|
|
||||||
|
|
||||||
/* Setup the Security Engine. */
|
/* Setup the Security Engine. */
|
||||||
setup_se();
|
setup_se();
|
||||||
|
|
||||||
|
@ -453,9 +439,6 @@ void load_package2(void) {
|
||||||
/* Set CORE0 entrypoint for Package2. */
|
/* Set CORE0 entrypoint for Package2. */
|
||||||
set_core_entrypoint_and_context_id(0, DRAM_BASE_PHYSICAL + header.metadata.entrypoint, 0);
|
set_core_entrypoint_and_context_id(0, DRAM_BASE_PHYSICAL + header.metadata.entrypoint, 0);
|
||||||
|
|
||||||
/* TODO: Nintendo clears 0x1F01FA7D0 to 0x1F01FA7E8. What does this do? Does it remove the identity mapping page tables? */
|
|
||||||
tlb_invalidate_all();
|
|
||||||
|
|
||||||
/* Synchronize with NX BOOTLOADER. */
|
/* Synchronize with NX BOOTLOADER. */
|
||||||
if (MAILBOX_NX_BOOTLOADER_SETUP_STATE == NX_BOOTLOADER_STATE_LOADED_PACKAGE2) {
|
if (MAILBOX_NX_BOOTLOADER_SETUP_STATE == NX_BOOTLOADER_STATE_LOADED_PACKAGE2) {
|
||||||
while (MAILBOX_NX_BOOTLOADER_SETUP_STATE < NX_BOOTLOADER_STATE_FINISHED) {
|
while (MAILBOX_NX_BOOTLOADER_SETUP_STATE < NX_BOOTLOADER_STATE_FINISHED) {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "memory_map.h"
|
||||||
|
|
||||||
#include "configitem.h"
|
#include "configitem.h"
|
||||||
#include "cpu_context.h"
|
#include "cpu_context.h"
|
||||||
#include "lock.h"
|
#include "lock.h"
|
||||||
|
@ -107,6 +109,20 @@ smc_table_t g_smc_tables[2] = {
|
||||||
bool g_is_user_smc_in_progress = false;
|
bool g_is_user_smc_in_progress = false;
|
||||||
bool g_is_priv_smc_in_progress = false;
|
bool g_is_priv_smc_in_progress = false;
|
||||||
|
|
||||||
|
uintptr_t get_smc_core012_stack_address(void) {
|
||||||
|
return tzram_get_segment_address(TZRAM_SEGMENT_ID_CORE012_STACK) + 0x1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t get_exception_entry_core3_stack_address(unsigned int core_id) {
|
||||||
|
/* For core3, this is also the smc stack */
|
||||||
|
if (core_id == 3) {
|
||||||
|
return tzram_get_segment_address(TZRAM_SEGMENT_ID_CORE3_STACK) + 0x1000;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return tzram_get_segment_address(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x80 * (core_id + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Privileged SMC lock must be available to exceptions.s. */
|
/* Privileged SMC lock must be available to exceptions.s. */
|
||||||
void set_priv_smc_in_progress(void) {
|
void set_priv_smc_in_progress(void) {
|
||||||
lock_acquire(&g_is_priv_smc_in_progress);
|
lock_acquire(&g_is_priv_smc_in_progress);
|
||||||
|
|
|
@ -13,7 +13,8 @@ typedef struct {
|
||||||
void set_priv_smc_in_progress(void);
|
void set_priv_smc_in_progress(void);
|
||||||
void clear_priv_smc_in_progress(void);
|
void clear_priv_smc_in_progress(void);
|
||||||
|
|
||||||
void get_smc_core012_stack_address(void);
|
uintptr_t get_smc_core012_stack_address(void);
|
||||||
|
uintptr_t get_exception_entry_core3_stack_address(void);
|
||||||
|
|
||||||
void call_smc_handler(unsigned int handler_id, smc_args_t *args);
|
void call_smc_handler(unsigned int handler_id, smc_args_t *args);
|
||||||
|
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
.align 6
|
|
||||||
.section .text.cold.start, "ax", %progbits
|
|
||||||
.global __start_cold
|
|
||||||
__start_cold:
|
|
||||||
/* Nintendo copy-pasted https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/nvidia/tegra/common/aarch64/tegra_helpers.S#L312 */
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
*/
|
|
||||||
/* The following comments are mine. */
|
|
||||||
/* mask all interrupts */
|
|
||||||
msr daifset, 0b1111
|
|
||||||
|
|
||||||
/*
|
|
||||||
Enable invalidates of branch target buffer, then flush
|
|
||||||
the entire instruction cache at the local level, and
|
|
||||||
with the reg change, the branch target buffer, then disable
|
|
||||||
invalidates of the branch target buffer again.
|
|
||||||
*/
|
|
||||||
mrs x0, cpuactlr_el1
|
|
||||||
orr x0, x0, #1
|
|
||||||
msr cpuactlr_el1, x0
|
|
||||||
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
ic iallu
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
|
|
||||||
mrs x0, cpuactlr_el1
|
|
||||||
bic x0, x0, #1
|
|
||||||
msr cpuactlr_el1, x0
|
|
||||||
|
|
||||||
.rept 7
|
|
||||||
nop /* wait long enough for the write to cpuactlr_el1 to have completed */
|
|
||||||
.endr
|
|
||||||
|
|
||||||
/* if the OS lock is set, disable it and request a warm reset */
|
|
||||||
mrs x0, oslsr_el1
|
|
||||||
ands x0, x0, #2
|
|
||||||
b.eq _set_lock_and_sp
|
|
||||||
mov x0, xzr
|
|
||||||
msr oslar_el1, x0
|
|
||||||
|
|
||||||
mov x0, #(1 << 63)
|
|
||||||
msr cpuactlr_el1, x0 /* disable regional clock gating */
|
|
||||||
isb
|
|
||||||
mov x0, #3
|
|
||||||
msr rmr_el3, x0
|
|
||||||
isb
|
|
||||||
dsb sy
|
|
||||||
/* Nintendo forgot to copy-paste the branch instruction below. */
|
|
||||||
_reset_wfi:
|
|
||||||
wfi
|
|
||||||
b _reset_wfi
|
|
||||||
.rept 65
|
|
||||||
nop /* guard against speculative excecution */
|
|
||||||
.endr
|
|
||||||
|
|
||||||
_set_lock_and_sp:
|
|
||||||
/* set the OS lock */
|
|
||||||
mov x0, #1
|
|
||||||
msr oslar_el1, x0
|
|
||||||
|
|
||||||
/* set SP = SP_EL0 (temporary stack) */
|
|
||||||
msr spsel, #0
|
|
||||||
ldr x20, =__cold_crt0_stack_top__
|
|
||||||
mov sp, x20
|
|
||||||
bl configure_memory
|
|
||||||
ldr x16, =__init_cold
|
|
||||||
br x16
|
|
||||||
|
|
||||||
.section .text.cold, "ax", %progbits
|
|
||||||
__init_cold:
|
|
||||||
/* set SP = SP_EL3 (exception stack) */
|
|
||||||
msr spsel, #1
|
|
||||||
ldr x20, =__main_stack_top__
|
|
||||||
mov sp, x20
|
|
||||||
|
|
||||||
/* set SP = SP_EL0 (temporary stack) */
|
|
||||||
msr spsel, #0
|
|
||||||
ldr x20, =__pk2_load_stack_top__
|
|
||||||
mov sp, x20
|
|
||||||
bl load_package2
|
|
||||||
ldr x20, =__cold_init_stack_top__
|
|
||||||
mov sp, x20
|
|
||||||
b coldboot_main
|
|
||||||
|
|
||||||
.global __set_sp_el0_and_jump_to_el1
|
|
||||||
.type __set_sp_el0_and_jump_to_el1, %function
|
|
||||||
__set_sp_el0_and_jump_to_el1:
|
|
||||||
/* the official handler does some weird stuff with SP_EL0 */
|
|
||||||
msr elr_el3, x1
|
|
||||||
mov sp, x2
|
|
||||||
|
|
||||||
mov x1, #0x3c5 /* EL1, all interrupts masked */
|
|
||||||
msr spsr_el3, x1
|
|
||||||
isb
|
|
||||||
eret
|
|
148
exosphere/start.s
Normal file
148
exosphere/start.s
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
.macro ERRATUM_INVALIDATE_BTB_AT_BOOT
|
||||||
|
/* Nintendo copy-pasted https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/nvidia/tegra/common/aarch64/tegra_helpers.S#L312 */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
/* The following comments are mine. */
|
||||||
|
/* mask all interrupts */
|
||||||
|
msr daifset, 0b1111
|
||||||
|
|
||||||
|
/*
|
||||||
|
Enable invalidates of branch target buffer, then flush
|
||||||
|
the entire instruction cache at the local level, and
|
||||||
|
with the reg change, the branch target buffer, then disable
|
||||||
|
invalidates of the branch target buffer again.
|
||||||
|
*/
|
||||||
|
mrs x0, cpuactlr_el1
|
||||||
|
orr x0, x0, #1
|
||||||
|
msr cpuactlr_el1, x0
|
||||||
|
|
||||||
|
dsb sy
|
||||||
|
isb
|
||||||
|
ic iallu
|
||||||
|
dsb sy
|
||||||
|
isb
|
||||||
|
|
||||||
|
mrs x0, cpuactlr_el1
|
||||||
|
bic x0, x0, #1
|
||||||
|
msr cpuactlr_el1, x0
|
||||||
|
|
||||||
|
.rept 7
|
||||||
|
nop /* wait long enough for the write to cpuactlr_el1 to have completed */
|
||||||
|
.endr
|
||||||
|
|
||||||
|
/* if the OS lock is set, disable it and request a warm reset */
|
||||||
|
mrs x0, oslsr_el1
|
||||||
|
ands x0, x0, #2
|
||||||
|
b.eq _set_lock_and_sp
|
||||||
|
mov x0, xzr
|
||||||
|
msr oslar_el1, x0
|
||||||
|
|
||||||
|
mov x0, #(1 << 63)
|
||||||
|
msr cpuactlr_el1, x0 /* disable regional clock gating */
|
||||||
|
isb
|
||||||
|
mov x0, #3
|
||||||
|
msr rmr_el3, x0
|
||||||
|
isb
|
||||||
|
dsb sy
|
||||||
|
/* Nintendo forgot to copy-paste the branch instruction below. */
|
||||||
|
_reset_wfi:
|
||||||
|
wfi
|
||||||
|
b _reset_wfi
|
||||||
|
.rept 65
|
||||||
|
nop /* guard against speculative excecution */
|
||||||
|
.endr
|
||||||
|
|
||||||
|
_set_lock_and_sp:
|
||||||
|
/* set the OS lock */
|
||||||
|
mov x0, #1
|
||||||
|
msr oslar_el1, x0
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.align 6
|
||||||
|
.section .text.cold.start, "ax", %progbits
|
||||||
|
.global __start_cold
|
||||||
|
__start_cold:
|
||||||
|
ERRATUM_INVALIDATE_BTB_AT_BOOT
|
||||||
|
|
||||||
|
msr spsel, #0
|
||||||
|
bl get_coldboot_crt0_stack_address /* should be optimized so it doesn't make function calls */
|
||||||
|
mov sp, x0
|
||||||
|
bl coldboot_init
|
||||||
|
ldr x16, =__jump_to_main_cold
|
||||||
|
br x16
|
||||||
|
|
||||||
|
.align 6
|
||||||
|
.section .text.warm.start, "ax", %progbits
|
||||||
|
.global __start_warm
|
||||||
|
__start_warm:
|
||||||
|
ERRATUM_INVALIDATE_BTB_AT_BOOT
|
||||||
|
|
||||||
|
/* For some reasons, Nintendo uses spsel, #1 here, causing issues if an exception occurs */
|
||||||
|
msr spsel, #0
|
||||||
|
bl get_warmboot_crt0_stack_address /* should be optimized so it doesn't make function calls */
|
||||||
|
mov sp, x0
|
||||||
|
bl warmboot_init
|
||||||
|
ldr x16, =__jump_to_main_warm
|
||||||
|
br x16
|
||||||
|
|
||||||
|
.section .text.__jump_to_main_cold, "ax", %progbits
|
||||||
|
__jump_to_main_cold:
|
||||||
|
bl __set_exception_entry_stack_pointer
|
||||||
|
|
||||||
|
bl get_pk2ldr_stack_address
|
||||||
|
mov sp, x0
|
||||||
|
bl load_package2
|
||||||
|
|
||||||
|
mov w0, #3 /* use core3 stack temporarily */
|
||||||
|
bl get_exception_entry_stack_address
|
||||||
|
mov sp, x0
|
||||||
|
b coldboot_main
|
||||||
|
|
||||||
|
.section .text.__jump_to_main_warm, "ax", %progbits
|
||||||
|
__jump_to_main_warm:
|
||||||
|
/* Nintendo doesn't do that here, causing issues if an exception occurs */
|
||||||
|
bl __set_exception_entry_stack_pointer
|
||||||
|
|
||||||
|
bl get_pk2ldr_stack_address
|
||||||
|
mov sp, x0
|
||||||
|
bl load_package2
|
||||||
|
|
||||||
|
mov w0, #3 /* use core0,1,2 stack bottom + 0x800 (VA of warmboot crt0 sp) temporarily */
|
||||||
|
bl get_exception_entry_stack_address
|
||||||
|
add sp, x0, #0x800
|
||||||
|
b warmboot_main
|
||||||
|
|
||||||
|
.section .text.__set_exception_entry_stack, "ax", %progbits
|
||||||
|
.type __set_exception_entry_stack, %function
|
||||||
|
.global __set_exception_entry_stack
|
||||||
|
__set_exception_entry_stack_pointer:
|
||||||
|
/* If SPSel == 1 on entry, make sure your function doesn't use stack variables! */
|
||||||
|
mov x16, lr
|
||||||
|
mrs x17, spsel
|
||||||
|
msr x0, mpidr_el1
|
||||||
|
and w0, w0, #3
|
||||||
|
bl get_exception_entry_stack_address /* should be optimized so it doesn't make function calls */
|
||||||
|
msr spsel, #1
|
||||||
|
mov sp, x0
|
||||||
|
msr spsel, x17
|
||||||
|
mov lr, x16
|
||||||
|
ret
|
||||||
|
|
||||||
|
.section .text.__jump_to_lower_el, "ax", %progbits
|
||||||
|
.global __jump_to_lower_el
|
||||||
|
.type __jump_to_lower_el, %function
|
||||||
|
__jump_to_lower_el:
|
||||||
|
/* x0: arg (context ID), x1: entrypoint, w2: exception level */
|
||||||
|
msr elr_el3, x1
|
||||||
|
|
||||||
|
mov x1, #((0b1111 << 6) | 1) /* DAIF set and SP = SP_ELx*/
|
||||||
|
orr x1, w2, lsl#2
|
||||||
|
msr spsr_el3, x1
|
||||||
|
|
||||||
|
bl __set_exception_entry_stack_pointer
|
||||||
|
|
||||||
|
isb
|
||||||
|
eret
|
|
@ -1,79 +0,0 @@
|
||||||
.align 6
|
|
||||||
.section .text.warm.start, "ax", %progbits
|
|
||||||
.global __start_warm
|
|
||||||
__start_warm:
|
|
||||||
/* Nintendo copy-pasted https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/nvidia/tegra/common/aarch64/tegra_helpers.S#L312 */
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
*/
|
|
||||||
/* The following comments are mine. */
|
|
||||||
/* mask all interrupts */
|
|
||||||
msr daifset, 0b1111
|
|
||||||
|
|
||||||
/*
|
|
||||||
Enable invalidates of branch target buffer, then flush
|
|
||||||
the entire instruction cache at the local level, and
|
|
||||||
with the reg change, the branch target buffer, then disable
|
|
||||||
invalidates of the branch target buffer again.
|
|
||||||
*/
|
|
||||||
mrs x0, cpuactlr_el1
|
|
||||||
orr x0, x0, #1
|
|
||||||
msr cpuactlr_el1, x0
|
|
||||||
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
ic iallu
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
|
|
||||||
mrs x0, cpuactlr_el1
|
|
||||||
bic x0, x0, #1
|
|
||||||
msr cpuactlr_el1, x0
|
|
||||||
|
|
||||||
.rept 7
|
|
||||||
nop /* wait long enough for the write to cpuactlr_el1 to have completed */
|
|
||||||
.endr
|
|
||||||
|
|
||||||
/* if the OS lock is set, disable it and request a warm reset */
|
|
||||||
mrs x0, oslsr_el1
|
|
||||||
ands x0, x0, #2
|
|
||||||
b.eq _set_lock_and_sp
|
|
||||||
mov x0, xzr
|
|
||||||
msr oslar_el1, x0
|
|
||||||
|
|
||||||
mov x0, #(1 << 63)
|
|
||||||
msr cpuactlr_el1, x0 /* disable regional clock gating */
|
|
||||||
isb
|
|
||||||
mov x0, #3
|
|
||||||
msr rmr_el3, x0
|
|
||||||
isb
|
|
||||||
dsb sy
|
|
||||||
/* Nintendo forgot to copy-paste the branch instruction below. */
|
|
||||||
_reset_wfi:
|
|
||||||
wfi
|
|
||||||
b _reset_wfi
|
|
||||||
.rept 65
|
|
||||||
nop /* guard against speculative excecution */
|
|
||||||
.endr
|
|
||||||
|
|
||||||
_set_lock_and_sp:
|
|
||||||
/* set the OS lock */
|
|
||||||
mov x0, #1
|
|
||||||
msr oslar_el1, x0
|
|
||||||
bl __synchronize_cores
|
|
||||||
|
|
||||||
/* set SP = SP_EL3 (handler stack) */
|
|
||||||
msr spsel, #1
|
|
||||||
ldr x20, =__warm_crt0_stack_top__
|
|
||||||
mov sp, x20
|
|
||||||
bl reconfigure_memory
|
|
||||||
ldr x16, =__init_warm
|
|
||||||
br x16
|
|
||||||
|
|
||||||
.section .text.warm, "ax", %progbits
|
|
||||||
__init_warm:
|
|
||||||
ldr x20, =__warm_init_stack_top__
|
|
||||||
mov sp, x20
|
|
||||||
b warmboot_main
|
|
|
@ -37,9 +37,9 @@ static __attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_
|
||||||
|
|
||||||
|
|
||||||
static inline unsigned int get_core_id(void) {
|
static inline unsigned int get_core_id(void) {
|
||||||
unsigned int core_id;
|
uint64_t core_id;
|
||||||
__asm__ __volatile__ ("mrs %0, MPIDR_EL1" : "=r"(core_id));
|
__asm__ __volatile__ ("mrs %0, MPIDR_EL1" : "=r"(core_id));
|
||||||
return core_id & 3;
|
return (unsigned int)core_id & 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
16
exosphere/warmboot_init.c
Normal file
16
exosphere/warmboot_init.c
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include "utils.h"
|
||||||
|
#include "memory_map.h"
|
||||||
|
|
||||||
|
uintptr_t get_warmboot_crt0_stack_address(void);
|
||||||
|
|
||||||
|
void flush_dcache_all_tzram_pa(void) {
|
||||||
|
/* TODO */
|
||||||
|
}
|
||||||
|
|
||||||
|
void invalidate_icache_all_tzram_pa(void) {
|
||||||
|
/* TODO */
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t get_coldboot_crt0_stack_address(void) {
|
||||||
|
return tzram_get_segment_pa(TZRAM_SEGMENT_ID_CORE3_STACK) + 0x800;
|
||||||
|
}
|
11
exosphere/warmboot_main.c
Normal file
11
exosphere/warmboot_main.c
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include "utils.h"
|
||||||
|
#include "mmu.h"
|
||||||
|
#include "memory_map.h"
|
||||||
|
|
||||||
|
extern void __jump_to_lower_el(uint64_t arg, uintptr_t ep, unsigned int el);
|
||||||
|
|
||||||
|
void warmboot_main(void);
|
||||||
|
|
||||||
|
void warmboot_main(void) {
|
||||||
|
/* TODO */
|
||||||
|
}
|
Loading…
Reference in a new issue