<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

理论部分请参考《深入理解Linux 内核》第三章。

1switch_to 宏:

#define switch_to(prev,next,last) /

do { /

last = __switch_to(prev,task_thread_info(prev), task_thread_info(next)); /

} while (0)

 

2__switch_to 的函数是现在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)

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_MMU

ldr r6, [r2, #TI_CPU_DOMAIN]

#endif

#if defined(CONFIG_HAS_TLS_REG)

mcr p15, 0, r3, c13, c0, 3 @ set TLS register

#elif !defined(CONFIG_TLS_REG_EMUL)

mov r4, #0xffff0fff

str r3, [r4, #-15] @ TLS val at 0xffff0ff0

#endif

#ifdef CONFIG_MMU

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

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)

 

为了便于分析,将上面的源代码用工具反汇编后得到下列的输出:

000004f0 <__switch_to>:

r0 = previous task_struct

r1 = previous thread_info

r2 = next thread_info

4f0: e281c01c add ip, r1, #28 ; 0x1c

ip 的内容为previou 进程的thread_info 结构体中cpu_context 成员的地址。

4f4: e5923060 ldr r3, [r2, #96]

取得next 进程的tp_value tp_value 里保存了将要写到arm TP 寄存器中的值,由于是armv7 新加功能,所以还没有看具体怎么用。

4f8: e8ac6ff0 stmia ip!, {r4, r5, r6, r7, r8, r9, sl, fp, sp, lr}

保存当且上下文到previou 进程的thread_info 结构体中cpu_context 成员中。

4fc: e5926018 ldr r6, [r2, #24]

取得next 进程的cpu_domain

500: ee0d3f70 mcr 15, 0, r3, cr13, cr0, {3}

504: ee036f10 mcr 15, 0, r6, cr3, cr0, {0}

next 进程的tp_value cpu_domain 写入arm TP 和域寄存器。

注:记得原来的内核只支持3 domain ,谁知道现在已经支持4 个了,这个有时间可以分析一下。

508: e1a05000 mov r5, r0

50c: e282401c add r4, r2, #28 ; 0x1c

510: e59f000c ldr r0, [pc, #12] ; 524 <__switch_to+0x34>

514: e3a01002 mov r1, #2 ; 0x2

518: ebfffffe bl 0 <atomic_notifier_call_chain>

向通知链上的子系统通知该事件。

51c: e1a00005 mov r0, r5

520: e894aff0 ldm r4, {r4, r5, r6, r7, r8, r9, sl, fp, sp, pc}

将新的进程(next 进程)的上下文恢复,程序切换的新的进程执行。

注:根据ATPCS r0~r2 用于传递参数,而r4~r11 全部由子程序负责保存(这个和x86 一人负责一部分的方式还不太一样)。所以r4 中的值可以继续使用,而r0 的值需暂时保存到r5 中。

 

Logo

更多推荐