xref: /kvm-unit-tests/arm/cstart64.S (revision 0917dc65eabbacb592456c0d1bb05e5828c23661)
1/*
2 * Boot entry point and assembler functions for aarch64 tests.
3 *
4 * Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2.
7 */
8#define __ASSEMBLY__
9#include <auxinfo.h>
10#include <asm/asm-offsets.h>
11#include <asm/ptrace.h>
12#include <asm/processor.h>
13#include <asm/page.h>
14#include <asm/pgtable-hwdef.h>
15#include <asm/thread_info.h>
16
17.macro zero_range, tmp1, tmp2
189998:	cmp	\tmp1, \tmp2
19	b.eq	9997f
20	stp	xzr, xzr, [\tmp1], #16
21	b	9998b
229997:
23.endm
24
25.section .init
26
27/*
28 * Bootloader params are in x0-x3. See kernel doc
29 * Documentation/arm64/booting.txt
30 */
31.globl start
32start:
33	/* get our base address */
34	adrp	x4, start
35	add     x4, x4, :lo12:start
36
37	/*
38	 * Update all R_AARCH64_RELATIVE relocations using the table
39	 * of Elf64_Rela entries between reloc_start/end. The build
40	 * will not emit other relocation types.
41	 *
42	 * struct Elf64_Rela {
43	 * 	uint64_t r_offset;
44	 * 	uint64_t r_info;
45	 * 	int64_t  r_addend;
46	 * }
47	 */
48	adrp	x5, reloc_start
49	add     x5, x5, :lo12:reloc_start
50	adrp	x6, reloc_end
51	add     x6, x6, :lo12:reloc_end
521:
53	cmp	x5, x6
54	b.hs	1f
55	ldr	x7, [x5]			// r_offset
56	ldr	x8, [x5, #16]			// r_addend
57	add	x8, x8, x4			// val = base + r_addend
58	str	x8, [x4, x7]			// base[r_offset] = val
59	add	x5, x5, #24
60	b	1b
61
621:
63	/* zero BSS */
64	adrp	x4, bss
65	add	x4, x4, :lo12:bss
66	adrp    x5, ebss
67	add     x5, x5, :lo12:ebss
68	zero_range x4, x5
69
70	/* zero and set up stack */
71	adrp    x5, stacktop
72	add     x5, x5, :lo12:stacktop
73	sub	x4, x5, #THREAD_SIZE
74	zero_range x4, x5
75	mov	x4, #1
76	msr	spsel, x4
77	isb
78	adrp    x4, stackptr
79	add     sp, x4, :lo12:stackptr
80
81	/* enable FP/ASIMD */
82	mov	x4, #(3 << 20)
83	msr	cpacr_el1, x4
84
85	/* set up exception handling */
86	bl	exceptions_init
87
88	/* complete setup */
89	bl	setup				// x0 is the addr of the dtb
90	bl	get_mmu_off
91	cbnz	x0, 1f
92	bl	setup_vm
93
941:
95	/* run the test */
96	adrp	x0, __argc
97	ldr	x0, [x0, :lo12:__argc]
98	adrp	x1, __argv
99	add	x1, x1, :lo12:__argv
100	adrp	x2, __environ
101	add	x2, x2, :lo12:__environ
102	bl	main
103	bl	exit
104	b	halt
105
106exceptions_init:
107	adrp	x4, vector_table
108	add	x4, x4, :lo12:vector_table
109	msr	vbar_el1, x4
110	isb
111	ret
112
113.text
114
115.globl get_mmu_off
116get_mmu_off:
117	adrp	x0, auxinfo
118	ldr	x0, [x0, :lo12:auxinfo + 8]
119	and	x0, x0, #AUXINFO_MMU_OFF
120	ret
121
122.globl secondary_entry
123secondary_entry:
124	/* Enable FP/ASIMD */
125	mov	x0, #(3 << 20)
126	msr	cpacr_el1, x0
127
128	/* set up exception handling */
129	bl	exceptions_init
130
131	/* enable the MMU unless requested off */
132	bl	get_mmu_off
133	cbnz	x0, 1f
134	adrp	x0, mmu_idmap
135	ldr	x0, [x0, :lo12:mmu_idmap]
136	bl	asm_mmu_enable
137
1381:
139	/* set the stack */
140	adrp	x0, secondary_data
141	ldr	x0, [x0, :lo12:secondary_data]
142	mov	sp, x0
143
144	/* finish init in C code */
145	bl	secondary_cinit
146
147	/* x0 is now the entry function, run it */
148	blr	x0
149	b	do_idle
150
151.globl halt
152halt:
1531:	wfi
154	b	1b
155
156/*
157 * asm_mmu_enable
158 *   Inputs:
159 *     x0 is the base address of the translation table
160 *   Outputs: none
161 *
162 * Adapted from
163 *   arch/arm64/kernel/head.S
164 *   arch/arm64/mm/proc.S
165 */
166
167/*
168 * Memory region attributes for LPAE:
169 *
170 *   n = AttrIndx[2:0]
171 *                      n       MAIR
172 *   DEVICE_nGnRnE      000     00000000
173 *   DEVICE_nGnRE       001     00000100
174 *   DEVICE_GRE         010     00001100
175 *   NORMAL_NC          011     01000100
176 *   NORMAL             100     11111111
177 *   NORMAL_WT          101     10111011
178 *   DEVICE_nGRE        110     00001000
179 */
180#define MAIR(attr, mt) ((attr) << ((mt) * 8))
181
182#if PAGE_SIZE == SZ_64K
183#define TCR_TG_FLAGS	TCR_TG0_64K | TCR_TG1_64K
184#elif PAGE_SIZE == SZ_16K
185#define TCR_TG_FLAGS	TCR_TG0_16K | TCR_TG1_16K
186#elif PAGE_SIZE == SZ_4K
187#define TCR_TG_FLAGS	TCR_TG0_4K | TCR_TG1_4K
188#endif
189
190.globl asm_mmu_enable
191asm_mmu_enable:
192	tlbi	vmalle1			// invalidate I + D TLBs
193	dsb	nsh
194
195	/* TCR */
196	ldr	x1, =TCR_TxSZ(VA_BITS) |		\
197		     TCR_TG_FLAGS  |			\
198		     TCR_IRGN_WBWA | TCR_ORGN_WBWA |	\
199		     TCR_SHARED
200	mrs	x2, id_aa64mmfr0_el1
201	bfi	x1, x2, #32, #3
202	msr	tcr_el1, x1
203
204	/* MAIR */
205	ldr	x1, =MAIR(0x00, MT_DEVICE_nGnRnE) |	\
206		     MAIR(0x04, MT_DEVICE_nGnRE) |	\
207		     MAIR(0x0c, MT_DEVICE_GRE) |	\
208		     MAIR(0x44, MT_NORMAL_NC) |		\
209		     MAIR(0xff, MT_NORMAL) |	        \
210		     MAIR(0xbb, MT_NORMAL_WT) |         \
211		     MAIR(0x08, MT_DEVICE_nGRE)
212	msr	mair_el1, x1
213
214	/* TTBR0 */
215	msr	ttbr0_el1, x0
216	isb
217
218	/* SCTLR */
219	mrs	x1, sctlr_el1
220	orr	x1, x1, SCTLR_EL1_C
221	orr	x1, x1, SCTLR_EL1_I
222	orr	x1, x1, SCTLR_EL1_M
223	msr	sctlr_el1, x1
224	isb
225
226	ret
227
228/* Taken with small changes from arch/arm64/incluse/asm/assembler.h */
229.macro dcache_by_line_op op, domain, start, end, tmp1, tmp2
230	adrp	\tmp1, dcache_line_size
231	ldr	\tmp1, [\tmp1, :lo12:dcache_line_size]
232	sub	\tmp2, \tmp1, #1
233	bic	\start, \start, \tmp2
2349998:
235	dc	\op , \start
236	add	\start, \start, \tmp1
237	cmp	\start, \end
238	b.lo	9998b
239	dsb	\domain
240.endm
241
242.globl asm_mmu_disable
243asm_mmu_disable:
244	mrs	x0, sctlr_el1
245	bic	x0, x0, SCTLR_EL1_M
246	msr	sctlr_el1, x0
247	isb
248
249	/* Clean + invalidate the entire memory */
250	adrp	x0, __phys_offset
251	ldr	x0, [x0, :lo12:__phys_offset]
252	adrp	x1, __phys_end
253	ldr	x1, [x1, :lo12:__phys_end]
254	dcache_by_line_op civac, sy, x0, x1, x2, x3
255	isb
256
257	ret
258
259/*
260 * Vectors
261 * Adapted from arch/arm64/kernel/entry.S
262 */
263.macro vector_stub, name, vec
264\name:
265	stp	 x0,  x1, [sp, #-S_FRAME_SIZE]!
266	stp	 x2,  x3, [sp,  #16]
267	stp	 x4,  x5, [sp,  #32]
268	stp	 x6,  x7, [sp,  #48]
269	stp	 x8,  x9, [sp,  #64]
270	stp	x10, x11, [sp,  #80]
271	stp	x12, x13, [sp,  #96]
272	stp	x14, x15, [sp, #112]
273	stp	x16, x17, [sp, #128]
274	stp	x18, x19, [sp, #144]
275	stp	x20, x21, [sp, #160]
276	stp	x22, x23, [sp, #176]
277	stp	x24, x25, [sp, #192]
278	stp	x26, x27, [sp, #208]
279	stp	x28, x29, [sp, #224]
280
281	str	x30, [sp, #S_LR]
282
283	.if \vec >= 8
284	mrs	x1, sp_el0
285	.else
286	add	x1, sp, #S_FRAME_SIZE
287	.endif
288	str	x1, [sp, #S_SP]
289
290	mrs	x1, elr_el1
291	mrs	x2, spsr_el1
292	stp	x1, x2, [sp, #S_PC]
293
294	mov	x0, \vec
295	mov	x1, sp
296	mrs	x2, esr_el1
297	bl	do_handle_exception
298
299	ldp	x1, x2, [sp, #S_PC]
300	msr	spsr_el1, x2
301	msr	elr_el1, x1
302
303	.if \vec >= 8
304	ldr	x1, [sp, #S_SP]
305	msr	sp_el0, x1
306	.endif
307
308	ldr	x30, [sp, #S_LR]
309
310	ldp	x28, x29, [sp, #224]
311	ldp	x26, x27, [sp, #208]
312	ldp	x24, x25, [sp, #192]
313	ldp	x22, x23, [sp, #176]
314	ldp	x20, x21, [sp, #160]
315	ldp	x18, x19, [sp, #144]
316	ldp	x16, x17, [sp, #128]
317	ldp	x14, x15, [sp, #112]
318	ldp	x12, x13, [sp,  #96]
319	ldp	x10, x11, [sp,  #80]
320	ldp	 x8,  x9, [sp,  #64]
321	ldp	 x6,  x7, [sp,  #48]
322	ldp	 x4,  x5, [sp,  #32]
323	ldp	 x2,  x3, [sp,  #16]
324	ldp	 x0,  x1, [sp], #S_FRAME_SIZE
325
326	eret
327.endm
328
329vector_stub	el1t_sync,     0
330vector_stub	el1t_irq,      1
331vector_stub	el1t_fiq,      2
332vector_stub	el1t_error,    3
333
334vector_stub	el1h_sync,     4
335vector_stub	el1h_irq,      5
336vector_stub	el1h_fiq,      6
337vector_stub	el1h_error,    7
338
339vector_stub	el0_sync_64,   8
340vector_stub	el0_irq_64,    9
341vector_stub	el0_fiq_64,   10
342vector_stub	el0_error_64, 11
343
344vector_stub	el0_sync_32,  12
345vector_stub	el0_irq_32,   13
346vector_stub	el0_fiq_32,   14
347vector_stub	el0_error_32, 15
348
349.section .text.ex
350
351.macro ventry, label
352.align 7
353	b	\label
354.endm
355
356.align 11
357vector_table:
358	ventry	el1t_sync			// Synchronous EL1t
359	ventry	el1t_irq			// IRQ EL1t
360	ventry	el1t_fiq			// FIQ EL1t
361	ventry	el1t_error			// Error EL1t
362
363	ventry	el1h_sync			// Synchronous EL1h
364	ventry	el1h_irq			// IRQ EL1h
365	ventry	el1h_fiq			// FIQ EL1h
366	ventry	el1h_error			// Error EL1h
367
368	ventry	el0_sync_64			// Synchronous 64-bit EL0
369	ventry	el0_irq_64			// IRQ 64-bit EL0
370	ventry	el0_fiq_64			// FIQ 64-bit EL0
371	ventry	el0_error_64			// Error 64-bit EL0
372
373	ventry	el0_sync_32			// Synchronous 32-bit EL0
374	ventry	el0_irq_32			// IRQ 32-bit EL0
375	ventry	el0_fiq_32			// FIQ 32-bit EL0
376	ventry	el0_error_32			// Error 32-bit EL0
377