186 lines
4.8 KiB
ArmAsm
186 lines
4.8 KiB
ArmAsm
/*
|
|
* Boot
|
|
*/
|
|
|
|
#define STACK_SIZE 0x4000
|
|
|
|
#define KERNEL_BASE 0xFFFF800000000000
|
|
#define LOWMEM(_x) (_x - KERNEL_BASE)
|
|
|
|
#define DIST_BASE_ADDR 0x2c000000
|
|
|
|
.section .boot, "ax"
|
|
|
|
.balign 4096
|
|
.space STACK_SIZE, 0
|
|
_bootstack:
|
|
|
|
/**
|
|
* _start --
|
|
*
|
|
* ELF entry point.
|
|
*/
|
|
.globl _lostart
|
|
.equ _lostart, LOWMEM(_start)
|
|
.globl _start
|
|
_start:
|
|
.extern _evt
|
|
// setup EVT for all levels (before MMU)
|
|
ldr x0,=LOWMEM(_evt)
|
|
msr VBAR_EL1, x0
|
|
msr VBAR_EL2, x0
|
|
msr VBAR_EL3, x0
|
|
|
|
// do interrupt stuff in EL3
|
|
mrs x0, ICC_IGRPEN1_EL3
|
|
orr w0, w0, #0b11 // enable secure & non secure group 1 interrupts
|
|
msr ICC_IGRPEN1_EL3, x0
|
|
|
|
// enable Disable Secure bit in GIC distributor
|
|
ldr x0, =DIST_BASE_ADDR + 0x0
|
|
ldrh w1, [x0]
|
|
orr w1, w1, #(1 << 6)
|
|
strh w1, [x0]
|
|
|
|
// switch from el3 to el2
|
|
msr sctlr_el2, xzr
|
|
msr hcr_el2, xzr
|
|
|
|
// Determine the EL2 Execution state
|
|
mrs X0, SCR_EL3
|
|
orr X0, X0, #(1<<10) // RW EL2 Execution state is AArch64.
|
|
orr X0, X0, #(1<<0) // NS EL1 is Non-secure world.
|
|
and X0, X0, #~(1<<3) // exceptions are not taken to EL3
|
|
msr SCR_EL3, X0
|
|
mov X0, #0b01001 // DAIF=0000
|
|
msr SPSR_EL3, X0 // M[4:0]=01001 EL2h must match SCR_EL3.RW
|
|
// Determine EL2 entry.
|
|
ldr X0, =LOWMEM(_el2_entry) // el2_entry points to the first instruction of
|
|
msr ELR_EL3, X0 // EL2 code.
|
|
eret // enter el2
|
|
|
|
_el2_entry:
|
|
// Initialize the SCTLR_EL1 register before entering EL1.
|
|
msr SCTLR_EL1, XZR
|
|
// Determine the EL1 Execution state.
|
|
mrs X0, HCR_EL2
|
|
orr X0, X0, #(1 << 31) // RW=1 EL1 Execution state is AArch64.
|
|
and X0, X0, #~(1 << 27) // exceptions are not taken to EL2
|
|
and X0, X0, #~(1 << 3) // FMO, FIQs are not taken to EL2
|
|
and X0, X0, #~(1 << 4) // IMO, IRQs are not taken to EL2
|
|
and X0, X0, #~(1 << 5) // AMO, SErrors are not taken to EL2
|
|
and X0, X0, #~(1 << 48) // GPF, Granule protections are not taken to EL2
|
|
and X0, X0, #~(1 << 37) // TEA, sync ext aborts are not taken to EL2
|
|
msr HCR_EL2, X0
|
|
|
|
mrs X0, CNTHCTL_EL2
|
|
orr x0, x0, #0b11 // enable access to el1 physical timer at el1
|
|
msr CNTHCTL_EL2, x0
|
|
|
|
mov X0, #0b00101 // DAIF=0000
|
|
msr SPSR_EL2, X0 // M[4:0]=00101 EL1h must match HCR_EL2.RW.
|
|
ldr X0, =LOWMEM(_el1_entry) // el1_entry points to the first instruction of
|
|
msr ELR_EL2, X0 // EL1 code.
|
|
eret // enter el1
|
|
|
|
_el1_entry:
|
|
mrs x0, CurrentEL
|
|
cmp x0, #(1 << 2)
|
|
cset x0, eq
|
|
tbz x0, 0, _halt
|
|
|
|
// enable SIMD
|
|
mrs x0, CPACR_EL1
|
|
orr x0, x0, #(0b11 << 20)
|
|
msr CPACR_EL1, x0
|
|
|
|
// setup boot MMU
|
|
#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16))
|
|
#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30))
|
|
ldr x0, =(TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB);
|
|
msr tcr_el1, x0
|
|
#define MAIR_IDX_NORMAL_CACHEABLE (0)
|
|
#define MAIR_IDX_DEVICE (1)
|
|
#define MAIR_VAL (0b11111111) | (0b00000000 << 8)
|
|
// 0 = b11111111 = Normal, Inner/Outer WB/WA/RA
|
|
// 1 = b00000000 = Device-nGnRnE
|
|
ldr x0, =(MAIR_VAL)
|
|
msr mair_el1, x0
|
|
// write paddr of page table base
|
|
ldr x0, =LOWMEM(_boot_ptl0lo)
|
|
msr ttbr0_el1, x0
|
|
ldr x0, =LOWMEM(_boot_ptl0hi)
|
|
msr ttbr1_el1, x0
|
|
// disable TTBR1 (only use ttbr0)
|
|
|
|
// setup page tables
|
|
#define PD_TABLE (0b11)
|
|
#define PD_BLOCK (0b01)
|
|
#define PD_ACCESS (1 << 10)
|
|
#define BOOT_PGD_ATTR (PD_TABLE)
|
|
#define BOOT_PUD_ATTR (PD_ACCESS | (MAIR_IDX_NORMAL_CACHEABLE << 2) | PD_BLOCK)
|
|
#define BOOT_PUD_DEV_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE << 2) | PD_BLOCK)
|
|
// ident map 0x00000000 -> 0x00000000 Size: 1G
|
|
ldr x0, =LOWMEM(_boot_ptl0lo) + 0x8 * 0 // x0 = L0 entry for vaddr 0x00000000
|
|
ldr x1, =LOWMEM(_boot_ptl1lo) + BOOT_PGD_ATTR
|
|
str x1, [x0]
|
|
|
|
ldr x0, =LOWMEM(_boot_ptl1lo) + 0x8 * 0 // x0 = L1 entry for vaddr 0x00000000
|
|
ldr x1, =0x00000000 | BOOT_PUD_ATTR // map to 0x80000000
|
|
str x1, [x0]
|
|
|
|
// map 0x00000000 -> 0xFFFF800000000000 Size: 1G
|
|
ldr x0, =LOWMEM(_boot_ptl0hi) + 0x8 * 256 // x0 = L0 entry for vaddr 0xFFFF800000000000
|
|
ldr x1, =LOWMEM(_boot_ptl1hi) + BOOT_PGD_ATTR
|
|
str x1, [x0]
|
|
|
|
ldr x0, =LOWMEM(_boot_ptl1hi) + 0x8 * 0 // x0 = L1 entry for vaddr 0xFFFF800000000000
|
|
ldr x1, =0x00000000 | BOOT_PUD_ATTR
|
|
str x1, [x0]
|
|
|
|
// enable MMU
|
|
mrs x0, sctlr_el1
|
|
orr x0, x0, #0x1 //enable MMU
|
|
orr x0, x0, #(0x1 << 12) // enable icache
|
|
orr x0, x0, #(0x1 << 2) // enable dcache
|
|
msr sctlr_el1, x0
|
|
dsb sy
|
|
isb // barriers
|
|
|
|
ldr x0, =_high_addr
|
|
br x0 // jump to kernel vspace
|
|
|
|
_high_addr:
|
|
// reload stack
|
|
ldr x0, =_bootstack
|
|
mov sp, x0
|
|
|
|
// re-setup el1 EVT with high addr
|
|
ldr x0, =_evt
|
|
msr VBAR_EL1, x0
|
|
.extern MachineBoot_Entry
|
|
ldr x0, =MachineBoot_Entry
|
|
blr x0
|
|
b _halt
|
|
|
|
.global _halt
|
|
_halt:
|
|
wfi
|
|
b _halt
|
|
|
|
.balign 4096
|
|
_boot_ptl0hi:
|
|
.space 4096,0
|
|
|
|
.balign 4096
|
|
_boot_ptl0lo:
|
|
.space 4096,0
|
|
|
|
.balign 4096
|
|
_boot_ptl1lo:
|
|
.space 4096,0
|
|
|
|
.balign 4096
|
|
_boot_ptl1hi:
|
|
.space 4096,0
|