1 /* SPDX-License-Identifier: GPL-2.0+ */
3 * (C) Copyright 2008 - 2013 Tensilica Inc.
4 * (C) Copyright 2014 - 2016 Cadence Design Systems Inc.
8 #include <asm/asmmacro.h>
9 #include <asm/cacheasm.h>
11 #include <asm/arch/tie.h>
12 #include <asm-offsets.h>
15 * Offsets into the the pt_regs struture.
16 * Make sure these always match with the structure defined in ptrace.h!
22 #define PT_EXCCAUSE 12
23 #define PT_EXCVADDR 16
24 #define PT_DEBUGCAUSE 20
30 #define PT_WINDOWBASE 44
31 #define PT_WINDOWSTART 48
33 #define PT_ICOUNTLEVEL 56
34 #define PT_RESERVED 60
36 #define PT_SIZE (64 + 64)
39 * Cache attributes are different for full MMU and region protection.
42 #if XCHAL_HAVE_PTP_MMU
43 #define CA_WRITEBACK (0x7)
45 #define CA_WRITEBACK (0x4)
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)
55 .section .ResetVector.text, "awx"
67 * Processor initialization. We still run in rom space.
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)
76 .section .reset.text, "ax"
80 /* Keep a0 = 0 for various initializations */
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.
90 #if XCHAL_HAVE_PTP_MMU
94 /* Disable dbreak debug exceptions */
96 #if XCHAL_HAVE_DEBUG && XCHAL_NUM_DBREAK > 0
98 .rept XCHAL_NUM_DBREAK
99 wsr a0, DBREAKC + _index
100 .set _index, _index + 1
104 /* Reset windowbase and windowstart */
106 #if XCHAL_HAVE_WINDOWED
111 movi a0, 0 /* windowbase might have changed */
115 * Vecbase in bitstream may differ from header files
119 #if XCHAL_HAVE_VECBASE
120 movi a3, XCHAL_VECBASE_RESET_VADDR /* VECBASE reset value */
130 /* Set PS.WOE = 0, PS.EXCM = 0 (for loop), PS.INTLEVEL = EXCM level */
135 movi a2, XCHAL_EXCM_LEVEL
140 /* Unlock and invalidate caches */
142 ___unlock_dcache_all a2, a3
143 ___invalidate_dcache_all a2, a3
144 ___unlock_icache_all a2, a3
145 ___invalidate_icache_all a2, a3
149 /* Unpack data sections */
151 movi a2, __reloc_table_start
152 movi a3, __reloc_table_end
154 1: 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
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.
166 #if XCHAL_HAVE_SPANNING_WAY && \
167 !(defined(CONFIG_SYS_DCACHE_OFF) && defined(CONFIG_SYS_ICACHE_OFF))
170 addi a7, a7, XCHAL_SPANNING_WAY
171 #ifndef CONFIG_SYS_DCACHE_OFF
175 addi a8, a8, CA_WRITEBACK
178 #ifndef CONFIG_SYS_ICACHE_OFF
182 addi a8, a8, CA_WRITEBACK
195 3: /* All code and initalized data segments have been copied */
197 /* Setup PS, PS.WOE = 1, PS.EXCM = 0, PS.INTLEVEL = EXCM level. */
199 #if __XTENSA_CALL0_ABI__
200 movi a2, XCHAL_EXCM_LEVEL
202 movi a2, (1<<PS_WOE_BIT) | XCHAL_EXCM_LEVEL
209 ___flush_dcache_all a2, a3
211 #ifdef __XTENSA_WINDOWED_ABI__
213 * In windowed ABI caller and call target need to be within the same
214 * gigabyte. Put the rest of the code into the text segment and jump
218 movi a4, .Lboard_init_code
227 movi sp, (XTENSA_SYS_TEXT_ADDR - 16) & 0xfffffff0
229 #ifdef CONFIG_DEBUG_UART
230 movi a4, debug_uart_init
231 #ifdef __XTENSA_CALL0_ABI__
238 movi a4, board_init_f_alloc_reserve
240 #ifdef __XTENSA_CALL0_ABI__
250 movi a4, board_init_f_init_reserve
252 #ifdef __XTENSA_CALL0_ABI__
259 * Call board initialization routine (never returns).
262 movi a4, board_init_f
264 #ifdef __XTENSA_CALL0_ABI__
275 * void relocate_code (addr_sp, gd, addr_moni)
277 * This "function" does not return, instead it continues in RAM
278 * after relocating the monitor code.
282 * a4 = destination address
290 #ifdef __XTENSA_CALL0_ABI__
294 movi a0, board_init_r
297 /* We can't movsp here, because the chain of stack frames may cross
298 * the now reserved memory. We need to toss all window frames except
299 * the current, create new pristine stack frame and start from scratch.
310 /* Reserve 16-byte save area */
314 movi a4, board_init_r
319 #if XCHAL_HAVE_EXCEPTIONS
325 * - We currently don't use the user exception vector (PS.UM is always 0),
326 * but do define such a vector, just in case. They both jump to the
327 * same exception handler, though.
328 * - We currently only save the bare minimum number of registers:
329 * a0...a15, sar, loop-registers, exception register (epc1, excvaddr,
331 * - WINDOWSTART is only saved to identify if registers have been spilled
332 * to the wrong stack (exception stack) while executing the exception
336 .section .KernelExceptionVector.text, "ax"
337 .global _KernelExceptionVector
338 _KernelExceptionVector:
341 movi a2, ExceptionHandler
344 .section .UserExceptionVector.text, "ax"
345 .global _UserExceptionVector
346 _UserExceptionVector:
349 movi a2, ExceptionHandler
353 .section .DoubleExceptionVector.text, "ax"
354 .global _DoubleExceptionVector
355 _DoubleExceptionVector:
357 #ifdef __XTENSA_CALL0_ABI__
359 movi a0, hang # report and ask user to reset board
363 movi a4, hang # report and ask user to reset board
367 /* Does not return here */
374 rsr a2, EXCCAUSE # find handler
376 #if XCHAL_HAVE_WINDOWED
377 /* Special case for alloca handler */
379 bnei a2, 5, 1f # jump if not alloca exception
381 addi a1, a1, -16 - 4 # create a small stack frame
382 s32i a3, a1, 0 # and save a3 (a2 still in excsave1)
383 movi a2, fast_alloca_exception
384 jx a2 # jump to fast_alloca_exception
386 /* All other exceptions go here: */
388 /* Create ptrace stack and save a0...a3 */
390 1: addi a2, a1, - PT_SIZE - 16
391 s32i a0, a2, PT_AREG + 0 * 4
392 s32i a1, a2, PT_AREG + 1 * 4
393 s32i a3, a2, PT_AREG + 3 * 4
395 s32i a3, a2, PT_AREG + 2 * 4
398 /* Save remaining AR registers */
400 s32i a4, a1, PT_AREG + 4 * 4
401 s32i a5, a1, PT_AREG + 5 * 4
402 s32i a6, a1, PT_AREG + 6 * 4
403 s32i a7, a1, PT_AREG + 7 * 4
404 s32i a8, a1, PT_AREG + 8 * 4
405 s32i a9, a1, PT_AREG + 9 * 4
406 s32i a10, a1, PT_AREG + 10 * 4
407 s32i a11, a1, PT_AREG + 11 * 4
408 s32i a12, a1, PT_AREG + 12 * 4
409 s32i a13, a1, PT_AREG + 13 * 4
410 s32i a14, a1, PT_AREG + 14 * 4
411 s32i a15, a1, PT_AREG + 15 * 4
415 #if XCHAL_HAVE_WINDOWED
417 s32i a2, a1, PT_WINDOWSTART
425 s32i a4, a1, PT_EXCVADDR
433 s32i a2, a1, PT_LCOUNT
437 /* Set up C environment and call registered handler */
438 /* Setup stack, PS.WOE = 1, PS.EXCM = 0, PS.INTLEVEL = EXCM level. */
442 movi a3, (1<<PS_WOE_BIT) | 1
443 #elif __XTENSA_CALL0_ABI__
444 movi a3, XCHAL_EXCM_LEVEL
446 movi a3, (1<<PS_WOE_BIT) | XCHAL_EXCM_LEVEL
450 s32i a2, a1, PT_EXCCAUSE
456 #ifdef __XTENSA_CALL0_ABI__
457 mov a2, a1 # Provide stack frame as only argument
461 mov a6, a1 # Provide stack frame as only argument
465 /* Restore PS and go to exception mode (PS.EXCM=1) */
469 /* Restore SR registers */
474 l32i a4, a1, PT_LCOUNT
485 #if XCHAL_HAVE_WINDOWED
486 /* Do we need to simulate a MOVSP? */
488 l32i a2, a1, PT_WINDOWSTART
491 beqz a2, 1f # Skip if regs were spilled before exc.
496 bnez a2, 1f # Skip if registers aren't spilled now
501 s32i a4, a1, PT_SIZE + 0
502 s32i a5, a1, PT_SIZE + 4
505 s32i a4, a1, PT_SIZE + 8
506 s32i a5, a1, PT_SIZE + 12
509 /* Restore address register */
511 1: l32i a15, a1, PT_AREG + 15 * 4
512 l32i a14, a1, PT_AREG + 14 * 4
513 l32i a13, a1, PT_AREG + 13 * 4
514 l32i a12, a1, PT_AREG + 12 * 4
515 l32i a11, a1, PT_AREG + 11 * 4
516 l32i a10, a1, PT_AREG + 10 * 4
517 l32i a9, a1, PT_AREG + 9 * 4
518 l32i a8, a1, PT_AREG + 8 * 4
519 l32i a7, a1, PT_AREG + 7 * 4
520 l32i a6, a1, PT_AREG + 6 * 4
521 l32i a5, a1, PT_AREG + 5 * 4
522 l32i a4, a1, PT_AREG + 4 * 4
523 l32i a3, a1, PT_AREG + 3 * 4
524 l32i a2, a1, PT_AREG + 2 * 4
525 l32i a0, a1, PT_AREG + 0 * 4
527 l32i a1, a1, PT_AREG + 1 * 4 # Remove ptrace stack frame
531 #endif /* XCHAL_HAVE_EXCEPTIONS */
533 #if XCHAL_HAVE_WINDOWED
536 * Window overflow and underflow handlers.
537 * The handlers must be 64 bytes apart, first starting with the underflow
538 * handlers underflow-4 to underflow-12, then the overflow handlers
539 * overflow-4 to overflow-12.
541 * Note: We rerun the underflow handlers if we hit an exception, so
542 * we try to access any page that would cause a page fault early.
545 .section .WindowVectors.text, "ax"
547 /* 4-Register Window Overflow Vector (Handler) */
550 .global _WindowOverflow4
559 /* 4-Register Window Underflow Vector (Handler) */
562 .global _WindowUnderflow4
572 * a1: new stack pointer = a1 - 16 - 4
573 * a2: available, saved in excsave1
574 * a3: available, saved on stack *a1
579 fast_alloca_exception: /* must be at _WindowUnderflow4 + 16 */
582 /* 19*/ rsr a3, WINDOWBASE
583 /* 22*/ extui a2, a2, PS_OWB_SHIFT, PS_OWB_SHIFT
584 /* 25*/ xor a2, a2, a3
586 /* 31*/ slli a2, a2, PS_OWB_SHIFT
587 /* 34*/ xor a2, a3, a2
590 /* 40*/ _l32i a3, a1, 0
591 /* 43*/ addi a1, a1, 16 + 4
592 /* 46*/ rsr a2, EXCSAVE1
595 /* 52*/ _bbci.l a4, 31, _WindowUnderflow4 /* 0x: call4 */
597 /* 58*/ _bbci.l a8, 30, _WindowUnderflow8 /* 10: call8 */
598 /* 61*/ _j __WindowUnderflow12 /* 11: call12 */
601 /* 8-Register Window Overflow Vector (Handler) */
604 .global _WindowOverflow8
617 /* 8-Register Window Underflow Vector (Handler) */
620 .global _WindowUnderflow8
633 /* 12-Register Window Overflow Vector (Handler) */
636 .global _WindowOverflow12
653 /* 12-Register Window Underflow Vector (Handler) */
655 .org _WindowOverflow12 + 64 - 3
658 .global _WindowUnderflow12
675 #endif /* XCHAL_HAVE_WINDOWED */