aa64: finalise context switch, page fault handler and syscall
[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 #include <hal/devtree.h>
5
6 #include "init.h"
7
8 static inline void
9 setup_pstate()
10 {
11     /*
12         SCTRL_EL1
13             EE=0, E0E=0     // all little endian
14             WXN=1           // write implie exec never
15             SA0=1, SA=1     // alignment check on SP
16             A=1             // alignment check on memref
17             NMI=1           // mask interrupt
18             M=1             // enable mmu
19     */
20
21    unsigned long sctrl = 0;
22
23    sctrl |= SCTRL_NMI;
24    sctrl |= SCTRL_WXN | SCTRL_nAA;
25    sctrl |= SCTRL_SA | SCTRL_SA0;
26    sctrl |= SCTRL_A | SCTRL_M;
27
28    set_sysreg(TCR_EL1, sctrl);
29    set_sysreg(SPSel, 1);
30 }
31
32 extern void aa64_vbase();
33
34 static inline void
35 setup_evbar()
36 {
37     set_sysreg(VBAR_EL1, __ptr(aa64_vbase));
38 }
39
40 static inline void
41 setup_ttbr()
42 {
43     /*
44         
45         TCR_EL1
46             SH0=3           // Inner sharable
47             ORGN0=0         // Normal memory, Outer Non-cacheable.
48             IRGN0=1         // Normal memory, Inner Write-Back Read-Allocate Write-Allocate Cacheable.
49             A1=0            // TTBR0 define ASID
50             EPD1=0
51             T1SZ=0
52             EPD0=1
53             T0SZ=16         // disable TTBR1, Use TTBR0 for all translation
54             TG0=0           // VA48, 256T, 4K Granule
55             TBI1=0,
56             TBI0=0          // Ignore top bits
57             AS=1            // 16bits asid
58             HA=1
59             HD=1            // Hardware managed dirty and access
60
61
62         We may use the follow practice later
63             TTBR0:  Translation for user-land (lowmem)
64             TTBR1:  Translation for kernel-land (highmem)
65     */
66
67     unsigned long tcr = 0;
68     ptr_t ttb;
69
70     tcr |= TCR_T1SZ(0) | TCR_T0SZ(16);
71     tcr |= TCR_TG0(TCR_G4K);
72     tcr |= TCR_AS | TCR_HA | TCR_HD;
73     tcr |= TCR_EPD0;
74
75     ttb = kremap();
76
77     set_sysreg(TTBR0_EL1, ttb);
78     set_sysreg(TCR_EL1, tcr);
79 }
80
81 #define MMAP_ENTS_CHUNK_SIZE    16
82
83 static inline void
84 extract_dtb_bootinfo(ptr_t dtb, struct boot_handoff* handoff)
85 {
86     struct fdt_blob fdt;
87     struct fdt_memscan mscan;
88     struct dt_memory_node mnode;
89
90     int mmap_len = 0, mmap_max_len = 16;
91     size_t pmem_size = 0;
92     struct boot_mmapent* mmap;
93
94     mmap = bootmem_alloc(sizeof(*mmap) * MMAP_ENTS_CHUNK_SIZE);
95     handoff->kexec.dtb_pa = dtb;
96     
97     // TODO extract /memory, /reserved-memories from dtb
98
99     fdt_load(&fdt, dtb);
100     fdt_memscan_begin(&mscan, &fdt);
101
102     struct boot_mmapent* mmap_ent;
103
104     while(fdt_memscan_nextnode(&mscan, &fdt))
105     {
106         while (fdt_memscan_nextrange(&mscan, &mnode)) 
107         {
108             mmap_ent = &mmap[mmap_len++];
109             *mmap_ent = (struct boot_mmapent) {
110                 .size = mnode.size,
111                 .start = mnode.base
112             };
113
114             if (mnode.type == FDT_MEM_FREE) {
115                 mmap_ent->type = BOOT_MMAP_FREE;
116                 pmem_size += mnode.size;
117             }
118             else {
119                 mmap_ent->type = BOOT_MMAP_RSVD;
120             }
121
122
123             if (mmap_len < mmap_max_len) {
124                 continue;
125             }
126
127             mmap_max_len += MMAP_ENTS_CHUNK_SIZE;
128
129             // another allocation is just expanding the previous allocation.
130             bootmem_alloc(sizeof(*mmap) * MMAP_ENTS_CHUNK_SIZE);
131         }
132     }
133
134     handoff->mem.mmap = mmap;
135     handoff->mem.mmap_len = mmap_len;
136     handoff->mem.size = pmem_size;
137 }
138
139 static inline void
140 setup_gic_sysreg()
141 {
142     int el;
143     bool has_el2;
144     u64_t pfr;
145
146     pfr = read_sysreg(ID_AA64PFR0_EL1);
147     el = read_sysreg(CurrentEL) >> 2;
148
149     // Arm A-Profile: D19.2.69, check for GIC sysreg avaliability
150
151     if (!BITS_GET(pfr, BITFIELD(27, 24))) {
152         return;
153     }
154
155     has_el2 = !!BITS_GET(pfr, BITFIELD(11, 8));
156
157     // GIC spec (v3,v4): 12.1.7, table 12-2
158     // GIC spec (v3,v4): ICC_SRE_ELx accessing
159     // Arm A-Profile: R_PCDTX, PSTATE.EL reset value
160
161     if (el == 3) {
162         sysreg_flagging(ICC_SRE_EL3, ICC_SRE_SRE, 0);
163     }
164     
165     if (has_el2) {
166         // el must be >= 2
167         sysreg_flagging(ICC_SRE_EL2, ICC_SRE_SRE, 0);
168     }
169
170     sysreg_flagging(ICC_SRE_EL1, ICC_SRE_SRE, 0);
171 }
172
173 void boot_text
174 aarch64_pre_el1_init()
175 {
176     setup_gic_sysreg();
177 }
178
179 bool boot_text
180 aarch64_prepare_el1_transfer()
181 {
182     ptr_t spsr;
183     int el;
184
185     el = read_sysreg(CurrentEL) >> 2;
186
187     if (el == 1) {
188         // no transfer required
189         return false;
190     }
191
192     spsr  = SPSR_EL1_preset;
193     spsr |= SPSR_AllInt | SPSR_I | SPSR_F | SPSR_A;
194
195     if (el == 2) {
196         set_sysreg(SPSR_EL2, spsr);
197     }
198     else {
199         set_sysreg(SPSR_EL3, spsr);
200     }
201
202     return true;
203 }
204
205 struct boot_handoff* boot_text
206 aarch64_init(ptr_t dtb)
207 {
208     setup_evbar();
209     setup_ttbr();
210     setup_pstate();
211
212     struct boot_handoff* handoff;
213     
214     handoff = bootmem_alloc(sizeof(*handoff));
215
216     extract_dtb_bootinfo(dtb, handoff);
217
218     return handoff;
219 }