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