switch_to 理解

最近看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;

时间: 2024-10-21 16:36:08

switch_to 理解的相关文章

Linux系统理解以及Linux系统学习心得

原创作品转载请注明出处  <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 作者:严哲璟 说一下我对Linux系统的理解 1.加载Linux内核准备:在加载基本输入输出模块(BIOS)之后,从磁盘的引导扇区读入操作系统的代码文件块到内存中,之后开始整个系统的初始化. 2.main.c的start_kernel函数是整个操作系统的入口,这也与Linux是基于C语言的特性相符,start_kernel具体做的动作很多

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

陈巧然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.视频内容 Linux系统的一般执行过程 最一般的情况:正在运行的用户态进程X切换到运行用户态进程Y的过程 1. 正在运行的用户态进程X 2. 发生中断——save cs:eip/esp/eflags(current) to kernel stack, then load cs:eip(entry of a specific IS

理解进程调度时机跟踪分析进程调度与进程切换的过程

李洋 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 这一次实验是针对linux系统中进程调度时机得深入理解. Linux 调度器将进程分为三类: 1. 交互式进程 2. 批处理进程 3. 实时进程 根据进程的不同分类 Linux 采用不同的调度策略.对于实时进程,采用 FIFO 或者 Round Robin 的调度策略.对于普通进程,则需要区分交互式和批处理式的不同.传统 Linux 

实验八——理解进程调度时机跟踪分析进程调度与进程切换的过程

理解进程调度时机跟踪分析进程调度与进程切换的过程 攥写人:李鹏举  学号:20132201 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000) 一.实验要求: 理解Linux系统中进程调度的时机,可以在内核代码中搜索schedule()函数,看都是哪里调用了schedule(),判断我们课程内容中的总结是否准确: 使用gdb跟踪分析一个schedule()函数 ,验

linux 内核的 switch_to原理

switch_to:这是一个宏,有三个参数prev,next,last 局部变量prev,next:指向进程描述符的内存地址 首先明确的是:last和prev是同一个,用last只是为了理解方便,完全可以用两个参数prev,next.因为last就是prev switch_to宏用于进程切换,给定了前一个进程结构体指针prev,以及需要切换到的进程结构体指针next,从prev切换到next.但是,实际上,switch_to宏有三个参数,除了上面说的两个参数之外,还有一个last参数.而且使用s

lab8:理解进程调度时机跟踪分析进程调度与进程切换的过程

李俊锋 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.实验原理 1.操作系统的基本概念 任何计算机系统都包含一个基本的程序集合,称为操作系统. – 内核(进程管理,进程调度,进程间通讯机制,内存管理,中断异常处理,文件系统,I/O系统,网络部分) – 其他程序(例如函数库.shell程序.系统程序等等) 操作系统的目的 – 与硬件交互,管理所有的硬件资源 – 为用户程序(应

Linux内核学习总结:Linux系统的理解及学习Linux内核的心得

作业一计算机是如何工作的进行http://www.cnblogs.com/zhengwei0712/p/5207299.html 作业二操作系统是如何工作的进行http://www.cnblogs.com/zhengwei0712/p/5234622.html 作业三LINUX内核的启动过程http://www.cnblogs.com/zhengwei0712/p/5253703.html    第一章:Linux发展与UNIX 第二章:内核源码获取.解压.配置.编译与安装 作业四系统调用的工作

Linux 0.12 sched.c代码理解

最近看看linux0.12,对自己理解内核有很大帮助,但是有些东西也确实需要时间去认真分析,今天看看了sched.c的代码,和大家分享一下.先上代码 /* * linux/kernel/sched.c * * (C) 1991 Linus Torvalds */ /* * 'sched.c' is the main kernel file. It contains scheduling primitives * (sleep_on, wakeup, schedule etc) as well a

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

一.原理分析 1.调度时机 背景不同类型的进程有不同的调度需求第一种分类I/O-bond:频繁的进行I/O:通常会花费很多时间等待I/O操作的完成CPU-bound:计算密集型:需要大量的CPU时间进行运算 第二种分批处理进程(batch process):不必与用户交互,通常在后台运行:不必很快响应.典型的批处理程序:编译程序.科学计算实时进程(real-time process):有实时需求,不应被低优先级的进程阻塞:响应时间要短.要稳定.典型的实时进程:视频/音频.机械控制等交互式进程(i