您的位置:首页 > 运维架构 > Linux

linux0.11任务切换switch_to

2014-12-13 20:54 288 查看
#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是否是当前任务,如果是就跳出,否则将current指向task
,然后长跳转任务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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: