最近看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. C++将类的构造函数、析构函数声明为private或者protected的用途

    如果将构造函数.析构函数声明为private或者protected,表示不能从类的外部正常调用构造和析构函数了. 这种用法的通常使用的场景如下: 1.如果不想让外面的用户直接构造一个类A的对象,而希望 ...

  2. SAP存货账龄分析之库存获取

    前段时间上面要求做一个历史库存账龄分析,取历史数据的时候一直纠结于用mchb/mchbh/mska/mskah等实时和历史库存表,然而试来试去还是不能成功,于是决定DEBUG下MB5B的源代码,测试了 ...

  3. VKP5 Price Calculation – List Variant & KZPBL (Delete site level)

    List Variant: Configuration in Logistic General –> Retail Pricing –> Sales Price Calculation – ...

  4. 解决ubuntu 14.04 下eclipse 3.7.2 不能启动,报Could not detect registered XULRunner to use 或 org.eclipse.swt.SWTError: XPCOM 等问题的处理

    对于eclipse 3.7.2在ubuntu 14.04下不能启动,需要在 eclipse/configuration 目录下的config.ini文件内增加一行org.eclipse.swt.bro ...

  5. DataGridView导入导出excel

    DataGridView导出到Excel #region 方法一 DateGridView导出到csv格式的Excel /// <summary> /// 导出数据到Excel.常用方法, ...

  6. Linux内核学习方法

    Makefile不是Make Love 从前在学校,混了四年,没有学到任何东西,每天就是逃课,上网,玩游戏,睡觉.毕业的时候,人家跟我说Makefile我完全不知,但是一说Make Love我就来劲了 ...

  7. 【go】sdk + idea-plugin 开发工具安装

    http://golang.org/doc/install/source 第一步:windows 安装 git第二步$ git clone https://go.googlesource.com/go ...

  8. 从零开始学ios开发(十二):Table Views(上)

    这次学习的控件非常重要且非常强大,是ios应用中使用率非常高的一个控件,可以说几乎每个app都会使用到它,它就是功能异常强大的Table Views.可以打开你的iphone中的phone.Messa ...

  9. hornetq 入门(1)

    Hornetq 版本2.4.0final  需要JDK7及以上 Hornetq官网 Hornetq2.1中文手册 step1.启动服务端 1.1准备配置文件(配置说明参考官网手册) hornetq-c ...

  10. ASP.NET MVC +EasyUI 权限设计(二)环境搭建

    请注明转载地址:http://www.cnblogs.com/arhat 今天突然发现博客园出问题了,老魏使用了PC,手机,平板都访问博客园了,都是不能正常的访问,原因是不能加载CSS,也就是不能访问 ...