switch_mm中是进行页表的切换,即将下一个的pgd的开始物理地址放入CP15中的C2 寄存器。进程的pgd的虚拟地址存放在task_struct结构中的pgd指针中,通过 __virt_to_phys宏可以转变成成物理地址。
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned int cpu) { if (prev != next) cpu_switch_mm(next->pgd, tsk); } #define cpu_switch_mm(pgd,tsk) cpu_set_pgd(__virt_to_phys((unsigned long)(pgd) )) #define cpu_get_pgd() \ ({ \ unsigned long pg; \ __asm__("mrc p15, 0, %0, c2, c0, 0" \ : "=r" (pg)); \ pg &= ~0x3fff; \ (pgd_t *)phys_to_virt(pg); \ })
switch_to()完成进程上下文的切换,通过调用汇编函数__switch_to 完成,其实现比较简单,也就是保存prev进程的上下文信息,该上下文信息由 context_save_struct结构描述,包括主要的寄存器,然后将next 的上下文信息读出,信息保存在task_struct中的thread.save中TSS_SAVE标识了thread. save在task_struct中的位置。
/* * Register switch for ARMv3 and ARMv4 processors * r0 = previous, r1 = next, return previous. * previous and next are guaranteed not to be the same. */ ENTRY(__switch_to) stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack mrs ip, cpsr str ip, [sp, #-4]! @ Save cpsr_SVC str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC ldr r2, [r1, #TSS_DOMAIN] |