最近看linux0.11源码时,看到任务切换函数switch_to,感觉很晦涩,于是在网上查了一些资料,现在终于有些眉目,特记录于此,以方便大家参考,有什么错误或不足之处,还请大家指出~

switch_to源码

/*
 *    switch_to(n) should switch tasks to task nr n, first
 * checking that n isn't the current task, in which case it does nothing.
 * This also clears the TS-flag if the task we switched to has used
 * tha math co-processor latest.
 */
#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])); \
}

大部分代码都很容易看懂,主要是:判断当前任务是否是要切换的任务,是则跳到标号1,即不做任何事;交换;调整等。。。

这里重点强调_TSS(n) 和ljmp %0;

(2)_TSS(n),作用是生成TSS的段选择符

#define FIRST_TSS_ENTRY 4

#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))

当通过以上两个代码是不足以明白_TSS(n)的机制,需要结合以下知识;

上图描述linux内核中GDT的布局;0-nul, 1-cs, 2-ds, 3-syscall, 4-TSS0, 5-LDT0, 6-TSS1 等。。。

上图是段选择符,TI=0表示在GDT(全局描述符表)中,1表示在LDT(局部描述符表)中,RPL表示优先级;描述符索引就是在GDT中的索引;

通过上面两张图,下面分析代码,从图1可以看出第一个TSS位于索引为4的位置,于是#define FIRST_TSS_ENTRY 4;而FIRST_TSS_ENTRY<<3表示左移3位,因为TI和RPL总共占3为;((unsigned long) n)<<4为什么要左移4位呢?从图1可以看出TSS索引都是偶数,于是TI(1位)+RPL(2位)+偶数位(1)=4;通过上述组合就可以得到TSS选择子;

()ljmp %0或(ljmp *%0)

首先是为什么要加*?这是gas语法,表示绝对跳转(与C中的*是不同的),若程序没有加*,则编译器会自己加上*,可以在linux中测试;

ljmp用法说明:(很重要)

按AS手册,ljmp指令存在两种形式,即:
   一、直接操作数跳转,此时操作数即为目标逻辑地址(选择子,偏移),即形如:ljmp $seg_selector, $offset的方式;
   二、使用内存操作数,这时候,AS手册规定,内存操作数必须用“*”作前缀,即形如:ljmp *mem48,其中内存位置mem48处存放目标逻辑地址: 高16bit存放的是seg_selector,低32bit存放的是offset。注意:这条指令里的“*”只是表示间接跳转的意思,与C语言里的“*”作用完全不同。

回到源码上,ljmp %0用的ljmp的第二种用法,“ljmp *%0”这条语句展开后相当于“ljmp *__tmp.a”,也就是跳转到地址&__tmp.a中包含的48bit逻辑地址处。而按struct _tmp的定义,这也就意味着__tmp.a即为该逻辑地址的offset部分,__tmp.b的低16bit为seg_selector(高16bit无用)部分。由于在"ljmp %0"之前,"movw %%dx,%1"这条语句已经把状态段选择子"__TSS(n)"的值赋给了__tmp.b的低16bit。至于为什么要用*&__tmp.a,目前还不清楚,其实*&__tmp.a和__tmp.a是一样的,通过汇编也可以看出;这里就先不用关心它了;

通过以上说明,可以知道了ljmp将跳转到选择子指定的地方,大致过程是,ljmp判断选择子为TSS类型,于是就告诉硬件要切换任务,硬件首先它要将当前的PC,esp,eax等现场信息保存在当前自己的TSS段描述符中,然后再将目标TSS段描述符中的pc,esp,eax的值拷贝至对应的寄存器中.当这些过程全部做完以后内核就实现了内核的切换;可以参考下图:

总结:

通过以上内容,可以大致了解到任务切换的流程,switch_to中关键是ljmp %0;

switch_to 理解的更多相关文章

  1. LINUX内核分析期末总结

    韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.课程总结 1 ...

  2. Linux内核分析之理解进程调度时机跟踪分析进程调度与进程切换的过程

    一.原理分析 1.调度时机 背景不同类型的进程有不同的调度需求第一种分类I/O-bond:频繁的进行I/O:通常会花费很多时间等待I/O操作的完成CPU-bound:计算密集型:需要大量的CPU时间进 ...

  3. 20135202闫佳歆--week 8 实验:理解进程调度时机跟踪分析进程调度与进程切换的过程--实验及总结

    week 8 实验:理解进程调度时机跟踪分析进程调度与进程切换的过程 1.环境搭建: rm menu -rf git clone https://github.com/megnning/menu.gi ...

  4. 对于Linux内核执行过程的理解(基于fork、execve、schedule等函数)

    382 + 原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/ 一.实验环境 win10 -> VMware -> Ubuntu1 ...

  5. Linux内核分析--理解进程调度时机、跟踪分析进程调度和进程切换的过程

    ID:fuchen1994 姓名:江军 作业要求: 理解Linux系统中进程调度的时机,可以在内核代码中搜索schedule()函数,看都是哪里调用了schedule(),判断我们课程内容中的总结是否 ...

  6. Linux内核设计第八周学习总结 理解进程调度时机跟踪分析进程调度与进程切换的过程

    陈巧然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.视频内容 Linux ...

  7. 理解进程调度时机跟踪分析进程调度与进程切换的过程(Linux)

    ----------------------------------------------------------------------------------- 理解进程调度时机跟踪分析进程调度 ...

  8. linux 内核的 switch_to原理

    switch_to:这是一个宏,有三个参数prev,next,last 局部变量prev,next:指向进程描述符的内存地址 首先明确的是:last和prev是同一个,用last只是为了理解方便,完全 ...

  9. 《深入理解Linux内核》 读书笔记

    深入理解Linux内核 读书笔记 一.概论 操作系统基本概念 多用户系统 允许多个用户登录系统,不同用户之间的有私有的空间 用户和组 每个用于属于一个组,组的权限和其他人的权限,和拥有者的权限不一样. ...

随机推荐

  1. 遇见NodeJS:JavaScript的贵人

    在大家的印象中,相当长一段时间里,JavaScript是一门脚本语言,一般不能成为某个项目的担纲主角,作用只是在浏览器里帮忙校验校验输入是不是正确,响应一下鼠标.键盘事件,或者让某个HTML元素动起来 ...

  2. 分享10款激发灵感的最新HTML5/CSS3应用

    1.HTML5/CSS3实现iOS Path菜单 菜单动画很酷 Path菜单相信大家都不陌生吧,它在iOS中非常流行,今天我们要分享的菜单就是利用HTML5和CSS3技术来模拟实现这款iOS Path ...

  3. Java线程面试题 Top 50(转载)

    原文链接:http://www.importnew.com/12773.html 本文由 ImportNew - 李 广 翻译自 javarevisited.欢迎加入Java小组.转载请参见文章末尾的 ...

  4. 对session和cookie的一些理解

    由于项目需要,最近用session容器比较多,传载的同时加上了自己的一些理解,不足之处还请大家补充和纠正.);                  response.addCookie(c1);   * ...

  5. corosync+pacemaker实现高可用(HA)集群

    corosync+pacemaker实现高可用(HA)集群(一)     重要概念 在准备部署HA集群前,需要对其涉及的大量的概念有一个初步的了解,这样在实际部署配置时,才不至于不知所云 资源.服务与 ...

  6. WordPress 主题开发 - (五)WordPress 主题模板及目录结构 待翻译

    While the most minimal of WordPress Themes really only need an index.php template and a style.css fi ...

  7. WordPress 主题开发 - (三) 开发工具 待翻译

    Before we get started building any WordPress Theme, we’re going to need to get our development tools ...

  8. Amazon S3 PHP Class Documentation

    API : http://undesigned.org.za/2007/10/22/amazon-s3-php-class/documentation Example: http://www.phpb ...

  9. Oracle varchar2 4000

    关于oracle varchar2 官方文档的描述 VARCHAR2 Data Type The VARCHAR2 data type specifies a variable-length char ...

  10. CentOS 6.4 安装搭建 Scrapy 0.22 环境

    一.安装Python2.7.6 更新CentOS lib库文件 yum -y update 安装开发工具包 yum groupinstall -y development 安装扩展包 yum inst ...