blob: f36f5bf8b9c1565b2492aa6b0f64d8803ff966c4 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001#include <asm.h>
2#include <arch/arm64/mmu.h>
3#include <arch/asm_macros.h>
4#include <arch/arch_ops.h>
5#include <kernel/vm.h>
6
7/*
8 * Register use:
9 * x0-x3 Arguments
10 * x9-x15 Scratch
11 * x19-x28 Globals
12 */
13tmp .req x9
14tmp2 .req x10
15wtmp2 .req w10
16idx .req x11
17idx_shift .req x12
18page_table .req x13
19new_page_table .req x14
20phys_offset .req x15
21
22cpuid .req x19
23page_table0 .req x20
24page_table1 .req x21
25mmu_initial_mapping .req x22
26vaddr .req x23
27paddr .req x24
28mapping_size .req x25
29size .req x26
30attr .req x27
31
32.section .text.boot
33FUNCTION(_start)
34.globl arm_reset
35arm_reset:
36
37 bl setup_el2_or_el3_exception_base
38
39 mrs tmp, CurrentEL
40 cmp tmp, #(0b11 << 2)
41 b.ne .Lsetup_el2_or_el3_stack
42
43 /* el3 set secure timer */
44 ldr tmp2, =13000000
45 msr cntfrq_el0, tmp2
46
47 /* el3 enable smp bit */
48 mrs tmp2, s3_1_c15_c2_1
49 orr tmp2, tmp2, #(1<<6)
50 msr s3_1_c15_c2_1, tmp2
51
52.Lsetup_el2_or_el3_stack:
53 /* set el2 or el3 stack pointer */
54 ldr tmp2, = __stack_end
55 mov sp, tmp2
56
57 /* initialization required in EL3. weak symbol at asm.S */
58 cmp tmp, #(0b11 << 2)
59 b.ne .LelX_to_el1
60 bl platform_el3_init
61
62.LelX_to_el1:
63 /* change to el1 */
64 bl arm64_elX_to_el1
65
66#if WITH_KERNEL_VM
67 /* enable caches so atomics and spinlocks work */
68 mrs tmp, sctlr_el1
69 orr tmp, tmp, #(1<<12) /* Enable icache */
70 orr tmp, tmp, #(1<<2) /* Enable dcache/ucache */
71 bic tmp, tmp, #(1<<3) /* Disable Stack Alignment Check */ /* TODO: don't use unaligned stacks */
72 msr sctlr_el1, tmp
73
74 /* set up the mmu according to mmu_initial_mappings */
75
76 /* load the base of the translation table and clear the table */
77 adrp page_table1, arm64_kernel_translation_table
78 add page_table1, page_table1, #:lo12:arm64_kernel_translation_table
79
80 /* Prepare tt_trampoline page table */
81 /* Calculate pagetable physical addresses */
82 adrp page_table0, tt_trampoline
83 add page_table0, page_table0, #:lo12:tt_trampoline
84
85#if WITH_SMP
86 mrs cpuid, mpidr_el1
87 ubfx cpuid, cpuid, #0, #SMP_CPU_ID_BITS
88 cbnz cpuid, .Lmmu_enable_secondary
89#endif
90
91 mov tmp, #0
92
93 /* walk through all the entries in the translation table, setting them up */
94.Lclear_top_page_table_loop:
95 str xzr, [page_table1, tmp, lsl #3]
96 add tmp, tmp, #1
97 cmp tmp, #MMU_KERNEL_PAGE_TABLE_ENTRIES_TOP
98 bne .Lclear_top_page_table_loop
99
100 /* load the address of the mmu_initial_mappings table and start processing */
101 adrp mmu_initial_mapping, mmu_initial_mappings
102 add mmu_initial_mapping, mmu_initial_mapping, #:lo12:mmu_initial_mappings
103
104.Linitial_mapping_loop:
105/* Read entry of mmu_initial_mappings (likely defined in platform.c) */
106 ldp paddr, vaddr, [mmu_initial_mapping, #__MMU_INITIAL_MAPPING_PHYS_OFFSET]
107 ldp size, tmp, [mmu_initial_mapping, #__MMU_INITIAL_MAPPING_SIZE_OFFSET]
108
109 tbzmask tmp, MMU_INITIAL_MAPPING_FLAG_DYNAMIC, .Lnot_dynamic
110 adr paddr, _start
111 mov size, x0
112 str paddr, [mmu_initial_mapping, #__MMU_INITIAL_MAPPING_PHYS_OFFSET]
113 str size, [mmu_initial_mapping, #__MMU_INITIAL_MAPPING_SIZE_OFFSET]
114
115.Lnot_dynamic:
116 /* if size == 0, end of list, done with initial mapping */
117 cbz size, .Linitial_mapping_done
118 mov mapping_size, size
119
120 /* set up the flags */
121 tbzmask tmp, MMU_INITIAL_MAPPING_FLAG_UNCACHED, .Lnot_uncached
122 ldr attr, =MMU_INITIAL_MAP_STRONGLY_ORDERED
123 b .Lmem_type_done
124
125.Lnot_uncached:
126 /* is this memory mapped to device/peripherals? */
127 tbzmask tmp, MMU_INITIAL_MAPPING_FLAG_DEVICE, .Lnot_device
128 ldr attr, =MMU_INITIAL_MAP_DEVICE
129 b .Lmem_type_done
130.Lnot_device:
131
132/* Determine the segment in which the memory resides and set appropriate
133 * attributes. In order to handle offset kernels, the following rules are
134 * implemented below:
135 * KERNEL_BASE to __code_start -read/write (see note below)
136 * __code_start to __rodata_start (.text) -read only
137 * __rodata_start to __data_start (.rodata) -read only, execute never
138 * __data_start to ..... (.data) -read/write
139 *
140 * The space below __code_start is presently left as read/write (same as .data)
141 * mainly as a workaround for the raspberry pi boot process. Boot vectors for
142 * secondary CPUs are in this area and need to be updated by cpu0 once the system
143 * is ready to boot the secondary processors.
144 * TODO: handle this via mmu_initial_mapping entries, which may need to be
145 * extended with additional flag types
146 */
147.Lmapping_size_loop:
148 ldr attr, =MMU_PTE_KERNEL_DATA_FLAGS
149 ldr tmp, =__code_start
150 subs size, tmp, vaddr
151 /* If page is below the entry point (_start) mark as kernel data */
152 b.hi .Lmem_type_done
153
154 ldr attr, =MMU_PTE_KERNEL_RO_FLAGS
155 ldr tmp, =__rodata_start
156 subs size, tmp, vaddr
157 b.hi .Lmem_type_done
158 orr attr, attr, #MMU_PTE_ATTR_PXN
159 ldr tmp, =__data_start
160 subs size, tmp, vaddr
161 b.hi .Lmem_type_done
162 ldr attr, =MMU_PTE_KERNEL_DATA_FLAGS
163 ldr tmp, =_end
164 subs size, tmp, vaddr
165 b.lo . /* Error: _end < vaddr */
166 cmp mapping_size, size
167 b.lo . /* Error: mapping_size < size => RAM size too small for data/bss */
168 mov size, mapping_size
169
170.Lmem_type_done:
171 subs mapping_size, mapping_size, size
172 b.lo . /* Error: mapping_size < size (RAM size too small for code/rodata?) */
173
174 /* Check that paddr, vaddr and size are page aligned */
175 orr tmp, vaddr, paddr
176 orr tmp, tmp, size
177 tst tmp, #(1 << MMU_KERNEL_PAGE_SIZE_SHIFT) - 1
178 bne . /* Error: not page aligned */
179
180 /* Clear top bits of virtual address (should be all set) */
181 eor vaddr, vaddr, #(~0 << MMU_KERNEL_SIZE_SHIFT)
182
183 /* Check that top bits were all set */
184 tst vaddr, #(~0 << MMU_KERNEL_SIZE_SHIFT)
185 bne . /* Error: vaddr out of range */
186
187.Lmap_range_top_loop:
188 /* Select top level page table */
189 mov page_table, page_table1
190 mov idx_shift, #MMU_KERNEL_TOP_SHIFT
191
192 lsr idx, vaddr, idx_shift
193
194
195/* determine the type of page table entry to use given alignment and size
196 * of the chunk of memory we are mapping
197 */
198.Lmap_range_one_table_loop:
199 /* Check if current level allow block descriptors */
200 cmp idx_shift, #MMU_PTE_DESCRIPTOR_BLOCK_MAX_SHIFT
201 b.hi .Lmap_range_need_page_table
202
203 /* Check if paddr and vaddr alignment allows a block descriptor */
204 orr tmp2, vaddr, paddr
205 lsr tmp, tmp2, idx_shift
206 lsl tmp, tmp, idx_shift
207 cmp tmp, tmp2
208 b.ne .Lmap_range_need_page_table
209
210 /* Check if size is large enough for a block mapping */
211 lsr tmp, size, idx_shift
212 cbz tmp, .Lmap_range_need_page_table
213
214 /* Select descriptor type, page for level 3, block for level 0-2 */
215 orr tmp, attr, #MMU_PTE_L3_DESCRIPTOR_PAGE
216 cmp idx_shift, MMU_KERNEL_PAGE_SIZE_SHIFT
217 beq .Lmap_range_l3
218 orr tmp, attr, #MMU_PTE_L012_DESCRIPTOR_BLOCK
219.Lmap_range_l3:
220
221 /* Write page table entry */
222 orr tmp, tmp, paddr
223 str tmp, [page_table, idx, lsl #3]
224
225 /* Move to next page table entry */
226 mov tmp, #1
227 lsl tmp, tmp, idx_shift
228 add vaddr, vaddr, tmp
229 add paddr, paddr, tmp
230 subs size, size, tmp
231 /* TODO: add local loop if next entry is in the same page table */
232 b.ne .Lmap_range_top_loop /* size != 0 */
233
234 /* Restore top bits of virtual address (should be all set) */
235 eor vaddr, vaddr, #(~0 << MMU_KERNEL_SIZE_SHIFT)
236 /* Move to next subtype of ram mmu_initial_mappings entry */
237 cbnz mapping_size, .Lmapping_size_loop
238
239 /* Move to next mmu_initial_mappings entry */
240 add mmu_initial_mapping, mmu_initial_mapping, __MMU_INITIAL_MAPPING_SIZE
241 b .Linitial_mapping_loop
242
243.Lmap_range_need_page_table:
244 /* Check if page table entry is unused */
245 ldr new_page_table, [page_table, idx, lsl #3]
246 cbnz new_page_table, .Lmap_range_has_page_table
247
248 /* Calculate phys offset (needed for memory allocation) */
249.Lphys_offset:
250 adr phys_offset, .Lphys_offset /* phys */
251 ldr tmp, =.Lphys_offset /* virt */
252 sub phys_offset, tmp, phys_offset
253
254 /* Allocate new page table */
255 calloc_bootmem_aligned new_page_table, tmp, tmp2, MMU_KERNEL_PAGE_SIZE_SHIFT, phys_offset
256
257 /* Write page table entry (with allocated page table) */
258 orr new_page_table, new_page_table, #MMU_PTE_L012_DESCRIPTOR_TABLE
259 str new_page_table, [page_table, idx, lsl #3]
260
261.Lmap_range_has_page_table:
262 /* Check descriptor type */
263 and tmp, new_page_table, #MMU_PTE_DESCRIPTOR_MASK
264 cmp tmp, #MMU_PTE_L012_DESCRIPTOR_TABLE
265 b.ne . /* Error: entry already in use (as a block entry) */
266
267 /* switch to next page table level */
268 bic page_table, new_page_table, #MMU_PTE_DESCRIPTOR_MASK
269 mov tmp, #~0
270 lsl tmp, tmp, idx_shift
271 bic tmp, vaddr, tmp
272 sub idx_shift, idx_shift, #(MMU_KERNEL_PAGE_SIZE_SHIFT - 3)
273 lsr idx, tmp, idx_shift
274
275 b .Lmap_range_one_table_loop
276
277.Linitial_mapping_done:
278
279 /* Prepare tt_trampoline page table */
280
281 /* Zero tt_trampoline translation tables */
282 mov tmp, #0
283.Lclear_tt_trampoline:
284 str xzr, [page_table0, tmp, lsl#3]
285 add tmp, tmp, #1
286 cmp tmp, #MMU_PAGE_TABLE_ENTRIES_IDENT
287 blt .Lclear_tt_trampoline
288
289 /* Setup mapping at phys -> phys */
290 adr tmp, .Lmmu_on_pc
291 lsr tmp, tmp, #MMU_IDENT_TOP_SHIFT /* tmp = paddr index */
292 ldr tmp2, =MMU_PTE_IDENT_FLAGS
293 add tmp2, tmp2, tmp, lsl #MMU_IDENT_TOP_SHIFT /* tmp2 = pt entry */
294
295 str tmp2, [page_table0, tmp, lsl #3] /* tt_trampoline[paddr index] = pt entry */
296
297#if WITH_SMP
298 adrp tmp, page_tables_not_ready
299 add tmp, tmp, #:lo12:page_tables_not_ready
300 str wzr, [tmp]
301 b .Lpage_tables_ready
302
303.Lmmu_enable_secondary:
304 adrp tmp, page_tables_not_ready
305 add tmp, tmp, #:lo12:page_tables_not_ready
306.Lpage_tables_not_ready:
307 ldr wtmp2, [tmp]
308 cbnz wtmp2, .Lpage_tables_not_ready
309.Lpage_tables_ready:
310#endif
311
312 /* set up the mmu */
313
314 /* Invalidate TLB */
315 tlbi vmalle1is
316 isb
317 dsb sy
318
319 /* Initialize Memory Attribute Indirection Register */
320 ldr tmp, =MMU_MAIR_VAL
321 msr mair_el1, tmp
322
323 /* Initialize TCR_EL1 */
324 /* set cacheable attributes on translation walk */
325 /* (SMP extensions) non-shareable, inner write-back write-allocate */
326 ldr tmp, =MMU_TCR_FLAGS_IDENT
327 msr tcr_el1, tmp
328
329 isb
330
331 /* Write ttbr with phys addr of the translation table */
332 msr ttbr0_el1, page_table0
333 msr ttbr1_el1, page_table1
334 isb
335
336 /* Read SCTLR */
337 mrs tmp, sctlr_el1
338
339 /* Turn on the MMU */
340 orr tmp, tmp, #0x1
341
342 /* Write back SCTLR */
343 msr sctlr_el1, tmp
344.Lmmu_on_pc:
345 isb
346
347 /* Jump to virtual code address */
348 ldr tmp, =.Lmmu_on_vaddr
349 br tmp
350
351.Lmmu_on_vaddr:
352
353 /* Disable trampoline page-table in ttbr0 */
354 ldr tmp, =MMU_TCR_FLAGS_KERNEL
355 msr tcr_el1, tmp
356 isb
357
358
359 /* Invalidate TLB */
360 tlbi vmalle1
361 isb
362
363#if WITH_SMP
364 cbnz cpuid, .Lsecondary_boot
365#endif
366#endif /* WITH_KERNEL_VM */
367
368 ldr tmp, =__stack_end
369 mov sp, tmp
370
371 /* clear bss */
372.L__do_bss:
373 /* clear out the bss excluding the stack and kernel translation table */
374 /* NOTE: relies on __post_prebss_bss_start and __bss_end being 8 byte aligned */
375 ldr tmp, =__post_prebss_bss_start
376 ldr tmp2, =__bss_end
377 sub tmp2, tmp2, tmp
378 cbz tmp2, .L__bss_loop_done
379.L__bss_loop:
380 sub tmp2, tmp2, #8
381 str xzr, [tmp], #8
382 cbnz tmp2, .L__bss_loop
383.L__bss_loop_done:
384
385 bl lk_main
386 b .
387
388#if WITH_SMP
389.Lsecondary_boot:
390 and tmp, cpuid, #0xff
391 cmp tmp, #(1 << SMP_CPU_CLUSTER_SHIFT)
392 bge .Lunsupported_cpu_trap
393 bic cpuid, cpuid, #0xff
394 orr cpuid, tmp, cpuid, LSR #(8 - SMP_CPU_CLUSTER_SHIFT)
395 adrp tmp, linear_cpuid_map
396 add tmp, tmp, #:lo12:linear_cpuid_map
397 ldr tmp, [tmp]
398 cbz tmp, .Lno_cpuid_remap
399 add tmp, tmp, cpuid
400 ldrb wtmp2, [tmp]
401 ubfx cpuid, tmp2, #0, #31
402
403.Lno_cpuid_remap:
404 cmp cpuid, #SMP_MAX_CPUS
405 bge .Lunsupported_cpu_trap
406
407 /* Set up the stack */
408 ldr tmp, =__stack_end
409 mov tmp2, #ARCH_DEFAULT_STACK_SIZE
410 mul tmp2, tmp2, cpuid
411 sub sp, tmp, tmp2
412
413 mov x0, cpuid
414 bl arm64_secondary_entry
415
416.Lunsupported_cpu_trap:
417 wfe
418 b .Lunsupported_cpu_trap
419#endif
420
421.ltorg
422
423#if WITH_SMP
424.data
425DATA(page_tables_not_ready)
426 .long 1
427#endif
428
429.section .bss.prebss.stack
430 .align 4
431DATA(__stack)
432 .skip ARCH_DEFAULT_STACK_SIZE * SMP_MAX_CPUS
433DATA(__stack_end)
434
435#if WITH_KERNEL_VM
436.section ".bss.prebss.translation_table"
437.align 3 + MMU_PAGE_TABLE_ENTRIES_IDENT_SHIFT
438DATA(tt_trampoline)
439 .skip 8 * MMU_PAGE_TABLE_ENTRIES_IDENT
440#endif