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,52 +13,37 @@
|
||||||
#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. */
|
||||||
se_verify_flags_cleared();
|
se_verify_flags_cleared();
|
||||||
se_clear_interrupts();
|
se_clear_interrupts();
|
||||||
|
|
||||||
/* Perform some sanity initialization. */
|
/* Perform some sanity initialization. */
|
||||||
security_engine_t *p_security_engine = get_security_engine_address();
|
security_engine_t *p_security_engine = get_security_engine_address();
|
||||||
p_security_engine->_0x4 = 0;
|
p_security_engine->_0x4 = 0;
|
||||||
p_security_engine->AES_KEY_READ_DISABLE_REG = 0;
|
p_security_engine->AES_KEY_READ_DISABLE_REG = 0;
|
||||||
p_security_engine->RSA_KEY_READ_DISABLE_REG = 0;
|
p_security_engine->RSA_KEY_READ_DISABLE_REG = 0;
|
||||||
p_security_engine->_0x0 &= 0xFFFFFFFB;
|
p_security_engine->_0x0 &= 0xFFFFFFFB;
|
||||||
|
|
||||||
/* Currently unknown what each flag does. */
|
/* Currently unknown what each flag does. */
|
||||||
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
||||||
set_aes_keyslot_flags(i, 0x15);
|
set_aes_keyslot_flags(i, 0x15);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 4; i < KEYSLOT_AES_MAX; i++) {
|
for (unsigned int i = 4; i < KEYSLOT_AES_MAX; i++) {
|
||||||
set_aes_keyslot_flags(i, 0x40);
|
set_aes_keyslot_flags(i, 0x40);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < KEYSLOT_RSA_MAX; i++) {
|
for (unsigned int i = 0; i < KEYSLOT_RSA_MAX; i++) {
|
||||||
set_rsa_keyslot_flags(i, 0x41);
|
set_rsa_keyslot_flags(i, 0x41);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detect Master Key revision. */
|
/* Detect Master Key revision. */
|
||||||
mkey_detect_revision();
|
mkey_detect_revision();
|
||||||
|
|
||||||
/* Setup new device key, if necessary. */
|
/* Setup new device key, if necessary. */
|
||||||
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||||
const uint8_t new_devicekey_source_4x[0x10] = {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D};
|
const uint8_t new_devicekey_source_4x[0x10] = {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D};
|
||||||
|
@ -66,23 +52,23 @@ void setup_se(void) {
|
||||||
clear_aes_keyslot(KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY);
|
clear_aes_keyslot(KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY);
|
||||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
|
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
se_initialize_rng(KEYSLOT_SWITCH_DEVICEKEY);
|
se_initialize_rng(KEYSLOT_SWITCH_DEVICEKEY);
|
||||||
|
|
||||||
/* Generate random data, transform with device key to get RNG key. */
|
/* Generate random data, transform with device key to get RNG key. */
|
||||||
se_generate_random(KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
se_generate_random(KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
||||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_RNGKEY, KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
decrypt_data_into_keyslot(KEYSLOT_SWITCH_RNGKEY, KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
||||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_RNGKEY, 0xFF);
|
set_aes_keyslot_flags(KEYSLOT_SWITCH_RNGKEY, 0xFF);
|
||||||
|
|
||||||
/* Repeat for Session key. */
|
/* Repeat for Session key. */
|
||||||
se_generate_random(KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
se_generate_random(KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
||||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_SESSIONKEY, KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
decrypt_data_into_keyslot(KEYSLOT_SWITCH_SESSIONKEY, KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
||||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_SESSIONKEY, 0xFF);
|
set_aes_keyslot_flags(KEYSLOT_SWITCH_SESSIONKEY, 0xFF);
|
||||||
|
|
||||||
/* 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,25 +78,24 @@ 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];
|
||||||
|
|
||||||
/* Hardcode RSA with keyslot 0. */
|
/* Hardcode RSA with keyslot 0. */
|
||||||
const uint8_t public_exponent[4] = {0x00, 0x01, 0x00, 0x01};
|
const uint8_t public_exponent[4] = {0x00, 0x01, 0x00, 0x01};
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy Salt into MGF1 Hash Buffer. */
|
/* Copy Salt into MGF1 Hash Buffer. */
|
||||||
memset(h_buf, 0, sizeof(h_buf));
|
memset(h_buf, 0, sizeof(h_buf));
|
||||||
memcpy(h_buf, message + RSA_2048_BYTES - 0x20 - 0x1, 0x20);
|
memcpy(h_buf, message + RSA_2048_BYTES - 0x20 - 0x1, 0x20);
|
||||||
|
|
||||||
/* Decrypt maskedDB (via inline MGF1). */
|
/* Decrypt maskedDB (via inline MGF1). */
|
||||||
uint8_t seed = 0;
|
uint8_t seed = 0;
|
||||||
uint8_t mgf1_buf[0x20];
|
uint8_t mgf1_buf[0x20];
|
||||||
|
@ -122,7 +107,7 @@ bool rsa2048_pss_verify(const void *signature, size_t signature_size, const void
|
||||||
message[i] ^= mgf1_buf[i - ofs];
|
message[i] ^= mgf1_buf[i - ofs];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Constant lmask for rsa-2048-pss. */
|
/* Constant lmask for rsa-2048-pss. */
|
||||||
message[0] &= 0x7F;
|
message[0] &= 0x7F;
|
||||||
|
|
||||||
|
@ -139,7 +124,7 @@ bool rsa2048_pss_verify(const void *signature, size_t signature_size, const void
|
||||||
/* Check hash correctness. */
|
/* Check hash correctness. */
|
||||||
uint8_t validate_buf[8 + 0x20 + 0x20];
|
uint8_t validate_buf[8 + 0x20 + 0x20];
|
||||||
uint8_t validate_hash[0x20];
|
uint8_t validate_hash[0x20];
|
||||||
|
|
||||||
memset(validate_buf, 0, sizeof(validate_buf));
|
memset(validate_buf, 0, sizeof(validate_buf));
|
||||||
flush_dcache_range((uint8_t *)data, (uint8_t *)data + data_size);
|
flush_dcache_range((uint8_t *)data, (uint8_t *)data + data_size);
|
||||||
se_calculate_sha256(&validate_buf[8], data, data_size);
|
se_calculate_sha256(&validate_buf[8], data, data_size);
|
||||||
|
@ -149,20 +134,20 @@ 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);
|
||||||
flush_dcache_range((uint8_t *)src, (uint8_t *)src + src_size);
|
flush_dcache_range((uint8_t *)src, (uint8_t *)src + src_size);
|
||||||
unsigned int keyslot = mkey_get_keyslot(master_key_rev);
|
unsigned int keyslot = mkey_get_keyslot(master_key_rev);
|
||||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_PACKAGE2KEY, keyslot, package2_key_source, 0x10);
|
decrypt_data_into_keyslot(KEYSLOT_SWITCH_PACKAGE2KEY, keyslot, package2_key_source, 0x10);
|
||||||
|
|
||||||
/* Perform Encryption. */
|
/* Perform Encryption. */
|
||||||
se_aes_ctr_crypt(KEYSLOT_SWITCH_PACKAGE2KEY, dst, dst_size, src, src_size, ctr, ctr_size);
|
se_aes_ctr_crypt(KEYSLOT_SWITCH_PACKAGE2KEY, dst, dst_size, src, src_size, ctr, ctr_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()) {
|
||||||
|
@ -206,14 +191,14 @@ void verify_header_signature(package2_header_t *header) {
|
||||||
};
|
};
|
||||||
modulus = package2_modulus_dev;
|
modulus = package2_modulus_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is normally only allowed on dev units, but we'll allow it anywhere. */
|
/* This is normally only allowed on dev units, but we'll allow it anywhere. */
|
||||||
if (bootconfig_is_package2_unsigned() == 0 && rsa2048_pss_verify(header->signature, 0x100, modulus, 0x100, header->encrypted_header, 0x100) == 0) {
|
if (bootconfig_is_package2_unsigned() == 0 && rsa2048_pss_verify(header->signature, 0x100, modulus, 0x100, header->encrypted_header, 0x100) == 0) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,12 +280,12 @@ 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) {
|
||||||
uint32_t mkey_rev;
|
uint32_t mkey_rev;
|
||||||
|
|
||||||
/* Try to decrypt for all possible master keys. */
|
/* Try to decrypt for all possible master keys. */
|
||||||
for (mkey_rev = 0; mkey_rev < MASTERKEY_REVISION_MAX; mkey_rev++) {
|
for (mkey_rev = 0; mkey_rev < MASTERKEY_REVISION_MAX; mkey_rev++) {
|
||||||
package2_crypt_ctr(mkey_rev, &metadata, sizeof(package2_meta_t), &header->metadata, sizeof(package2_meta_t), header->metadata.ctr, sizeof(header->metadata.ctr));
|
package2_crypt_ctr(mkey_rev, &metadata, sizeof(package2_meta_t), &header->metadata, sizeof(package2_meta_t), header->metadata.ctr, sizeof(header->metadata.ctr));
|
||||||
|
@ -312,17 +297,17 @@ uint32_t decrypt_and_validate_header(package2_header_t *header) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure we successfully decrypted the header. */
|
/* Ensure we successfully decrypted the header. */
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
|
||||||
/* Check whether any of our sections overlap this region. If they do, we must relocate and copy from elsewhere. */
|
/* Check whether any of our sections overlap this region. If they do, we must relocate and copy from elsewhere. */
|
||||||
bool needs_relocation = false;
|
bool needs_relocation = false;
|
||||||
for (unsigned int section = 0; section < PACKAGE2_SECTION_MAX; section++) {
|
for (unsigned int section = 0; section < PACKAGE2_SECTION_MAX; section++) {
|
||||||
|
@ -365,13 +350,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);
|
||||||
load_buf = (void *)potential_base_start;
|
load_buf = (void *)potential_base_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy each section to its appropriate location, decrypting if necessary. */
|
/* Copy each section to its appropriate location, decrypting if necessary. */
|
||||||
for (unsigned int section = 0; section < PACKAGE2_SECTION_MAX; section++) {
|
for (unsigned int section = 0; section < PACKAGE2_SECTION_MAX; section++) {
|
||||||
if (metadata->section_sizes[section] == 0) {
|
if (metadata->section_sizes[section] == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *dst_start = (void *)(DRAM_BASE_PHYSICAL + (uint64_t)metadata->section_offsets[section]);
|
void *dst_start = (void *)(DRAM_BASE_PHYSICAL + (uint64_t)metadata->section_offsets[section]);
|
||||||
void *src_start = load_buf + sizeof(package2_header_t) + metadata->section_offsets[section];
|
void *src_start = load_buf + sizeof(package2_header_t) + metadata->section_offsets[section];
|
||||||
size_t size = (size_t)metadata->section_sizes[section];
|
size_t size = (size_t)metadata->section_sizes[section];
|
||||||
|
@ -382,17 +367,18 @@ void load_package2_sections(package2_meta_t *metadata, uint32_t master_key_rev)
|
||||||
package2_crypt_ctr(master_key_rev, dst_start, size, src_start, size, metadata->section_ctrs[section], 0x10);
|
package2_crypt_ctr(master_key_rev, dst_start, size, src_start, size, metadata->section_ctrs[section], 0x10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the encrypted package2 from memory. */
|
/* Clear the encrypted package2 from memory. */
|
||||||
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();
|
||||||
|
|
||||||
|
@ -408,12 +394,12 @@ void load_package2(void) {
|
||||||
|
|
||||||
/* Initialize cache'd random bytes for kernel. */
|
/* Initialize cache'd random bytes for kernel. */
|
||||||
randomcache_init();
|
randomcache_init();
|
||||||
|
|
||||||
/* TODO: memclear the initial copy of Exosphere running in IRAM (relocated to TZRAM by earlier code). */
|
/* TODO: memclear the initial copy of Exosphere running in IRAM (relocated to TZRAM by earlier code). */
|
||||||
|
|
||||||
/* Let NX Bootloader know that we're running. */
|
/* Let NX Bootloader know that we're running. */
|
||||||
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE = 1;
|
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE = 1;
|
||||||
|
|
||||||
/* Synchronize with NX BOOTLOADER. */
|
/* Synchronize with NX BOOTLOADER. */
|
||||||
if (MAILBOX_NX_BOOTLOADER_SETUP_STATE == NX_BOOTLOADER_STATE_INIT) {
|
if (MAILBOX_NX_BOOTLOADER_SETUP_STATE == NX_BOOTLOADER_STATE_INIT) {
|
||||||
while (MAILBOX_NX_BOOTLOADER_SETUP_STATE < NX_BOOTLOADER_STATE_MOVED_BOOTCONFIG) {
|
while (MAILBOX_NX_BOOTLOADER_SETUP_STATE < NX_BOOTLOADER_STATE_MOVED_BOOTCONFIG) {
|
||||||
|
@ -423,47 +409,44 @@ void load_package2(void) {
|
||||||
|
|
||||||
/* Load Boot Config into global. */
|
/* Load Boot Config into global. */
|
||||||
setup_boot_config();
|
setup_boot_config();
|
||||||
|
|
||||||
/* Synchronize with NX BOOTLOADER. */
|
/* Synchronize with NX BOOTLOADER. */
|
||||||
if (MAILBOX_NX_BOOTLOADER_SETUP_STATE == NX_BOOTLOADER_STATE_MOVED_BOOTCONFIG) {
|
if (MAILBOX_NX_BOOTLOADER_SETUP_STATE == NX_BOOTLOADER_STATE_MOVED_BOOTCONFIG) {
|
||||||
while (MAILBOX_NX_BOOTLOADER_SETUP_STATE < NX_BOOTLOADER_STATE_LOADED_PACKAGE2) {
|
while (MAILBOX_NX_BOOTLOADER_SETUP_STATE < NX_BOOTLOADER_STATE_LOADED_PACKAGE2) {
|
||||||
wait(1);
|
wait(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load header from NX_BOOTLOADER-initialized DRAM. */
|
/* Load header from NX_BOOTLOADER-initialized DRAM. */
|
||||||
package2_header_t header;
|
package2_header_t header;
|
||||||
flush_dcache_range((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, (uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(header));
|
flush_dcache_range((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, (uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(header));
|
||||||
memcpy(&header, NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, sizeof(header));
|
memcpy(&header, NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, sizeof(header));
|
||||||
flush_dcache_range((uint8_t *)&header, (uint8_t *)&header + sizeof(header));
|
flush_dcache_range((uint8_t *)&header, (uint8_t *)&header + sizeof(header));
|
||||||
|
|
||||||
/* Perform signature checks. */
|
/* Perform signature checks. */
|
||||||
verify_header_signature(&header);
|
verify_header_signature(&header);
|
||||||
|
|
||||||
/* Decrypt header, get key revision required. */
|
/* Decrypt header, get key revision required. */
|
||||||
uint32_t package2_mkey_rev = decrypt_and_validate_header(&header);
|
uint32_t package2_mkey_rev = decrypt_and_validate_header(&header);
|
||||||
|
|
||||||
/* Load Package2 Sections. */
|
/* Load Package2 Sections. */
|
||||||
load_package2_sections(&header.metadata, package2_mkey_rev);
|
load_package2_sections(&header.metadata, package2_mkey_rev);
|
||||||
|
|
||||||
/* Clean up cache. */
|
/* Clean up cache. */
|
||||||
flush_dcache_all();
|
flush_dcache_all();
|
||||||
invalidate_icache_inner_shareable();
|
invalidate_icache_inner_shareable();
|
||||||
|
|
||||||
/* 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) {
|
||||||
wait(1);
|
wait(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: MISC register 0x1F0098C00 |= 0x2000; */
|
/* TODO: MISC register 0x1F0098C00 |= 0x2000; */
|
||||||
|
|
||||||
/* TODO: Update SCR_EL3 depending on value in Bootconfig. */
|
/* TODO: Update SCR_EL3 depending on value in Bootconfig. */
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,8 +13,9 @@ 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);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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