1/* 2 * arch/xtensa/kernel/entry.S 3 * 4 * Low-level exception handling 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file "COPYING" in the main directory of this archive 8 * for more details. 9 * 10 * Copyright (C) 2004 - 2008 by Tensilica Inc. 11 * 12 * Chris Zankel <chris@zankel.net> 13 * 14 */ 15 16#include <linux/linkage.h> 17#include <asm/asm-offsets.h> 18#include <asm/processor.h> 19#include <asm/coprocessor.h> 20#include <asm/thread_info.h> 21#include <asm/uaccess.h> 22#include <asm/unistd.h> 23#include <asm/ptrace.h> 24#include <asm/current.h> 25#include <asm/pgtable.h> 26#include <asm/page.h> 27#include <asm/signal.h> 28#include <asm/tlbflush.h> 29#include <variant/tie-asm.h> 30 31/* Unimplemented features. */ 32 33#undef KERNEL_STACK_OVERFLOW_CHECK 34 35/* Not well tested. 36 * 37 * - fast_coprocessor 38 */ 39 40/* 41 * Macro to find first bit set in WINDOWBASE from the left + 1 42 * 43 * 100....0 -> 1 44 * 010....0 -> 2 45 * 000....1 -> WSBITS 46 */ 47 48 .macro ffs_ws bit mask 49 50#if XCHAL_HAVE_NSA 51 nsau \bit, \mask # 32-WSBITS ... 31 (32 iff 0) 52 addi \bit, \bit, WSBITS - 32 + 1 # uppest bit set -> return 1 53#else 54 movi \bit, WSBITS 55#if WSBITS > 16 56 _bltui \mask, 0x10000, 99f 57 addi \bit, \bit, -16 58 extui \mask, \mask, 16, 16 59#endif 60#if WSBITS > 8 6199: _bltui \mask, 0x100, 99f 62 addi \bit, \bit, -8 63 srli \mask, \mask, 8 64#endif 6599: _bltui \mask, 0x10, 99f 66 addi \bit, \bit, -4 67 srli \mask, \mask, 4 6899: _bltui \mask, 0x4, 99f 69 addi \bit, \bit, -2 70 srli \mask, \mask, 2 7199: _bltui \mask, 0x2, 99f 72 addi \bit, \bit, -1 7399: 74 75#endif 76 .endm 77 78/* ----------------- DEFAULT FIRST LEVEL EXCEPTION HANDLERS ----------------- */ 79 80/* 81 * First-level exception handler for user exceptions. 82 * Save some special registers, extra states and all registers in the AR 83 * register file that were in use in the user task, and jump to the common 84 * exception code. 85 * We save SAR (used to calculate WMASK), and WB and WS (we don't have to 86 * save them for kernel exceptions). 87 * 88 * Entry condition for user_exception: 89 * 90 * a0: trashed, original value saved on stack (PT_AREG0) 91 * a1: a1 92 * a2: new stack pointer, original value in depc 93 * a3: a3 94 * depc: a2, original value saved on stack (PT_DEPC) 95 * excsave1: dispatch table 96 * 97 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 98 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 99 * 100 * Entry condition for _user_exception: 101 * 102 * a0-a3 and depc have been saved to PT_AREG0...PT_AREG3 and PT_DEPC 103 * excsave has been restored, and 104 * stack pointer (a1) has been set. 105 * 106 * Note: _user_exception might be at an odd address. Don't use call0..call12 107 */ 108 109ENTRY(user_exception) 110 111 /* Save a1, a2, a3, and set SP. */ 112 113 rsr a0, depc 114 s32i a1, a2, PT_AREG1 115 s32i a0, a2, PT_AREG2 116 s32i a3, a2, PT_AREG3 117 mov a1, a2 118 119 .globl _user_exception 120_user_exception: 121 122 /* Save SAR and turn off single stepping */ 123 124 movi a2, 0 125 wsr a2, depc # terminate user stack trace with 0 126 rsr a3, sar 127 xsr a2, icountlevel 128 s32i a3, a1, PT_SAR 129 s32i a2, a1, PT_ICOUNTLEVEL 130 131#if XCHAL_HAVE_THREADPTR 132 rur a2, threadptr 133 s32i a2, a1, PT_THREADPTR 134#endif 135 136 /* Rotate ws so that the current windowbase is at bit0. */ 137 /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */ 138 139 rsr a2, windowbase 140 rsr a3, windowstart 141 ssr a2 142 s32i a2, a1, PT_WINDOWBASE 143 s32i a3, a1, PT_WINDOWSTART 144 slli a2, a3, 32-WSBITS 145 src a2, a3, a2 146 srli a2, a2, 32-WSBITS 147 s32i a2, a1, PT_WMASK # needed for restoring registers 148 149 /* Save only live registers. */ 150 151 _bbsi.l a2, 1, 1f 152 s32i a4, a1, PT_AREG4 153 s32i a5, a1, PT_AREG5 154 s32i a6, a1, PT_AREG6 155 s32i a7, a1, PT_AREG7 156 _bbsi.l a2, 2, 1f 157 s32i a8, a1, PT_AREG8 158 s32i a9, a1, PT_AREG9 159 s32i a10, a1, PT_AREG10 160 s32i a11, a1, PT_AREG11 161 _bbsi.l a2, 3, 1f 162 s32i a12, a1, PT_AREG12 163 s32i a13, a1, PT_AREG13 164 s32i a14, a1, PT_AREG14 165 s32i a15, a1, PT_AREG15 166 _bnei a2, 1, 1f # only one valid frame? 167 168 /* Only one valid frame, skip saving regs. */ 169 170 j 2f 171 172 /* Save the remaining registers. 173 * We have to save all registers up to the first '1' from 174 * the right, except the current frame (bit 0). 175 * Assume a2 is: 001001000110001 176 * All register frames starting from the top field to the marked '1' 177 * must be saved. 178 */ 179 1801: addi a3, a2, -1 # eliminate '1' in bit 0: yyyyxxww0 181 neg a3, a3 # yyyyxxww0 -> YYYYXXWW1+1 182 and a3, a3, a2 # max. only one bit is set 183 184 /* Find number of frames to save */ 185 186 ffs_ws a0, a3 # number of frames to the '1' from left 187 188 /* Store information into WMASK: 189 * bits 0..3: xxx1 masked lower 4 bits of the rotated windowstart, 190 * bits 4...: number of valid 4-register frames 191 */ 192 193 slli a3, a0, 4 # number of frames to save in bits 8..4 194 extui a2, a2, 0, 4 # mask for the first 16 registers 195 or a2, a3, a2 196 s32i a2, a1, PT_WMASK # needed when we restore the reg-file 197 198 /* Save 4 registers at a time */ 199 2001: rotw -1 201 s32i a0, a5, PT_AREG_END - 16 202 s32i a1, a5, PT_AREG_END - 12 203 s32i a2, a5, PT_AREG_END - 8 204 s32i a3, a5, PT_AREG_END - 4 205 addi a0, a4, -1 206 addi a1, a5, -16 207 _bnez a0, 1b 208 209 /* WINDOWBASE still in SAR! */ 210 211 rsr a2, sar # original WINDOWBASE 212 movi a3, 1 213 ssl a2 214 sll a3, a3 215 wsr a3, windowstart # set corresponding WINDOWSTART bit 216 wsr a2, windowbase # and WINDOWSTART 217 rsync 218 219 /* We are back to the original stack pointer (a1) */ 220 2212: /* Now, jump to the common exception handler. */ 222 223 j common_exception 224 225ENDPROC(user_exception) 226 227/* 228 * First-level exit handler for kernel exceptions 229 * Save special registers and the live window frame. 230 * Note: Even though we changes the stack pointer, we don't have to do a 231 * MOVSP here, as we do that when we return from the exception. 232 * (See comment in the kernel exception exit code) 233 * 234 * Entry condition for kernel_exception: 235 * 236 * a0: trashed, original value saved on stack (PT_AREG0) 237 * a1: a1 238 * a2: new stack pointer, original in DEPC 239 * a3: a3 240 * depc: a2, original value saved on stack (PT_DEPC) 241 * excsave_1: dispatch table 242 * 243 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 244 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 245 * 246 * Entry condition for _kernel_exception: 247 * 248 * a0-a3 and depc have been saved to PT_AREG0...PT_AREG3 and PT_DEPC 249 * excsave has been restored, and 250 * stack pointer (a1) has been set. 251 * 252 * Note: _kernel_exception might be at an odd address. Don't use call0..call12 253 */ 254 255ENTRY(kernel_exception) 256 257 /* Save a1, a2, a3, and set SP. */ 258 259 rsr a0, depc # get a2 260 s32i a1, a2, PT_AREG1 261 s32i a0, a2, PT_AREG2 262 s32i a3, a2, PT_AREG3 263 mov a1, a2 264 265 .globl _kernel_exception 266_kernel_exception: 267 268 /* Save SAR and turn off single stepping */ 269 270 movi a2, 0 271 rsr a3, sar 272 xsr a2, icountlevel 273 s32i a3, a1, PT_SAR 274 s32i a2, a1, PT_ICOUNTLEVEL 275 276 /* Rotate ws so that the current windowbase is at bit0. */ 277 /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */ 278 279 rsr a2, windowbase # don't need to save these, we only 280 rsr a3, windowstart # need shifted windowstart: windowmask 281 ssr a2 282 slli a2, a3, 32-WSBITS 283 src a2, a3, a2 284 srli a2, a2, 32-WSBITS 285 s32i a2, a1, PT_WMASK # needed for kernel_exception_exit 286 287 /* Save only the live window-frame */ 288 289 _bbsi.l a2, 1, 1f 290 s32i a4, a1, PT_AREG4 291 s32i a5, a1, PT_AREG5 292 s32i a6, a1, PT_AREG6 293 s32i a7, a1, PT_AREG7 294 _bbsi.l a2, 2, 1f 295 s32i a8, a1, PT_AREG8 296 s32i a9, a1, PT_AREG9 297 s32i a10, a1, PT_AREG10 298 s32i a11, a1, PT_AREG11 299 _bbsi.l a2, 3, 1f 300 s32i a12, a1, PT_AREG12 301 s32i a13, a1, PT_AREG13 302 s32i a14, a1, PT_AREG14 303 s32i a15, a1, PT_AREG15 304 305 _bnei a2, 1, 1f 306 307 /* Copy spill slots of a0 and a1 to imitate movsp 308 * in order to keep exception stack continuous 309 */ 310 l32i a3, a1, PT_SIZE 311 l32i a0, a1, PT_SIZE + 4 312 s32e a3, a1, -16 313 s32e a0, a1, -12 3141: 315 l32i a0, a1, PT_AREG0 # restore saved a0 316 wsr a0, depc 317 318#ifdef KERNEL_STACK_OVERFLOW_CHECK 319 320 /* Stack overflow check, for debugging */ 321 extui a2, a1, TASK_SIZE_BITS,XX 322 movi a3, SIZE?? 323 _bge a2, a3, out_of_stack_panic 324 325#endif 326 327/* 328 * This is the common exception handler. 329 * We get here from the user exception handler or simply by falling through 330 * from the kernel exception handler. 331 * Save the remaining special registers, switch to kernel mode, and jump 332 * to the second-level exception handler. 333 * 334 */ 335 336common_exception: 337 338 /* Save some registers, disable loops and clear the syscall flag. */ 339 340 rsr a2, debugcause 341 rsr a3, epc1 342 s32i a2, a1, PT_DEBUGCAUSE 343 s32i a3, a1, PT_PC 344 345 movi a2, -1 346 rsr a3, excvaddr 347 s32i a2, a1, PT_SYSCALL 348 movi a2, 0 349 s32i a3, a1, PT_EXCVADDR 350 xsr a2, lcount 351 s32i a2, a1, PT_LCOUNT 352 353 /* It is now save to restore the EXC_TABLE_FIXUP variable. */ 354 355 rsr a0, exccause 356 movi a3, 0 357 rsr a2, excsave1 358 s32i a0, a1, PT_EXCCAUSE 359 s32i a3, a2, EXC_TABLE_FIXUP 360 361 /* All unrecoverable states are saved on stack, now, and a1 is valid. 362 * Now we can allow exceptions again. In case we've got an interrupt 363 * PS.INTLEVEL is set to LOCKLEVEL disabling furhter interrupts, 364 * otherwise it's left unchanged. 365 * 366 * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X) 367 */ 368 369 rsr a3, ps 370 addi a0, a0, -EXCCAUSE_LEVEL1_INTERRUPT 371 movi a2, LOCKLEVEL 372 extui a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH 373 # a3 = PS.INTLEVEL 374 moveqz a3, a2, a0 # a3 = LOCKLEVEL iff interrupt 375 movi a2, 1 << PS_WOE_BIT 376 or a3, a3, a2 377 rsr a2, exccause 378 /* restore return address (or 0 if return to userspace) */ 379 rsr a0, depc 380 xsr a3, ps 381 382 s32i a3, a1, PT_PS # save ps 383 384 /* Save lbeg, lend */ 385 386 rsr a4, lbeg 387 rsr a3, lend 388 s32i a4, a1, PT_LBEG 389 s32i a3, a1, PT_LEND 390 391 /* Save SCOMPARE1 */ 392 393#if XCHAL_HAVE_S32C1I 394 rsr a3, scompare1 395 s32i a3, a1, PT_SCOMPARE1 396#endif 397 398 /* Save optional registers. */ 399 400 save_xtregs_opt a1 a3 a4 a5 a6 a7 PT_XTREGS_OPT 401 402#ifdef CONFIG_TRACE_IRQFLAGS 403 l32i a4, a1, PT_DEPC 404 /* Double exception means we came here with an exception 405 * while PS.EXCM was set, i.e. interrupts disabled. 406 */ 407 bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f 408 bnei a2, EXCCAUSE_LEVEL1_INTERRUPT, 1f 409 /* We came here with an interrupt means interrupts were enabled 410 * and we've just disabled them. 411 */ 412 movi a4, trace_hardirqs_off 413 callx4 a4 4141: 415#endif 416 417 /* Go to second-level dispatcher. Set up parameters to pass to the 418 * exception handler and call the exception handler. 419 */ 420 421 rsr a4, excsave1 422 mov a6, a1 # pass stack frame 423 mov a7, a2 # pass EXCCAUSE 424 addx4 a4, a2, a4 425 l32i a4, a4, EXC_TABLE_DEFAULT # load handler 426 427 /* Call the second-level handler */ 428 429 callx4 a4 430 431 /* Jump here for exception exit */ 432 .global common_exception_return 433common_exception_return: 434 4351: 436 rsil a2, LOCKLEVEL 437 438 /* Jump if we are returning from kernel exceptions. */ 439 440 l32i a3, a1, PT_PS 441 GET_THREAD_INFO(a2, a1) 442 l32i a4, a2, TI_FLAGS 443 _bbci.l a3, PS_UM_BIT, 6f 444 445 /* Specific to a user exception exit: 446 * We need to check some flags for signal handling and rescheduling, 447 * and have to restore WB and WS, extra states, and all registers 448 * in the register file that were in use in the user task. 449 * Note that we don't disable interrupts here. 450 */ 451 452 _bbsi.l a4, TIF_NEED_RESCHED, 3f 453 _bbsi.l a4, TIF_NOTIFY_RESUME, 2f 454 _bbci.l a4, TIF_SIGPENDING, 5f 455 4562: l32i a4, a1, PT_DEPC 457 bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f 458 459 /* Call do_signal() */ 460 461 rsil a2, 0 462 movi a4, do_notify_resume # int do_notify_resume(struct pt_regs*) 463 mov a6, a1 464 callx4 a4 465 j 1b 466 4673: /* Reschedule */ 468 469 rsil a2, 0 470 movi a4, schedule # void schedule (void) 471 callx4 a4 472 j 1b 473 474#ifdef CONFIG_PREEMPT 4756: 476 _bbci.l a4, TIF_NEED_RESCHED, 4f 477 478 /* Check current_thread_info->preempt_count */ 479 480 l32i a4, a2, TI_PRE_COUNT 481 bnez a4, 4f 482 movi a4, preempt_schedule_irq 483 callx4 a4 484 j 1b 485#endif 486 4875: 488#ifdef CONFIG_DEBUG_TLB_SANITY 489 l32i a4, a1, PT_DEPC 490 bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f 491 movi a4, check_tlb_sanity 492 callx4 a4 493#endif 4946: 4954: 496#ifdef CONFIG_TRACE_IRQFLAGS 497 l32i a4, a1, PT_DEPC 498 /* Double exception means we came here with an exception 499 * while PS.EXCM was set, i.e. interrupts disabled. 500 */ 501 bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f 502 l32i a4, a1, PT_EXCCAUSE 503 bnei a4, EXCCAUSE_LEVEL1_INTERRUPT, 1f 504 /* We came here with an interrupt means interrupts were enabled 505 * and we'll reenable them on return. 506 */ 507 movi a4, trace_hardirqs_on 508 callx4 a4 5091: 510#endif 511 /* Restore optional registers. */ 512 513 load_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT 514 515 /* Restore SCOMPARE1 */ 516 517#if XCHAL_HAVE_S32C1I 518 l32i a2, a1, PT_SCOMPARE1 519 wsr a2, scompare1 520#endif 521 wsr a3, ps /* disable interrupts */ 522 523 _bbci.l a3, PS_UM_BIT, kernel_exception_exit 524 525user_exception_exit: 526 527 /* Restore the state of the task and return from the exception. */ 528 529 /* Switch to the user thread WINDOWBASE. Save SP temporarily in DEPC */ 530 531 l32i a2, a1, PT_WINDOWBASE 532 l32i a3, a1, PT_WINDOWSTART 533 wsr a1, depc # use DEPC as temp storage 534 wsr a3, windowstart # restore WINDOWSTART 535 ssr a2 # preserve user's WB in the SAR 536 wsr a2, windowbase # switch to user's saved WB 537 rsync 538 rsr a1, depc # restore stack pointer 539 l32i a2, a1, PT_WMASK # register frames saved (in bits 4...9) 540 rotw -1 # we restore a4..a7 541 _bltui a6, 16, 1f # only have to restore current window? 542 543 /* The working registers are a0 and a3. We are restoring to 544 * a4..a7. Be careful not to destroy what we have just restored. 545 * Note: wmask has the format YYYYM: 546 * Y: number of registers saved in groups of 4 547 * M: 4 bit mask of first 16 registers 548 */ 549 550 mov a2, a6 551 mov a3, a5 552 5532: rotw -1 # a0..a3 become a4..a7 554 addi a3, a7, -4*4 # next iteration 555 addi a2, a6, -16 # decrementing Y in WMASK 556 l32i a4, a3, PT_AREG_END + 0 557 l32i a5, a3, PT_AREG_END + 4 558 l32i a6, a3, PT_AREG_END + 8 559 l32i a7, a3, PT_AREG_END + 12 560 _bgeui a2, 16, 2b 561 562 /* Clear unrestored registers (don't leak anything to user-land */ 563 5641: rsr a0, windowbase 565 rsr a3, sar 566 sub a3, a0, a3 567 beqz a3, 2f 568 extui a3, a3, 0, WBBITS 569 5701: rotw -1 571 addi a3, a7, -1 572 movi a4, 0 573 movi a5, 0 574 movi a6, 0 575 movi a7, 0 576 bgei a3, 1, 1b 577 578 /* We are back were we were when we started. 579 * Note: a2 still contains WMASK (if we've returned to the original 580 * frame where we had loaded a2), or at least the lower 4 bits 581 * (if we have restored WSBITS-1 frames). 582 */ 583 5842: 585#if XCHAL_HAVE_THREADPTR 586 l32i a3, a1, PT_THREADPTR 587 wur a3, threadptr 588#endif 589 590 j common_exception_exit 591 592 /* This is the kernel exception exit. 593 * We avoided to do a MOVSP when we entered the exception, but we 594 * have to do it here. 595 */ 596 597kernel_exception_exit: 598 599 /* Check if we have to do a movsp. 600 * 601 * We only have to do a movsp if the previous window-frame has 602 * been spilled to the *temporary* exception stack instead of the 603 * task's stack. This is the case if the corresponding bit in 604 * WINDOWSTART for the previous window-frame was set before 605 * (not spilled) but is zero now (spilled). 606 * If this bit is zero, all other bits except the one for the 607 * current window frame are also zero. So, we can use a simple test: 608 * 'and' WINDOWSTART and WINDOWSTART-1: 609 * 610 * (XXXXXX1[0]* - 1) AND XXXXXX1[0]* = XXXXXX0[0]* 611 * 612 * The result is zero only if one bit was set. 613 * 614 * (Note: We might have gone through several task switches before 615 * we come back to the current task, so WINDOWBASE might be 616 * different from the time the exception occurred.) 617 */ 618 619 /* Test WINDOWSTART before and after the exception. 620 * We actually have WMASK, so we only have to test if it is 1 or not. 621 */ 622 623 l32i a2, a1, PT_WMASK 624 _beqi a2, 1, common_exception_exit # Spilled before exception,jump 625 626 /* Test WINDOWSTART now. If spilled, do the movsp */ 627 628 rsr a3, windowstart 629 addi a0, a3, -1 630 and a3, a3, a0 631 _bnez a3, common_exception_exit 632 633 /* Do a movsp (we returned from a call4, so we have at least a0..a7) */ 634 635 addi a0, a1, -16 636 l32i a3, a0, 0 637 l32i a4, a0, 4 638 s32i a3, a1, PT_SIZE+0 639 s32i a4, a1, PT_SIZE+4 640 l32i a3, a0, 8 641 l32i a4, a0, 12 642 s32i a3, a1, PT_SIZE+8 643 s32i a4, a1, PT_SIZE+12 644 645 /* Common exception exit. 646 * We restore the special register and the current window frame, and 647 * return from the exception. 648 * 649 * Note: We expect a2 to hold PT_WMASK 650 */ 651 652common_exception_exit: 653 654 /* Restore address registers. */ 655 656 _bbsi.l a2, 1, 1f 657 l32i a4, a1, PT_AREG4 658 l32i a5, a1, PT_AREG5 659 l32i a6, a1, PT_AREG6 660 l32i a7, a1, PT_AREG7 661 _bbsi.l a2, 2, 1f 662 l32i a8, a1, PT_AREG8 663 l32i a9, a1, PT_AREG9 664 l32i a10, a1, PT_AREG10 665 l32i a11, a1, PT_AREG11 666 _bbsi.l a2, 3, 1f 667 l32i a12, a1, PT_AREG12 668 l32i a13, a1, PT_AREG13 669 l32i a14, a1, PT_AREG14 670 l32i a15, a1, PT_AREG15 671 672 /* Restore PC, SAR */ 673 6741: l32i a2, a1, PT_PC 675 l32i a3, a1, PT_SAR 676 wsr a2, epc1 677 wsr a3, sar 678 679 /* Restore LBEG, LEND, LCOUNT */ 680 681 l32i a2, a1, PT_LBEG 682 l32i a3, a1, PT_LEND 683 wsr a2, lbeg 684 l32i a2, a1, PT_LCOUNT 685 wsr a3, lend 686 wsr a2, lcount 687 688 /* We control single stepping through the ICOUNTLEVEL register. */ 689 690 l32i a2, a1, PT_ICOUNTLEVEL 691 movi a3, -2 692 wsr a2, icountlevel 693 wsr a3, icount 694 695 /* Check if it was double exception. */ 696 697 l32i a0, a1, PT_DEPC 698 l32i a3, a1, PT_AREG3 699 l32i a2, a1, PT_AREG2 700 _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f 701 702 /* Restore a0...a3 and return */ 703 704 l32i a0, a1, PT_AREG0 705 l32i a1, a1, PT_AREG1 706 rfe 707 7081: wsr a0, depc 709 l32i a0, a1, PT_AREG0 710 l32i a1, a1, PT_AREG1 711 rfde 712 713ENDPROC(kernel_exception) 714 715/* 716 * Debug exception handler. 717 * 718 * Currently, we don't support KGDB, so only user application can be debugged. 719 * 720 * When we get here, a0 is trashed and saved to excsave[debuglevel] 721 */ 722 723ENTRY(debug_exception) 724 725 rsr a0, SREG_EPS + XCHAL_DEBUGLEVEL 726 bbsi.l a0, PS_EXCM_BIT, 1f # exception mode 727 728 /* Set EPC1 and EXCCAUSE */ 729 730 wsr a2, depc # save a2 temporarily 731 rsr a2, SREG_EPC + XCHAL_DEBUGLEVEL 732 wsr a2, epc1 733 734 movi a2, EXCCAUSE_MAPPED_DEBUG 735 wsr a2, exccause 736 737 /* Restore PS to the value before the debug exc but with PS.EXCM set.*/ 738 739 movi a2, 1 << PS_EXCM_BIT 740 or a2, a0, a2 741 movi a0, debug_exception # restore a3, debug jump vector 742 wsr a2, ps 743 xsr a0, SREG_EXCSAVE + XCHAL_DEBUGLEVEL 744 745 /* Switch to kernel/user stack, restore jump vector, and save a0 */ 746 747 bbsi.l a2, PS_UM_BIT, 2f # jump if user mode 748 749 addi a2, a1, -16-PT_SIZE # assume kernel stack 750 s32i a0, a2, PT_AREG0 751 movi a0, 0 752 s32i a1, a2, PT_AREG1 753 s32i a0, a2, PT_DEPC # mark it as a regular exception 754 xsr a0, depc 755 s32i a3, a2, PT_AREG3 756 s32i a0, a2, PT_AREG2 757 mov a1, a2 758 j _kernel_exception 759 7602: rsr a2, excsave1 761 l32i a2, a2, EXC_TABLE_KSTK # load kernel stack pointer 762 s32i a0, a2, PT_AREG0 763 movi a0, 0 764 s32i a1, a2, PT_AREG1 765 s32i a0, a2, PT_DEPC 766 xsr a0, depc 767 s32i a3, a2, PT_AREG3 768 s32i a0, a2, PT_AREG2 769 mov a1, a2 770 j _user_exception 771 772 /* Debug exception while in exception mode. */ 7731: j 1b // FIXME!! 774 775ENDPROC(debug_exception) 776 777/* 778 * We get here in case of an unrecoverable exception. 779 * The only thing we can do is to be nice and print a panic message. 780 * We only produce a single stack frame for panic, so ??? 781 * 782 * 783 * Entry conditions: 784 * 785 * - a0 contains the caller address; original value saved in excsave1. 786 * - the original a0 contains a valid return address (backtrace) or 0. 787 * - a2 contains a valid stackpointer 788 * 789 * Notes: 790 * 791 * - If the stack pointer could be invalid, the caller has to setup a 792 * dummy stack pointer (e.g. the stack of the init_task) 793 * 794 * - If the return address could be invalid, the caller has to set it 795 * to 0, so the backtrace would stop. 796 * 797 */ 798 .align 4 799unrecoverable_text: 800 .ascii "Unrecoverable error in exception handler\0" 801 802ENTRY(unrecoverable_exception) 803 804 movi a0, 1 805 movi a1, 0 806 807 wsr a0, windowstart 808 wsr a1, windowbase 809 rsync 810 811 movi a1, (1 << PS_WOE_BIT) | LOCKLEVEL 812 wsr a1, ps 813 rsync 814 815 movi a1, init_task 816 movi a0, 0 817 addi a1, a1, PT_REGS_OFFSET 818 819 movi a4, panic 820 movi a6, unrecoverable_text 821 822 callx4 a4 823 8241: j 1b 825 826ENDPROC(unrecoverable_exception) 827 828/* -------------------------- FAST EXCEPTION HANDLERS ----------------------- */ 829 830/* 831 * Fast-handler for alloca exceptions 832 * 833 * The ALLOCA handler is entered when user code executes the MOVSP 834 * instruction and the caller's frame is not in the register file. 835 * 836 * This algorithm was taken from the Ross Morley's RTOS Porting Layer: 837 * 838 * /home/ross/rtos/porting/XtensaRTOS-PortingLayer-20090507/xtensa_vectors.S 839 * 840 * It leverages the existing window spill/fill routines and their support for 841 * double exceptions. The 'movsp' instruction will only cause an exception if 842 * the next window needs to be loaded. In fact this ALLOCA exception may be 843 * replaced at some point by changing the hardware to do a underflow exception 844 * of the proper size instead. 845 * 846 * This algorithm simply backs out the register changes started by the user 847 * excpetion handler, makes it appear that we have started a window underflow 848 * by rotating the window back and then setting the old window base (OWB) in 849 * the 'ps' register with the rolled back window base. The 'movsp' instruction 850 * will be re-executed and this time since the next window frames is in the 851 * active AR registers it won't cause an exception. 852 * 853 * If the WindowUnderflow code gets a TLB miss the page will get mapped 854 * the the partial windeowUnderflow will be handeled in the double exception 855 * handler. 856 * 857 * Entry condition: 858 * 859 * a0: trashed, original value saved on stack (PT_AREG0) 860 * a1: a1 861 * a2: new stack pointer, original in DEPC 862 * a3: a3 863 * depc: a2, original value saved on stack (PT_DEPC) 864 * excsave_1: dispatch table 865 * 866 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 867 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 868 */ 869 870ENTRY(fast_alloca) 871 rsr a0, windowbase 872 rotw -1 873 rsr a2, ps 874 extui a3, a2, PS_OWB_SHIFT, PS_OWB_WIDTH 875 xor a3, a3, a4 876 l32i a4, a6, PT_AREG0 877 l32i a1, a6, PT_DEPC 878 rsr a6, depc 879 wsr a1, depc 880 slli a3, a3, PS_OWB_SHIFT 881 xor a2, a2, a3 882 wsr a2, ps 883 rsync 884 885 _bbci.l a4, 31, 4f 886 rotw -1 887 _bbci.l a8, 30, 8f 888 rotw -1 889 j _WindowUnderflow12 8908: j _WindowUnderflow8 8914: j _WindowUnderflow4 892ENDPROC(fast_alloca) 893 894/* 895 * fast system calls. 896 * 897 * WARNING: The kernel doesn't save the entire user context before 898 * handling a fast system call. These functions are small and short, 899 * usually offering some functionality not available to user tasks. 900 * 901 * BE CAREFUL TO PRESERVE THE USER'S CONTEXT. 902 * 903 * Entry condition: 904 * 905 * a0: trashed, original value saved on stack (PT_AREG0) 906 * a1: a1 907 * a2: new stack pointer, original in DEPC 908 * a3: a3 909 * depc: a2, original value saved on stack (PT_DEPC) 910 * excsave_1: dispatch table 911 */ 912 913ENTRY(fast_syscall_kernel) 914 915 /* Skip syscall. */ 916 917 rsr a0, epc1 918 addi a0, a0, 3 919 wsr a0, epc1 920 921 l32i a0, a2, PT_DEPC 922 bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_syscall_unrecoverable 923 924 rsr a0, depc # get syscall-nr 925 _beqz a0, fast_syscall_spill_registers 926 _beqi a0, __NR_xtensa, fast_syscall_xtensa 927 928 j kernel_exception 929 930ENDPROC(fast_syscall_kernel) 931 932ENTRY(fast_syscall_user) 933 934 /* Skip syscall. */ 935 936 rsr a0, epc1 937 addi a0, a0, 3 938 wsr a0, epc1 939 940 l32i a0, a2, PT_DEPC 941 bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_syscall_unrecoverable 942 943 rsr a0, depc # get syscall-nr 944 _beqz a0, fast_syscall_spill_registers 945 _beqi a0, __NR_xtensa, fast_syscall_xtensa 946 947 j user_exception 948 949ENDPROC(fast_syscall_user) 950 951ENTRY(fast_syscall_unrecoverable) 952 953 /* Restore all states. */ 954 955 l32i a0, a2, PT_AREG0 # restore a0 956 xsr a2, depc # restore a2, depc 957 958 wsr a0, excsave1 959 movi a0, unrecoverable_exception 960 callx0 a0 961 962ENDPROC(fast_syscall_unrecoverable) 963 964/* 965 * sysxtensa syscall handler 966 * 967 * int sysxtensa (SYS_XTENSA_ATOMIC_SET, ptr, val, unused); 968 * int sysxtensa (SYS_XTENSA_ATOMIC_ADD, ptr, val, unused); 969 * int sysxtensa (SYS_XTENSA_ATOMIC_EXG_ADD, ptr, val, unused); 970 * int sysxtensa (SYS_XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval); 971 * a2 a6 a3 a4 a5 972 * 973 * Entry condition: 974 * 975 * a0: a2 (syscall-nr), original value saved on stack (PT_AREG0) 976 * a1: a1 977 * a2: new stack pointer, original in a0 and DEPC 978 * a3: a3 979 * a4..a15: unchanged 980 * depc: a2, original value saved on stack (PT_DEPC) 981 * excsave_1: dispatch table 982 * 983 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 984 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 985 * 986 * Note: we don't have to save a2; a2 holds the return value 987 * 988 * We use the two macros TRY and CATCH: 989 * 990 * TRY adds an entry to the __ex_table fixup table for the immediately 991 * following instruction. 992 * 993 * CATCH catches any exception that occurred at one of the preceding TRY 994 * statements and continues from there 995 * 996 * Usage TRY l32i a0, a1, 0 997 * <other code> 998 * done: rfe 999 * CATCH <set return code> 1000 * j done 1001 */ 1002 1003#ifdef CONFIG_FAST_SYSCALL_XTENSA 1004 1005#define TRY \ 1006 .section __ex_table, "a"; \ 1007 .word 66f, 67f; \ 1008 .text; \ 100966: 1010 1011#define CATCH \ 101267: 1013 1014ENTRY(fast_syscall_xtensa) 1015 1016 s32i a7, a2, PT_AREG7 # we need an additional register 1017 movi a7, 4 # sizeof(unsigned int) 1018 access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp 1019 1020 _bgeui a6, SYS_XTENSA_COUNT, .Lill 1021 _bnei a6, SYS_XTENSA_ATOMIC_CMP_SWP, .Lnswp 1022 1023 /* Fall through for ATOMIC_CMP_SWP. */ 1024 1025.Lswp: /* Atomic compare and swap */ 1026 1027TRY l32i a0, a3, 0 # read old value 1028 bne a0, a4, 1f # same as old value? jump 1029TRY s32i a5, a3, 0 # different, modify value 1030 l32i a7, a2, PT_AREG7 # restore a7 1031 l32i a0, a2, PT_AREG0 # restore a0 1032 movi a2, 1 # and return 1 1033 rfe 1034 10351: l32i a7, a2, PT_AREG7 # restore a7 1036 l32i a0, a2, PT_AREG0 # restore a0 1037 movi a2, 0 # return 0 (note that we cannot set 1038 rfe 1039 1040.Lnswp: /* Atomic set, add, and exg_add. */ 1041 1042TRY l32i a7, a3, 0 # orig 1043 addi a6, a6, -SYS_XTENSA_ATOMIC_SET 1044 add a0, a4, a7 # + arg 1045 moveqz a0, a4, a6 # set 1046 addi a6, a6, SYS_XTENSA_ATOMIC_SET 1047TRY s32i a0, a3, 0 # write new value 1048 1049 mov a0, a2 1050 mov a2, a7 1051 l32i a7, a0, PT_AREG7 # restore a7 1052 l32i a0, a0, PT_AREG0 # restore a0 1053 rfe 1054 1055CATCH 1056.Leac: l32i a7, a2, PT_AREG7 # restore a7 1057 l32i a0, a2, PT_AREG0 # restore a0 1058 movi a2, -EFAULT 1059 rfe 1060 1061.Lill: l32i a7, a2, PT_AREG7 # restore a7 1062 l32i a0, a2, PT_AREG0 # restore a0 1063 movi a2, -EINVAL 1064 rfe 1065 1066ENDPROC(fast_syscall_xtensa) 1067 1068#else /* CONFIG_FAST_SYSCALL_XTENSA */ 1069 1070ENTRY(fast_syscall_xtensa) 1071 1072 l32i a0, a2, PT_AREG0 # restore a0 1073 movi a2, -ENOSYS 1074 rfe 1075 1076ENDPROC(fast_syscall_xtensa) 1077 1078#endif /* CONFIG_FAST_SYSCALL_XTENSA */ 1079 1080 1081/* fast_syscall_spill_registers. 1082 * 1083 * Entry condition: 1084 * 1085 * a0: trashed, original value saved on stack (PT_AREG0) 1086 * a1: a1 1087 * a2: new stack pointer, original in DEPC 1088 * a3: a3 1089 * depc: a2, original value saved on stack (PT_DEPC) 1090 * excsave_1: dispatch table 1091 * 1092 * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler. 1093 */ 1094 1095#ifdef CONFIG_FAST_SYSCALL_SPILL_REGISTERS 1096 1097ENTRY(fast_syscall_spill_registers) 1098 1099 /* Register a FIXUP handler (pass current wb as a parameter) */ 1100 1101 xsr a3, excsave1 1102 movi a0, fast_syscall_spill_registers_fixup 1103 s32i a0, a3, EXC_TABLE_FIXUP 1104 rsr a0, windowbase 1105 s32i a0, a3, EXC_TABLE_PARAM 1106 xsr a3, excsave1 # restore a3 and excsave_1 1107 1108 /* Save a3, a4 and SAR on stack. */ 1109 1110 rsr a0, sar 1111 s32i a3, a2, PT_AREG3 1112 s32i a0, a2, PT_SAR 1113 1114 /* The spill routine might clobber a4, a7, a8, a11, a12, and a15. */ 1115 1116 s32i a4, a2, PT_AREG4 1117 s32i a7, a2, PT_AREG7 1118 s32i a8, a2, PT_AREG8 1119 s32i a11, a2, PT_AREG11 1120 s32i a12, a2, PT_AREG12 1121 s32i a15, a2, PT_AREG15 1122 1123 /* 1124 * Rotate ws so that the current windowbase is at bit 0. 1125 * Assume ws = xxxwww1yy (www1 current window frame). 1126 * Rotate ws right so that a4 = yyxxxwww1. 1127 */ 1128 1129 rsr a0, windowbase 1130 rsr a3, windowstart # a3 = xxxwww1yy 1131 ssr a0 # holds WB 1132 slli a0, a3, WSBITS 1133 or a3, a3, a0 # a3 = xxxwww1yyxxxwww1yy 1134 srl a3, a3 # a3 = 00xxxwww1yyxxxwww1 1135 1136 /* We are done if there are no more than the current register frame. */ 1137 1138 extui a3, a3, 1, WSBITS-1 # a3 = 0yyxxxwww 1139 movi a0, (1 << (WSBITS-1)) 1140 _beqz a3, .Lnospill # only one active frame? jump 1141 1142 /* We want 1 at the top, so that we return to the current windowbase */ 1143 1144 or a3, a3, a0 # 1yyxxxwww 1145 1146 /* Skip empty frames - get 'oldest' WINDOWSTART-bit. */ 1147 1148 wsr a3, windowstart # save shifted windowstart 1149 neg a0, a3 1150 and a3, a0, a3 # first bit set from right: 000010000 1151 1152 ffs_ws a0, a3 # a0: shifts to skip empty frames 1153 movi a3, WSBITS 1154 sub a0, a3, a0 # WSBITS-a0:number of 0-bits from right 1155 ssr a0 # save in SAR for later. 1156 1157 rsr a3, windowbase 1158 add a3, a3, a0 1159 wsr a3, windowbase 1160 rsync 1161 1162 rsr a3, windowstart 1163 srl a3, a3 # shift windowstart 1164 1165 /* WB is now just one frame below the oldest frame in the register 1166 window. WS is shifted so the oldest frame is in bit 0, thus, WB 1167 and WS differ by one 4-register frame. */ 1168 1169 /* Save frames. Depending what call was used (call4, call8, call12), 1170 * we have to save 4,8. or 12 registers. 1171 */ 1172 1173 1174.Lloop: _bbsi.l a3, 1, .Lc4 1175 _bbci.l a3, 2, .Lc12 1176 1177.Lc8: s32e a4, a13, -16 1178 l32e a4, a5, -12 1179 s32e a8, a4, -32 1180 s32e a5, a13, -12 1181 s32e a6, a13, -8 1182 s32e a7, a13, -4 1183 s32e a9, a4, -28 1184 s32e a10, a4, -24 1185 s32e a11, a4, -20 1186 srli a11, a3, 2 # shift windowbase by 2 1187 rotw 2 1188 _bnei a3, 1, .Lloop 1189 j .Lexit 1190 1191.Lc4: s32e a4, a9, -16 1192 s32e a5, a9, -12 1193 s32e a6, a9, -8 1194 s32e a7, a9, -4 1195 1196 srli a7, a3, 1 1197 rotw 1 1198 _bnei a3, 1, .Lloop 1199 j .Lexit 1200 1201.Lc12: _bbci.l a3, 3, .Linvalid_mask # bit 2 shouldn't be zero! 1202 1203 /* 12-register frame (call12) */ 1204 1205 l32e a0, a5, -12 1206 s32e a8, a0, -48 1207 mov a8, a0 1208 1209 s32e a9, a8, -44 1210 s32e a10, a8, -40 1211 s32e a11, a8, -36 1212 s32e a12, a8, -32 1213 s32e a13, a8, -28 1214 s32e a14, a8, -24 1215 s32e a15, a8, -20 1216 srli a15, a3, 3 1217 1218 /* The stack pointer for a4..a7 is out of reach, so we rotate the 1219 * window, grab the stackpointer, and rotate back. 1220 * Alternatively, we could also use the following approach, but that 1221 * makes the fixup routine much more complicated: 1222 * rotw 1 1223 * s32e a0, a13, -16 1224 * ... 1225 * rotw 2 1226 */ 1227 1228 rotw 1 1229 mov a4, a13 1230 rotw -1 1231 1232 s32e a4, a8, -16 1233 s32e a5, a8, -12 1234 s32e a6, a8, -8 1235 s32e a7, a8, -4 1236 1237 rotw 3 1238 1239 _beqi a3, 1, .Lexit 1240 j .Lloop 1241 1242.Lexit: 1243 1244 /* Done. Do the final rotation and set WS */ 1245 1246 rotw 1 1247 rsr a3, windowbase 1248 ssl a3 1249 movi a3, 1 1250 sll a3, a3 1251 wsr a3, windowstart 1252.Lnospill: 1253 1254 /* Advance PC, restore registers and SAR, and return from exception. */ 1255 1256 l32i a3, a2, PT_SAR 1257 l32i a0, a2, PT_AREG0 1258 wsr a3, sar 1259 l32i a3, a2, PT_AREG3 1260 1261 /* Restore clobbered registers. */ 1262 1263 l32i a4, a2, PT_AREG4 1264 l32i a7, a2, PT_AREG7 1265 l32i a8, a2, PT_AREG8 1266 l32i a11, a2, PT_AREG11 1267 l32i a12, a2, PT_AREG12 1268 l32i a15, a2, PT_AREG15 1269 1270 movi a2, 0 1271 rfe 1272 1273.Linvalid_mask: 1274 1275 /* We get here because of an unrecoverable error in the window 1276 * registers, so set up a dummy frame and kill the user application. 1277 * Note: We assume EXC_TABLE_KSTK contains a valid stack pointer. 1278 */ 1279 1280 movi a0, 1 1281 movi a1, 0 1282 1283 wsr a0, windowstart 1284 wsr a1, windowbase 1285 rsync 1286 1287 movi a0, 0 1288 1289 rsr a3, excsave1 1290 l32i a1, a3, EXC_TABLE_KSTK 1291 1292 movi a4, (1 << PS_WOE_BIT) | LOCKLEVEL 1293 wsr a4, ps 1294 rsync 1295 1296 movi a6, SIGSEGV 1297 movi a4, do_exit 1298 callx4 a4 1299 1300 /* shouldn't return, so panic */ 1301 1302 wsr a0, excsave1 1303 movi a0, unrecoverable_exception 1304 callx0 a0 # should not return 13051: j 1b 1306 1307 1308ENDPROC(fast_syscall_spill_registers) 1309 1310/* Fixup handler. 1311 * 1312 * We get here if the spill routine causes an exception, e.g. tlb miss. 1313 * We basically restore WINDOWBASE and WINDOWSTART to the condition when 1314 * we entered the spill routine and jump to the user exception handler. 1315 * 1316 * Note that we only need to restore the bits in windowstart that have not 1317 * been spilled yet by the _spill_register routine. Luckily, a3 contains a 1318 * rotated windowstart with only those bits set for frames that haven't been 1319 * spilled yet. Because a3 is rotated such that bit 0 represents the register 1320 * frame for the current windowbase - 1, we need to rotate a3 left by the 1321 * value of the current windowbase + 1 and move it to windowstart. 1322 * 1323 * a0: value of depc, original value in depc 1324 * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE 1325 * a3: exctable, original value in excsave1 1326 */ 1327 1328ENTRY(fast_syscall_spill_registers_fixup) 1329 1330 rsr a2, windowbase # get current windowbase (a2 is saved) 1331 xsr a0, depc # restore depc and a0 1332 ssl a2 # set shift (32 - WB) 1333 1334 /* We need to make sure the current registers (a0-a3) are preserved. 1335 * To do this, we simply set the bit for the current window frame 1336 * in WS, so that the exception handlers save them to the task stack. 1337 * 1338 * Note: we use a3 to set the windowbase, so we take a special care 1339 * of it, saving it in the original _spill_registers frame across 1340 * the exception handler call. 1341 */ 1342 1343 xsr a3, excsave1 # get spill-mask 1344 slli a3, a3, 1 # shift left by one 1345 addi a3, a3, 1 # set the bit for the current window frame 1346 1347 slli a2, a3, 32-WSBITS 1348 src a2, a3, a2 # a2 = xxwww1yyxxxwww1yy...... 1349 wsr a2, windowstart # set corrected windowstart 1350 1351 srli a3, a3, 1 1352 rsr a2, excsave1 1353 l32i a2, a2, EXC_TABLE_DOUBLE_SAVE # restore a2 1354 xsr a2, excsave1 1355 s32i a3, a2, EXC_TABLE_DOUBLE_SAVE # save a3 1356 l32i a3, a2, EXC_TABLE_PARAM # original WB (in user task) 1357 xsr a2, excsave1 1358 1359 /* Return to the original (user task) WINDOWBASE. 1360 * We leave the following frame behind: 1361 * a0, a1, a2 same 1362 * a3: trashed (saved in EXC_TABLE_DOUBLE_SAVE) 1363 * depc: depc (we have to return to that address) 1364 * excsave_1: exctable 1365 */ 1366 1367 wsr a3, windowbase 1368 rsync 1369 1370 /* We are now in the original frame when we entered _spill_registers: 1371 * a0: return address 1372 * a1: used, stack pointer 1373 * a2: kernel stack pointer 1374 * a3: available 1375 * depc: exception address 1376 * excsave: exctable 1377 * Note: This frame might be the same as above. 1378 */ 1379 1380 /* Setup stack pointer. */ 1381 1382 addi a2, a2, -PT_USER_SIZE 1383 s32i a0, a2, PT_AREG0 1384 1385 /* Make sure we return to this fixup handler. */ 1386 1387 movi a3, fast_syscall_spill_registers_fixup_return 1388 s32i a3, a2, PT_DEPC # setup depc 1389 1390 /* Jump to the exception handler. */ 1391 1392 rsr a3, excsave1 1393 rsr a0, exccause 1394 addx4 a0, a0, a3 # find entry in table 1395 l32i a0, a0, EXC_TABLE_FAST_USER # load handler 1396 l32i a3, a3, EXC_TABLE_DOUBLE_SAVE 1397 jx a0 1398 1399ENDPROC(fast_syscall_spill_registers_fixup) 1400 1401ENTRY(fast_syscall_spill_registers_fixup_return) 1402 1403 /* When we return here, all registers have been restored (a2: DEPC) */ 1404 1405 wsr a2, depc # exception address 1406 1407 /* Restore fixup handler. */ 1408 1409 rsr a2, excsave1 1410 s32i a3, a2, EXC_TABLE_DOUBLE_SAVE 1411 movi a3, fast_syscall_spill_registers_fixup 1412 s32i a3, a2, EXC_TABLE_FIXUP 1413 rsr a3, windowbase 1414 s32i a3, a2, EXC_TABLE_PARAM 1415 l32i a2, a2, EXC_TABLE_KSTK 1416 1417 /* Load WB at the time the exception occurred. */ 1418 1419 rsr a3, sar # WB is still in SAR 1420 neg a3, a3 1421 wsr a3, windowbase 1422 rsync 1423 1424 rsr a3, excsave1 1425 l32i a3, a3, EXC_TABLE_DOUBLE_SAVE 1426 1427 rfde 1428 1429ENDPROC(fast_syscall_spill_registers_fixup_return) 1430 1431#else /* CONFIG_FAST_SYSCALL_SPILL_REGISTERS */ 1432 1433ENTRY(fast_syscall_spill_registers) 1434 1435 l32i a0, a2, PT_AREG0 # restore a0 1436 movi a2, -ENOSYS 1437 rfe 1438 1439ENDPROC(fast_syscall_spill_registers) 1440 1441#endif /* CONFIG_FAST_SYSCALL_SPILL_REGISTERS */ 1442 1443#ifdef CONFIG_MMU 1444/* 1445 * We should never get here. Bail out! 1446 */ 1447 1448ENTRY(fast_second_level_miss_double_kernel) 1449 14501: movi a0, unrecoverable_exception 1451 callx0 a0 # should not return 14521: j 1b 1453 1454ENDPROC(fast_second_level_miss_double_kernel) 1455 1456/* First-level entry handler for user, kernel, and double 2nd-level 1457 * TLB miss exceptions. Note that for now, user and kernel miss 1458 * exceptions share the same entry point and are handled identically. 1459 * 1460 * An old, less-efficient C version of this function used to exist. 1461 * We include it below, interleaved as comments, for reference. 1462 * 1463 * Entry condition: 1464 * 1465 * a0: trashed, original value saved on stack (PT_AREG0) 1466 * a1: a1 1467 * a2: new stack pointer, original in DEPC 1468 * a3: a3 1469 * depc: a2, original value saved on stack (PT_DEPC) 1470 * excsave_1: dispatch table 1471 * 1472 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 1473 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 1474 */ 1475 1476ENTRY(fast_second_level_miss) 1477 1478 /* Save a1 and a3. Note: we don't expect a double exception. */ 1479 1480 s32i a1, a2, PT_AREG1 1481 s32i a3, a2, PT_AREG3 1482 1483 /* We need to map the page of PTEs for the user task. Find 1484 * the pointer to that page. Also, it's possible for tsk->mm 1485 * to be NULL while tsk->active_mm is nonzero if we faulted on 1486 * a vmalloc address. In that rare case, we must use 1487 * active_mm instead to avoid a fault in this handler. See 1488 * 1489 * http://mail.nl.linux.org/linux-mm/2002-08/msg00258.html 1490 * (or search Internet on "mm vs. active_mm") 1491 * 1492 * if (!mm) 1493 * mm = tsk->active_mm; 1494 * pgd = pgd_offset (mm, regs->excvaddr); 1495 * pmd = pmd_offset (pgd, regs->excvaddr); 1496 * pmdval = *pmd; 1497 */ 1498 1499 GET_CURRENT(a1,a2) 1500 l32i a0, a1, TASK_MM # tsk->mm 1501 beqz a0, 9f 1502 15038: rsr a3, excvaddr # fault address 1504 _PGD_OFFSET(a0, a3, a1) 1505 l32i a0, a0, 0 # read pmdval 1506 beqz a0, 2f 1507 1508 /* Read ptevaddr and convert to top of page-table page. 1509 * 1510 * vpnval = read_ptevaddr_register() & PAGE_MASK; 1511 * vpnval += DTLB_WAY_PGTABLE; 1512 * pteval = mk_pte (virt_to_page(pmd_val(pmdval)), PAGE_KERNEL); 1513 * write_dtlb_entry (pteval, vpnval); 1514 * 1515 * The messy computation for 'pteval' above really simplifies 1516 * into the following: 1517 * 1518 * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_DIRECTORY 1519 */ 1520 1521 movi a1, (-PAGE_OFFSET) & 0xffffffff 1522 add a0, a0, a1 # pmdval - PAGE_OFFSET 1523 extui a1, a0, 0, PAGE_SHIFT # ... & PAGE_MASK 1524 xor a0, a0, a1 1525 1526 movi a1, _PAGE_DIRECTORY 1527 or a0, a0, a1 # ... | PAGE_DIRECTORY 1528 1529 /* 1530 * We utilize all three wired-ways (7-9) to hold pmd translations. 1531 * Memory regions are mapped to the DTLBs according to bits 28 and 29. 1532 * This allows to map the three most common regions to three different 1533 * DTLBs: 1534 * 0,1 -> way 7 program (0040.0000) and virtual (c000.0000) 1535 * 2 -> way 8 shared libaries (2000.0000) 1536 * 3 -> way 0 stack (3000.0000) 1537 */ 1538 1539 extui a3, a3, 28, 2 # addr. bit 28 and 29 0,1,2,3 1540 rsr a1, ptevaddr 1541 addx2 a3, a3, a3 # -> 0,3,6,9 1542 srli a1, a1, PAGE_SHIFT 1543 extui a3, a3, 2, 2 # -> 0,0,1,2 1544 slli a1, a1, PAGE_SHIFT # ptevaddr & PAGE_MASK 1545 addi a3, a3, DTLB_WAY_PGD 1546 add a1, a1, a3 # ... + way_number 1547 15483: wdtlb a0, a1 1549 dsync 1550 1551 /* Exit critical section. */ 1552 15534: rsr a3, excsave1 1554 movi a0, 0 1555 s32i a0, a3, EXC_TABLE_FIXUP 1556 1557 /* Restore the working registers, and return. */ 1558 1559 l32i a0, a2, PT_AREG0 1560 l32i a1, a2, PT_AREG1 1561 l32i a3, a2, PT_AREG3 1562 l32i a2, a2, PT_DEPC 1563 1564 bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f 1565 1566 /* Restore excsave1 and return. */ 1567 1568 rsr a2, depc 1569 rfe 1570 1571 /* Return from double exception. */ 1572 15731: xsr a2, depc 1574 esync 1575 rfde 1576 15779: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 0 1578 j 8b 1579 1580#if (DCACHE_WAY_SIZE > PAGE_SIZE) 1581 15822: /* Special case for cache aliasing. 1583 * We (should) only get here if a clear_user_page, copy_user_page 1584 * or the aliased cache flush functions got preemptively interrupted 1585 * by another task. Re-establish temporary mapping to the 1586 * TLBTEMP_BASE areas. 1587 */ 1588 1589 /* We shouldn't be in a double exception */ 1590 1591 l32i a0, a2, PT_DEPC 1592 bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 2f 1593 1594 /* Make sure the exception originated in the special functions */ 1595 1596 movi a0, __tlbtemp_mapping_start 1597 rsr a3, epc1 1598 bltu a3, a0, 2f 1599 movi a0, __tlbtemp_mapping_end 1600 bgeu a3, a0, 2f 1601 1602 /* Check if excvaddr was in one of the TLBTEMP_BASE areas. */ 1603 1604 movi a3, TLBTEMP_BASE_1 1605 rsr a0, excvaddr 1606 bltu a0, a3, 2f 1607 1608 addi a1, a0, -TLBTEMP_SIZE 1609 bgeu a1, a3, 2f 1610 1611 /* Check if we have to restore an ITLB mapping. */ 1612 1613 movi a1, __tlbtemp_mapping_itlb 1614 rsr a3, epc1 1615 sub a3, a3, a1 1616 1617 /* Calculate VPN */ 1618 1619 movi a1, PAGE_MASK 1620 and a1, a1, a0 1621 1622 /* Jump for ITLB entry */ 1623 1624 bgez a3, 1f 1625 1626 /* We can use up to two TLBTEMP areas, one for src and one for dst. */ 1627 1628 extui a3, a0, PAGE_SHIFT + DCACHE_ALIAS_ORDER, 1 1629 add a1, a3, a1 1630 1631 /* PPN is in a6 for the first TLBTEMP area and in a7 for the second. */ 1632 1633 mov a0, a6 1634 movnez a0, a7, a3 1635 j 3b 1636 1637 /* ITLB entry. We only use dst in a6. */ 1638 16391: witlb a6, a1 1640 isync 1641 j 4b 1642 1643 1644#endif // DCACHE_WAY_SIZE > PAGE_SIZE 1645 1646 16472: /* Invalid PGD, default exception handling */ 1648 1649 rsr a1, depc 1650 s32i a1, a2, PT_AREG2 1651 mov a1, a2 1652 1653 rsr a2, ps 1654 bbsi.l a2, PS_UM_BIT, 1f 1655 j _kernel_exception 16561: j _user_exception 1657 1658ENDPROC(fast_second_level_miss) 1659 1660/* 1661 * StoreProhibitedException 1662 * 1663 * Update the pte and invalidate the itlb mapping for this pte. 1664 * 1665 * Entry condition: 1666 * 1667 * a0: trashed, original value saved on stack (PT_AREG0) 1668 * a1: a1 1669 * a2: new stack pointer, original in DEPC 1670 * a3: a3 1671 * depc: a2, original value saved on stack (PT_DEPC) 1672 * excsave_1: dispatch table 1673 * 1674 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 1675 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 1676 */ 1677 1678ENTRY(fast_store_prohibited) 1679 1680 /* Save a1 and a3. */ 1681 1682 s32i a1, a2, PT_AREG1 1683 s32i a3, a2, PT_AREG3 1684 1685 GET_CURRENT(a1,a2) 1686 l32i a0, a1, TASK_MM # tsk->mm 1687 beqz a0, 9f 1688 16898: rsr a1, excvaddr # fault address 1690 _PGD_OFFSET(a0, a1, a3) 1691 l32i a0, a0, 0 1692 beqz a0, 2f 1693 1694 /* 1695 * Note that we test _PAGE_WRITABLE_BIT only if PTE is present 1696 * and is not PAGE_NONE. See pgtable.h for possible PTE layouts. 1697 */ 1698 1699 _PTE_OFFSET(a0, a1, a3) 1700 l32i a3, a0, 0 # read pteval 1701 movi a1, _PAGE_CA_INVALID 1702 ball a3, a1, 2f 1703 bbci.l a3, _PAGE_WRITABLE_BIT, 2f 1704 1705 movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE 1706 or a3, a3, a1 1707 rsr a1, excvaddr 1708 s32i a3, a0, 0 1709 1710 /* We need to flush the cache if we have page coloring. */ 1711#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK 1712 dhwb a0, 0 1713#endif 1714 pdtlb a0, a1 1715 wdtlb a3, a0 1716 1717 /* Exit critical section. */ 1718 1719 movi a0, 0 1720 rsr a3, excsave1 1721 s32i a0, a3, EXC_TABLE_FIXUP 1722 1723 /* Restore the working registers, and return. */ 1724 1725 l32i a3, a2, PT_AREG3 1726 l32i a1, a2, PT_AREG1 1727 l32i a0, a2, PT_AREG0 1728 l32i a2, a2, PT_DEPC 1729 1730 bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f 1731 1732 rsr a2, depc 1733 rfe 1734 1735 /* Double exception. Restore FIXUP handler and return. */ 1736 17371: xsr a2, depc 1738 esync 1739 rfde 1740 17419: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 0 1742 j 8b 1743 17442: /* If there was a problem, handle fault in C */ 1745 1746 rsr a3, depc # still holds a2 1747 s32i a3, a2, PT_AREG2 1748 mov a1, a2 1749 1750 rsr a2, ps 1751 bbsi.l a2, PS_UM_BIT, 1f 1752 j _kernel_exception 17531: j _user_exception 1754 1755ENDPROC(fast_store_prohibited) 1756 1757#endif /* CONFIG_MMU */ 1758 1759/* 1760 * System Calls. 1761 * 1762 * void system_call (struct pt_regs* regs, int exccause) 1763 * a2 a3 1764 */ 1765 1766ENTRY(system_call) 1767 1768 entry a1, 32 1769 1770 /* regs->syscall = regs->areg[2] */ 1771 1772 l32i a3, a2, PT_AREG2 1773 mov a6, a2 1774 movi a4, do_syscall_trace_enter 1775 s32i a3, a2, PT_SYSCALL 1776 callx4 a4 1777 1778 /* syscall = sys_call_table[syscall_nr] */ 1779 1780 movi a4, sys_call_table; 1781 movi a5, __NR_syscall_count 1782 movi a6, -ENOSYS 1783 bgeu a3, a5, 1f 1784 1785 addx4 a4, a3, a4 1786 l32i a4, a4, 0 1787 movi a5, sys_ni_syscall; 1788 beq a4, a5, 1f 1789 1790 /* Load args: arg0 - arg5 are passed via regs. */ 1791 1792 l32i a6, a2, PT_AREG6 1793 l32i a7, a2, PT_AREG3 1794 l32i a8, a2, PT_AREG4 1795 l32i a9, a2, PT_AREG5 1796 l32i a10, a2, PT_AREG8 1797 l32i a11, a2, PT_AREG9 1798 1799 /* Pass one additional argument to the syscall: pt_regs (on stack) */ 1800 s32i a2, a1, 0 1801 1802 callx4 a4 1803 18041: /* regs->areg[2] = return_value */ 1805 1806 s32i a6, a2, PT_AREG2 1807 movi a4, do_syscall_trace_leave 1808 mov a6, a2 1809 callx4 a4 1810 retw 1811 1812ENDPROC(system_call) 1813 1814/* 1815 * Spill live registers on the kernel stack macro. 1816 * 1817 * Entry condition: ps.woe is set, ps.excm is cleared 1818 * Exit condition: windowstart has single bit set 1819 * May clobber: a12, a13 1820 */ 1821 .macro spill_registers_kernel 1822 1823#if XCHAL_NUM_AREGS > 16 1824 call12 1f 1825 _j 2f 1826 retw 1827 .align 4 18281: 1829 _entry a1, 48 1830 addi a12, a0, 3 1831#if XCHAL_NUM_AREGS > 32 1832 .rept (XCHAL_NUM_AREGS - 32) / 12 1833 _entry a1, 48 1834 mov a12, a0 1835 .endr 1836#endif 1837 _entry a1, 48 1838#if XCHAL_NUM_AREGS % 12 == 0 1839 mov a8, a8 1840#elif XCHAL_NUM_AREGS % 12 == 4 1841 mov a12, a12 1842#elif XCHAL_NUM_AREGS % 12 == 8 1843 mov a4, a4 1844#endif 1845 retw 18462: 1847#else 1848 mov a12, a12 1849#endif 1850 .endm 1851 1852/* 1853 * Task switch. 1854 * 1855 * struct task* _switch_to (struct task* prev, struct task* next) 1856 * a2 a2 a3 1857 */ 1858 1859ENTRY(_switch_to) 1860 1861 entry a1, 16 1862 1863 mov a11, a3 # and 'next' (a3) 1864 1865 l32i a4, a2, TASK_THREAD_INFO 1866 l32i a5, a3, TASK_THREAD_INFO 1867 1868 save_xtregs_user a4 a6 a8 a9 a12 a13 THREAD_XTREGS_USER 1869 1870#if THREAD_RA > 1020 || THREAD_SP > 1020 1871 addi a10, a2, TASK_THREAD 1872 s32i a0, a10, THREAD_RA - TASK_THREAD # save return address 1873 s32i a1, a10, THREAD_SP - TASK_THREAD # save stack pointer 1874#else 1875 s32i a0, a2, THREAD_RA # save return address 1876 s32i a1, a2, THREAD_SP # save stack pointer 1877#endif 1878 1879 /* Disable ints while we manipulate the stack pointer. */ 1880 1881 rsil a14, LOCKLEVEL 1882 rsr a3, excsave1 1883 rsync 1884 s32i a3, a3, EXC_TABLE_FIXUP /* enter critical section */ 1885 1886 /* Switch CPENABLE */ 1887 1888#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS) 1889 l32i a3, a5, THREAD_CPENABLE 1890 xsr a3, cpenable 1891 s32i a3, a4, THREAD_CPENABLE 1892#endif 1893 1894 /* Flush register file. */ 1895 1896 spill_registers_kernel 1897 1898 /* Set kernel stack (and leave critical section) 1899 * Note: It's save to set it here. The stack will not be overwritten 1900 * because the kernel stack will only be loaded again after 1901 * we return from kernel space. 1902 */ 1903 1904 rsr a3, excsave1 # exc_table 1905 movi a6, 0 1906 addi a7, a5, PT_REGS_OFFSET 1907 s32i a6, a3, EXC_TABLE_FIXUP 1908 s32i a7, a3, EXC_TABLE_KSTK 1909 1910 /* restore context of the task 'next' */ 1911 1912 l32i a0, a11, THREAD_RA # restore return address 1913 l32i a1, a11, THREAD_SP # restore stack pointer 1914 1915 load_xtregs_user a5 a6 a8 a9 a12 a13 THREAD_XTREGS_USER 1916 1917 wsr a14, ps 1918 rsync 1919 1920 retw 1921 1922ENDPROC(_switch_to) 1923 1924ENTRY(ret_from_fork) 1925 1926 /* void schedule_tail (struct task_struct *prev) 1927 * Note: prev is still in a6 (return value from fake call4 frame) 1928 */ 1929 movi a4, schedule_tail 1930 callx4 a4 1931 1932 movi a4, do_syscall_trace_leave 1933 mov a6, a1 1934 callx4 a4 1935 1936 j common_exception_return 1937 1938ENDPROC(ret_from_fork) 1939 1940/* 1941 * Kernel thread creation helper 1942 * On entry, set up by copy_thread: a2 = thread_fn, a3 = thread_fn arg 1943 * left from _switch_to: a6 = prev 1944 */ 1945ENTRY(ret_from_kernel_thread) 1946 1947 call4 schedule_tail 1948 mov a6, a3 1949 callx4 a2 1950 j common_exception_return 1951 1952ENDPROC(ret_from_kernel_thread) 1953