内核版本 3.10.90
arch\arm\kernel\entry-armv.S
/*
* 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) /* 其调用流程为:__schedule --> context_switch --> switch_to --> __switch_to
* 由于 arch\arm\include\asm\switch_to.h 里:
* #define switch_to(prev,next,last) \
* do { \
* last = __switch_to(prev,task_thread_info(prev), task_thread_info(next)); \
* } while (0)
* 从而执行到该函数时,lr 为 context_switch 中 switch_to 的下一条指令,即 barrier();
*/
UNWIND(.fnstart )
UNWIND(.cantunwind )
add ip, r1, #TI_CPU_SAVE /* r1 指向的是当前运行进程的 thread_info 中的 struct cpu_context_save cpu_context;
* 在 arch\arm\kernel\asm-offsets.c
* DEFINE(TI_CPU_SAVE, offsetof(struct thread_info, cpu_context));
* 在 arch\arm\include\asm\thread_info.h
* struct cpu_context_save {
* __u32 r4;
* __u32 r5;
* __u32 r6;
* __u32 r7;
* __u32 r8;
* __u32 r9;
* __u32 sl;
* __u32 fp;
* __u32 sp;
* __u32 pc;
* __u32 extra[2]; /* Xscale 'acc' register, etc */
* };
*/
ldr r3, [r2, #TI_TP_VALUE] /* r2 指向的是要切换进程的 thread_info
* 在 arch\arm\kernel\asm-offsets.c 里
* DEFINE(TI_TP_VALUE, offsetof(struct thread_info, tp_value));
* r3 得到要切换进程的 tp_value.
*/
ARM( stmia ip!, {r4 - sl, fp, sp, lr} ) @ Store most regs on stack
/* 将当前进程寄存器的值保存到当前进程 thread info的 cpu_context 里
* 其中 lr 保存到了 cpu_context_save 里的 pc 里。
* ia 表示 increase after, 由于使用了 !, 从而 ip也会一直更新,
* 最后指向了 cpu_context 里的 extra
*/
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] /* DEFINE(TI_TASK, offsetof(struct thread_info, task));
* 通过thread info 得到要切入进程的 task
*/
ldr r8, =__stack_chk_guard
ldr r7, [r7, #TSK_STACK_CANARY] /* DEFINE(TSK_STACK_CANARY, offsetof(struct task_struct, stack_canary));
* 得到切入进程的 task 中的随机值
*/
#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 /* r4 指向的要切入进程的 thread_info 中的 struct cpu_context_save cpu_context; */
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] /* 将 task 的随机值 stack_canary 保存到 __stack_chk_guard ,用于栈越界检测 */
#endif
THUMB( mov ip, r4 )
mov r0, r5 /* 此时 r0 表示 previous task_struct ,即要切出的进程的 task */
ARM( ldmia r4, {r4 - sl, fp, sp, pc} ) @ Load all regs saved previously
/* 将要切入进程的 cpu_context 的值加载到寄存器,
* 其中加载到 pc,实现跳转执行
* 如果该切入的进程是之前切出的的,则加载到 pc 的值,为
* context_switch 中 switch_to 的下一条指令,即 barrier();
*/
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)