]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ARC: r25 saved/restored for K->K transitions as well
authorVineet Gupta <vgupta@synopsys.com>
Tue, 28 May 2013 08:20:41 +0000 (13:50 +0530)
committerVineet Gupta <vgupta@synopsys.com>
Mon, 17 Jun 2013 13:02:22 +0000 (18:32 +0530)
(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>
arch/arc/include/asm/entry.h
arch/arc/include/asm/processor.h
arch/arc/include/asm/ptrace.h
arch/arc/kernel/asm-offsets.c
arch/arc/kernel/entry.S
arch/arc/kernel/process.c

index 2cf6aa08cfca5b9eec1207bd70f346d10835c8e5..72a7ed47117a30c0f617d96069c61ba60a40e1d6 100644 (file)
        POP     r2
        POP     r1
        POP     r0
+
+#ifdef CONFIG_ARC_CURR_IN_REG
+       ld      r25, [sp, 12]
+#endif
 .endm
 
 /*--------------------------------------------------------------
        POP     r13
 .endm
 
+#define OFF_USER_R25_FROM_R24  (SZ_CALLEE_REGS + SZ_PT_REGS - 8)/4
 
 /*--------------------------------------------------------------
  * Collect User Mode callee regs as struct callee_regs - needed by
 
 #ifdef CONFIG_ARC_CURR_IN_REG
        ; Retrieve orig r25 and save it on stack
-       ld      r12, [r25, TASK_THREAD + THREAD_USER_R25]
+       ld.as   r12, [sp, OFF_USER_R25_FROM_R24]
        st.a    r12, [sp, -4]
 #else
        PUSH    r25
 
 #ifdef CONFIG_ARC_CURR_IN_REG
        ld.ab   r12, [sp, 4]
-       st      r12, [r25, TASK_THREAD + THREAD_USER_R25]
+       st.as   r12, [sp, OFF_USER_R25_FROM_R24]
 #else
        POP     r25
 #endif
        add     sp, sp, SZ_CALLEE_REGS
 .endm
 
-/*--------------------------------------------------------------
- * Restore User mode r25 saved in task_struct->thread.user_r25
- *-------------------------------------------------------------*/
-.macro RESTORE_USER_R25
-       ld  r25, [r25, TASK_THREAD + THREAD_USER_R25]
-.endm
-
 /*-------------------------------------------------------------
  * given a tsk struct, get to the base of it's kernel mode stack
  * tsk->thread_info is really a PAGE, whose bottom hoists stack
 
        GET_CURR_TASK_ON_CPU   r9
 
-#ifdef CONFIG_ARC_CURR_IN_REG
-
-       /* If current task pointer cached in r25, time to
-        *  -safekeep USER r25 in task->thread_struct->user_r25
-        *  -load r25 with current task ptr
-        */
-       st.as   r25, [r9, (TASK_THREAD + THREAD_USER_R25)/4]
-       mov     r25, r9
-#endif
-
        /* With current tsk in r9, get it's kernel mode stack base */
        GET_TSK_STACK_BASE  r9, r9
 
 66:
+#ifdef CONFIG_ARC_CURR_IN_REG
+       /*
+        * Treat r25 as scratch reg, save it on stack first
+        * Load it with current task pointer
+        */
+       st      r25, [r9, -4]
+       GET_CURR_TASK_ON_CPU   r25
+#endif
+
        /* Save Pre Intr/Exception User SP on kernel stack */
-       st.a    sp, [r9, -12]   ; Make room for orig_r0 and orig_r8
+       st.a    sp, [r9, -16]   ; Make room for orig_r0, orig_r8, user_r25
 
        /* CAUTION:
         * SP should be set at the very end when we are done with everything
        RESTORE_R12_TO_R0
 
        ld  sp, [sp] /* restore original sp */
-       /* orig_r0 and orig_r8 skipped automatically */
+       /* orig_r0, orig_r8, user_r25 skipped automatically */
 .endm
 
 
        RESTORE_R12_TO_R0
 
        ld  sp, [sp] /* restore original sp */
-       /* orig_r0 and orig_r8 skipped automatically */
+       /* orig_r0, orig_r8, user_r25 skipped automatically */
 .endm
 
 .macro RESTORE_ALL_INT2
        RESTORE_R12_TO_R0
 
        ld  sp, [sp] /* restore original sp */
-       /* orig_r0 and orig_r8 skipped automatically */
+       /* orig_r0, orig_r8, user_r25 skipped automatically */
 .endm
 
 
index 8c77e623c4e5bf908611c3c13f6d5e90a8ba427b..b0b5d2d9b3d3654895f2048f52f6d92022a194a8 100644 (file)
@@ -30,9 +30,6 @@ struct thread_struct {
        unsigned long callee_reg;       /* pointer to callee regs */
        unsigned long fault_address;    /* dbls as brkpt holder as well */
        unsigned long cause_code;       /* Exception Cause Code (ECR) */
-#ifdef CONFIG_ARC_CURR_IN_REG
-       unsigned long user_r25;
-#endif
 #ifdef CONFIG_ARC_FPU_SAVE_RESTORE
        struct arc_fpu fpu;
 #endif
index 47801ba135b3b4bf2c0f743b03838454e7748b31..7b2de6f7025a22c4e58ebe70832cc25d1f715aca 100644 (file)
@@ -54,6 +54,8 @@ struct pt_regs {
 #endif
                long orig_r8_word;
        };
+
+       long user_r25;
 };
 
 /* Callee saved registers - need to be saved only when you are scheduled out */
index fdcd76532b7069f81cc4bfa2cf87a349ccf3e637..75f05b83d77d309322122c7d4c2b05b0f5f64f6a 100644 (file)
@@ -24,9 +24,6 @@ int main(void)
 
        DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
        DEFINE(THREAD_CALLEE_REG, offsetof(struct thread_struct, callee_reg));
-#ifdef CONFIG_ARC_CURR_IN_REG
-       DEFINE(THREAD_USER_R25, offsetof(struct thread_struct, user_r25));
-#endif
        DEFINE(THREAD_FAULT_ADDR,
               offsetof(struct thread_struct, fault_address));
 
@@ -61,5 +58,6 @@ int main(void)
        DEFINE(PT_r7, offsetof(struct pt_regs, r7));
 
        DEFINE(SZ_CALLEE_REGS, sizeof(struct callee_regs));
+       DEFINE(SZ_PT_REGS, sizeof(struct pt_regs));
        return 0;
 }
index 919e2f065d2fbd9cf05173a690c59a403d66776e..fd5f9160bbd215845f773454dba2e52cdb3d242e 100644 (file)
@@ -680,17 +680,6 @@ restore_regs :
        ; XXX can this be optimised out
        IRQ_DISABLE_SAVE    r9, r10     ;@r10 has prisitine (pre-disable) copy
 
-#ifdef CONFIG_ARC_CURR_IN_REG
-       ; Restore User R25
-       ; Earlier this used to be only for returning to user mode
-       ; However with 2 levels of IRQ this can also happen even if
-       ; in kernel mode
-       ld r9, [sp, PT_sp]
-       brhs r9, VMALLOC_START, 8f
-       RESTORE_USER_R25
-8:
-#endif
-
        ; Restore REG File. In case multiple Events outstanding,
        ; use the same priorty as rtie: EXCPN, L2 IRQ, L1 IRQ, None
        ; Note that we use realtime STATUS32 (not pt_regs->status32) to
index c6e22e060578e3f5c21d6a04d4b488dc54a06a33..a3cc6a57703924f29b0349b7cec8fea0c632c8ec 100644 (file)
@@ -77,6 +77,7 @@ asmlinkage void ret_from_fork(void);
  * |      SP        |
  * |    orig_r0     |
  * |    orig_r8     |
+ * |    user_r25    |
  * ------------------  <===== END of PAGE
  */
 int copy_thread(unsigned long clone_flags,