diff options
| author | Chris Zankel <chris@zankel.net> | 2008-01-22 03:45:25 -0500 |
|---|---|---|
| committer | Chris Zankel <chris@zankel.net> | 2008-02-13 20:43:54 -0500 |
| commit | e1088430626b2ec4cd64f2fb7d9fd7c6df5d5824 (patch) | |
| tree | ce563e0400ad22974ae65e25d2534432f5d4e76b | |
| parent | 9f8fcf38e8928cccf8c7b32668d146e457f2ccf2 (diff) | |
[XTENSA] Fix register corruption for certain processor configurations
For processor configurations that have optional registers
(compiler-used but non-coprocessor), user space registers
might get corrupted when there are only 4 registers in
the current window-frame, ie. register a4 belongs to the
oldest frame in the register file.
Signed-off-by: Chris Zankel <chris@zankel.net>
| -rw-r--r-- | arch/xtensa/kernel/entry.S | 44 |
1 files changed, 15 insertions, 29 deletions
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 24770b6a5e4c..dfd35dcc1cb5 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S | |||
| @@ -395,55 +395,49 @@ common_exception_return: | |||
| 395 | /* Jump if we are returning from kernel exceptions. */ | 395 | /* Jump if we are returning from kernel exceptions. */ |
| 396 | 396 | ||
| 397 | 1: l32i a3, a1, PT_PS | 397 | 1: l32i a3, a1, PT_PS |
| 398 | _bbsi.l a3, PS_UM_BIT, 2f | 398 | _bbci.l a3, PS_UM_BIT, 4f |
| 399 | j kernel_exception_exit | ||
| 400 | 399 | ||
| 401 | /* Specific to a user exception exit: | 400 | /* Specific to a user exception exit: |
| 402 | * We need to check some flags for signal handling and rescheduling, | 401 | * We need to check some flags for signal handling and rescheduling, |
| 403 | * and have to restore WB and WS, extra states, and all registers | 402 | * and have to restore WB and WS, extra states, and all registers |
| 404 | * in the register file that were in use in the user task. | 403 | * in the register file that were in use in the user task. |
| 405 | */ | 404 | * Note that we don't disable interrupts here. |
| 406 | |||
| 407 | 2: wsr a3, PS /* disable interrupts */ | ||
| 408 | |||
| 409 | /* Check for signals (keep interrupts disabled while we read TI_FLAGS) | ||
| 410 | * Note: PS.INTLEVEL = 0, PS.EXCM = 1 | ||
| 411 | */ | 405 | */ |
| 412 | 406 | ||
| 413 | GET_THREAD_INFO(a2,a1) | 407 | GET_THREAD_INFO(a2,a1) |
| 414 | l32i a4, a2, TI_FLAGS | 408 | l32i a4, a2, TI_FLAGS |
| 415 | 409 | ||
| 416 | /* Enable interrupts again. | ||
| 417 | * Note: When we get here, we certainly have handled any interrupts. | ||
| 418 | * (Hint: There is only one user exception frame on stack) | ||
| 419 | */ | ||
| 420 | |||
| 421 | movi a3, 1 << PS_WOE_BIT | ||
| 422 | |||
| 423 | _bbsi.l a4, TIF_NEED_RESCHED, 3f | 410 | _bbsi.l a4, TIF_NEED_RESCHED, 3f |
| 424 | _bbci.l a4, TIF_SIGPENDING, 4f | 411 | _bbci.l a4, TIF_SIGPENDING, 4f |
| 425 | 412 | ||
| 426 | l32i a4, a1, PT_DEPC | 413 | l32i a4, a1, PT_DEPC |
| 427 | bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f | 414 | bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f |
| 428 | /* Reenable interrupts and call do_signal() */ | ||
| 429 | 415 | ||
| 430 | wsr a3, PS | 416 | /* Call do_signal() */ |
| 417 | |||
| 431 | movi a4, do_signal # int do_signal(struct pt_regs*, sigset_t*) | 418 | movi a4, do_signal # int do_signal(struct pt_regs*, sigset_t*) |
| 432 | mov a6, a1 | 419 | mov a6, a1 |
| 433 | movi a7, 0 | 420 | movi a7, 0 |
| 434 | callx4 a4 | 421 | callx4 a4 |
| 435 | j 1b | 422 | j 1b |
| 436 | 423 | ||
| 437 | 3: /* Reenable interrupts and reschedule */ | 424 | 3: /* Reschedule */ |
| 438 | 425 | ||
| 439 | wsr a3, PS | ||
| 440 | movi a4, schedule # void schedule (void) | 426 | movi a4, schedule # void schedule (void) |
| 441 | callx4 a4 | 427 | callx4 a4 |
| 442 | j 1b | 428 | j 1b |
| 443 | 429 | ||
| 444 | /* Restore the state of the task and return from the exception. */ | 430 | 4: /* Restore optional registers. */ |
| 431 | |||
| 432 | load_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT | ||
| 445 | 433 | ||
| 446 | 4: /* a2 holds GET_CURRENT(a2,a1) */ | 434 | wsr a3, PS /* disable interrupts */ |
| 435 | |||
| 436 | _bbci.l a3, PS_UM_BIT, kernel_exception_exit | ||
| 437 | |||
| 438 | user_exception_exit: | ||
| 439 | |||
| 440 | /* Restore the state of the task and return from the exception. */ | ||
| 447 | 441 | ||
| 448 | /* Switch to the user thread WINDOWBASE. Save SP temporarily in DEPC */ | 442 | /* Switch to the user thread WINDOWBASE. Save SP temporarily in DEPC */ |
| 449 | 443 | ||
| @@ -509,10 +503,6 @@ common_exception_return: | |||
| 509 | 503 | ||
| 510 | kernel_exception_exit: | 504 | kernel_exception_exit: |
| 511 | 505 | ||
| 512 | /* Disable interrupts (a3 holds PT_PS) */ | ||
| 513 | |||
| 514 | wsr a3, PS | ||
| 515 | |||
| 516 | #ifdef PREEMPTIBLE_KERNEL | 506 | #ifdef PREEMPTIBLE_KERNEL |
| 517 | 507 | ||
| 518 | #ifdef CONFIG_PREEMPT | 508 | #ifdef CONFIG_PREEMPT |
| @@ -591,10 +581,6 @@ kernel_exception_exit: | |||
| 591 | 581 | ||
| 592 | common_exception_exit: | 582 | common_exception_exit: |
| 593 | 583 | ||
| 594 | /* Restore optional registers. */ | ||
| 595 | |||
| 596 | load_xtregs_opt a1 a3 a4 a5 a6 a7 PT_XTREGS_OPT | ||
| 597 | |||
| 598 | /* Restore address registers. */ | 584 | /* Restore address registers. */ |
| 599 | 585 | ||
| 600 | _bbsi.l a2, 1, 1f | 586 | _bbsi.l a2, 1, 1f |
