xref: /openbmc/qemu/tests/tcg/arm/system/boot.S (revision 7d87775f)
1/*
2 * Minimal ArmV7 system boot code.
3 *
4 * Using semihosting for serial output and exit functions.
5 */
6
7/*
8 * Semihosting interface on ARM AArch32
9 * R0 - semihosting call number
10 * R1 - semihosting parameter
11 */
12#define semihosting_call svc 0x123456
13#define SYS_WRITEC	0x03	/* character to debug channel */
14#define SYS_WRITE0	0x04	/* string to debug channel */
15#define SYS_EXIT	0x18
16
17#define ADP_Stopped_ApplicationExit	0x20026
18#define ADP_Stopped_InternalError	0x20024
19
20/*
21 * Helper macro for annotating functions with elf type and size.
22 */
23.macro endf name
24	.global	\name
25	.type		\name, %function
26	.size		\name, . - \name
27.endm
28
29	.section	.interrupt_vector, "ax"
30	.align	5
31
32vector_table:
33	b   reset		/* reset vector */
34	b   undef_instr        /* undefined instruction vector */
35	b   software_intr    	/* software interrupt vector */
36	b   prefetch_abort		/* prefetch abort vector */
37	b   data_abort	        /* data abort vector */
38	nop			            /* reserved */
39	b   IRQ_handler        	/* IRQ vector */
40	b   FIQ_handler        	/* FIQ vector */
41
42endf	vector_table
43
44	.text
45__start:
46	ldr  	r0, =vector_table
47	mcr  	p15, 0, r0, c12, c0, 0  /* Set up VBAR */
48
49	ldr	sp, =stack_end		/* Set up the stack */
50	bl	mmu_setup		/* Set up the MMU */
51	bl	main			/* Jump to main */
52
53endf	__start
54
55_exit:
56	cmp r0, #0
57	ite EQ  // if-then-else. "EQ" is for if equal, else otherwise
58	ldreq r1, =ADP_Stopped_ApplicationExit // if r0 == 0
59	ldrne r1, =ADP_Stopped_InternalError   // else
60	mov r0, #SYS_EXIT
61	semihosting_call
62
63endf	_exit
64
65/*
66 * Helper Functions
67 */
68
69mmu_setup:
70	/*
71	 * The MMU setup for this is very simple using two stage one
72	 * translations. The first 1Mb section points to the text
73	 * section and the second points to the data and rss.
74	 * Currently the fattest test only needs ~50k for that so we
75	 * have plenty of space.
76	 *
77	 * The short descriptor Section format is as follows:
78	 *
79	 *  PA[31:20] - Section Base Address
80	 *  NS[19] - Non-secure bit
81	 *  0[18] - Section (1 for Super Section)
82	 *  nG[17] - Not global bit
83	 *  S[16] - Shareable
84	 *  TEX[14:12] - Memory Region Attributes
85	 *  AP[15, 11:10] - Access Permission Bits
86	 *  IMPDEF[9]
87	 *  Domain[8:5]
88	 *  XN[4] - Execute never bit
89	 *  C[3] - Memory Region Attributes
90	 *  B[2] - Memory Region Attributes
91	 *  1[1]
92	 *  PXN[0] - Privileged Execute Never
93	 *
94	 * r0 - point at the table
95	 * r1 - address
96	 * r2 - entry
97	 * r3 - common section bits
98	 * r4 - scratch
99	 */
100
101	/*
102	 * Memory Region Bits
103	 *
104	 *   TEX[14:12] = 000
105	 *     C[3]     = 1
106	 *     B[2]     = 1
107	 *
108	 * Outer and Inner WB, no write allocate
109	 */
110	mov r3, #0
111	ldr r4, =(3 << 2)
112	orr r3, r4, r4
113
114	/* Section bit */
115	orr r3, r3, #2
116
117	/* Page table setup (identity mapping). */
118	ldr r0, =ttb
119
120	/* First block: .text/RO/execute enabled */
121	ldr r1, =.text
122	ldr r2, =0xFFF00000  			/* 1MB block alignment */
123	and r2, r1, r2
124	orr r2, r2, r3				/* common bits */
125	orr r2, r2, #(1 << 15)			/* AP[2] = 1 */
126	orr r2, r2, #(1 << 10)			/* AP[0] = 1 => RO @ PL1 */
127
128	lsr r4, r2, #(20 - 2)
129	str r2, [r0, r4, lsl #0]		/* write entry */
130
131	/* Second block: .data/RW/no execute */
132	ldr r1, =.data
133	ldr r2, =0xFFF00000  			/* 1MB block alignment */
134	and r2, r1, r2
135	orr r2, r2, r3				/* common bits */
136	orr r2, r2, #(1 << 10)			/* AP[0] = 1 => RW @ PL1 */
137	orr r2, r2, #(1 << 4)			/* XN[4] => no execute */
138
139	lsr r4, r2, #(20 - 2)
140	str r2, [r0, r4, lsl #0]		/* write entry */
141
142	/*
143	 * DACR - Domain Control
144	 *
145	 * Enable client mode for domain 0 (we don't use any others)
146	 */
147	ldr r0, =0x1
148	mcr p15, 0, r0, c3, c0, 0
149
150	/*
151	 * TTCBR - Translation Table Base Control Register
152	 *
153	 * EAE[31] = 0, 32-bit translation, short descriptor format
154	 * N[2:0] = 5 ( TTBRO uses 31:14-5 => 9 bit lookup stage )
155	 */
156	ldr r0, =0x5
157	mcr p15, 0, r0, c1, c0, 2
158
159	/*
160	 * TTBR0 -Translation Table Base Register 0
161	 *
162	 * [31:9] = Base address of table
163	 *
164	 * QEMU doesn't really care about the cache sharing
165	 * attributes so we don't need to either.
166	 */
167	ldr r0, =ttb
168	mcr p15, 0, r0, c2, c0, 0
169
170	/*
171	 * SCTLR- System Control Register
172	 *
173   	 * TE[30] = 0, exceptions to A32 state
174	 * AFE[29] = 0, AP[0] is the access permissions bit
175	 * EE[25] = 0, Little-endian
176	 * WXN[19] = 0 = no effect, Write does not imply XN (execute never)
177	 * I[12] = Instruction cachability control
178	 * C[2] = Data cachability control
179	 * M[0] = 1, enable stage 1 address translation for EL0/1
180         *
181	 * At this point virtual memory is enabled.
182	 */
183	ldr r0, =0x1005
184	mcr p15, 0, r0, c1, c0, 0
185
186	isb
187
188	mov  pc, lr  /* done, return to caller */
189
190endf	mmu_setup
191
192/* Output a single character to serial port */
193__sys_outc:
194	STMFD sp!, {r0-r1}  // push r0, r1 onto stack
195	mov r1, sp
196	mov r0, #SYS_WRITEC
197	semihosting_call
198	LDMFD sp!, {r0-r1}  // pop r0, r1 from stack
199	bx lr
200
201endf	__sys_outc
202
203reset:
204	ldr	r1, =reset_error
205	b exception_handler
206
207endf	reset
208
209undef_instr:
210	ldr	r1, =undef_intr_error
211	b exception_handler
212
213endf	undef_instr
214
215software_intr:
216	ldr	r1, =software_intr_error
217	b exception_handler
218
219endf	software_intr
220
221prefetch_abort:
222	ldr	r1, =prefetch_abort_error
223	b exception_handler
224
225endf	prefetch_abort
226
227data_abort:
228	ldr	r1, =data_abort_error
229	b exception_handler
230
231endf	data_abort
232
233IRQ_handler:
234	ldr	r1, =irq_error
235	b exception_handler
236
237endf	IRQ_handler
238
239FIQ_handler:
240	ldr	r1, =fiq_error
241	b exception_handler
242
243endf	FIQ_handler
244
245/*
246 * Initiate a exit semihosting call whenever there is any exception
247 * r1 already holds the string.
248 */
249exception_handler:
250	mov	r0, #SYS_WRITE0
251	semihosting_call
252	mov	r0, #SYS_EXIT
253	mov	r1, #1
254	semihosting_call
255
256endf	exception_handler
257
258/*
259 * We implement a stub raise() function which errors out as tests
260 * shouldn't trigger maths errors.
261 */
262	.global raise
263raise:
264	mov	r0, #SYS_WRITE0
265	ldr	r1, =maths_error
266	semihosting_call
267	mov	r0, #SYS_EXIT
268	ldr	r1, =ADP_Stopped_InternalError
269	semihosting_call
270
271endf	raise
272
273	.data
274
275.data
276
277reset_error:
278	.ascii "Reset exception occurred.\n\0"
279
280undef_intr_error:
281	.ascii "Undefined Instruction Exception Occurred.\n\0"
282
283software_intr_error:
284	.ascii "Software Interrupt Occurred.\n\0"
285
286prefetch_abort_error:
287	.ascii "Prefetch Abort Occurred.\n\0"
288
289data_abort_error:
290	.ascii "Data Abort Occurred.\n\0"
291
292irq_error:
293	.ascii "IRQ exception occurred.\n\0"
294
295fiq_error:
296	.ascii "FIQ exception occurred.\n\0"
297
298maths_error:
299	.ascii "Software maths exception.\n\0"
300
301
302	/*
303	 * 1st Stage Translation table
304	 * 4096 entries, indexed by [31:20]
305	 * each entry covers 1Mb of address space
306	 * aligned on 16kb
307	 */
308	.align	15
309ttb:
310	.space	(4096 * 4), 0
311
312	.align	12
313
314	/* Space for stack */
315	.align	5
316	.section .bss
317stack:
318	.space 65536, 0
319stack_end:
320