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 |