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