metal-cos/sys/arm64/locore.S
2024-09-26 04:07:50 +08:00

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