static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)----------------(1)
{
unsigned int cpu = smp_processor_id();
if (prev == next)--------------------(2)
return;
if (next == &init_mm) {-----------------(3)
cpu_set_reserved_ttbr0();
return;
}
check_and_switch_context(next, cpu);
}
(1)prev是要切出的地址空间,next是要切入的地址空间,tsk是将要切入的进程。
(2)要切出的地址空间和要切入的地址空间是一个地址空间的话,那么切换地址空间也就没有什么意义了。
(3)在ARM64中,地址空间的切换主要是切换ttbr0_el1,对于swapper进程的地址空间,其用户空间没有任何的mapping,而如果要切入的地址空间就是swapper进程的地址空间的时候,将(设定ttbr0_el1指向empty_zero_page)。
(4)check_and_switch_context中有很多TLB、ASID相关的操作,我们将会在另外的文档中给出细致描述,这里就简单略过,实际上,最终该函数会调用arch/arm64/mm/proc.S文件中的cpu_do_switch_mm将要切入进程的L0 Translation table物理地址(保存在内存描述符的pgd成员)写入ttbr0_el1。
六、ARM64的的进程切换
由于存在MMU,内存中可以有多个task,并且由调度器依次调度到cpu core上实际执行。系统有多少个cpu core就可以有多少个进程(线程)同时执行。即便是对于一个特定的cpu core,调度器可以可以不断的将控制权从一个task切换到另外一个task上。实际的context switch的动作也不复杂:就是将当前的上下文保存在内存中,然后从内存中恢复另外一个task的上下文。对于ARM64而言,context包括:
(1)通用寄存器
(2)浮点寄存器
(3)地址空间寄存器(ttbr0_el1和ttbr1_el1),上一节已经描述

(4)其他寄存器(ASID、thread process ID register等)
__switch_to代码(位于arch/arm64/kernel/process.c)如下:
struct task_struct *__switch_to(struct task_struct *prev,
struct task_struct *next)
{
struct task_struct *last;
fpsimd_thread_switch(next);--------------(1)
tls_thread_switch(next);----------------(2)
hw_breakpoint_thread_switch(next);--和硬件跟踪相关
contextidr_thread_switch(next); --和硬件跟踪相关
dsb(ish);
last = cpu_switch_to(prev, next); ------------(3)
return last;
}
(1)fp是float-point的意思,和浮点运算相关。simd是Single Instruction Multiple Data的意思,和多媒体以及信号处理相关。fpsimd_thread_switch其实就是把当前FPSIMD的状态保存到了内存中(task.thread.fpsimd_state),从要切入的next进程描述符中获取FPSIMD状态,并加载到CPU上。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-76979-4.html
或者军事表演秀
打路过的还不如先干掉霸占的