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 !(CONFIG_IS_ENABLED(SYS_DCACHE_OFF) && \
168 CONFIG_IS_ENABLED(SYS_ICACHE_OFF))
171 addi a7, a7, XCHAL_SPANNING_WAY
172 #if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
176 addi a8, a8, CA_WRITEBACK
179 #if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
183 addi a8, a8, CA_WRITEBACK
196 3: /* All code and initalized data segments have been copied */
198 /* Setup PS, PS.WOE = 1, PS.EXCM = 0, PS.INTLEVEL = EXCM level. */
200 #if __XTENSA_CALL0_ABI__
201 movi a2, XCHAL_EXCM_LEVEL
203 movi a2, (1<<PS_WOE_BIT) | XCHAL_EXCM_LEVEL
210 ___flush_dcache_all a2, a3
212 #ifdef __XTENSA_WINDOWED_ABI__
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
219 movi a4, .Lboard_init_code
228 movi sp, (XTENSA_SYS_TEXT_ADDR - 16) & 0xfffffff0
230 #ifdef CONFIG_DEBUG_UART
231 movi a4, debug_uart_init
232 #ifdef __XTENSA_CALL0_ABI__
239 movi a4, board_init_f_alloc_reserve
241 #ifdef __XTENSA_CALL0_ABI__
251 movi a4, board_init_f_init_reserve
253 #ifdef __XTENSA_CALL0_ABI__
260 * Call board initialization routine (never returns).
263 movi a4, board_init_f
265 #ifdef __XTENSA_CALL0_ABI__
276 * void relocate_code (addr_sp, gd, addr_moni)
278 * This "function" does not return, instead it continues in RAM
279 * after relocating the monitor code.
283 * a4 = destination address
291 #ifdef __XTENSA_CALL0_ABI__
295 movi a0, board_init_r
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.
311 /* Reserve 16-byte save area */
315 movi a4, board_init_r
320 #if XCHAL_HAVE_EXCEPTIONS
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,
332 * - WINDOWSTART is only saved to identify if registers have been spilled
333 * to the wrong stack (exception stack) while executing the exception
337 .section .KernelExceptionVector.text, "ax"
338 .global _KernelExceptionVector
339 _KernelExceptionVector:
342 movi a2, ExceptionHandler
345 .section .UserExceptionVector.text, "ax"
346 .global _UserExceptionVector
347 _UserExceptionVector:
350 movi a2, ExceptionHandler
354 .section .DoubleExceptionVector.text, "ax"
355 .global _DoubleExceptionVector
356 _DoubleExceptionVector:
358 #ifdef __XTENSA_CALL0_ABI__
360 movi a0, hang # report and ask user to reset board
364 movi a4, hang # report and ask user to reset board
368 /* Does not return here */
375 rsr a2, EXCCAUSE # find handler
377 #if XCHAL_HAVE_WINDOWED
378 /* Special case for alloca handler */
380 bnei a2, 5, 1f # jump if not alloca exception
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
387 /* All other exceptions go here: */
389 /* Create ptrace stack and save a0...a3 */
391 1: 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
396 s32i a3, a2, PT_AREG + 2 * 4
399 /* Save remaining AR registers */
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
416 #if XCHAL_HAVE_WINDOWED
418 s32i a2, a1, PT_WINDOWSTART
426 s32i a4, a1, PT_EXCVADDR
434 s32i a2, a1, PT_LCOUNT
438 /* Set up C environment and call registered handler */
439 /* Setup stack, PS.WOE = 1, PS.EXCM = 0, PS.INTLEVEL = EXCM level. */
443 movi a3, (1<<PS_WOE_BIT) | 1
444 #elif __XTENSA_CALL0_ABI__
445 movi a3, XCHAL_EXCM_LEVEL
447 movi a3, (1<<PS_WOE_BIT) | XCHAL_EXCM_LEVEL
451 s32i a2, a1, PT_EXCCAUSE
457 #ifdef __XTENSA_CALL0_ABI__
458 mov a2, a1 # Provide stack frame as only argument
462 mov a6, a1 # Provide stack frame as only argument
466 /* Restore PS and go to exception mode (PS.EXCM=1) */
470 /* Restore SR registers */
475 l32i a4, a1, PT_LCOUNT
486 #if XCHAL_HAVE_WINDOWED
487 /* Do we need to simulate a MOVSP? */
489 l32i a2, a1, PT_WINDOWSTART
492 beqz a2, 1f # Skip if regs were spilled before exc.
497 bnez a2, 1f # Skip if registers aren't spilled now
502 s32i a4, a1, PT_SIZE + 0
503 s32i a5, a1, PT_SIZE + 4
506 s32i a4, a1, PT_SIZE + 8
507 s32i a5, a1, PT_SIZE + 12
510 /* Restore address register */
512 1: 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
528 l32i a1, a1, PT_AREG + 1 * 4 # Remove ptrace stack frame
532 #endif /* XCHAL_HAVE_EXCEPTIONS */
534 #if XCHAL_HAVE_WINDOWED
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.
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.
546 .section .WindowVectors.text, "ax"
548 /* 4-Register Window Overflow Vector (Handler) */
551 .global _WindowOverflow4
560 /* 4-Register Window Underflow Vector (Handler) */
563 .global _WindowUnderflow4
573 * a1: new stack pointer = a1 - 16 - 4
574 * a2: available, saved in excsave1
575 * a3: available, saved on stack *a1
580 fast_alloca_exception: /* must be at _WindowUnderflow4 + 16 */
583 /* 19*/ rsr a3, WINDOWBASE
584 /* 22*/ extui a2, a2, PS_OWB_SHIFT, PS_OWB_SHIFT
585 /* 25*/ xor a2, a2, a3
587 /* 31*/ slli a2, a2, PS_OWB_SHIFT
588 /* 34*/ xor a2, a3, a2
591 /* 40*/ _l32i a3, a1, 0
592 /* 43*/ addi a1, a1, 16 + 4
593 /* 46*/ rsr a2, EXCSAVE1
596 /* 52*/ _bbci.l a4, 31, _WindowUnderflow4 /* 0x: call4 */
598 /* 58*/ _bbci.l a8, 30, _WindowUnderflow8 /* 10: call8 */
599 /* 61*/ _j __WindowUnderflow12 /* 11: call12 */
602 /* 8-Register Window Overflow Vector (Handler) */
605 .global _WindowOverflow8
618 /* 8-Register Window Underflow Vector (Handler) */
621 .global _WindowUnderflow8
634 /* 12-Register Window Overflow Vector (Handler) */
637 .global _WindowOverflow12
654 /* 12-Register Window Underflow Vector (Handler) */
656 .org _WindowOverflow12 + 64 - 3
659 .global _WindowUnderflow12
676 #endif /* XCHAL_HAVE_WINDOWED */