Linux switch_to(n)理解
任务门
+----------+---+-----------+-------------------+-----------------------+----------+----------+
| 16bits | P | DPL(2bit) | 5 bits | 8 bits | 16bits | 16bits |
+----------+---+-----------+-------------------+-----------------------+----------+----------+
| NA | 1 | 00 | 00101 | NA | TSS | NA |
+----------+---+-----------+-------------------+-----------------------+----------+----------+
通过ljmp指令跳到TSS即可实现任务切换
// __tmp用来构造ljmp的操作数。该操作数由4字节偏移和2字节选择符组成。当TSS选择符
// 当ljmp的操作输是TSS选择符时,指令忽略4字节偏移,CPU硬件自动判断。
// %0 内存地址 __tmp.a的地址,用来放偏移
// %1 内存地址 __tmp.b的地址,用来放TSS选择符
// %2 edx 任务号为n的TSS选择符
// %3 ecx task[n]
#define switch_to(n) {\ struct {long a,b;} __tmp; \ __asm__("cmpl %%ecx,current\n\t" \ //将task[n]与current比较,其中task[n]是要切换到的任务,current是当前任务 "je 1f\n\t" \ //如果是当前current,则直接退出 "movw %%dx,%1\n\t" \ //根据AT汇编我们知道edx存放了TSS段选择子,将段选择子存放到参数1中,也就是__tmp.b "xchgl %%ecx,current\n\t" \ //交换current和ecx的指,ecx是切换的进程指针 "ljmp *%0\n\t" \ //不深究,我们知道这个指令执行完成后跳转到任务n即可 "cmpl %%ecx,last_task_used_math\n\t" \ "jne 1f\n\t" \ "clts\n" \ "1:" \ ::"m" (*&__tmp.a),"m" (*&__tmp.b), \ "d" (_TSS(n)),"c" ((long) task[n])); \ }
当段间指令jmp所含指针的选择符指示一个可用任务状态段的TSS描述符时,将造成任务切换。那么CPU怎么识别描述符是TSS描述符而不是其他描述符呢?这是因为所有描述符(一个描述符是64位)中都有4位用来指示该描述符的类型,如描述符类型值是9或11都表示该描述符是TSS描述符。好了,CPU得到TSS描述符后,就会将其加载到任务寄存器TR中,然后根据TSS描述符的信息(主要是基址)找到任务的tss内容(包括所有的寄存器信息,如eip),根据其内容就可以开始新任务的运行。我们暂且把这个恢复所有寄存器状态的过程称为恢复寄存器现场。任务切换时CPU会恢复寄存器现场,那么它当然也会保存寄存器现场了。这些寄存器现场都会被写入原任务的tss结构里,值得注意的是,EIP会指向引起任务切换指令(第7行)的下一条指令(第8行),所以,很明显,当原任务有朝一日再次被调度运行时,它将从EIP所指的地方(第8行)开始运行。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律