xref: /openbmc/u-boot/arch/xtensa/cpu/start.S (revision 17fa0326)
1/*
2 * (C) Copyright 2008 - 2013 Tensilica Inc.
3 * (C) Copyright 2014 - 2016 Cadence Design Systems Inc.
4 *
5 * SPDX-License-Identifier:	GPL-2.0+
6 */
7
8#include <config.h>
9#include <asm/asmmacro.h>
10#include <asm/cacheasm.h>
11#include <asm/regs.h>
12#include <asm/arch/tie.h>
13#include <asm-offsets.h>
14
15/*
16 * Offsets into the the pt_regs struture.
17 * Make sure these always match with the structure defined in ptrace.h!
18 */
19
20#define PT_PC		0
21#define PT_PS		4
22#define PT_DEPC		8
23#define PT_EXCCAUSE	12
24#define PT_EXCVADDR	16
25#define PT_DEBUGCAUSE	20
26#define PT_WMASK	24
27#define PT_LBEG		28
28#define PT_LEND		32
29#define PT_LCOUNT	36
30#define PT_SAR		40
31#define PT_WINDOWBASE	44
32#define PT_WINDOWSTART	48
33#define PT_SYSCALL	52
34#define PT_ICOUNTLEVEL	56
35#define PT_RESERVED	60
36#define PT_AREG		64
37#define PT_SIZE		(64 + 64)
38
39/*
40 * Cache attributes are different for full MMU and region protection.
41 */
42
43#if XCHAL_HAVE_PTP_MMU
44#define CA_WRITEBACK	(0x7)
45#else
46#define CA_WRITEBACK	(0x4)
47#endif
48
49/*
50 * Reset vector.
51 * Only a trampoline to jump to _start
52 * (Note that we have to mark the section writable as the section contains
53 *  a relocatable literal)
54 */
55
56	.section .ResetVector.text, "awx"
57	.global _ResetVector
58_ResetVector:
59
60	j	1f
61	.align 4
622:	.long	_start
631:	l32r	a2, 2b
64	jx	a2
65
66
67/*
68 * Processor initialization. We still run in rom space.
69 *
70 * NOTE: Running in ROM
71 *  For Xtensa, we currently don't allow to run some code from ROM but
72 *  unpack the data immediately to memory. This requires, for example,
73 *  that DDR has been set up before running U-Boot. (See also comments
74 *  inline for ways to change it)
75 */
76
77	.section .reset.text, "ax"
78	.global _start
79	.align 4
80_start:
81	/* Keep a0 = 0 for various initializations */
82
83	movi	a0, 0
84
85	/*
86	 * For full MMU cores, put page table at unmapped virtual address.
87	 * This ensures that accesses outside the static maps result
88	 * in miss exceptions rather than random behaviour.
89	 */
90
91#if XCHAL_HAVE_PTP_MMU
92	wsr	a0, PTEVADDR
93#endif
94
95	/* Disable dbreak debug exceptions */
96
97#if XCHAL_HAVE_DEBUG && XCHAL_NUM_DBREAK > 0
98	.set	_index, 0
99	.rept	XCHAL_NUM_DBREAK
100	wsr	a0, DBREAKC + _index
101	.set	_index, _index + 1
102	.endr
103#endif
104
105	/* Reset windowbase and windowstart */
106
107#if XCHAL_HAVE_WINDOWED
108	movi	a3, 1
109	wsr	a3, windowstart
110	wsr	a0, windowbase
111	rsync
112	movi	a0, 0			/* windowbase might have changed */
113#endif
114
115	/*
116	 * Vecbase in bitstream may differ from header files
117	 * set or check it.
118	 */
119
120#if XCHAL_HAVE_VECBASE
121	movi	a3, XCHAL_VECBASE_RESET_VADDR	/* VECBASE reset value */
122	wsr	a3, VECBASE
123#endif
124
125#if XCHAL_HAVE_LOOPS
126	/* Disable loops */
127
128	wsr	a0, LCOUNT
129#endif
130
131	/* Set PS.WOE = 0, PS.EXCM = 0 (for loop), PS.INTLEVEL = EXCM level */
132
133#if XCHAL_HAVE_XEA1
134	movi	a2, 1
135#else
136	movi	a2, XCHAL_EXCM_LEVEL
137#endif
138	wsr	a2, PS
139	rsync
140
141	/* Unlock and invalidate caches */
142
143	___unlock_dcache_all a2, a3
144	___invalidate_dcache_all a2, a3
145	___unlock_icache_all a2, a3
146	___invalidate_icache_all a2, a3
147
148	isync
149
150	/* Unpack data sections */
151
152	movi	a2, __reloc_table_start
153	movi	a3, __reloc_table_end
154
1551:	beq	a2, a3, 3f	# no more entries?
156	l32i	a4, a2, 0	# start destination (in RAM)
157	l32i	a5, a2, 4	# end destination (in RAM)
158	l32i	a6, a2, 8	# start source (in ROM)
159	addi	a2, a2, 12	# next entry
160	beq	a4, a5, 1b	# skip, empty entry
161	beq	a4, a6, 1b	# skip, source and destination are the same
162
163	/* If there's memory protection option with 512MB TLB regions and
164	 * cache attributes in TLB entries and caching is not inhibited,
165	 * enable data/instruction cache for relocated image.
166	 */
167#if XCHAL_HAVE_SPANNING_WAY && \
168	(!defined(CONFIG_SYS_DCACHE_OFF) || \
169	 !defined(CONFIG_SYS_ICACHE_OFF))
170	srli	a7, a4, 29
171	slli	a7, a7, 29
172	addi	a7, a7, XCHAL_SPANNING_WAY
173#ifndef CONFIG_SYS_DCACHE_OFF
174	rdtlb1	a8, a7
175	srli	a8, a8, 4
176	slli	a8, a8, 4
177	addi	a8, a8, CA_WRITEBACK
178	wdtlb	a8, a7
179#endif
180#ifndef CONFIG_SYS_ICACHE_OFF
181	ritlb1	a8, a7
182	srli	a8, a8, 4
183	slli	a8, a8, 4
184	addi	a8, a8, CA_WRITEBACK
185	witlb	a8, a7
186#endif
187	isync
188#endif
189
1902:	l32i	a7, a6, 0
191	addi	a6, a6, 4
192	s32i	a7, a4, 0
193	addi	a4, a4, 4
194	bltu	a4, a5, 2b
195	j	1b
196
1973:	/* All code and initalized data segments have been copied */
198
199	/* Setup PS, PS.WOE = 1, PS.EXCM = 0, PS.INTLEVEL = EXCM level. */
200
201#if __XTENSA_CALL0_ABI__
202	movi	a2, XCHAL_EXCM_LEVEL
203#else
204	movi	a2, (1<<PS_WOE_BIT) | XCHAL_EXCM_LEVEL
205#endif
206	wsr	a2, PS
207	rsync
208
209	/* Writeback */
210
211	___flush_dcache_all a2, a3
212
213#ifdef __XTENSA_WINDOWED_ABI__
214	/*
215	 * In windowed ABI caller and call target need to be within the same
216	 * gigabyte. Put the rest of the code into the text segment and jump
217	 * there.
218	 */
219
220	movi	a4, .Lboard_init_code
221	jx	a4
222
223	.text
224	.align	4
225.Lboard_init_code:
226#endif
227
228	movi	a0, 0
229	movi	sp, (CONFIG_SYS_TEXT_ADDR - 16) & 0xfffffff0
230
231#ifdef CONFIG_DEBUG_UART
232	movi	a4, debug_uart_init
233#ifdef __XTENSA_CALL0_ABI__
234	callx0	a4
235#else
236	callx4	a4
237#endif
238#endif
239
240	movi	a4, board_init_f_alloc_reserve
241
242#ifdef __XTENSA_CALL0_ABI__
243	mov	a2, sp
244	callx0	a4
245	mov	sp, a2
246#else
247	mov	a6, sp
248	callx4	a4
249	movsp	sp, a6
250#endif
251
252	movi	a4, board_init_f_init_reserve
253
254#ifdef __XTENSA_CALL0_ABI__
255	callx0	a4
256#else
257	callx4	a4
258#endif
259
260        /*
261	 * Call board initialization routine (never returns).
262	 */
263
264	movi	a4, board_init_f
265
266#ifdef __XTENSA_CALL0_ABI__
267	movi	a2, 0
268	callx0	a4
269#else
270	movi	a6, 0
271	callx4	a4
272#endif
273	/* Never Returns */
274	ill
275
276/*
277 * void relocate_code (addr_sp, gd, addr_moni)
278 *
279 * This "function" does not return, instead it continues in RAM
280 * after relocating the monitor code.
281 *
282 * a2 = addr_sp
283 * a3 = gd
284 * a4 = destination address
285 */
286	.text
287	.globl relocate_code
288	.align 4
289relocate_code:
290	abi_entry
291
292#ifdef __XTENSA_CALL0_ABI__
293	mov	a1, a2
294	mov	a2, a3
295	mov	a3, a4
296	movi	a0, board_init_r
297	callx0	a0
298#else
299	/* We can't movsp here, because the chain of stack frames may cross
300	 * the now reserved memory. We need to toss all window frames except
301	 * the current, create new pristine stack frame and start from scratch.
302	 */
303	rsr	a0, windowbase
304	ssl	a0
305	movi	a0, 1
306	sll	a0, a0
307	wsr	a0, windowstart
308	rsync
309
310	movi	a0, 0
311
312	/* Reserve 16-byte save area */
313	addi	sp, a2, -16
314	mov	a6, a3
315	mov	a7, a4
316	movi	a4, board_init_r
317	callx4	a4
318#endif
319	ill
320
321#if XCHAL_HAVE_EXCEPTIONS
322
323/*
324 * Exception vectors.
325 *
326 *  Various notes:
327 *   - We currently don't use the user exception vector (PS.UM is always 0),
328 *     but do define such a vector, just in case. They both jump to the
329 *     same exception handler, though.
330 *   - We currently only save the bare minimum number of registers:
331 *     a0...a15, sar, loop-registers, exception register (epc1, excvaddr,
332 *     exccause, depc)
333 *   - WINDOWSTART is only saved to identify if registers have been spilled
334 *     to the wrong stack (exception stack) while executing the exception
335 *     handler.
336 */
337
338	.section .KernelExceptionVector.text, "ax"
339	.global _KernelExceptionVector
340_KernelExceptionVector:
341
342	wsr	a2, EXCSAVE1
343	movi	a2, ExceptionHandler
344	jx	a2
345
346	.section .UserExceptionVector.text, "ax"
347	.global _UserExceptionVector
348_UserExceptionVector:
349
350	wsr	a2, EXCSAVE1
351	movi	a2, ExceptionHandler
352	jx	a2
353
354#if !XCHAL_HAVE_XEA1
355	.section .DoubleExceptionVector.text, "ax"
356	.global _DoubleExceptionVector
357_DoubleExceptionVector:
358
359#ifdef __XTENSA_CALL0_ABI__
360	wsr	a0, EXCSAVE1
361	movi    a0, hang                # report and ask user to reset board
362	callx0	a0
363#else
364	wsr	a4, EXCSAVE1
365	movi    a4, hang                # report and ask user to reset board
366	callx4	a4
367#endif
368#endif
369	/* Does not return here */
370
371
372	.text
373	.align 4
374ExceptionHandler:
375
376	rsr	a2, EXCCAUSE		# find handler
377
378#if XCHAL_HAVE_WINDOWED
379	/* Special case for alloca handler */
380
381	bnei	a2, 5, 1f		# jump if not alloca exception
382
383	addi	a1, a1, -16 - 4		# create a small stack frame
384	s32i	a3, a1, 0		# and save a3 (a2 still in excsave1)
385	movi	a2, fast_alloca_exception
386	jx	a2			# jump to fast_alloca_exception
387#endif
388	/* All other exceptions go here: */
389
390	/* Create ptrace stack and save a0...a3 */
391
3921:	addi	a2, a1, - PT_SIZE - 16
393	s32i	a0, a2, PT_AREG + 0 * 4
394	s32i	a1, a2, PT_AREG + 1 * 4
395	s32i	a3, a2, PT_AREG + 3 * 4
396	rsr	a3, EXCSAVE1
397	s32i	a3, a2, PT_AREG + 2 * 4
398	mov	a1, a2
399
400	/* Save remaining AR registers */
401
402	s32i	a4, a1, PT_AREG + 4 * 4
403	s32i	a5, a1, PT_AREG + 5 * 4
404	s32i	a6, a1, PT_AREG + 6 * 4
405	s32i	a7, a1, PT_AREG + 7 * 4
406	s32i	a8, a1, PT_AREG + 8 * 4
407	s32i	a9, a1, PT_AREG + 9 * 4
408	s32i	a10, a1, PT_AREG + 10 * 4
409	s32i	a11, a1, PT_AREG + 11 * 4
410	s32i	a12, a1, PT_AREG + 12 * 4
411	s32i	a13, a1, PT_AREG + 13 * 4
412	s32i	a14, a1, PT_AREG + 14 * 4
413	s32i	a15, a1, PT_AREG + 15 * 4
414
415	/* Save SRs */
416
417#if XCHAL_HAVE_WINDOWED
418	rsr	a2, WINDOWSTART
419	s32i	a2, a1, PT_WINDOWSTART
420#endif
421
422	rsr	a2, SAR
423	rsr	a3, EPC1
424	rsr	a4, EXCVADDR
425	s32i	a2, a1, PT_SAR
426	s32i	a3, a1, PT_PC
427	s32i	a4, a1, PT_EXCVADDR
428
429#if XCHAL_HAVE_LOOPS
430	movi	a2, 0
431	rsr	a3, LBEG
432	xsr	a2, LCOUNT
433	s32i	a3, a1, PT_LBEG
434	rsr	a3, LEND
435	s32i	a2, a1, PT_LCOUNT
436	s32i	a3, a1, PT_LEND
437#endif
438
439	/* Set up C environment and call registered handler */
440	/* Setup stack, PS.WOE = 1, PS.EXCM = 0, PS.INTLEVEL = EXCM level. */
441
442	rsr	a2, EXCCAUSE
443#if XCHAL_HAVE_XEA1
444	movi	a3, (1<<PS_WOE_BIT) | 1
445#elif __XTENSA_CALL0_ABI__
446	movi	a3, XCHAL_EXCM_LEVEL
447#else
448	movi	a3, (1<<PS_WOE_BIT) | XCHAL_EXCM_LEVEL
449#endif
450	xsr	a3, PS
451	rsync
452	s32i	a2, a1, PT_EXCCAUSE
453	s32i	a3, a1, PT_PS
454
455	movi	a0, exc_table
456	addx4	a0, a2, a0
457	l32i	a0, a0, 0
458#ifdef __XTENSA_CALL0_ABI__
459	mov	a2, a1			# Provide stack frame as only argument
460	callx0	a0
461	l32i	a3, a1, PT_PS
462#else
463	mov	a6, a1			# Provide stack frame as only argument
464	callx4	a0
465#endif
466
467	/* Restore PS and go to exception mode (PS.EXCM=1) */
468
469	wsr	a3, PS
470
471	/* Restore SR registers */
472
473#if XCHAL_HAVE_LOOPS
474	l32i	a2, a1, PT_LBEG
475	l32i	a3, a1, PT_LEND
476	l32i	a4, a1, PT_LCOUNT
477	wsr	a2, LBEG
478	wsr	a3, LEND
479	wsr	a4, LCOUNT
480#endif
481
482	l32i	a2, a1, PT_SAR
483	l32i	a3, a1, PT_PC
484	wsr	a2, SAR
485	wsr	a3, EPC1
486
487#if XCHAL_HAVE_WINDOWED
488	/* Do we need to simulate a MOVSP? */
489
490	l32i	a2, a1, PT_WINDOWSTART
491	addi	a3, a2, -1
492	and	a2, a2, a3
493	beqz	a2, 1f			# Skip if regs were spilled before exc.
494
495	rsr	a2, WINDOWSTART
496	addi	a3, a2, -1
497	and	a2, a2, a3
498	bnez	a2, 1f			# Skip if registers aren't spilled now
499
500	addi	a2, a1, -16
501	l32i	a4, a2, 0
502	l32i	a5, a2, 4
503	s32i	a4, a1, PT_SIZE + 0
504	s32i	a5, a1, PT_SIZE + 4
505	l32i	a4, a2, 8
506	l32i	a5, a2, 12
507	s32i	a4, a1, PT_SIZE + 8
508	s32i	a5, a1, PT_SIZE + 12
509#endif
510
511	/* Restore address register */
512
5131:	l32i	a15, a1, PT_AREG + 15 * 4
514	l32i	a14, a1, PT_AREG + 14 * 4
515	l32i	a13, a1, PT_AREG + 13 * 4
516	l32i	a12, a1, PT_AREG + 12 * 4
517	l32i	a11, a1, PT_AREG + 11 * 4
518	l32i	a10, a1, PT_AREG + 10 * 4
519	l32i	a9, a1, PT_AREG + 9 * 4
520	l32i	a8, a1, PT_AREG + 8 * 4
521	l32i	a7, a1, PT_AREG + 7 * 4
522	l32i	a6, a1, PT_AREG + 6 * 4
523	l32i	a5, a1, PT_AREG + 5 * 4
524	l32i	a4, a1, PT_AREG + 4 * 4
525	l32i	a3, a1, PT_AREG + 3 * 4
526	l32i	a2, a1, PT_AREG + 2 * 4
527	l32i	a0, a1, PT_AREG + 0 * 4
528
529	l32i	a1, a1, PT_AREG + 1 * 4 # Remove ptrace stack frame
530
531	rfe
532
533#endif /* XCHAL_HAVE_EXCEPTIONS */
534
535#if XCHAL_HAVE_WINDOWED
536
537/*
538 * Window overflow and underflow handlers.
539 * The handlers must be 64 bytes apart, first starting with the underflow
540 * handlers underflow-4 to underflow-12, then the overflow handlers
541 * overflow-4 to overflow-12.
542 *
543 * Note: We rerun the underflow handlers if we hit an exception, so
544 *	 we try to access any page that would cause a page fault early.
545 */
546
547	.section .WindowVectors.text, "ax"
548
549/* 4-Register Window Overflow Vector (Handler) */
550
551	.align 64
552.global _WindowOverflow4
553_WindowOverflow4:
554	s32e	a0, a5, -16
555	s32e	a1, a5, -12
556	s32e	a2, a5,  -8
557	s32e	a3, a5,  -4
558	rfwo
559
560
561/* 4-Register Window Underflow Vector (Handler) */
562
563	.align 64
564.global _WindowUnderflow4
565_WindowUnderflow4:
566	l32e	a0, a5, -16
567	l32e	a1, a5, -12
568	l32e	a2, a5,  -8
569	l32e	a3, a5,  -4
570	rfwu
571
572/*
573 * a0:	a0
574 * a1:	new stack pointer = a1 - 16 - 4
575 * a2:	available, saved in excsave1
576 * a3:	available, saved on stack *a1
577 */
578
579/* 15*/	.byte	0xff
580
581fast_alloca_exception:	/* must be at _WindowUnderflow4 + 16 */
582
583/* 16*/	rsr	a2, PS
584/* 19*/	rsr	a3, WINDOWBASE
585/* 22*/	extui	a2, a2, PS_OWB_SHIFT, PS_OWB_SHIFT
586/* 25*/	xor	a2, a2, a3
587/* 28*/	rsr	a3, PS
588/* 31*/	slli	a2, a2, PS_OWB_SHIFT
589/* 34*/	xor	a2, a3, a2
590/* 37*/	wsr	a2, PS
591
592/* 40*/	_l32i	a3, a1, 0
593/* 43*/	addi	a1, a1, 16 + 4
594/* 46*/	rsr	a2, EXCSAVE1
595
596/* 49*/	rotw	-1
597/* 52*/	_bbci.l	a4, 31, _WindowUnderflow4	/* 0x: call4 */
598/* 55*/	rotw	-1
599/* 58*/	_bbci.l	a8, 30, _WindowUnderflow8	/* 10: call8 */
600/* 61*/ _j	__WindowUnderflow12		/* 11: call12 */
601/* 64*/
602
603/* 8-Register Window Overflow Vector (Handler) */
604
605	.align 64
606.global _WindowOverflow8
607_WindowOverflow8:
608	s32e	a0, a9, -16
609	l32e	a0, a1, -12
610	s32e	a2, a9,  -8
611	s32e	a1, a9, -12
612	s32e	a3, a9,  -4
613	s32e	a4, a0, -32
614	s32e	a5, a0, -28
615	s32e	a6, a0, -24
616	s32e	a7, a0, -20
617	rfwo
618
619/* 8-Register Window Underflow Vector (Handler) */
620
621	.align 64
622.global _WindowUnderflow8
623_WindowUnderflow8:
624	l32e	a1, a9, -12
625	l32e	a0, a9, -16
626	l32e	a7, a1, -12
627	l32e	a2, a9,  -8
628	l32e	a4, a7, -32
629	l32e	a3, a9,  -4
630	l32e	a5, a7, -28
631	l32e	a6, a7, -24
632	l32e	a7, a7, -20
633	rfwu
634
635/* 12-Register Window Overflow Vector (Handler) */
636
637	.align 64
638.global _WindowOverflow12
639_WindowOverflow12:
640	s32e	a0,  a13, -16
641	l32e	a0,  a1,  -12
642	s32e	a1,  a13, -12
643	s32e	a2,  a13,  -8
644	s32e	a3,  a13,  -4
645	s32e	a4,  a0,  -48
646	s32e	a5,  a0,  -44
647	s32e	a6,  a0,  -40
648	s32e	a7,  a0,  -36
649	s32e	a8,  a0,  -32
650	s32e	a9,  a0,  -28
651	s32e	a10, a0,  -24
652	s32e	a11, a0,  -20
653	rfwo
654
655/* 12-Register Window Underflow Vector (Handler) */
656
657	.org _WindowOverflow12 + 64 - 3
658__WindowUnderflow12:
659	rotw	-1
660.global _WindowUnderflow12
661_WindowUnderflow12:
662	l32e	a1,  a13, -12
663	l32e	a0,  a13, -16
664	l32e	a11, a1,  -12
665	l32e	a2,  a13,  -8
666	l32e	a4,  a11, -48
667	l32e	a8,  a11, -32
668	l32e	a3,  a13,  -4
669	l32e	a5,  a11, -44
670	l32e	a6,  a11, -40
671	l32e	a7,  a11, -36
672	l32e	a9,  a11, -28
673	l32e	a10, a11, -24
674	l32e	a11, a11, -20
675	rfwu
676
677#endif /* XCHAL_HAVE_WINDOWED */
678