123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677 |
- /*
- * (C) Copyright 2008 - 2013 Tensilica Inc.
- * (C) Copyright 2014 - 2016 Cadence Design Systems Inc.
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
- #include <config.h>
- #include <asm/asmmacro.h>
- #include <asm/cacheasm.h>
- #include <asm/regs.h>
- #include <asm/arch/tie.h>
- #include <asm-offsets.h>
- /*
- * Offsets into the the pt_regs struture.
- * Make sure these always match with the structure defined in ptrace.h!
- */
- #define PT_PC 0
- #define PT_PS 4
- #define PT_DEPC 8
- #define PT_EXCCAUSE 12
- #define PT_EXCVADDR 16
- #define PT_DEBUGCAUSE 20
- #define PT_WMASK 24
- #define PT_LBEG 28
- #define PT_LEND 32
- #define PT_LCOUNT 36
- #define PT_SAR 40
- #define PT_WINDOWBASE 44
- #define PT_WINDOWSTART 48
- #define PT_SYSCALL 52
- #define PT_ICOUNTLEVEL 56
- #define PT_RESERVED 60
- #define PT_AREG 64
- #define PT_SIZE (64 + 64)
- /*
- * Cache attributes are different for full MMU and region protection.
- */
- #if XCHAL_HAVE_PTP_MMU
- #define CA_WRITEBACK (0x7)
- #else
- #define CA_WRITEBACK (0x4)
- #endif
- /*
- * Reset vector.
- * Only a trampoline to jump to _start
- * (Note that we have to mark the section writable as the section contains
- * a relocatable literal)
- */
- .section .ResetVector.text, "awx"
- .global _ResetVector
- _ResetVector:
- j 1f
- .align 4
- 2: .long _start
- 1: l32r a2, 2b
- jx a2
- /*
- * Processor initialization. We still run in rom space.
- *
- * NOTE: Running in ROM
- * For Xtensa, we currently don't allow to run some code from ROM but
- * unpack the data immediately to memory. This requires, for example,
- * that DDR has been set up before running U-Boot. (See also comments
- * inline for ways to change it)
- */
- .section .reset.text, "ax"
- .global _start
- .align 4
- _start:
- /* Keep a0 = 0 for various initializations */
- movi a0, 0
- /*
- * For full MMU cores, put page table at unmapped virtual address.
- * This ensures that accesses outside the static maps result
- * in miss exceptions rather than random behaviour.
- */
- #if XCHAL_HAVE_PTP_MMU
- wsr a0, PTEVADDR
- #endif
- /* Disable dbreak debug exceptions */
- #if XCHAL_HAVE_DEBUG && XCHAL_NUM_DBREAK > 0
- .set _index, 0
- .rept XCHAL_NUM_DBREAK
- wsr a0, DBREAKC + _index
- .set _index, _index + 1
- .endr
- #endif
- /* Reset windowbase and windowstart */
- #if XCHAL_HAVE_WINDOWED
- movi a3, 1
- wsr a3, windowstart
- wsr a0, windowbase
- rsync
- movi a0, 0 /* windowbase might have changed */
- #endif
- /*
- * Vecbase in bitstream may differ from header files
- * set or check it.
- */
- #if XCHAL_HAVE_VECBASE
- movi a3, XCHAL_VECBASE_RESET_VADDR /* VECBASE reset value */
- wsr a3, VECBASE
- #endif
- #if XCHAL_HAVE_LOOPS
- /* Disable loops */
- wsr a0, LCOUNT
- #endif
- /* Set PS.WOE = 0, PS.EXCM = 0 (for loop), PS.INTLEVEL = EXCM level */
- #if XCHAL_HAVE_XEA1
- movi a2, 1
- #else
- movi a2, XCHAL_EXCM_LEVEL
- #endif
- wsr a2, PS
- rsync
- /* Unlock and invalidate caches */
- ___unlock_dcache_all a2, a3
- ___invalidate_dcache_all a2, a3
- ___unlock_icache_all a2, a3
- ___invalidate_icache_all a2, a3
- isync
- /* Unpack data sections */
- movi a2, __reloc_table_start
- movi a3, __reloc_table_end
- 1: beq a2, a3, 3f # no more entries?
- l32i a4, a2, 0 # start destination (in RAM)
- l32i a5, a2, 4 # end destination (in RAM)
- l32i a6, a2, 8 # start source (in ROM)
- addi a2, a2, 12 # next entry
- beq a4, a5, 1b # skip, empty entry
- beq a4, a6, 1b # skip, source and destination are the same
- /* If there's memory protection option with 512MB TLB regions and
- * cache attributes in TLB entries and caching is not inhibited,
- * enable data/instruction cache for relocated image.
- */
- #if XCHAL_HAVE_SPANNING_WAY && \
- (!defined(CONFIG_SYS_DCACHE_OFF) || \
- !defined(CONFIG_SYS_ICACHE_OFF))
- srli a7, a4, 29
- slli a7, a7, 29
- addi a7, a7, XCHAL_SPANNING_WAY
- #ifndef CONFIG_SYS_DCACHE_OFF
- rdtlb1 a8, a7
- srli a8, a8, 4
- slli a8, a8, 4
- addi a8, a8, CA_WRITEBACK
- wdtlb a8, a7
- #endif
- #ifndef CONFIG_SYS_ICACHE_OFF
- ritlb1 a8, a7
- srli a8, a8, 4
- slli a8, a8, 4
- addi a8, a8, CA_WRITEBACK
- witlb a8, a7
- #endif
- isync
- #endif
- 2: l32i a7, a6, 0
- addi a6, a6, 4
- s32i a7, a4, 0
- addi a4, a4, 4
- bltu a4, a5, 2b
- j 1b
- 3: /* All code and initalized data segments have been copied */
- /* Setup PS, PS.WOE = 1, PS.EXCM = 0, PS.INTLEVEL = EXCM level. */
- #if __XTENSA_CALL0_ABI__
- movi a2, XCHAL_EXCM_LEVEL
- #else
- movi a2, (1<<PS_WOE_BIT) | XCHAL_EXCM_LEVEL
- #endif
- wsr a2, PS
- rsync
- /* Writeback */
- ___flush_dcache_all a2, a3
- #ifdef __XTENSA_WINDOWED_ABI__
- /*
- * In windowed ABI caller and call target need to be within the same
- * gigabyte. Put the rest of the code into the text segment and jump
- * there.
- */
- movi a4, .Lboard_init_code
- jx a4
- .text
- .align 4
- .Lboard_init_code:
- #endif
- movi a0, 0
- movi sp, (CONFIG_SYS_TEXT_ADDR - 16) & 0xfffffff0
- #ifdef CONFIG_DEBUG_UART
- movi a4, debug_uart_init
- #ifdef __XTENSA_CALL0_ABI__
- callx0 a4
- #else
- callx4 a4
- #endif
- #endif
- movi a4, board_init_f_alloc_reserve
- #ifdef __XTENSA_CALL0_ABI__
- mov a2, sp
- callx0 a4
- mov sp, a2
- #else
- mov a6, sp
- callx4 a4
- movsp sp, a6
- #endif
- movi a4, board_init_f_init_reserve
- #ifdef __XTENSA_CALL0_ABI__
- callx0 a4
- #else
- callx4 a4
- #endif
- /*
- * Call board initialization routine (never returns).
- */
- movi a4, board_init_f
- #ifdef __XTENSA_CALL0_ABI__
- movi a2, 0
- callx0 a4
- #else
- movi a6, 0
- callx4 a4
- #endif
- /* Never Returns */
- ill
- /*
- * void relocate_code (addr_sp, gd, addr_moni)
- *
- * This "function" does not return, instead it continues in RAM
- * after relocating the monitor code.
- *
- * a2 = addr_sp
- * a3 = gd
- * a4 = destination address
- */
- .text
- .globl relocate_code
- .align 4
- relocate_code:
- abi_entry
- #ifdef __XTENSA_CALL0_ABI__
- mov a1, a2
- mov a2, a3
- mov a3, a4
- movi a0, board_init_r
- callx0 a0
- #else
- /* We can't movsp here, because the chain of stack frames may cross
- * the now reserved memory. We need to toss all window frames except
- * the current, create new pristine stack frame and start from scratch.
- */
- rsr a0, windowbase
- ssl a0
- movi a0, 1
- sll a0, a0
- wsr a0, windowstart
- rsync
- movi a0, 0
- /* Reserve 16-byte save area */
- addi sp, a2, -16
- mov a6, a3
- mov a7, a4
- movi a4, board_init_r
- callx4 a4
- #endif
- ill
- #if XCHAL_HAVE_EXCEPTIONS
- /*
- * Exception vectors.
- *
- * Various notes:
- * - We currently don't use the user exception vector (PS.UM is always 0),
- * but do define such a vector, just in case. They both jump to the
- * same exception handler, though.
- * - We currently only save the bare minimum number of registers:
- * a0...a15, sar, loop-registers, exception register (epc1, excvaddr,
- * exccause, depc)
- * - WINDOWSTART is only saved to identify if registers have been spilled
- * to the wrong stack (exception stack) while executing the exception
- * handler.
- */
- .section .KernelExceptionVector.text, "ax"
- .global _KernelExceptionVector
- _KernelExceptionVector:
- wsr a2, EXCSAVE1
- movi a2, ExceptionHandler
- jx a2
- .section .UserExceptionVector.text, "ax"
- .global _UserExceptionVector
- _UserExceptionVector:
- wsr a2, EXCSAVE1
- movi a2, ExceptionHandler
- jx a2
- #if !XCHAL_HAVE_XEA1
- .section .DoubleExceptionVector.text, "ax"
- .global _DoubleExceptionVector
- _DoubleExceptionVector:
- #ifdef __XTENSA_CALL0_ABI__
- wsr a0, EXCSAVE1
- movi a0, hang # report and ask user to reset board
- callx0 a0
- #else
- wsr a4, EXCSAVE1
- movi a4, hang # report and ask user to reset board
- callx4 a4
- #endif
- #endif
- /* Does not return here */
- .text
- .align 4
- ExceptionHandler:
- rsr a2, EXCCAUSE # find handler
- #if XCHAL_HAVE_WINDOWED
- /* Special case for alloca handler */
- bnei a2, 5, 1f # jump if not alloca exception
- addi a1, a1, -16 - 4 # create a small stack frame
- s32i a3, a1, 0 # and save a3 (a2 still in excsave1)
- movi a2, fast_alloca_exception
- jx a2 # jump to fast_alloca_exception
- #endif
- /* All other exceptions go here: */
- /* Create ptrace stack and save a0...a3 */
- 1: addi a2, a1, - PT_SIZE - 16
- s32i a0, a2, PT_AREG + 0 * 4
- s32i a1, a2, PT_AREG + 1 * 4
- s32i a3, a2, PT_AREG + 3 * 4
- rsr a3, EXCSAVE1
- s32i a3, a2, PT_AREG + 2 * 4
- mov a1, a2
- /* Save remaining AR registers */
- s32i a4, a1, PT_AREG + 4 * 4
- s32i a5, a1, PT_AREG + 5 * 4
- s32i a6, a1, PT_AREG + 6 * 4
- s32i a7, a1, PT_AREG + 7 * 4
- s32i a8, a1, PT_AREG + 8 * 4
- s32i a9, a1, PT_AREG + 9 * 4
- s32i a10, a1, PT_AREG + 10 * 4
- s32i a11, a1, PT_AREG + 11 * 4
- s32i a12, a1, PT_AREG + 12 * 4
- s32i a13, a1, PT_AREG + 13 * 4
- s32i a14, a1, PT_AREG + 14 * 4
- s32i a15, a1, PT_AREG + 15 * 4
- /* Save SRs */
- #if XCHAL_HAVE_WINDOWED
- rsr a2, WINDOWSTART
- s32i a2, a1, PT_WINDOWSTART
- #endif
- rsr a2, SAR
- rsr a3, EPC1
- rsr a4, EXCVADDR
- s32i a2, a1, PT_SAR
- s32i a3, a1, PT_PC
- s32i a4, a1, PT_EXCVADDR
- #if XCHAL_HAVE_LOOPS
- movi a2, 0
- rsr a3, LBEG
- xsr a2, LCOUNT
- s32i a3, a1, PT_LBEG
- rsr a3, LEND
- s32i a2, a1, PT_LCOUNT
- s32i a3, a1, PT_LEND
- #endif
- /* Set up C environment and call registered handler */
- /* Setup stack, PS.WOE = 1, PS.EXCM = 0, PS.INTLEVEL = EXCM level. */
- rsr a2, EXCCAUSE
- #if XCHAL_HAVE_XEA1
- movi a3, (1<<PS_WOE_BIT) | 1
- #elif __XTENSA_CALL0_ABI__
- movi a3, XCHAL_EXCM_LEVEL
- #else
- movi a3, (1<<PS_WOE_BIT) | XCHAL_EXCM_LEVEL
- #endif
- xsr a3, PS
- rsync
- s32i a2, a1, PT_EXCCAUSE
- s32i a3, a1, PT_PS
- movi a0, exc_table
- addx4 a0, a2, a0
- l32i a0, a0, 0
- #ifdef __XTENSA_CALL0_ABI__
- mov a2, a1 # Provide stack frame as only argument
- callx0 a0
- l32i a3, a1, PT_PS
- #else
- mov a6, a1 # Provide stack frame as only argument
- callx4 a0
- #endif
- /* Restore PS and go to exception mode (PS.EXCM=1) */
- wsr a3, PS
- /* Restore SR registers */
- #if XCHAL_HAVE_LOOPS
- l32i a2, a1, PT_LBEG
- l32i a3, a1, PT_LEND
- l32i a4, a1, PT_LCOUNT
- wsr a2, LBEG
- wsr a3, LEND
- wsr a4, LCOUNT
- #endif
- l32i a2, a1, PT_SAR
- l32i a3, a1, PT_PC
- wsr a2, SAR
- wsr a3, EPC1
- #if XCHAL_HAVE_WINDOWED
- /* Do we need to simulate a MOVSP? */
- l32i a2, a1, PT_WINDOWSTART
- addi a3, a2, -1
- and a2, a2, a3
- beqz a2, 1f # Skip if regs were spilled before exc.
- rsr a2, WINDOWSTART
- addi a3, a2, -1
- and a2, a2, a3
- bnez a2, 1f # Skip if registers aren't spilled now
- addi a2, a1, -16
- l32i a4, a2, 0
- l32i a5, a2, 4
- s32i a4, a1, PT_SIZE + 0
- s32i a5, a1, PT_SIZE + 4
- l32i a4, a2, 8
- l32i a5, a2, 12
- s32i a4, a1, PT_SIZE + 8
- s32i a5, a1, PT_SIZE + 12
- #endif
- /* Restore address register */
- 1: l32i a15, a1, PT_AREG + 15 * 4
- l32i a14, a1, PT_AREG + 14 * 4
- l32i a13, a1, PT_AREG + 13 * 4
- l32i a12, a1, PT_AREG + 12 * 4
- l32i a11, a1, PT_AREG + 11 * 4
- l32i a10, a1, PT_AREG + 10 * 4
- l32i a9, a1, PT_AREG + 9 * 4
- l32i a8, a1, PT_AREG + 8 * 4
- l32i a7, a1, PT_AREG + 7 * 4
- l32i a6, a1, PT_AREG + 6 * 4
- l32i a5, a1, PT_AREG + 5 * 4
- l32i a4, a1, PT_AREG + 4 * 4
- l32i a3, a1, PT_AREG + 3 * 4
- l32i a2, a1, PT_AREG + 2 * 4
- l32i a0, a1, PT_AREG + 0 * 4
- l32i a1, a1, PT_AREG + 1 * 4 # Remove ptrace stack frame
- rfe
- #endif /* XCHAL_HAVE_EXCEPTIONS */
- #if XCHAL_HAVE_WINDOWED
- /*
- * Window overflow and underflow handlers.
- * The handlers must be 64 bytes apart, first starting with the underflow
- * handlers underflow-4 to underflow-12, then the overflow handlers
- * overflow-4 to overflow-12.
- *
- * Note: We rerun the underflow handlers if we hit an exception, so
- * we try to access any page that would cause a page fault early.
- */
- .section .WindowVectors.text, "ax"
- /* 4-Register Window Overflow Vector (Handler) */
- .align 64
- .global _WindowOverflow4
- _WindowOverflow4:
- s32e a0, a5, -16
- s32e a1, a5, -12
- s32e a2, a5, -8
- s32e a3, a5, -4
- rfwo
- /* 4-Register Window Underflow Vector (Handler) */
- .align 64
- .global _WindowUnderflow4
- _WindowUnderflow4:
- l32e a0, a5, -16
- l32e a1, a5, -12
- l32e a2, a5, -8
- l32e a3, a5, -4
- rfwu
- /*
- * a0: a0
- * a1: new stack pointer = a1 - 16 - 4
- * a2: available, saved in excsave1
- * a3: available, saved on stack *a1
- */
- /* 15*/ .byte 0xff
- fast_alloca_exception: /* must be at _WindowUnderflow4 + 16 */
- /* 16*/ rsr a2, PS
- /* 19*/ rsr a3, WINDOWBASE
- /* 22*/ extui a2, a2, PS_OWB_SHIFT, PS_OWB_SHIFT
- /* 25*/ xor a2, a2, a3
- /* 28*/ rsr a3, PS
- /* 31*/ slli a2, a2, PS_OWB_SHIFT
- /* 34*/ xor a2, a3, a2
- /* 37*/ wsr a2, PS
- /* 40*/ _l32i a3, a1, 0
- /* 43*/ addi a1, a1, 16 + 4
- /* 46*/ rsr a2, EXCSAVE1
- /* 49*/ rotw -1
- /* 52*/ _bbci.l a4, 31, _WindowUnderflow4 /* 0x: call4 */
- /* 55*/ rotw -1
- /* 58*/ _bbci.l a8, 30, _WindowUnderflow8 /* 10: call8 */
- /* 61*/ _j __WindowUnderflow12 /* 11: call12 */
- /* 64*/
- /* 8-Register Window Overflow Vector (Handler) */
- .align 64
- .global _WindowOverflow8
- _WindowOverflow8:
- s32e a0, a9, -16
- l32e a0, a1, -12
- s32e a2, a9, -8
- s32e a1, a9, -12
- s32e a3, a9, -4
- s32e a4, a0, -32
- s32e a5, a0, -28
- s32e a6, a0, -24
- s32e a7, a0, -20
- rfwo
- /* 8-Register Window Underflow Vector (Handler) */
- .align 64
- .global _WindowUnderflow8
- _WindowUnderflow8:
- l32e a1, a9, -12
- l32e a0, a9, -16
- l32e a7, a1, -12
- l32e a2, a9, -8
- l32e a4, a7, -32
- l32e a3, a9, -4
- l32e a5, a7, -28
- l32e a6, a7, -24
- l32e a7, a7, -20
- rfwu
- /* 12-Register Window Overflow Vector (Handler) */
- .align 64
- .global _WindowOverflow12
- _WindowOverflow12:
- s32e a0, a13, -16
- l32e a0, a1, -12
- s32e a1, a13, -12
- s32e a2, a13, -8
- s32e a3, a13, -4
- s32e a4, a0, -48
- s32e a5, a0, -44
- s32e a6, a0, -40
- s32e a7, a0, -36
- s32e a8, a0, -32
- s32e a9, a0, -28
- s32e a10, a0, -24
- s32e a11, a0, -20
- rfwo
- /* 12-Register Window Underflow Vector (Handler) */
- .org _WindowOverflow12 + 64 - 3
- __WindowUnderflow12:
- rotw -1
- .global _WindowUnderflow12
- _WindowUnderflow12:
- l32e a1, a13, -12
- l32e a0, a13, -16
- l32e a11, a1, -12
- l32e a2, a13, -8
- l32e a4, a11, -48
- l32e a8, a11, -32
- l32e a3, a13, -4
- l32e a5, a11, -44
- l32e a6, a11, -40
- l32e a7, a11, -36
- l32e a9, a11, -28
- l32e a10, a11, -24
- l32e a11, a11, -20
- rfwu
- #endif /* XCHAL_HAVE_WINDOWED */
|