diff options
| -rw-r--r-- | arch/xtensa/kernel/vectors.S | 158 | ||||
| -rw-r--r-- | arch/xtensa/kernel/vmlinux.lds.S | 4 |
2 files changed, 138 insertions, 24 deletions
diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S index f9e1ec346e35..8453e6e39895 100644 --- a/arch/xtensa/kernel/vectors.S +++ b/arch/xtensa/kernel/vectors.S | |||
| @@ -376,38 +376,42 @@ _DoubleExceptionVector_WindowOverflow: | |||
| 376 | beqz a2, 1f # if at start of vector, don't restore | 376 | beqz a2, 1f # if at start of vector, don't restore |
| 377 | 377 | ||
| 378 | addi a0, a0, -128 | 378 | addi a0, a0, -128 |
| 379 | bbsi a0, 8, 1f # don't restore except for overflow 8 and 12 | 379 | bbsi.l a0, 8, 1f # don't restore except for overflow 8 and 12 |
| 380 | bbsi a0, 7, 2f | 380 | |
| 381 | /* | ||
| 382 | * This fixup handler is for the extremely unlikely case where the | ||
| 383 | * overflow handler's reference thru a0 gets a hardware TLB refill | ||
| 384 | * that bumps out the (distinct, aliasing) TLB entry that mapped its | ||
| 385 | * prior references thru a9/a13, and where our reference now thru | ||
| 386 | * a9/a13 gets a 2nd-level miss exception (not hardware TLB refill). | ||
| 387 | */ | ||
| 388 | movi a2, window_overflow_restore_a0_fixup | ||
| 389 | s32i a2, a3, EXC_TABLE_FIXUP | ||
| 390 | l32i a2, a3, EXC_TABLE_DOUBLE_SAVE | ||
| 391 | xsr a3, excsave1 | ||
| 392 | |||
| 393 | bbsi.l a0, 7, 2f | ||
| 381 | 394 | ||
| 382 | /* | 395 | /* |
| 383 | * Restore a0 as saved by _WindowOverflow8(). | 396 | * Restore a0 as saved by _WindowOverflow8(). |
| 384 | * | ||
| 385 | * FIXME: we really need a fixup handler for this L32E, | ||
| 386 | * for the extremely unlikely case where the overflow handler's | ||
| 387 | * reference thru a0 gets a hardware TLB refill that bumps out | ||
| 388 | * the (distinct, aliasing) TLB entry that mapped its prior | ||
| 389 | * references thru a9, and where our reference now thru a9 | ||
| 390 | * gets a 2nd-level miss exception (not hardware TLB refill). | ||
| 391 | */ | 397 | */ |
| 392 | 398 | ||
| 393 | l32e a2, a9, -16 | 399 | l32e a0, a9, -16 |
| 394 | wsr a2, depc # replace the saved a0 | 400 | wsr a0, depc # replace the saved a0 |
| 395 | j 1f | 401 | j 3f |
| 396 | 402 | ||
| 397 | 2: | 403 | 2: |
| 398 | /* | 404 | /* |
| 399 | * Restore a0 as saved by _WindowOverflow12(). | 405 | * Restore a0 as saved by _WindowOverflow12(). |
| 400 | * | ||
| 401 | * FIXME: we really need a fixup handler for this L32E, | ||
| 402 | * for the extremely unlikely case where the overflow handler's | ||
| 403 | * reference thru a0 gets a hardware TLB refill that bumps out | ||
| 404 | * the (distinct, aliasing) TLB entry that mapped its prior | ||
| 405 | * references thru a13, and where our reference now thru a13 | ||
| 406 | * gets a 2nd-level miss exception (not hardware TLB refill). | ||
| 407 | */ | 406 | */ |
| 408 | 407 | ||
| 409 | l32e a2, a13, -16 | 408 | l32e a0, a13, -16 |
| 410 | wsr a2, depc # replace the saved a0 | 409 | wsr a0, depc # replace the saved a0 |
| 410 | 3: | ||
| 411 | xsr a3, excsave1 | ||
| 412 | movi a0, 0 | ||
| 413 | s32i a0, a3, EXC_TABLE_FIXUP | ||
| 414 | s32i a2, a3, EXC_TABLE_DOUBLE_SAVE | ||
| 411 | 1: | 415 | 1: |
| 412 | /* | 416 | /* |
| 413 | * Restore WindowBase while leaving all address registers restored. | 417 | * Restore WindowBase while leaving all address registers restored. |
| @@ -449,6 +453,7 @@ _DoubleExceptionVector_WindowOverflow: | |||
| 449 | 453 | ||
| 450 | s32i a0, a2, PT_DEPC | 454 | s32i a0, a2, PT_DEPC |
| 451 | 455 | ||
| 456 | _DoubleExceptionVector_handle_exception: | ||
| 452 | addx4 a0, a0, a3 | 457 | addx4 a0, a0, a3 |
| 453 | l32i a0, a0, EXC_TABLE_FAST_USER | 458 | l32i a0, a0, EXC_TABLE_FAST_USER |
| 454 | xsr a3, excsave1 | 459 | xsr a3, excsave1 |
| @@ -464,11 +469,120 @@ _DoubleExceptionVector_WindowOverflow: | |||
| 464 | rotw -3 | 469 | rotw -3 |
| 465 | j 1b | 470 | j 1b |
| 466 | 471 | ||
| 467 | .end literal_prefix | ||
| 468 | 472 | ||
| 469 | ENDPROC(_DoubleExceptionVector) | 473 | ENDPROC(_DoubleExceptionVector) |
| 470 | 474 | ||
| 471 | /* | 475 | /* |
| 476 | * Fixup handler for TLB miss in double exception handler for window owerflow. | ||
| 477 | * We get here with windowbase set to the window that was being spilled and | ||
| 478 | * a0 trashed. a0 bit 7 determines if this is a call8 (bit clear) or call12 | ||
| 479 | * (bit set) window. | ||
| 480 | * | ||
| 481 | * We do the following here: | ||
| 482 | * - go to the original window retaining a0 value; | ||
| 483 | * - set up exception stack to return back to appropriate a0 restore code | ||
| 484 | * (we'll need to rotate window back and there's no place to save this | ||
| 485 | * information, use different return address for that); | ||
| 486 | * - handle the exception; | ||
| 487 | * - go to the window that was being spilled; | ||
| 488 | * - set up window_overflow_restore_a0_fixup as a fixup routine; | ||
| 489 | * - reload a0; | ||
| 490 | * - restore the original window; | ||
| 491 | * - reset the default fixup routine; | ||
| 492 | * - return to user. By the time we get to this fixup handler all information | ||
| 493 | * about the conditions of the original double exception that happened in | ||
| 494 | * the window overflow handler is lost, so we just return to userspace to | ||
| 495 | * retry overflow from start. | ||
| 496 | * | ||
| 497 | * a0: value of depc, original value in depc | ||
| 498 | * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE | ||
| 499 | * a3: exctable, original value in excsave1 | ||
| 500 | */ | ||
| 501 | |||
| 502 | ENTRY(window_overflow_restore_a0_fixup) | ||
| 503 | |||
| 504 | rsr a0, ps | ||
| 505 | extui a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH | ||
| 506 | rsr a2, windowbase | ||
| 507 | sub a0, a2, a0 | ||
| 508 | extui a0, a0, 0, 3 | ||
| 509 | l32i a2, a3, EXC_TABLE_DOUBLE_SAVE | ||
| 510 | xsr a3, excsave1 | ||
| 511 | |||
| 512 | _beqi a0, 1, .Lhandle_1 | ||
| 513 | _beqi a0, 3, .Lhandle_3 | ||
| 514 | |||
| 515 | .macro overflow_fixup_handle_exception_pane n | ||
| 516 | |||
| 517 | rsr a0, depc | ||
| 518 | rotw -\n | ||
| 519 | |||
| 520 | xsr a3, excsave1 | ||
| 521 | wsr a2, depc | ||
| 522 | l32i a2, a3, EXC_TABLE_KSTK | ||
| 523 | s32i a0, a2, PT_AREG0 | ||
| 524 | |||
| 525 | movi a0, .Lrestore_\n | ||
| 526 | s32i a0, a2, PT_DEPC | ||
| 527 | rsr a0, exccause | ||
| 528 | j _DoubleExceptionVector_handle_exception | ||
| 529 | |||
| 530 | .endm | ||
| 531 | |||
| 532 | overflow_fixup_handle_exception_pane 2 | ||
| 533 | .Lhandle_1: | ||
| 534 | overflow_fixup_handle_exception_pane 1 | ||
| 535 | .Lhandle_3: | ||
| 536 | overflow_fixup_handle_exception_pane 3 | ||
| 537 | |||
| 538 | .macro overflow_fixup_restore_a0_pane n | ||
| 539 | |||
| 540 | rotw \n | ||
| 541 | /* Need to preserve a0 value here to be able to handle exception | ||
| 542 | * that may occur on a0 reload from stack. It may occur because | ||
| 543 | * TLB miss handler may not be atomic and pointer to page table | ||
| 544 | * may be lost before we get here. There are no free registers, | ||
| 545 | * so we need to use EXC_TABLE_DOUBLE_SAVE area. | ||
| 546 | */ | ||
| 547 | xsr a3, excsave1 | ||
| 548 | s32i a2, a3, EXC_TABLE_DOUBLE_SAVE | ||
| 549 | movi a2, window_overflow_restore_a0_fixup | ||
| 550 | s32i a2, a3, EXC_TABLE_FIXUP | ||
| 551 | l32i a2, a3, EXC_TABLE_DOUBLE_SAVE | ||
| 552 | xsr a3, excsave1 | ||
| 553 | bbsi.l a0, 7, 1f | ||
| 554 | l32e a0, a9, -16 | ||
| 555 | j 2f | ||
| 556 | 1: | ||
| 557 | l32e a0, a13, -16 | ||
| 558 | 2: | ||
| 559 | rotw -\n | ||
| 560 | |||
| 561 | .endm | ||
| 562 | |||
| 563 | .Lrestore_2: | ||
| 564 | overflow_fixup_restore_a0_pane 2 | ||
| 565 | |||
| 566 | .Lset_default_fixup: | ||
| 567 | xsr a3, excsave1 | ||
| 568 | s32i a2, a3, EXC_TABLE_DOUBLE_SAVE | ||
| 569 | movi a2, 0 | ||
| 570 | s32i a2, a3, EXC_TABLE_FIXUP | ||
| 571 | l32i a2, a3, EXC_TABLE_DOUBLE_SAVE | ||
| 572 | xsr a3, excsave1 | ||
| 573 | rfe | ||
| 574 | |||
| 575 | .Lrestore_1: | ||
| 576 | overflow_fixup_restore_a0_pane 1 | ||
| 577 | j .Lset_default_fixup | ||
| 578 | .Lrestore_3: | ||
| 579 | overflow_fixup_restore_a0_pane 3 | ||
| 580 | j .Lset_default_fixup | ||
| 581 | |||
| 582 | ENDPROC(window_overflow_restore_a0_fixup) | ||
| 583 | |||
| 584 | .end literal_prefix | ||
| 585 | /* | ||
| 472 | * Debug interrupt vector | 586 | * Debug interrupt vector |
| 473 | * | 587 | * |
| 474 | * There is not much space here, so simply jump to another handler. | 588 | * There is not much space here, so simply jump to another handler. |
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S index ee32c0085dff..d16db6df86f8 100644 --- a/arch/xtensa/kernel/vmlinux.lds.S +++ b/arch/xtensa/kernel/vmlinux.lds.S | |||
| @@ -269,13 +269,13 @@ SECTIONS | |||
| 269 | .UserExceptionVector.literal) | 269 | .UserExceptionVector.literal) |
| 270 | SECTION_VECTOR (_DoubleExceptionVector_literal, | 270 | SECTION_VECTOR (_DoubleExceptionVector_literal, |
| 271 | .DoubleExceptionVector.literal, | 271 | .DoubleExceptionVector.literal, |
| 272 | DOUBLEEXC_VECTOR_VADDR - 16, | 272 | DOUBLEEXC_VECTOR_VADDR - 40, |
| 273 | SIZEOF(.UserExceptionVector.text), | 273 | SIZEOF(.UserExceptionVector.text), |
| 274 | .UserExceptionVector.text) | 274 | .UserExceptionVector.text) |
| 275 | SECTION_VECTOR (_DoubleExceptionVector_text, | 275 | SECTION_VECTOR (_DoubleExceptionVector_text, |
| 276 | .DoubleExceptionVector.text, | 276 | .DoubleExceptionVector.text, |
| 277 | DOUBLEEXC_VECTOR_VADDR, | 277 | DOUBLEEXC_VECTOR_VADDR, |
| 278 | 32, | 278 | 40, |
| 279 | .DoubleExceptionVector.literal) | 279 | .DoubleExceptionVector.literal) |
| 280 | 280 | ||
| 281 | . = (LOADADDR( .DoubleExceptionVector.text ) + SIZEOF( .DoubleExceptionVector.text ) + 3) & ~ 3; | 281 | . = (LOADADDR( .DoubleExceptionVector.text ) + SIZEOF( .DoubleExceptionVector.text ) + 3) & ~ 3; |
