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