ARC: entry: use gp to cache task pointer (vs. r25)
authorVineet Gupta <vgupta@kernel.org>
Wed, 13 May 2020 05:18:08 +0000 (22:18 -0700)
committerVineet Gupta <vgupta@kernel.org>
Fri, 18 Aug 2023 03:31:59 +0000 (20:31 -0700)
The motivation is eventual ABI considerations for ARCv3 but even without
it this change us worthwhile as diffstat reduces 100 net lines

r25 is a callee saved register, normally not saved by entry code in
pt_regs. However because of its usage in CONFIG_ARC_CURR_IN_REG it needs
to be. This in turn requires a whole bunch of special casing when we
need to access r25. Then there is distinction between user mode r25 vs.
kernel mode r25 - hence distinct SAVE_CALLEE_SAVED_{USER,KERNEL}

Instead use gp which is a scratch register and thus saved already in entry
code. This cleans things up significantly and much nocer on eyes:

 - SAVE_CALLEE_SAVED_{USER,KERNEL} are now exactly same
 - no special user_r25 slot in pt_reggs

Note that typical global asm registers are callee-saved (r25), but gp is
not callee-saved thus needs additional -ffixed-<reg> toggle

Signed-off-by: Vineet Gupta <vgupta@kernel.org>
13 files changed:
arch/arc/Kconfig
arch/arc/Makefile
arch/arc/include/asm/current.h
arch/arc/include/asm/entry-arcv2.h
arch/arc/include/asm/entry-compact.h
arch/arc/include/asm/entry.h
arch/arc/include/asm/ptrace.h
arch/arc/kernel/asm-offsets.c
arch/arc/kernel/ctx_sw.c
arch/arc/kernel/ctx_sw_asm.S
arch/arc/kernel/entry.S
arch/arc/kernel/process.c
arch/arc/kernel/ptrace.c

index 47b4acc..c92bacc 100644 (file)
@@ -492,11 +492,11 @@ config ARC_KVADDR_SIZE
          kernel-user gutter)
 
 config ARC_CURR_IN_REG
-       bool "Dedicate Register r25 for current_task pointer"
+       bool "cache current task pointer in gp"
        default y
        help
-         This reserved Register R25 to point to Current Task in
-         kernel mode. This saves memory access for each such access
+         This reserves gp register to point to Current Task in
+         kernel mode eliding memory access for each access
 
 
 config ARC_EMUL_UNALIGNED
index 329400a..2390dd0 100644 (file)
@@ -28,14 +28,14 @@ cflags-y                            += $(tune-mcpu-def-y)
 endif
 endif
 
-
 ifdef CONFIG_ARC_CURR_IN_REG
 # For a global register definition, make sure it gets passed to every file
 # We had a customer reported bug where some code built in kernel was NOT using
-# any kernel headers, and missing the r25 global register
+# any kernel headers, and missing the global register
 # Can't do unconditionally because of recursive include issues
 # due to <linux/thread_info.h>
 LINUXINCLUDE   +=  -include $(srctree)/arch/arc/include/asm/current.h
+cflags-y       += -ffixed-gp
 endif
 
 cflags-y                               += -fsection-anchors
@@ -67,7 +67,7 @@ cflags-$(CONFIG_ARC_DW2_UNWIND)               += -fasynchronous-unwind-tables $(cfi)
 # small data is default for elf32 tool-chain. If not usable, disable it
 # This also allows repurposing GP as scratch reg to gcc reg allocator
 disable_small_data := y
-cflags-$(disable_small_data)           += -mno-sdata -fcall-used-gp
+cflags-$(disable_small_data)           += -mno-sdata
 
 cflags-$(CONFIG_CPU_BIG_ENDIAN)                += -mbig-endian
 ldflags-$(CONFIG_CPU_BIG_ENDIAN)       += -EB
index 9b9bdd3..06be89f 100644 (file)
@@ -13,7 +13,7 @@
 
 #ifdef CONFIG_ARC_CURR_IN_REG
 
-register struct task_struct *curr_arc asm("r25");
+register struct task_struct *curr_arc asm("gp");
 #define current (curr_arc)
 
 #else
index 0ff4c06..858742f 100644 (file)
@@ -18,7 +18,6 @@
  *              |      orig_r0      |
  *              |      event/ECR    |
  *              |      bta          |
- *              |      user_r25     |
  *              |      gp           |
  *              |      fp           |
  *              |      sp           |
@@ -56,7 +55,7 @@
        ;                 hardware does even if CONFIG_ARC_IRQ_NO_AUTOSAVE
        ;   4. Auto save: (optional) r0-r11, blink, LPE,LPS,LPC, JLI,LDI,EI
        ;
-       ; (B) Manually saved some regs: r12,r25,r30, sp,fp,gp, ACCL pair
+       ; (B) Manually saved some regs: r12,r30, sp,fp,gp, ACCL pair
 
 #ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE
        ; carve pt_regs on stack (case #3), PC/STAT32 already on stack
 
        st      r10, [sp, PT_sp]        ; SP (pt_regs->sp)
 
-#ifdef CONFIG_ARC_CURR_IN_REG
-       st      r25, [sp, PT_user_r25]
-       GET_CURR_TASK_ON_CPU    r25
-#endif
-
 #ifdef CONFIG_ARC_HAS_ACCL_REGS
        ST2     r58, r59, PT_r58
 #endif
 
        /* clobbers r10, r11 registers pair */
        DSP_SAVE_REGFILE_IRQ
+
+#ifdef CONFIG_ARC_CURR_IN_REG
+       GET_CURR_TASK_ON_CPU    gp
+#endif
+
 .endm
 
 /*------------------------------------------------------------------------*/
        sr      r10, [AUX_USER_SP]
 1:
 
-#ifdef CONFIG_ARC_CURR_IN_REG
-       ld      r25, [sp, PT_user_r25]
-#endif
-
        /* clobbers r10, r11 registers pair */
        DSP_RESTORE_REGFILE_IRQ
 
index 67ff06e..e3383e1 100644 (file)
        /* ARC700 doesn't provide auto-stack switching */
        SWITCH_TO_KERNEL_STK
 
-#ifdef CONFIG_ARC_CURR_IN_REG
-       /* Treat r25 as scratch reg (save on stack) and load with "current" */
-       PUSH    r25
-       GET_CURR_TASK_ON_CPU   r25
-#else
-       sub     sp, sp, 4
-#endif
-
        st.a    r0, [sp, -8]    /* orig_r0 needed for syscall (skip ECR slot) */
        sub     sp, sp, 4       /* skip pt_regs->sp, already saved above */
 
 
        lr      r10, [ecr]
        st      r10, [sp, PT_event]    /* EV_Trap expects r10 to have ECR */
+
+#ifdef CONFIG_ARC_CURR_IN_REG
+       /* gp already saved on stack: now load with "current" */
+       GET_CURR_TASK_ON_CPU   gp
+#endif
 .endm
 
 /*--------------------------------------------------------------
        POP     gp
        RESTORE_R12_TO_R0
 
-#ifdef CONFIG_ARC_CURR_IN_REG
-       ld      r25, [sp, 12]
-#endif
        ld  sp, [sp] /* restore original sp */
-       /* orig_r0, ECR, user_r25 skipped automatically */
+       /* orig_r0, ECR skipped automatically */
 .endm
 
 /* Dummy ECR values for Interrupts */
 
        SWITCH_TO_KERNEL_STK
 
-#ifdef CONFIG_ARC_CURR_IN_REG
-       /* Treat r25 as scratch reg (save on stack) and load with "current" */
-       PUSH    r25
-       GET_CURR_TASK_ON_CPU   r25
-#else
-       sub     sp, sp, 4
-#endif
 
        PUSH    0x003\LVL\()abcd    /* Dummy ECR */
        sub     sp, sp, 8           /* skip orig_r0 (not needed)
        PUSHAX  lp_start
        PUSHAX  bta_l\LVL\()
 
+#ifdef CONFIG_ARC_CURR_IN_REG
+       /* gp already saved on stack: now load with "current" */
+       GET_CURR_TASK_ON_CPU   gp
+#endif
 .endm
 
 /*--------------------------------------------------------------
        POP     gp
        RESTORE_R12_TO_R0
 
-#ifdef CONFIG_ARC_CURR_IN_REG
-       ld      r25, [sp, 12]
-#endif
-       ld  sp, [sp] /* restore original sp */
-       /* orig_r0, ECR, user_r25 skipped automatically */
+       ld  sp, [sp] /* restore original sp; orig_r0, ECR skipped implicitly */
 .endm
 
 /* Get thread_info of "current" tsk */
index 2980bc9..49c2e09 100644 (file)
@@ -91,7 +91,7 @@
  * Helpers to save/restore callee-saved regs:
  * used by several macros below
  *-------------------------------------------------------------*/
-.macro SAVE_R13_TO_R24
+.macro SAVE_R13_TO_R25
        PUSH    r13
        PUSH    r14
        PUSH    r15
        PUSH    r22
        PUSH    r23
        PUSH    r24
+       PUSH    r25
 .endm
 
-.macro RESTORE_R24_TO_R13
+.macro RESTORE_R25_TO_R13
+       POP     r25
        POP     r24
        POP     r23
        POP     r22
        POP     r13
 .endm
 
-/*--------------------------------------------------------------
- * Collect User Mode callee regs as struct callee_regs - needed by
- * fork/do_signal/unaligned-access-emulation.
- * (By default only scratch regs are saved on entry to kernel)
- *
- * Special handling for r25 if used for caching Task Pointer.
- * It would have been saved in task->thread.user_r25 already, but to keep
- * the interface same it is copied into regular r25 placeholder in
- * struct callee_regs.
- *-------------------------------------------------------------*/
+/*
+ * save user mode callee regs as struct callee_regs
+ *  - needed by fork/do_signal/unaligned-access-emulation.
+ */
 .macro SAVE_CALLEE_SAVED_USER
+       SAVE_R13_TO_R25
+.endm
 
-       mov     r12, sp         ; save SP as ref to pt_regs
-       SAVE_R13_TO_R24
-
-#ifdef CONFIG_ARC_CURR_IN_REG
-       ; Retrieve orig r25 and save it with rest of callee_regs
-       ld      r12, [r12, PT_user_r25]
-       PUSH    r12
-#else
-       PUSH    r25
-#endif
-
+/*
+ * restore user mode callee regs as struct callee_regs
+ *  - could have been changed by ptrace tracer or unaligned-access fixup
+ */
+.macro RESTORE_CALLEE_SAVED_USER
+       RESTORE_R25_TO_R13
 .endm
 
-/*--------------------------------------------------------------
- * Save kernel Mode callee regs at the time of Contect Switch.
- *
- * Special handling for r25 if used for caching Task Pointer.
- * Kernel simply skips saving it since it will be loaded with
- * incoming task pointer anyways
- *-------------------------------------------------------------*/
+/*
+ * save/restore kernel mode callee regs at the time of context switch
+ */
 .macro SAVE_CALLEE_SAVED_KERNEL
-
-       SAVE_R13_TO_R24
-
-#ifdef CONFIG_ARC_CURR_IN_REG
-       sub     sp, sp, 4
-#else
-       PUSH    r25
-#endif
+       SAVE_R13_TO_R25
 .endm
 
-/*--------------------------------------------------------------
- * Opposite of SAVE_CALLEE_SAVED_KERNEL
- *-------------------------------------------------------------*/
 .macro RESTORE_CALLEE_SAVED_KERNEL
-
-#ifdef CONFIG_ARC_CURR_IN_REG
-       add     sp, sp, 4  /* skip usual r25 placeholder */
-#else
-       POP     r25
-#endif
-       RESTORE_R24_TO_R13
-.endm
-
-/*--------------------------------------------------------------
- * Opposite of SAVE_CALLEE_SAVED_USER
- *
- * ptrace tracer or unaligned-access fixup might have changed a user mode
- * callee reg which is saved back to usual r25 storage location
- *-------------------------------------------------------------*/
-.macro RESTORE_CALLEE_SAVED_USER
-
-#ifdef CONFIG_ARC_CURR_IN_REG
-       POP     r12
-#else
-       POP     r25
-#endif
-       RESTORE_R24_TO_R13
-
-       ; SP is back to start of pt_regs
-#ifdef CONFIG_ARC_CURR_IN_REG
-       st      r12, [sp, PT_user_r25]
-#endif
+       RESTORE_R25_TO_R13
 .endm
 
 /*--------------------------------------------------------------
 
 #ifdef CONFIG_SMP
 
-/*-------------------------------------------------
+/*
  * Retrieve the current running task on this CPU
- * 1. Determine curr CPU id.
- * 2. Use it to index into _current_task[ ]
+ *  - loads it from backing _current_task[] (and can't use the
+ *    caching reg for current task
  */
 .macro  GET_CURR_TASK_ON_CPU   reg
        GET_CPU_ID  \reg
        add2 \tmp, @_current_task, \tmp
        st   \tsk, [\tmp]
 #ifdef CONFIG_ARC_CURR_IN_REG
-       mov r25, \tsk
+       mov gp, \tsk
 #endif
 
 .endm
 .macro  SET_CURR_TASK_ON_CPU    tsk, tmp
        st  \tsk, [@_current_task]
 #ifdef CONFIG_ARC_CURR_IN_REG
-       mov r25, \tsk
+       mov gp, \tsk
 #endif
 .endm
 
 #endif /* SMP / UNI */
 
-/* ------------------------------------------------------------------
+/*
  * Get the ptr to some field of Current Task at @off in task struct
- *  -Uses r25 for Current task ptr if that is enabled
+ *  - Uses current task cached in reg if enabled
  */
-
 #ifdef CONFIG_ARC_CURR_IN_REG
 
 .macro GET_CURR_TASK_FIELD_PTR  off,  reg
-       add \reg, r25, \off
+       add \reg, gp, \off
 .endm
 
 #else
index cf90fcd..e9798f4 100644 (file)
@@ -52,11 +52,9 @@ struct pt_regs {
                };
                unsigned long event;
        };
-
-       unsigned long user_r25;
 };
 
-#define MAX_REG_OFFSET offsetof(struct pt_regs, user_r25)
+#define MAX_REG_OFFSET offsetof(struct pt_regs, event)
 
 #else
 
@@ -79,8 +77,6 @@ struct pt_regs {
 
        unsigned long bta;      /* bta_l1, bta_l2, erbta */
 
-       unsigned long user_r25;
-
        unsigned long r26;      /* gp */
        unsigned long fp;
        unsigned long sp;       /* user/kernel sp depending on where we came from  */
index 0e88403..37324fd 100644 (file)
@@ -63,8 +63,6 @@ int main(void)
        DEFINE(PT_blink, offsetof(struct pt_regs, blink));
        DEFINE(PT_lpe, offsetof(struct pt_regs, lp_end));
        DEFINE(PT_lpc, offsetof(struct pt_regs, lp_count));
-       DEFINE(PT_user_r25, offsetof(struct pt_regs, user_r25));
-
        DEFINE(SZ_CALLEE_REGS, sizeof(struct callee_regs));
        DEFINE(SZ_PT_REGS, sizeof(struct pt_regs));
 
index bf16f77..40d8944 100644 (file)
@@ -38,11 +38,7 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
                "st.a    r22, [sp, -4]   \n\t"
                "st.a    r23, [sp, -4]   \n\t"
                "st.a    r24, [sp, -4]   \n\t"
-#ifndef CONFIG_ARC_CURR_IN_REG
                "st.a    r25, [sp, -4]   \n\t"
-#else
-               "sub     sp, sp, 4      \n\t"   /* usual r25 placeholder */
-#endif
 
                /* set ksp of outgoing task in tsk->thread.ksp */
 #if KSP_WORD_OFF <= 255
@@ -58,7 +54,7 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
 
                /*
                 * setup _current_task with incoming tsk.
-                * optionally, set r25 to that as well
+                * optionally, set caching reg to that as well
                 * For SMP extra work to get to &_current_task[cpu]
                 * (open coded SET_CURR_TASK_ON_CPU)
                 */
@@ -72,19 +68,14 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
                "st   %2,  [r24]                \n\t"
 #endif
 #ifdef CONFIG_ARC_CURR_IN_REG
-               "mov r25, %2   \n\t"
+               "mov gp, %2   \n\t"
 #endif
 
                /* get ksp of incoming task from tsk->thread.ksp */
                "ld.as  sp, [%2, %1]   \n\t"
 
                /* start loading it's CALLEE reg file */
-
-#ifndef CONFIG_ARC_CURR_IN_REG
                "ld.ab   r25, [sp, 4]   \n\t"
-#else
-               "add    sp, sp, 4       \n\t"
-#endif
                "ld.ab   r24, [sp, 4]   \n\t"
                "ld.ab   r23, [sp, 4]   \n\t"
                "ld.ab   r22, [sp, 4]   \n\t"
index 02c4614..95cba62 100644 (file)
@@ -49,7 +49,7 @@ __switch_to:
        SET_CURR_TASK_ON_CPU  r1, r3
 
        /* reload SP with kernel mode stack pointer in task->thread.ksp */
-       ld.as  sp, [r1, (TASK_THREAD + THREAD_KSP)/4]
+       ld.as  sp, [r1, KSP_WORD_OFF]
 
        /* restore the registers */
        RESTORE_CALLEE_SAVED_KERNEL
index 54e91df..cd26e0f 100644 (file)
@@ -210,7 +210,6 @@ trap_with_param:
 
        ; Save callee regs in case gdb wants to have a look
        ; SP will grow up by size of CALLEE Reg-File
-       ; NOTE: clobbers r12
        SAVE_CALLEE_SAVED_USER
 
        ; save location of saved Callee Regs @ thread_struct->pc
@@ -318,7 +317,7 @@ resume_user_mode_begin:
        ;      tracer might call PEEKUSR(CALLEE reg)
        ;
        ; NOTE: SP will grow up by size of CALLEE Reg-File
-       SAVE_CALLEE_SAVED_USER          ; clobbers r12
+       SAVE_CALLEE_SAVED_USER
 
        ; save location of saved Callee Regs @ thread_struct->callee
        GET_CURR_TASK_FIELD_PTR   TASK_THREAD, r10
index 980b71d..96f5915 100644 (file)
@@ -162,7 +162,6 @@ asmlinkage void ret_from_fork(void);
  * |      SP        |
  * |    orig_r0     |
  * |    event/ECR   |
- * |    user_r25    |
  * ------------------  <===== END of PAGE
  */
 int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
@@ -243,16 +242,6 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
         */
        c_callee->r25 = task_thread_info(p)->thr_ptr;
 
-#ifdef CONFIG_ARC_CURR_IN_REG
-       /*
-        * setup usermode thread pointer #2:
-        * however for this special use of r25 in kernel, __switch_to() sets
-        * r25 for kernel needs and only in the final return path is usermode
-        * r25 setup, from pt_regs->user_r25. So set that up as well
-        */
-       c_regs->user_r25 = c_callee->r25;
-#endif
-
        return 0;
 }
 
index 2abdcd9..8226df3 100644 (file)
@@ -47,7 +47,6 @@ static const struct pt_regs_offset regoffset_table[] = {
        REG_OFFSET_NAME(sp),
        REG_OFFSET_NAME(orig_r0),
        REG_OFFSET_NAME(event),
-       REG_OFFSET_NAME(user_r25),
        REG_OFFSET_END,
 };
 
@@ -57,7 +56,6 @@ static const struct pt_regs_offset regoffset_table[] = {
        REG_OFFSET_NAME(orig_r0),
        REG_OFFSET_NAME(event),
        REG_OFFSET_NAME(bta),
-       REG_OFFSET_NAME(user_r25),
        REG_OFFSET_NAME(r26),
        REG_OFFSET_NAME(fp),
        REG_OFFSET_NAME(sp),