最近看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. 超赞值得一试的六款jQuery插件和CSS3应用

    1.jQuery图片横向滚动插件 这是一款利用jQuery实现的图片横向滚动插件,我们可以设置任意数量的图片,然后点击左右箭头按钮即可分组浏览这些图片.这款jQuery图片插件的优势有两点,其一是可以 ...

  2. Data Mining Resources

    韩家炜 http://www.cs.uiuc.edu/~hanj/ 著名数据挖掘书籍,<数据挖掘概念和技术>作者,在DM界久负盛名.他的个人主页里面有很多他的papers,都非常经典:还有 ...

  3. POJ 2837 Til the Cows Come Home

    Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 45515   Accepted: 15434 Description Bes ...

  4. Python深拷贝和浅拷贝

    1- Python引用计数[1] 1.1 引用计数机制 引用计数是计算机编程语言中的一种内存管理技术,是指将资源(可以是对象.内存或磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其释放的 ...

  5. easyUI中treegrid组件构造树形表格(简单数据类型)+ssm后台

    这几天做的项目要求用树形表格的形式展示一部分数据,于是就想到了使用easyUI的treegrid组件,但几经翻查各种资料,发现数据类型大多采取标准数据类型,即包含children元素的数据类型,小编查 ...

  6. UVA10361 -自动作诗机

    UVA10361 - Automatic Poetry(自动作诗机) A Schuttelreim seems to be a typical German invention. The funny ...

  7. 用golang启动一个daemon

    用golang启动一个daemon package main import ( "fmt" "log" "os" "runtime ...

  8. IDEA笔记

    快捷键: 查找类:ctrl + shif + R (eclipse)查找文件:double shift查找文件中的变量名和方法:ctrl + H (eclipse)system.out:输入 sout ...

  9. 每日一“酷”之string

    介绍:string模块可以追溯到最早的Python版本中.现在很多的被移植为str和unicode对象的方法,在python3.0中会被完全去除.string模块中,有很多有用的常量和累,用来处理st ...

  10. 大陆Azure 改版

    好吧主页的又改版了这下终于容易区分大陆与国际版的区别了.2014年12月12日起改版. 主页再次沦落为找不到东西的后果,其实很少进入这个主页,一般也直接使用http://manage.windowsa ...