linux0.11任务切换switch_to

来源:互联网 发布:美国网站域名后缀 编辑:程序博客网 时间:2024/05/16 17:35

#define switch_to(n) {\struct {long a,b;} __tmp; \__asm__("cmpl %%ecx,current\n\t" \"je 1f\n\t" \"movw %%dx,%1\n\t" \"xchgl %%ecx,current\n\t" \"ljmp *%0\n\t" \"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])); \}

上面的嵌入宏汇编代码就是完成任务的切换操作。首先判断传递进来的任务号n是否是当前任务,如果是就跳出,否则将current指向task[n],然后长跳转任务n的TSS选择符,这样就完成了任务切换操作。

注意:

1. 跳转到TSS段选择符会造成任务切换到该TSS对应的进程。
2. 对于造成任务切换的长跳转,TSS段基址无用。

在保护模式下CPU进行长跳转,如果发现段选择符指向TSS段,那么CPU将会自动将TSS段的内容加载到当前CPU寄存器中,比如eax,ldr,cs,ss,esp等等,其实就是104字节的TSS结构的所有成员变量赋值给CPU寄存器(注意这里是ss0和esp0)。再次强调这个过程是自动完成的。进程TSS结构的初始值在copy_process函数中完成,最后调用set_tss_desc函数将tss段插入到gdt描述符表中,在该函数中设置TSS的段基址和段长度(104字节)。

代码中 ljmp  *%0 指令需要说明下,对于长跳转首先要指定段寄存器,其次就是偏移。在32位保护模式下,长跳转段寄存器其实也就变成了段选择符,即ljmp  sel:offset。代码中该条指令的操作数是一个结构体,其实这个结构体的第一个成员就是偏移,第二个成员也就是选择子了。由于选择子是16位的,所以第二个成员的高2字节无用,程序中定义成32位的long型是为了字节对齐。所以要跳转到任务n的TSS段,首先就要对__tmp结构的b成员赋值,如果目标段为TSS段,则段基址无用,至于原因,这是intel规定的,所以没有为什么。因此最后ljmp  *%0就是ljmp  __tmp.b : __tmp.a





0 0
原创粉丝点击