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
相关文章推荐
- Linux任务切换代码(switch_to)详解(转)
- Linux任务切换代码(switch_to)详解
- linux0.11学习笔记-技术铺垫-简单AB任务切换程序(3)-调试手段和方法
- linux0.11学习笔记-技术铺垫-简单AB任务切换程序(4)-向现存写数据并响应时钟中断
- Linux 内核--任务0的运行(切换到用户模式)move_to_user_mode
- linux-0.11内核中任务的堆栈切换
- linux0.11学习笔记-技术铺垫-简单AB任务切换程序(5)-实现三个任务切换
- switch_to及ret_from_sys_call控制任务的切换与返回
- switch_to及ret_from_sys_call控制任务的切换与返回
- 对linux 0.11版本中switch_to()的理解
- linux0.11 汇编 切换到任务0 的相关描述
- linux0.11学习笔记-技术铺垫-简单AB任务切换程序(2)-可加载执行其他程序的bootloader
- linux0.11中switch_to理解
- switch_to及ret_from_sys_call控制任务的切换与返回
- linux0.11学习笔记-技术铺垫-简单AB任务切换程序(1)-实现一个简单的bootloader
- linux0.11学习笔记-技术铺垫-简单AB任务切换程序(3)-调试手段和方法
- Linux 内核--任务0的运行(切换到用户模式)move_to_user_mode
- Linux 内核--任务0的运行(切换到用户模式)move_to_user_mode
- 分析Linux 0.11中的任务切换
- Linux进程(之)进程切换函数switch_to()解析