xref: /openbmc/qemu/tests/tcg/aarch64/system/boot.S (revision 673d8215)
1f6482872SAlex Bennée/*
2f6482872SAlex Bennée * Minimal AArch64 system boot code.
3f6482872SAlex Bennée *
4f6482872SAlex Bennée * Copyright Linaro Ltd 2019
5f6482872SAlex Bennée *
6f6482872SAlex Bennée * Loosely based on the newlib/libgloss setup stubs. Using semihosting
7f6482872SAlex Bennée * for serial output and exit functions.
8f6482872SAlex Bennée */
9f6482872SAlex Bennée
10f6482872SAlex Bennée/*
11f6482872SAlex Bennée * Semihosting interface on ARM AArch64
12*673d8215SMichael Tokarev * See "Semihosting for AArch32 and AArch64 Release 2.0" by ARM
13f6482872SAlex Bennée * w0 - semihosting call number
14f6482872SAlex Bennée * x1 - semihosting parameter
15f6482872SAlex Bennée */
16f6482872SAlex Bennée#define semihosting_call hlt 0xf000
17f6482872SAlex Bennée#define SYS_WRITEC	0x03	/* character to debug channel */
18f6482872SAlex Bennée#define SYS_WRITE0	0x04	/* string to debug channel */
19f6482872SAlex Bennée#define SYS_EXIT	0x18
20f6482872SAlex Bennée
21f6482872SAlex Bennée	.align	12
22f6482872SAlex Bennée
23f6482872SAlex Bennée	.macro	ventry	label
24f6482872SAlex Bennée	.align	7
25f6482872SAlex Bennée	b	\label
26f6482872SAlex Bennée	.endm
27f6482872SAlex Bennée
28f6482872SAlex Bennéevector_table:
29f6482872SAlex Bennée	/* Current EL with SP0.	 */
30f6482872SAlex Bennée	ventry	curr_sp0_sync		/* Synchronous	*/
31f6482872SAlex Bennée	ventry	curr_sp0_irq		/* Irq/vIRQ  */
32f6482872SAlex Bennée	ventry	curr_sp0_fiq		/* Fiq/vFIQ  */
33f6482872SAlex Bennée	ventry	curr_sp0_serror		/* SError/VSError  */
34f6482872SAlex Bennée
35f6482872SAlex Bennée	/* Current EL with SPx.	 */
36f6482872SAlex Bennée	ventry	curr_spx_sync		/* Synchronous	*/
37f6482872SAlex Bennée	ventry	curr_spx_irq		/* IRQ/vIRQ  */
38f6482872SAlex Bennée	ventry	curr_spx_fiq		/* FIQ/vFIQ  */
39f6482872SAlex Bennée	ventry	curr_spx_serror		/* SError/VSError  */
40f6482872SAlex Bennée
41f6482872SAlex Bennée	/* Lower EL using AArch64.  */
42f6482872SAlex Bennée	ventry	lower_a64_sync		/* Synchronous	*/
43f6482872SAlex Bennée	ventry	lower_a64_irq		/* IRQ/vIRQ  */
44f6482872SAlex Bennée	ventry	lower_a64_fiq		/* FIQ/vFIQ  */
45f6482872SAlex Bennée	ventry	lower_a64_serror	/* SError/VSError  */
46f6482872SAlex Bennée
47f6482872SAlex Bennée	/* Lower EL using AArch32.  */
48f6482872SAlex Bennée	ventry	lower_a32_sync		/* Synchronous	*/
49f6482872SAlex Bennée	ventry	lower_a32_irq		/* IRQ/vIRQ  */
50f6482872SAlex Bennée	ventry	lower_a32_fiq		/* FIQ/vFIQ  */
51f6482872SAlex Bennée	ventry	lower_a32_serror	/* SError/VSError  */
52f6482872SAlex Bennée
53f6482872SAlex Bennée	.text
54f6482872SAlex Bennée	.align 4
55f6482872SAlex Bennée
56f6482872SAlex Bennée	/* Common vector handling for now */
57f6482872SAlex Bennéecurr_sp0_sync:
58f6482872SAlex Bennéecurr_sp0_irq:
59f6482872SAlex Bennéecurr_sp0_fiq:
60f6482872SAlex Bennéecurr_sp0_serror:
61f6482872SAlex Bennéecurr_spx_sync:
62f6482872SAlex Bennéecurr_spx_irq:
63f6482872SAlex Bennéecurr_spx_fiq:
64f6482872SAlex Bennéecurr_spx_serror:
65f6482872SAlex Bennéelower_a64_sync:
66f6482872SAlex Bennéelower_a64_irq:
67f6482872SAlex Bennéelower_a64_fiq:
68f6482872SAlex Bennéelower_a64_serror:
69f6482872SAlex Bennéelower_a32_sync:
70f6482872SAlex Bennéelower_a32_irq:
71f6482872SAlex Bennéelower_a32_fiq:
72f6482872SAlex Bennéelower_a32_serror:
73f6482872SAlex Bennée	mov	x0, SYS_WRITE0
74f6482872SAlex Bennée	adr	x1, .error
75f6482872SAlex Bennée	semihosting_call
76f6482872SAlex Bennée	mov	x0, SYS_EXIT
77f6482872SAlex Bennée	mov	x1, 1
78f6482872SAlex Bennée	semihosting_call
79f6482872SAlex Bennée	/* never returns */
80f6482872SAlex Bennée
81f6482872SAlex Bennée	.section .rodata
82f6482872SAlex Bennée.error:
83f6482872SAlex Bennée	.string "Terminated by exception.\n"
84f6482872SAlex Bennée
85f6482872SAlex Bennée	.text
86f6482872SAlex Bennée	.align 4
87f6482872SAlex Bennée	.global __start
88f6482872SAlex Bennée__start:
89f6482872SAlex Bennée	/* Installs a table of exception vectors to catch and handle all
90f6482872SAlex Bennée	   exceptions by terminating the process with a diagnostic.  */
91f6482872SAlex Bennée	adr	x0, vector_table
92f6482872SAlex Bennée	msr	vbar_el1, x0
93f6482872SAlex Bennée
94f6482872SAlex Bennée	/* Page table setup (identity mapping). */
95f6482872SAlex Bennée	adrp	x0, ttb
96f6482872SAlex Bennée	add	x0, x0, :lo12:ttb
97f6482872SAlex Bennée	msr	ttbr0_el1, x0
98f6482872SAlex Bennée
99f6482872SAlex Bennée	/*
100f6482872SAlex Bennée	 * Setup a flat address mapping page-tables. Stage one simply
101f6482872SAlex Bennée	 * maps RAM to the first Gb. The stage2 tables have two 2mb
102f6482872SAlex Bennée	 * translation block entries covering a series of adjacent
103f6482872SAlex Bennée	 * 4k pages.
104f6482872SAlex Bennée	*/
105f6482872SAlex Bennée
106f6482872SAlex Bennée	/* Stage 1 entry: indexed by IA[38:30] */
107f6482872SAlex Bennée	adr	x1, .				/* phys address */
108f6482872SAlex Bennée	bic	x1, x1, #(1 << 30) - 1		/* 1GB alignment*/
109f6482872SAlex Bennée	add	x2, x0, x1, lsr #(30 - 3)	/* offset in l1 page table */
110f6482872SAlex Bennée
111f6482872SAlex Bennée	/* point to stage 2 table [47:12] */
112f6482872SAlex Bennée	adrp	x0, ttb_stage2
113f6482872SAlex Bennée	orr 	x1, x0, #3 			/* ptr to stage 2 */
114f6482872SAlex Bennée	str	x1, [x2]
115f6482872SAlex Bennée
116f6482872SAlex Bennée	/* Stage 2 entries: indexed by IA[29:21] */
117f6482872SAlex Bennée	ldr	x5, =(((1 << 9) - 1) << 21)
118f6482872SAlex Bennée
119f6482872SAlex Bennée	/* First block: .text/RO/execute enabled */
120f6482872SAlex Bennée	adr	x1, .				/* phys address */
121f6482872SAlex Bennée	bic	x1, x1, #(1 << 21) - 1		/* 2mb block alignment	*/
122f6482872SAlex Bennée	and	x4, x1, x5			/* IA[29:21] */
123f6482872SAlex Bennée	add	x2, x0, x4, lsr #(21 - 3)	/* offset in l2 page table */
124f6482872SAlex Bennée	ldr	x3, =0x401			/* attr(AF, block) */
125f6482872SAlex Bennée	orr	x1, x1, x3
126f6482872SAlex Bennée	str	x1, [x2]			/* 1st 2mb (.text & rodata) */
127f6482872SAlex Bennée
128f6482872SAlex Bennée	/* Second block: .data/RW/no execute */
129f6482872SAlex Bennée	adrp	x1, .data
130f6482872SAlex Bennée	add	x1, x1, :lo12:.data
131f6482872SAlex Bennée	bic	x1, x1, #(1 << 21) - 1		/* 2mb block alignment */
132f6482872SAlex Bennée	and	x4, x1, x5			/* IA[29:21] */
133f6482872SAlex Bennée	add	x2, x0, x4, lsr #(21 - 3)	/* offset in l2 page table */
134f6482872SAlex Bennée	ldr	x3, =(3 << 53) | 0x401		/* attr(AF, NX, block) */
135f6482872SAlex Bennée	orr	x1, x1, x3
136f6482872SAlex Bennée	str	x1, [x2]			/* 2nd 2mb (.data & .bss)*/
137f6482872SAlex Bennée
138f6482872SAlex Bennée	/* Setup/enable the MMU.  */
139f6482872SAlex Bennée
140f6482872SAlex Bennée	/*
141f6482872SAlex Bennée	 * TCR_EL1 - Translation Control Registers
142f6482872SAlex Bennée	 *
143f6482872SAlex Bennée	 * IPS[34:32] = 40-bit PA, 1TB
144f6482872SAlex Bennée	 * TG0[14:15] = b00 => 4kb granuale
145f6482872SAlex Bennée	 * ORGN0[11:10] = Outer: Normal, WB Read-Alloc No Write-Alloc Cacheable
146f6482872SAlex Bennée	 * IRGN0[9:8] = Inner: Normal, WB Read-Alloc No Write-Alloc Cacheable
147f6482872SAlex Bennée	 * T0SZ[5:0]  = 2^(64 - 25)
148f6482872SAlex Bennée	 *
149f6482872SAlex Bennée	 * The size of T0SZ controls what the initial lookup level. It
150*673d8215SMichael Tokarev	 * would be nice to start at level 2 but unfortunately for a
151f6482872SAlex Bennée	 * flat-mapping on the virt machine we need to handle IA's
152f6482872SAlex Bennée	 * with at least 1gb range to see RAM. So we start with a
153f6482872SAlex Bennée	 * level 1 lookup.
154f6482872SAlex Bennée	 */
155f6482872SAlex Bennée	ldr	x0, = (2 << 32) | 25 | (3 << 10) | (3 << 8)
156f6482872SAlex Bennée	msr	tcr_el1, x0
157f6482872SAlex Bennée
158f6482872SAlex Bennée	mov	x0, #0xee			/* Inner/outer cacheable WB */
159f6482872SAlex Bennée	msr	mair_el1, x0
160f6482872SAlex Bennée	isb
161f6482872SAlex Bennée
162f6482872SAlex Bennée	/*
163f6482872SAlex Bennée	 * SCTLR_EL1 - System Control Register
164f6482872SAlex Bennée	 *
165f6482872SAlex Bennée	 * WXN[19] = 0 = no effect, Write does not imply XN (execute never)
166f6482872SAlex Bennée	 * I[12] = Instruction cachability control
167f6482872SAlex Bennée	 * SA[3] = SP alignment check
168f6482872SAlex Bennée	 * C[2] = Data cachability control
169f6482872SAlex Bennée	 * M[0] = 1, enable stage 1 address translation for EL0/1
170f6482872SAlex Bennée	 */
171f6482872SAlex Bennée	mrs	x0, sctlr_el1
172f6482872SAlex Bennée	ldr	x1, =0x100d			/* bits I(12) SA(3) C(2) M(0) */
173f6482872SAlex Bennée	bic	x0, x0, #(1 << 1)		/* clear bit A(1) */
174f6482872SAlex Bennée	bic	x0, x0, #(1 << 19)		/* clear WXN */
175f6482872SAlex Bennée	orr	x0, x0, x1			/* set bits */
176f6482872SAlex Bennée
177f6482872SAlex Bennée	dsb	sy
178f6482872SAlex Bennée	msr	sctlr_el1, x0
179f6482872SAlex Bennée	isb
180f6482872SAlex Bennée
181f6482872SAlex Bennée	/*
182d54c6d3bSAlex Bennée	 * Enable FP/SVE registers. The standard C pre-amble will be
183f6482872SAlex Bennée	 * saving these and A-profile compilers will use AdvSIMD
184f6482872SAlex Bennée	 * registers unless we tell it not to.
185f6482872SAlex Bennée	*/
186f6482872SAlex Bennée	mrs	x0, cpacr_el1
187f6482872SAlex Bennée	orr	x0, x0, #(3 << 20)
188d54c6d3bSAlex Bennée	orr	x0, x0, #(3 << 16)
189f6482872SAlex Bennée	msr	cpacr_el1, x0
190f6482872SAlex Bennée
191f6482872SAlex Bennée	/* Setup some stack space and enter the test code.
192*673d8215SMichael Tokarev	 * Assume everything except the return value is garbage when we
193f6482872SAlex Bennée	 * return, we won't need it.
194f6482872SAlex Bennée	 */
195f6482872SAlex Bennée	adrp	x0, stack_end
196f6482872SAlex Bennée	add	x0, x0, :lo12:stack_end
197f6482872SAlex Bennée	mov	sp, x0
198f6482872SAlex Bennée	bl	main
199f6482872SAlex Bennée
200f6482872SAlex Bennée	/* pass return value to sys exit */
201c00506aaSAlex Bennée_exit:
202f6482872SAlex Bennée	mov    x1, x0
203f6482872SAlex Bennée	ldr    x0, =0x20026 /* ADP_Stopped_ApplicationExit */
204f6482872SAlex Bennée	stp    x0, x1, [sp, #-16]!
205f6482872SAlex Bennée	mov    x1, sp
206f6482872SAlex Bennée	mov    x0, SYS_EXIT
207f6482872SAlex Bennée	semihosting_call
208f6482872SAlex Bennée	/* never returns */
209f6482872SAlex Bennée
210f6482872SAlex Bennée	/*
211f6482872SAlex Bennée	 * Helper Functions
212f6482872SAlex Bennée	*/
213f6482872SAlex Bennée
214f6482872SAlex Bennée	/* Output a single character to serial port */
215f6482872SAlex Bennée	.global __sys_outc
216f6482872SAlex Bennée__sys_outc:
217f6482872SAlex Bennée	stp x0, x1, [sp, #-16]!
218f6482872SAlex Bennée	/* pass address of c on stack */
219f6482872SAlex Bennée	mov x1, sp
220f6482872SAlex Bennée	mov x0, SYS_WRITEC
221f6482872SAlex Bennée	semihosting_call
222f6482872SAlex Bennée	ldp x0, x1, [sp], #16
223f6482872SAlex Bennée	ret
224f6482872SAlex Bennée
225f6482872SAlex Bennée	.data
226f6482872SAlex Bennée	.align	12
227f6482872SAlex Bennée
228f6482872SAlex Bennée	/* Translation table
229f6482872SAlex Bennée	 * @4k granuale: 9 bit lookup, 512 entries
230f6482872SAlex Bennée	*/
231f6482872SAlex Bennéettb:
232f6482872SAlex Bennée	.space	4096, 0
233f6482872SAlex Bennée
234f6482872SAlex Bennée	.align	12
235f6482872SAlex Bennéettb_stage2:
236f6482872SAlex Bennée	.space	4096, 0
237f6482872SAlex Bennée
238f6482872SAlex Bennée	.align	12
239f6482872SAlex Bennéestack:
240f6482872SAlex Bennée	.space 65536, 0
241f6482872SAlex Bennéestack_end:
242