mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-25 21:54:06 +08:00
b008848020
commit 91d1aa43
(context_tracking: New context tracking susbsystem)
generalized parts of the RCU userspace extended quiescent state into
the context tracking subsystem. Context tracking is then used
to implement adaptive tickless (a.k.a extended nohz)
To support the new context tracking subsystem on ARM, the user/kernel
boundary transtions need to be instrumented.
For exceptions and IRQs in usermode, the existing usr_entry macro is
used to instrument the user->kernel transition. For the return to
usermode path, the ret_to_user* path is instrumented. Using the
usr_entry macro, this covers interrupts in userspace, data abort and
prefetch abort exceptions in userspace as well as undefined exceptions
in userspace (which is where FP emulation and VFP are handled.)
For syscalls, the slow return path is covered by instrumenting the
ret_to_user path. In addition, the syscall entry point is
instrumented which covers the user->kernel transition for both fast
and slow syscalls, and an additional instrumentation point is added
for the fast syscall return path (ret_fast_syscall).
Cc: Mats Liljegren <mats.liljegren@enea.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Kevin Hilman <khilman@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
208 lines
4.8 KiB
ArmAsm
208 lines
4.8 KiB
ArmAsm
#include <linux/init.h>
|
|
#include <linux/linkage.h>
|
|
|
|
#include <asm/assembler.h>
|
|
#include <asm/asm-offsets.h>
|
|
#include <asm/errno.h>
|
|
#include <asm/thread_info.h>
|
|
|
|
@ Bad Abort numbers
|
|
@ -----------------
|
|
@
|
|
#define BAD_PREFETCH 0
|
|
#define BAD_DATA 1
|
|
#define BAD_ADDREXCPTN 2
|
|
#define BAD_IRQ 3
|
|
#define BAD_UNDEFINSTR 4
|
|
|
|
@
|
|
@ Most of the stack format comes from struct pt_regs, but with
|
|
@ the addition of 8 bytes for storing syscall args 5 and 6.
|
|
@ This _must_ remain a multiple of 8 for EABI.
|
|
@
|
|
#define S_OFF 8
|
|
|
|
/*
|
|
* The SWI code relies on the fact that R0 is at the bottom of the stack
|
|
* (due to slow/fast restore user regs).
|
|
*/
|
|
#if S_R0 != 0
|
|
#error "Please fix"
|
|
#endif
|
|
|
|
.macro zero_fp
|
|
#ifdef CONFIG_FRAME_POINTER
|
|
mov fp, #0
|
|
#endif
|
|
.endm
|
|
|
|
.macro alignment_trap, rtemp
|
|
#ifdef CONFIG_ALIGNMENT_TRAP
|
|
ldr \rtemp, .LCcralign
|
|
ldr \rtemp, [\rtemp]
|
|
mcr p15, 0, \rtemp, c1, c0
|
|
#endif
|
|
.endm
|
|
|
|
@
|
|
@ Store/load the USER SP and LR registers by switching to the SYS
|
|
@ mode. Useful in Thumb-2 mode where "stm/ldm rd, {sp, lr}^" is not
|
|
@ available. Should only be called from SVC mode
|
|
@
|
|
.macro store_user_sp_lr, rd, rtemp, offset = 0
|
|
mrs \rtemp, cpsr
|
|
eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
|
|
msr cpsr_c, \rtemp @ switch to the SYS mode
|
|
|
|
str sp, [\rd, #\offset] @ save sp_usr
|
|
str lr, [\rd, #\offset + 4] @ save lr_usr
|
|
|
|
eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
|
|
msr cpsr_c, \rtemp @ switch back to the SVC mode
|
|
.endm
|
|
|
|
.macro load_user_sp_lr, rd, rtemp, offset = 0
|
|
mrs \rtemp, cpsr
|
|
eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
|
|
msr cpsr_c, \rtemp @ switch to the SYS mode
|
|
|
|
ldr sp, [\rd, #\offset] @ load sp_usr
|
|
ldr lr, [\rd, #\offset + 4] @ load lr_usr
|
|
|
|
eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
|
|
msr cpsr_c, \rtemp @ switch back to the SVC mode
|
|
.endm
|
|
|
|
#ifndef CONFIG_THUMB2_KERNEL
|
|
.macro svc_exit, rpsr
|
|
msr spsr_cxsf, \rpsr
|
|
#if defined(CONFIG_CPU_V6)
|
|
ldr r0, [sp]
|
|
strex r1, r2, [sp] @ clear the exclusive monitor
|
|
ldmib sp, {r1 - pc}^ @ load r1 - pc, cpsr
|
|
#elif defined(CONFIG_CPU_32v6K)
|
|
clrex @ clear the exclusive monitor
|
|
ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
|
|
#else
|
|
ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
|
|
#endif
|
|
.endm
|
|
|
|
.macro restore_user_regs, fast = 0, offset = 0
|
|
ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr
|
|
ldr lr, [sp, #\offset + S_PC]! @ get pc
|
|
msr spsr_cxsf, r1 @ save in spsr_svc
|
|
#if defined(CONFIG_CPU_V6)
|
|
strex r1, r2, [sp] @ clear the exclusive monitor
|
|
#elif defined(CONFIG_CPU_32v6K)
|
|
clrex @ clear the exclusive monitor
|
|
#endif
|
|
.if \fast
|
|
ldmdb sp, {r1 - lr}^ @ get calling r1 - lr
|
|
.else
|
|
ldmdb sp, {r0 - lr}^ @ get calling r0 - lr
|
|
.endif
|
|
mov r0, r0 @ ARMv5T and earlier require a nop
|
|
@ after ldm {}^
|
|
add sp, sp, #S_FRAME_SIZE - S_PC
|
|
movs pc, lr @ return & move spsr_svc into cpsr
|
|
.endm
|
|
|
|
.macro get_thread_info, rd
|
|
mov \rd, sp, lsr #13
|
|
mov \rd, \rd, lsl #13
|
|
.endm
|
|
|
|
@
|
|
@ 32-bit wide "mov pc, reg"
|
|
@
|
|
.macro movw_pc, reg
|
|
mov pc, \reg
|
|
.endm
|
|
#else /* CONFIG_THUMB2_KERNEL */
|
|
.macro svc_exit, rpsr
|
|
ldr lr, [sp, #S_SP] @ top of the stack
|
|
ldrd r0, r1, [sp, #S_LR] @ calling lr and pc
|
|
clrex @ clear the exclusive monitor
|
|
stmdb lr!, {r0, r1, \rpsr} @ calling lr and rfe context
|
|
ldmia sp, {r0 - r12}
|
|
mov sp, lr
|
|
ldr lr, [sp], #4
|
|
rfeia sp!
|
|
.endm
|
|
|
|
.macro restore_user_regs, fast = 0, offset = 0
|
|
clrex @ clear the exclusive monitor
|
|
mov r2, sp
|
|
load_user_sp_lr r2, r3, \offset + S_SP @ calling sp, lr
|
|
ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr
|
|
ldr lr, [sp, #\offset + S_PC] @ get pc
|
|
add sp, sp, #\offset + S_SP
|
|
msr spsr_cxsf, r1 @ save in spsr_svc
|
|
.if \fast
|
|
ldmdb sp, {r1 - r12} @ get calling r1 - r12
|
|
.else
|
|
ldmdb sp, {r0 - r12} @ get calling r0 - r12
|
|
.endif
|
|
add sp, sp, #S_FRAME_SIZE - S_SP
|
|
movs pc, lr @ return & move spsr_svc into cpsr
|
|
.endm
|
|
|
|
.macro get_thread_info, rd
|
|
mov \rd, sp
|
|
lsr \rd, \rd, #13
|
|
mov \rd, \rd, lsl #13
|
|
.endm
|
|
|
|
@
|
|
@ 32-bit wide "mov pc, reg"
|
|
@
|
|
.macro movw_pc, reg
|
|
mov pc, \reg
|
|
nop
|
|
.endm
|
|
#endif /* !CONFIG_THUMB2_KERNEL */
|
|
|
|
/*
|
|
* Context tracking subsystem. Used to instrument transitions
|
|
* between user and kernel mode.
|
|
*/
|
|
.macro ct_user_exit, save = 1
|
|
#ifdef CONFIG_CONTEXT_TRACKING
|
|
.if \save
|
|
stmdb sp!, {r0-r3, ip, lr}
|
|
bl user_exit
|
|
ldmia sp!, {r0-r3, ip, lr}
|
|
.else
|
|
bl user_exit
|
|
.endif
|
|
#endif
|
|
.endm
|
|
|
|
.macro ct_user_enter, save = 1
|
|
#ifdef CONFIG_CONTEXT_TRACKING
|
|
.if \save
|
|
stmdb sp!, {r0-r3, ip, lr}
|
|
bl user_enter
|
|
ldmia sp!, {r0-r3, ip, lr}
|
|
.else
|
|
bl user_enter
|
|
.endif
|
|
#endif
|
|
.endm
|
|
|
|
/*
|
|
* These are the registers used in the syscall handler, and allow us to
|
|
* have in theory up to 7 arguments to a function - r0 to r6.
|
|
*
|
|
* r7 is reserved for the system call number for thumb mode.
|
|
*
|
|
* Note that tbl == why is intentional.
|
|
*
|
|
* We must set at least "tsk" and "why" when calling ret_with_reschedule.
|
|
*/
|
|
scno .req r7 @ syscall number
|
|
tbl .req r8 @ syscall table pointer
|
|
why .req r8 @ Linux syscall (!= 0)
|
|
tsk .req r9 @ current thread_info
|