add el1 transfer at the boot stage in case higher EL is implemented
[lunaix-os.git] / lunaix-os / arch / aarch64 / boot / init.c
1 #include <lunaix/boot_generic.h>
2 #include <asm/aa64.h>
3 #include <asm/aa64_spsr.h>
4
5 #include "init.h"
6
7 static inline void
8 setup_pstate()
9 {
10     /*
11         SCTRL_EL1
12             EE=0, E0E=0     // all little endian
13             WXN=1           // write implie exec never
14             SA0=1, SA=1     // alignment check on SP
15             A=1             // alignment check on memref
16             NMI=1           // mask interrupt
17             M=1             // enable mmu
18     */
19
20    unsigned long sctrl = 0;
21
22    sctrl |= SCTRL_NMI;
23    sctrl |= SCTRL_WXN | SCTRL_nAA;
24    sctrl |= SCTRL_SA | SCTRL_SA0;
25    sctrl |= SCTRL_A | SCTRL_M;
26
27    set_sysreg(TCR_EL1, sctrl);
28    set_sysreg(SPSel, 1);
29 }
30
31 extern void aa64_vbase();
32
33 static inline void
34 setup_evbar()
35 {
36     set_sysreg(VBAR_EL1, __ptr(aa64_vbase));
37 }
38
39 static inline void
40 setup_ttbr()
41 {
42     /*
43         
44         TCR_EL1
45             SH0=3           // Inner sharable
46             ORGN0=0         // Normal memory, Outer Non-cacheable.
47             IRGN0=1         // Normal memory, Inner Write-Back Read-Allocate Write-Allocate Cacheable.
48             A1=0            // TTBR0 define ASID
49             EPD1=0
50             T1SZ=0
51             EPD0=1
52             T0SZ=16         // disable TTBR1, Use TTBR0 for all translation
53             TG0=0           // VA48, 256T, 4K Granule
54             TBI1=0,
55             TBI0=0          // Ignore top bits
56             AS=1            // 16bits asid
57             HA=1
58             HD=1            // Hardware managed dirty and access
59
60
61         We may use the follow practice later
62             TTBR0:  Translation for user-land (lowmem)
63             TTBR1:  Translation for kernel-land (highmem)
64     */
65
66     unsigned long tcr = 0;
67     ptr_t ttb;
68
69     tcr |= TCR_T1SZ(0) | TCR_T0SZ(16);
70     tcr |= TCR_TG0(TCR_G4K);
71     tcr |= TCR_AS | TCR_HA | TCR_HD;
72     tcr |= TCR_EPD0;
73
74     ttb = kremap();
75
76     set_sysreg(TTBR0_EL1, ttb);
77     set_sysreg(TCR_EL1, tcr);
78 }
79
80 static inline void
81 extract_dtb_bootinfo(ptr_t dtb, struct boot_handoff* handoff)
82 {
83     handoff->kexec.dtb_pa = dtb;
84     
85     // TODO extract /memory, /reserved-memories from dtb
86 }
87
88 static inline void
89 setup_gic_sysreg()
90 {
91     int el;
92     bool has_el2;
93     u64_t pfr;
94
95     pfr = read_sysreg(ID_AA64PFR0_EL1);
96     el = read_sysreg(CurrentEL) >> 2;
97
98     // Arm A-Profile: D19.2.69, check for GIC sysreg avaliability
99
100     if (!BITS_GET(pfr, BITFIELD(27, 24))) {
101         return;
102     }
103
104     has_el2 = !!BITS_GET(pfr, BITFIELD(11, 8));
105
106     // GIC spec (v3,v4): 12.1.7, table 12-2
107     // GIC spec (v3,v4): ICC_SRE_ELx accessing
108     // Arm A-Profile: R_PCDTX, PSTATE.EL reset value
109
110     if (el == 3) {
111         sysreg_flagging(ICC_SRE_EL3, ICC_SRE_SRE, 0);
112     }
113     
114     if (has_el2) {
115         // el must be >= 2
116         sysreg_flagging(ICC_SRE_EL2, ICC_SRE_SRE, 0);
117     }
118
119     sysreg_flagging(ICC_SRE_EL1, ICC_SRE_SRE, 0);
120 }
121
122 void
123 aarch64_pre_el1_init()
124 {
125     setup_gic_sysreg();
126 }
127
128 bool
129 aarch64_prepare_el1_transfer()
130 {
131     ptr_t spsr;
132     int el;
133
134     el = read_sysreg(CurrentEL) >> 2;
135
136     if (el == 1) {
137         return false;
138     }
139
140     spsr = SPSR_AllInt | SPSR_I | SPSR_F | SPSR_SP;
141     spsr = BITS_SET(spsr, SPSR_EL, 1);
142
143     if (el == 2) {
144         set_sysreg(SPSR_EL2, spsr);
145     }
146     else {
147         set_sysreg(SPSR_EL3, spsr);
148     }
149
150     return true;
151 }
152
153 struct boot_handoff*
154 aarch64_init(ptr_t dtb)
155 {
156     setup_evbar();
157     setup_ttbr();
158     setup_pstate();
159
160     struct boot_handoff* handoff;
161     
162     handoff = bootmem_alloc(sizeof(*handoff));
163
164     extract_dtb_bootinfo(dtb, handoff);
165
166     return handoff;
167 }