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