ARC: entry: use gp to cache task pointer (vs. r25)

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>
This commit is contained in:
Vineet Gupta 2020-05-12 22:18:08 -07:00
parent fad84e39f1
commit cfca4b5abe
13 changed files with 60 additions and 156 deletions

View 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

View 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

View 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

View 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
@ -157,17 +156,17 @@
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
/*------------------------------------------------------------------------*/
@ -188,10 +187,6 @@
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

View File

@ -151,14 +151,6 @@
/* 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 */
@ -179,6 +171,11 @@
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
/*--------------------------------------------------------------
@ -208,11 +205,8 @@
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 */
@ -229,13 +223,6 @@
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)
@ -255,6 +242,10 @@
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
/*--------------------------------------------------------------
@ -282,11 +273,7 @@
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 */

View 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
@ -104,9 +104,11 @@
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
@ -121,81 +123,31 @@
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
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
SAVE_R13_TO_R25
.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
*-------------------------------------------------------------*/
.macro SAVE_CALLEE_SAVED_KERNEL
SAVE_R13_TO_R24
#ifdef CONFIG_ARC_CURR_IN_REG
sub sp, sp, 4
#else
PUSH r25
#endif
.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
*-------------------------------------------------------------*/
/*
* 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
#ifdef CONFIG_ARC_CURR_IN_REG
POP r12
#else
POP r25
#endif
RESTORE_R24_TO_R13
/*
* save/restore kernel mode callee regs at the time of context switch
*/
.macro SAVE_CALLEE_SAVED_KERNEL
SAVE_R13_TO_R25
.endm
; SP is back to start of pt_regs
#ifdef CONFIG_ARC_CURR_IN_REG
st r12, [sp, PT_user_r25]
#endif
.macro RESTORE_CALLEE_SAVED_KERNEL
RESTORE_R25_TO_R13
.endm
/*--------------------------------------------------------------
@ -231,10 +183,10 @@
#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
@ -256,7 +208,7 @@
add2 \tmp, @_current_task, \tmp
st \tsk, [\tmp]
#ifdef CONFIG_ARC_CURR_IN_REG
mov r25, \tsk
mov gp, \tsk
#endif
.endm
@ -271,21 +223,20 @@
.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

View 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 */

View 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));

View 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"

View 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

View 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

View 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;
}

View 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),