当执行完 system_interrupt 函数,执行 153 行 iret 时,记录栈的变化情况。

任务0在刚进入system_interrupt函数时(调用中断int 0x80处理程序),栈空间为任务0的内核栈,即krn_stk0。(CS = 0X8, SS = 0x10, ESP = 0xe4c)

查看栈空间,里面存放着5个双字,即任务0执行的状态信息(EIP、SS、EFLAGS、ESP、SS)。具体信息是任务0的运行位置:0x10e0 movl $0xfff,%ecx,是int 0x80的下一条指令。还有任务0的栈空间地址,即任务0的用户栈(init_stack)。

在执行iret指令前,该函数压栈保存程序用到的寄存器,最后弹栈。所以,在iret执行前,栈空间即如上。

在执行iret指令后,回到任务0调用中断处的下一条指令,栈空间又切换为了任务0的用户栈(CS = 0Xf, EIP = 0x10eb, SS = 0x17, ESP = 0xbd8)。这是因为将之前栈中信息弹出到对应的寄存器中。

所以,当任务0执行system_interrupt函数时,执行完iret指令后,栈变化的情况是:任务0的用户栈保持不变,任务0的内核栈仍然为空。

任务1同理。

当进入和退出 system_interrupt 时,都发生了模式切换,请总结模式切换时,特权级是如何改变的?栈切换吗?如何进行切换的?

特权级改变

仍然以任务0为例子,任务0 CS = 0xf,是任务0 LDT的代码段描述符的选择子,特权级为 3。当进入system_interrupt后,CS = 0x8,是GDT内核代码段的选择子,特权级为 0。

特权级的改变是通过该陷阱门实现的。该陷阱门的DPL为3,允许特权级为3的程序执行,执行后,该陷阱门中的段选择符为 0x8,是内核代码段选择符(中断程序属于内核)。所以,在经过特权级检查成功通过后,特权级就由 3变为了 0。

返回时,允许返回到低特权级程序。特权级也就从 0变为了 3。

栈切换

栈也会切换。在进入system_interrupt时,特权级会变为 0,栈空间指针(SS ESP)就会变为从TSS里取出特权级 0对应的栈指针。

退出时,因为在进入时被调用者栈中保存了原栈空间指针,则直接弹栈,将保存的SS ESP值加载到SS ESP 寄存器中,从而切换回调用者的堆栈。

当时钟中断发生,进入到 timer_interrupt 程序,请详细记录从任务 0 切换到任务 1 的过程。

在程序中,有一块 4字的空间存放着一个数值(可以认为是一个全局变量),为current。在timer_interrupt程序中,若current值为 0,则之前执行的是任务 0,要切换到任务 1;若current值为1,则之前执行的是任务 1,要切换到任务 0。

通过判断current值,进行不同的跳转(长跳转),从而实现任务 0与 1之间的切换。

当第一次时钟中断发生,任务 0在loop指令处。栈空间切换为任务 0特权级0 的栈空间(即任务 0的内核栈空间)。在该栈空间中,保存着任务 0运行的状态信息SS ESP EFLAGS CS EIP。

timer_interrupt 程序顺序向下运行,在判断当前current值不为1时,将current更新为1,然后长跳转到任务 1。

跳转的具体过程是,长跳转提供了一个远指针。该指针中的段选择符指向了TSS1。任务1的TSS保存着它状态信息 ,包括跳转后的栈指针、EFLAGS、代码指针。这些信息,在第一次切换到任务 1时,分别是任务1的用户栈,任务1的第一条指令地址。

如此,便从任务0切换到了任务1。

又过了 10ms ,从任务1切换回到任务 0 ,整个流程是怎样的? TSS 是如何变化的?各个寄存器的值是如何变化的?

在第一次从任务0切换到任务1后,查看任务0的TSS,发现任务 0的CS:EIP为0X08:0x150,即为内核代码段,是system_interrupt中指令jmp 2f,是切换到任务1的远跳转的后一条指令。

当运行任务1时,与任务0同理,在loop指令处,触发时钟中断,进入到 timer_interrupt 程序。

因为之前,current值为设置为 1,那么这次就会长跳转到任务 0。在执行该指令ljmp $TSS0_SEL,$0前,寄存器值:

执行后发现,待执行的指令为<0x0150> jmp .+17(0x0163),这正是之前任务 0的TSS保存的指令执行地址。此时的寄存器值:

可以看到,通用寄存器值、段寄存器值、标志寄存器值、指令指针EIP值,均对应之前查看的任务0 TSS。

此时,再查看任务1的TSS。

正是保存着执行前任务1的寄存器值,其中CS:EIP指向了下一条指令<0x0163> pop eax。

请详细总结任务切换的过程。

对于该例子,是当前任务对GDT的TSS段描述符执行JMP指令。则任务切换的过程是:

  1. 从JMP指令操作数中,取得新任务的TSS段选择子。

  2. 特权级检查。当前任务的CPL和新任务段选择符的RPL必须小于等于TSS段描述符的DPL。

  3. 检查新任务的TSS段描述符是标注为存在的(P = 1),并且TSS段长度有效。

  4. 将当前任务忙标志B复位。

  5. 把当前任务的状态保存到当前任务的TSS中。

  6. 设置新任务的忙标志B。

  7. 使用新任务的TSS的段选择符和描述符加载任务寄存器TR (包括隐藏部分)。设置CR0寄存器的TS标志。

  8. 加载新任务的TSS状态,包括LDTR寄存器,PDBR(CR3)寄存器、EFLAGS寄存器、EIP寄存器以及通用寄存器和段选择符。

  9. 开始执行新任务。

注意:

任务切换时,新任务的特权级和原任务的特权级没有任何关系。新任务在CS寄存器的CPL字段指定的特权级上运行,因为各个任务通过它们独立的地址空间和TSS段相互隔绝,并且特权级规则已经控制对TSS的访问,所以在任务切换时软件不需要再进行特权级检查。

调试分析 Linux 0.00 多任务切换的更多相关文章

  1. 通过gdb调试分析Linux内核的启动过程

    作者:吴乐 山东师范大学 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.实验流程 1.打开环境 执 ...

  2. Linux调试分析诊断利器——strace

    strace是个功能强大的Linux调试分析诊断工具,可用于跟踪程序执行时进程系统调用(system call)和所接收的信号,尤其是针对源码不可读或源码无法再编译的程序. 在Linux系统中,用户程 ...

  3. Linux 线程实现机制分析 Linux 线程模型的比较:LinuxThreads 和 NPTL

    Linux 线程实现机制分析 Linux 线程实现机制分析  Linux 线程模型的比较:LinuxThreads 和 NPTL http://www.ibm.com/developerworks/c ...

  4. Linux 线程实现机制分析 Linux 线程实现机制分析 Linux 线程模型的比较:LinuxThreads 和 NPTL

    Linux 线程实现机制分析 Linux 线程实现机制分析  Linux 线程模型的比较:LinuxThreads 和 NPTL http://www.ibm.com/developerworks/c ...

  5. 跟踪分析Linux内核的启动过程小解

    跟踪分析Linux内核的启动过程 “20135224陈实  + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029 ...

  6. 20135239 益西拉姆 linux内核分析 跟踪分析Linux内核的启动过程

    回顾 1.中断上下文的切换——保存现场&恢复现场 本节主要课程内容 Linux内核源代码简介 1.打开内核源代码页面 arch/目录:支持不同CPU的源代码:其中的X86是重点 init/目录 ...

  7. CVE-2012-0003:Microsoft Windows Media Player winmm.dll MIDI 文件堆溢出漏洞调试分析

    0x01 蜘蛛漏洞攻击包 前言:2012 年 2月,地下黑产中流行着一款国产名为蜘蛛漏洞的攻击包 -- "Zhi-Zhu Exploit Pack",该工具包含 5 个漏洞,都是在 ...

  8. 分析Linux内核创建一个新进程的过程【转】

    转自:http://www.cnblogs.com/MarkWoo/p/4420588.html 前言说明 本篇为网易云课堂Linux内核分析课程的第六周作业,本次作业我们将具体来分析fork系统调用 ...

  9. 通过从代码层面分析Linux内核启动来探知操作系统的启动过程

    通过从代码层面分析Linux内核启动来探知操作系统的启动过程 前言说明 本篇为网易云课堂Linux内核分析课程的第三周作业,我将围绕Linux 3.18的内核中的start_kernel到init进程 ...

  10. Linux 0.11下信号量的实现和应用

    Linux 011下信号量的实现和应用 生产者-消费者问题 实现信号量 信号量的代码实现 关于sem_wait和sem_post sem_wait和sem_post函数的代码实现 信号量的完整代码 实 ...

随机推荐

  1. python快速入门【五】---- 面向对象编程、python类

    python入门合集: python快速入门[一]-----基础语法 python快速入门[二]----常见的数据结构 python快速入门[三]-----For 循环.While 循环 python ...

  2. 基于 hugging face 预训练模型的实体识别智能标注方案:生成doccano要求json格式

    强烈推荐:数据标注平台doccano----简介.安装.使用.踩坑记录_汀.的博客-CSDN博客_doccano huggingface官网 参考:数据标注平台doccano----简介.安装.使用. ...

  3. C/C++ MinHook 库的使用技巧

    在上面的各种Hook挂钩方式中,我们都是在手写封装代码,但这样的方式并不高效,真正的生产环境中我们必须使用现成的Hook库,常用的Hook库有免费开源的MinHook和商业的Detours Hook, ...

  4. docker中的mysql时区修改

    永久修改 进入容器 docker exec -it mysql5.7 bash 查看当前时区 date -R 修改时区 cp /usr/share/zoneinfo/PRC /etc/localtim ...

  5. Windows上部署Python flask项目

    最近使用Python flask做了一个项目要部署,网上一大堆教程没有一个完整,最后看了多个教程才配置完成,下面根据自己的环境整理一下做个备忘录 环境: Windows 10 apache httpd ...

  6. TF-VAEGAN:添加潜在嵌入(Latent Embedding)的VAEGAN处理零样本学习

    前面介绍了将VAE+GAN解决零样本学习的方法:f-VAEGAN-D2,这里继续讨论引入生成模型处理零样本学习(Zero-shot Learning, ZSL)问题.论文"Latent Em ...

  7. .NET Core开发实战(第27课:定义Entity:区分领域模型的内在逻辑和外在行为)--学习笔记

    27 | 定义Entity:区分领域模型的内在逻辑和外在行为 上一节讲到领域模型分为两层 一层是抽象层,定义了公共的接口和类 另一层就是领域模型的定义层 先看一下抽象层的定义 1.实体接口 IEnti ...

  8. Linux 在线安装MySQL8.0

    1.更新Linux yum yum update 2.安装wget工具(如果已经安装wget,可以跳过该步骤) yum install wget 3.使用wget下载MySQL Yum Reposit ...

  9. 【译】发布 .NET Aspire 预览版 2(二)

    原文 | Damian Edwards 翻译 | 郑子铭 组件更新 组件包现在有单独的图标 大多数 Aspire 组件的 NuGet 包现在都具有代表性图标,以便在 NuGet 包管理器对话框中更轻松 ...

  10. angularjs国际化多语言,angular-translate教程详解,$translate.instant()为什么不生效

    壹 ❀ 引 最近项目要求支持国际化多语言,由于项目用的还是angularjs,那么首当其冲的选择了angularjs封装的I18N插件angular-translate,本文主要会从三个方向展开讨论, ...