arch/arm/kernel/entry-armv.S
arm架构相关的 swtich_to代码
/*
* Register switch for ARMv3 and ARMv4 processors
* r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
* previous and next are guaranteed not to be the same.
*/
ENTRY(__switch_to)
UNWIND(.fnstart )
UNWIND(.cantunwind )
add ip, r1, #TI_CPU_SAVE
ldr r3, [r2, #TI_TP_VALUE]
ARM( stmia ip!, {r4 - sl, fp, sp, lr} )
@ Store most regs on stack
THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack
THUMB( str sp, [ip], #4 )
THUMB( str lr, [ip], #4 )
#ifdef CONFIG_CPU_USE_DOMAINS
ldr r6, [r2, #TI_CPU_DOMAIN]
#endif
set_tls r3, r4, r5
#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
ldr r7, [r2, #TI_TASK]
ldr r8, =__stack_chk_guard
ldr r7, [r7, #TSK_STACK_CANARY]
#endif
#ifdef CONFIG_CPU_USE_DOMAINS
mcr p15, 0, r6, c3, c0, 0 @
Set domain register
#endif
mov r5, r0
add r4, r2, #TI_CPU_SAVE
ldr r0, =thread_notify_head
mov r1, #THREAD_NOTIFY_SWITCH
bl atomic_notifier_call_chain
#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
str r7, [r8]
#endif
THUMB( mov ip, r4 )
mov r0, r5
ARM( ldmia r4, {r4 - sl, fp, sp, pc} ) @
Load all regs saved previously
THUMB( ldmia ip!, {r4 - sl, fp} ) @ Load all regs saved previously
THUMB( ldr sp, [ip], #4 )
THUMB( ldr pc, [ip] )
UNWIND(.fnend )
ENDPROC(__switch_to)
从生成的代码看
/*
* Register switch for ARMv3 and ARMv4 processors
* r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
* previous and next are guaranteed not to be the same.
*/
crash> dis -l __switch_to
../arch/arm/kernel/entry-armv.S
/*1. 保存上下文
**/
0xc000dfe8 <__switch_to>: add r12, r1, #28
0xc000dfec <__switch_to+4>: ldr r3, [r2, #96] ; 0x60
0xc000dff0 <__switch_to+8>: stmia r12!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, lr}
/*2. 设置next 进程的domain
**/
0xc000dff4 <__switch_to+12>: mcr 15, 0, r3, cr13, cr0, {3}
0xc000dff8 <__switch_to+16>: mov r4, #0
0xc000dffc <__switch_to+20>: mcr 15, 0, r4, cr13, cr0, {2}
/*3. 调用函数 atomic_notifier_call_chain
**/
0xc000e000 <__switch_to+24>: mov r5, r0
0xc000e004 <__switch_to+28>: add r4, r2, #28
0xc000e008 <__switch_to+32>: ldr r0, [pc, #12] ; 0xc000e01c
0xc000e00c <__switch_to+36>: mov r1, #2
0xc000e010 <__switch_to+40>: bl 0xc0048ef8 <atomic_notifier_call_chain>
/*4. 设置新的上下文
**/
0xc000e014 <__switch_to+44>: mov r0, r5
0xc000e018 <__switch_to+48>: ldm r4, {r4, r5, r6, r7, r8, r9, r10, r11, sp, pc}
0xc000e01c <__switch_to+52>: rsbsgt r1, r7, r12, lsr r1
0xc000e020 <__switch_to+56>: nop {0}
0xc000e024 <__switch_to+60>: nop {0}
0xc000e028 <__switch_to+64>: nop {0}
0xc000e02c <__switch_to+68>: nop {0}
0xc000e030 <__switch_to+72>: nop {0}
0xc000e034 <__switch_to+76>: nop {0}
0xc000e038 <__switch_to+80>: nop {0}
0xc000e03c <__switch_to+84>: nop {0}
add r12, r1, #28
为什么是28?就是偏移到struct cpu_context_save
struct thread_info {
[0] unsigned long flags;
[4] int preempt_count;
[8] mm_segment_t addr_limit;
[12] struct task_struct *task;
[16] struct exec_domain *exec_domain;
[20] __u32 cpu;
[24] __u32 cpu_domain;
[28] struct cpu_context_save cpu_context;
[76] __u32 syscall;
[80] __u8 used_cp[16];
[96] unsigned long tp_value;
[100] struct crunch_state crunchstate;
[288] union fp_state fpstate;
[432] union vfp_state vfpstate;
[712] struct restart_block restart_block;
}
crash> cpu_context_save
struct cpu_context_save {
__u32 r4;
__u32 r5;
__u32 r6;
__u32 r7;
__u32 r8;
__u32 r9;
__u32 sl;[r10]
__u32 fp;[r11]
__u32 sp;[r13]
__u32 pc;
[r15/r14]/*保存的是lr,恢复到pc*/
__u32 extra[2];
}
add r12, r1, #28
ldr r3, [r2, #96]; 0x60
偏移量 96:
struct thread_info {
[96] unsigned long tp_value;
这个数值和后面的mcr有关系,进而对domain的操作。
总结:
switch_to的操作主要是thread_info的cpu_context_save的保存和恢复。
且保存的并不是所以的寄存器,其中就不包括: r0/1/2/3/12.