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