aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arc
diff options
context:
space:
mode:
authorVineet Gupta <vgupta@synopsys.com>2013-05-28 04:20:41 -0400
committerVineet Gupta <vgupta@synopsys.com>2013-06-22 09:53:25 -0400
commit359105bdb06f8421fd8e69ae47fd052e398b6778 (patch)
tree025dfe3a68cb9afa0a6e877ad264bbb8cf957783 /arch/arc
parentba3558c772ce1ac64d07f46b8c763349a0e51ba3 (diff)
ARC: pt_regs update #4: r25 saved/restored unconditionally
(This is a VERY IMP change for low level interrupt/exception handling) ----------------------------------------------------------------------- WHAT ----------------------------------------------------------------------- * User 25 now saved in pt_regs->user_r25 (vs. tsk->thread_info.user_r25) * This allows Low level interrupt code to unconditionally save r25 (vs. the prev version which would only do it for U->K transition). Ofcourse for nested interrupts, only the pt_regs->user_r25 of bottom-most frame is useful. * simplifies the interrupt prologue/epilogue * Needed for ARCv2 ISA code and done here to keep design similar with ARCompact event handling ----------------------------------------------------------------------- WHY ------------------------------------------------------------------------- With CONFIG_ARC_CURR_IN_REG, r25 is used to cache "current" task pointer in kernel mode. So when entering kernel mode from User Mode - user r25 is specially safe-kept (it being a callee reg is NOT part of pt_regs which are saved by default on each interrupt/trap/exception) - r25 loaded with current task pointer. Further, if interrupt was taken in kernel mode, this is skipped since we know that r25 already has valid "current" pointer. With 2 level of interrupts in ARCompact ISA, detecting this is difficult but still possible, since we could be in kernel mode but r25 not already saved (in fact the stack itself might not have been switched). A. User mode B. L1 IRQ taken C. L2 IRQ taken (while on 1st line of L1 ISR) So in #C, although in kernel mode, r25 not saved (infact SP not switched at all) Given that ARcompact has manual stack switching, we could use a bit of trickey - The low level code would make sure that SP is only set to kernel mode value at the very end (after saving r25). So a non kernel mode SP, even if in kernel mode, meant r25 was NOT saved. The same paradigm won't work in ARCv2 ISA since SP is auto-switched so it's setting can't be delayed/constrained. Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Diffstat (limited to 'arch/arc')
-rw-r--r--arch/arc/include/asm/entry.h43
-rw-r--r--arch/arc/include/asm/processor.h3
-rw-r--r--arch/arc/include/asm/ptrace.h2
-rw-r--r--arch/arc/kernel/asm-offsets.c4
-rw-r--r--arch/arc/kernel/entry.S11
-rw-r--r--arch/arc/kernel/process.c1
6 files changed, 24 insertions, 40 deletions
diff --git a/arch/arc/include/asm/entry.h b/arch/arc/include/asm/entry.h
index 2cf6aa08cfca..72a7ed47117a 100644
--- a/arch/arc/include/asm/entry.h
+++ b/arch/arc/include/asm/entry.h
@@ -102,6 +102,10 @@
102 POP r2 102 POP r2
103 POP r1 103 POP r1
104 POP r0 104 POP r0
105
106#ifdef CONFIG_ARC_CURR_IN_REG
107 ld r25, [sp, 12]
108#endif
105.endm 109.endm
106 110
107/*-------------------------------------------------------------- 111/*--------------------------------------------------------------
@@ -138,6 +142,7 @@
138 POP r13 142 POP r13
139.endm 143.endm
140 144
145#define OFF_USER_R25_FROM_R24 (SZ_CALLEE_REGS + SZ_PT_REGS - 8)/4
141 146
142/*-------------------------------------------------------------- 147/*--------------------------------------------------------------
143 * Collect User Mode callee regs as struct callee_regs - needed by 148 * Collect User Mode callee regs as struct callee_regs - needed by
@@ -155,7 +160,7 @@
155 160
156#ifdef CONFIG_ARC_CURR_IN_REG 161#ifdef CONFIG_ARC_CURR_IN_REG
157 ; Retrieve orig r25 and save it on stack 162 ; Retrieve orig r25 and save it on stack
158 ld r12, [r25, TASK_THREAD + THREAD_USER_R25] 163 ld.as r12, [sp, OFF_USER_R25_FROM_R24]
159 st.a r12, [sp, -4] 164 st.a r12, [sp, -4]
160#else 165#else
161 PUSH r25 166 PUSH r25
@@ -204,7 +209,7 @@
204 209
205#ifdef CONFIG_ARC_CURR_IN_REG 210#ifdef CONFIG_ARC_CURR_IN_REG
206 ld.ab r12, [sp, 4] 211 ld.ab r12, [sp, 4]
207 st r12, [r25, TASK_THREAD + THREAD_USER_R25] 212 st.as r12, [sp, OFF_USER_R25_FROM_R24]
208#else 213#else
209 POP r25 214 POP r25
210#endif 215#endif
@@ -218,13 +223,6 @@
218 add sp, sp, SZ_CALLEE_REGS 223 add sp, sp, SZ_CALLEE_REGS
219.endm 224.endm
220 225
221/*--------------------------------------------------------------
222 * Restore User mode r25 saved in task_struct->thread.user_r25
223 *-------------------------------------------------------------*/
224.macro RESTORE_USER_R25
225 ld r25, [r25, TASK_THREAD + THREAD_USER_R25]
226.endm
227
228/*------------------------------------------------------------- 226/*-------------------------------------------------------------
229 * given a tsk struct, get to the base of it's kernel mode stack 227 * given a tsk struct, get to the base of it's kernel mode stack
230 * tsk->thread_info is really a PAGE, whose bottom hoists stack 228 * tsk->thread_info is really a PAGE, whose bottom hoists stack
@@ -297,22 +295,21 @@
297 295
298 GET_CURR_TASK_ON_CPU r9 296 GET_CURR_TASK_ON_CPU r9
299 297
300#ifdef CONFIG_ARC_CURR_IN_REG
301
302 /* If current task pointer cached in r25, time to
303 * -safekeep USER r25 in task->thread_struct->user_r25
304 * -load r25 with current task ptr
305 */
306 st.as r25, [r9, (TASK_THREAD + THREAD_USER_R25)/4]
307 mov r25, r9
308#endif
309
310 /* With current tsk in r9, get it's kernel mode stack base */ 298 /* With current tsk in r9, get it's kernel mode stack base */
311 GET_TSK_STACK_BASE r9, r9 299 GET_TSK_STACK_BASE r9, r9
312 300
31366: 30166:
302#ifdef CONFIG_ARC_CURR_IN_REG
303 /*
304 * Treat r25 as scratch reg, save it on stack first
305 * Load it with current task pointer
306 */
307 st r25, [r9, -4]
308 GET_CURR_TASK_ON_CPU r25
309#endif
310
314 /* Save Pre Intr/Exception User SP on kernel stack */ 311 /* Save Pre Intr/Exception User SP on kernel stack */
315 st.a sp, [r9, -12] ; Make room for orig_r0 and orig_r8 312 st.a sp, [r9, -16] ; Make room for orig_r0, orig_r8, user_r25
316 313
317 /* CAUTION: 314 /* CAUTION:
318 * SP should be set at the very end when we are done with everything 315 * SP should be set at the very end when we are done with everything
@@ -466,7 +463,7 @@
466 RESTORE_R12_TO_R0 463 RESTORE_R12_TO_R0
467 464
468 ld sp, [sp] /* restore original sp */ 465 ld sp, [sp] /* restore original sp */
469 /* orig_r0 and orig_r8 skipped automatically */ 466 /* orig_r0, orig_r8, user_r25 skipped automatically */
470.endm 467.endm
471 468
472 469
@@ -549,7 +546,7 @@
549 RESTORE_R12_TO_R0 546 RESTORE_R12_TO_R0
550 547
551 ld sp, [sp] /* restore original sp */ 548 ld sp, [sp] /* restore original sp */
552 /* orig_r0 and orig_r8 skipped automatically */ 549 /* orig_r0, orig_r8, user_r25 skipped automatically */
553.endm 550.endm
554 551
555.macro RESTORE_ALL_INT2 552.macro RESTORE_ALL_INT2
@@ -568,7 +565,7 @@
568 RESTORE_R12_TO_R0 565 RESTORE_R12_TO_R0
569 566
570 ld sp, [sp] /* restore original sp */ 567 ld sp, [sp] /* restore original sp */
571 /* orig_r0 and orig_r8 skipped automatically */ 568 /* orig_r0, orig_r8, user_r25 skipped automatically */
572.endm 569.endm
573 570
574 571
diff --git a/arch/arc/include/asm/processor.h b/arch/arc/include/asm/processor.h
index 8c77e623c4e5..b0b5d2d9b3d3 100644
--- a/arch/arc/include/asm/processor.h
+++ b/arch/arc/include/asm/processor.h
@@ -30,9 +30,6 @@ struct thread_struct {
30 unsigned long callee_reg; /* pointer to callee regs */ 30 unsigned long callee_reg; /* pointer to callee regs */
31 unsigned long fault_address; /* dbls as brkpt holder as well */ 31 unsigned long fault_address; /* dbls as brkpt holder as well */
32 unsigned long cause_code; /* Exception Cause Code (ECR) */ 32 unsigned long cause_code; /* Exception Cause Code (ECR) */
33#ifdef CONFIG_ARC_CURR_IN_REG
34 unsigned long user_r25;
35#endif
36#ifdef CONFIG_ARC_FPU_SAVE_RESTORE 33#ifdef CONFIG_ARC_FPU_SAVE_RESTORE
37 struct arc_fpu fpu; 34 struct arc_fpu fpu;
38#endif 35#endif
diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h
index 47801ba135b3..7b2de6f7025a 100644
--- a/arch/arc/include/asm/ptrace.h
+++ b/arch/arc/include/asm/ptrace.h
@@ -54,6 +54,8 @@ struct pt_regs {
54#endif 54#endif
55 long orig_r8_word; 55 long orig_r8_word;
56 }; 56 };
57
58 long user_r25;
57}; 59};
58 60
59/* Callee saved registers - need to be saved only when you are scheduled out */ 61/* Callee saved registers - need to be saved only when you are scheduled out */
diff --git a/arch/arc/kernel/asm-offsets.c b/arch/arc/kernel/asm-offsets.c
index fdcd76532b70..75f05b83d77d 100644
--- a/arch/arc/kernel/asm-offsets.c
+++ b/arch/arc/kernel/asm-offsets.c
@@ -24,9 +24,6 @@ int main(void)
24 24
25 DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp)); 25 DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
26 DEFINE(THREAD_CALLEE_REG, offsetof(struct thread_struct, callee_reg)); 26 DEFINE(THREAD_CALLEE_REG, offsetof(struct thread_struct, callee_reg));
27#ifdef CONFIG_ARC_CURR_IN_REG
28 DEFINE(THREAD_USER_R25, offsetof(struct thread_struct, user_r25));
29#endif
30 DEFINE(THREAD_FAULT_ADDR, 27 DEFINE(THREAD_FAULT_ADDR,
31 offsetof(struct thread_struct, fault_address)); 28 offsetof(struct thread_struct, fault_address));
32 29
@@ -61,5 +58,6 @@ int main(void)
61 DEFINE(PT_r7, offsetof(struct pt_regs, r7)); 58 DEFINE(PT_r7, offsetof(struct pt_regs, r7));
62 59
63 DEFINE(SZ_CALLEE_REGS, sizeof(struct callee_regs)); 60 DEFINE(SZ_CALLEE_REGS, sizeof(struct callee_regs));
61 DEFINE(SZ_PT_REGS, sizeof(struct pt_regs));
64 return 0; 62 return 0;
65} 63}
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S
index 919e2f065d2f..fd5f9160bbd2 100644
--- a/arch/arc/kernel/entry.S
+++ b/arch/arc/kernel/entry.S
@@ -680,17 +680,6 @@ restore_regs :
680 ; XXX can this be optimised out 680 ; XXX can this be optimised out
681 IRQ_DISABLE_SAVE r9, r10 ;@r10 has prisitine (pre-disable) copy 681 IRQ_DISABLE_SAVE r9, r10 ;@r10 has prisitine (pre-disable) copy
682 682
683#ifdef CONFIG_ARC_CURR_IN_REG
684 ; Restore User R25
685 ; Earlier this used to be only for returning to user mode
686 ; However with 2 levels of IRQ this can also happen even if
687 ; in kernel mode
688 ld r9, [sp, PT_sp]
689 brhs r9, VMALLOC_START, 8f
690 RESTORE_USER_R25
6918:
692#endif
693
694 ; Restore REG File. In case multiple Events outstanding, 683 ; Restore REG File. In case multiple Events outstanding,
695 ; use the same priorty as rtie: EXCPN, L2 IRQ, L1 IRQ, None 684 ; use the same priorty as rtie: EXCPN, L2 IRQ, L1 IRQ, None
696 ; Note that we use realtime STATUS32 (not pt_regs->status32) to 685 ; Note that we use realtime STATUS32 (not pt_regs->status32) to
diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c
index c6e22e060578..a3cc6a577039 100644
--- a/arch/arc/kernel/process.c
+++ b/arch/arc/kernel/process.c
@@ -77,6 +77,7 @@ asmlinkage void ret_from_fork(void);
77 * | SP | 77 * | SP |
78 * | orig_r0 | 78 * | orig_r0 |
79 * | orig_r8 | 79 * | orig_r8 |
80 * | user_r25 |
80 * ------------------ <===== END of PAGE 81 * ------------------ <===== END of PAGE
81 */ 82 */
82int copy_thread(unsigned long clone_flags, 83int copy_thread(unsigned long clone_flags,