:: limine / common / lib / spinup.asm_aarch64 2.9 KB raw

1
#include <lib/macros.aarch64_asm.h>
2
3
.section .text
4
5
// noreturn void enter_in_el1(uint64_t entry, uint64_t sp, uint64_t sctlr,
6
//                            uint64_t mair, uint64_t tcr, uint64_t ttbr0,
7
//                            uint64_t ttbr1, uint64_t direct_map_offset)
8
// Configure EL1 state and jump to kernel. Must be called at EL1.
9
10
.global enter_in_el1
11
enter_in_el1:
12
    msr spsel, #0
13
    mov sp, x1
14
15
    // Switch to the new page tables
16
17
    // Point the EL1t handler to the continuation, such that after we page fault,
18
    // execution continues and the kernel is entered.
19
    adrp x8, 1f
20
    add x8, x8, #:lo12:1f
21
    add x8, x8, x7
22
    msr vbar_el1, x8
23
    isb
24
    dsb sy
25
    isb
26
27
    // Switch the page table registers
28
    msr mair_el1, x3
29
    msr tcr_el1, x4
30
    msr ttbr0_el1, x5
31
    msr ttbr1_el1, x6
32
    msr sctlr_el1, x2
33
    isb
34
    dsb sy
35
    isb
36
37
    // Jump to the higher half mapping in case we didn't immediately crash
38
    br x8
39
40
// Alignment required by VBAR register
41
.align 11
42
1:
43
    // Zero out VBAR to avoid confusion
44
    msr vbar_el1, xzr
45
46
    // Disable FP/SIMD/SVE
47
    msr cpacr_el1, xzr
48
49
    // Enter kernel in EL1
50
    mov x8, #0x3c4
51
    msr spsr_el1, x8
52
    msr elr_el1, x0
53
54
    mov x0, xzr
55
    ZERO_REGS_EXCEPT_X0
56
57
    eret
58
59
// noreturn void enter_in_el2(uint64_t entry, uint64_t sp, uint64_t sctlr,
60
//                            uint64_t mair, uint64_t tcr, uint64_t ttbr0,
61
//                            uint64_t ttbr1, uint64_t direct_map_offset)
62
// Enter kernel at EL2 with VHE. Must be called at EL2.
63
64
.global enter_in_el2
65
enter_in_el2:
66
    msr spsel, #0
67
    mov sp, x1
68
69
    // Enable E2H if not already set
70
    mrs x8, hcr_el2
71
    orr x8, x8, #(1 << 34)
72
    msr hcr_el2, x8
73
    isb
74
75
    // Switch page tables using VHE-redirected register names.
76
    // Under VHE, *_el1 writes go to the EL2 register bank.
77
78
    // Point the exception handler to the continuation so that if we page fault
79
    // during the switch, execution continues at the kernel entry.
80
    adrp x8, 5f
81
    add x8, x8, #:lo12:5f
82
    add x8, x8, x7
83
    msr vbar_el1, x8
84
    isb
85
    dsb sy
86
    isb
87
88
    // Switch the page table registers (VHE redirects to EL2)
89
    msr mair_el1, x3
90
    msr tcr_el1, x4
91
    msr ttbr0_el1, x5
92
    msr ttbr1_el1, x6
93
    msr sctlr_el1, x2
94
    isb
95
    dsb sy
96
    isb
97
98
    // Jump to the higher half mapping in case we didn't immediately crash
99
    br x8
100
101
// Alignment required by VBAR register
102
.align 11
103
5:
104
    // Zero out VBAR to avoid confusion
105
    msr vbar_el1, xzr
106
107
    // Configure EL2 state for VHE
108
109
    // Don't trap counters
110
    mov x8, #3
111
    msr cnthctl_el2, x8
112
    msr cntvoff_el2, xzr
113
114
    // HCR: E2H + TGE + RW + SWIO
115
    ldr x8, =0x488000002
116
    msr hcr_el2, x8
117
118
    // Disable FP/SIMD/SVE (VHE CPTR_EL2 layout, CPACR-like)
119
    msr cptr_el2, xzr
120
    msr hstr_el2, xzr
121
122
    // Enter kernel in EL2
123
    mov x8, #0x3c8
124
    msr spsr_el1, x8
125
    msr elr_el1, x0
126
127
    mov x0, xzr
128
    ZERO_REGS_EXCEPT_X0
129
130
    eret
131
132
.section .note.GNU-stack,"",%progbits
tab: 248 wrap: offon