任务切换——《x86汇编语言:从实模式到保护模式》读书笔记38

  1. 本文及后面的几篇博文是原书第15章的学习笔记。
  2. 本章依然使用第13章的主引导程序。

1. 协同式多任务与抢占式多任务

有两种基本的任务切换方式,一种是协同式的,一种是抢占式的。

1.1 协同式

从一个任务切换到另一个任务,需要当前任务主动地请求暂时放弃执行权,或者在通过调用门请求操作系统服务时,由操作系统趁机将控制转移到另一个任务。这种方式依赖于每个任务的“自律”性,当一个任务失控时,其他任务可能得不到执行的机会。

1.2 抢占式

可以安装一个定时器中断,并在中断服务例程中实施任务切换。硬件中断信号总会定时出现,在这种情况下,每个任务都能获得平等的执行机会。而且,即使一个任务失控,也不会导致其他任务没有机会执行。

抢占式多任务将在第17章学习。这一章,我们通过代码学习任务切换的几种方法,以及它们各自的特点。

关于任务切换的几种方法,可以参考我的博文:
任务切换的方法——《x86汇编语言:从实模式到保护模式》读书笔记36

2. 代码清单

本章实验需要3个源文件,分别是:
c13_mbr.asm(依然用第13章的引导程序)
c15_core.asm(第689和706行少了dword,应该加上)
c15.asm

3. 代码讲解

首先有几点需要说明:
1. 处理器在刚进入保护模式的时候,是以0特权级运行的;
2. 任务不一定非得是3特权级,也可以是0特权级;
3. 操作系统除了为每一个任务提供服务外,也会有一个作为任务而独立存在的部分,而且是0特权级别的任务,以完成一些管理和控制的功能。

内核开始的工作和上一章相同:主要是显示处理器的品牌信息,安装调用门。接下来的工作是创建0特权级的内核任务。

3.1 创建0特权级的内核任务——程序管理器

3.1.1 为程序管理器的TSS分配内存

908         ;为程序管理器的TSS分配内存空间
909         mov ecx,104                        ;为该任务的TSS分配内存
910         call sys_routine_seg_sel:allocate_memory
911         mov [prgman_tss+0x00],ecx          ;保存程序管理器的TSS基地址 

注意,为了追踪程序管理器的TSS,需要保存它的基地址和选择子。为此,作者在内核数据段声明并且初始化了6个字节。

430         ;程序管理器的任务信息
431         prgman_tss       dd  0             ;程序管理器的TSS基地址
432                          dw  0             ;程序管理器的TSS描述符选择子 

3.1.2 填写程序管理器的TSS

913         ;在程序管理器的TSS中设置必要的项目
914         mov word [es:ecx+96],0             ;没有LDT。处理器允许没有LDT的任务。
915         mov word [es:ecx+102],103          ;没有I/O位图。0特权级事实上不需要。
916         mov word [es:ecx+0],0              ;反向链=0
917         mov dword [es:ecx+28],0            ;登记CR3(PDBR)
918         mov word [es:ecx+100],0            ;T=0
919                                            ;不需要0、1、2特权级堆栈。0特级不
920                                            ;会向低特权级转移控制。

3.1.3 在GDT中创建TSS描述符

922         ;创建TSS描述符,并安装到GDT中
923         mov eax,ecx                        ;TSS的起始线性地址
924         mov ebx,103                        ;段长度(界限)
925         mov ecx,0x00408900                 ;TSS描述符,特权级0
926         call sys_routine_seg_sel:make_seg_descriptor
927         call sys_routine_seg_sel:set_up_gdt_descriptor
928         mov [prgman_tss+0x04],cx           ;保存程序管理器的TSS描述符选择子 

注意:TSS描述符只能安装在GDT中。

3.1.4 加载TR寄存器

930         ;任务寄存器TR中的内容是任务存在的标志,该内容也决定了当前任务是谁。
931         ;下面的指令为当前正在执行的0特权级任务“程序管理器”后补手续(TSS)。
932         ltr cx

第932行执行后,处理器用该选择子(CX的值)访问GDT,找到对应的TSS描述符,将其B位置1,表示该任务正在执行中(或者处于挂起状态);同时,还要把该TSS描述符传送到TR的描述符高速缓存器中。此时,可认为“程序管理器”任务正在执行中。

3.2 加载用户程序

3.2.1 分配一个任务控制块(TCB)

938         mov ecx,0x46
939         call sys_routine_seg_sel:allocate_memory
940         call append_to_tcb_link            ;将此TCB添加到TCB链中 

任务控制块依然用第14章的结构。

3.2.2 调用过程load_relocate_program

942         push dword 50                      ;用户程序位于逻辑50扇区
943         push ecx                           ;压入任务控制块起始线性地址
944
945         call load_relocate_program         

过程load_relocate_program的代码和上一章相比没有太大的变化,仅仅是对TSS的填写比较完整。

3.2.3 通过CALL指令切换到用户任务

947         call far [es:ecx+0x14]             ;执行任务切换。和上一章不同,任务切
948                                            ;换时要恢复TSS内容,所以在创建任务
949                                            ;时TSS要填写完整 

第947行是一个间接远调用指令,在TCB偏移为0x14的地方,应该先是一个32位的段内偏移,然后是一个16位的代码段选择子或者调用门选择子。

但是,结合TCB的结构图,我们发现先是一个TSS基地址(丢弃不用),然后是一个TSS的选择子。虽然有点奇怪,但是却合法。当处理器发现是TSS的选择子,就会执行任务切换。主要过程如下:
1. 保护现场,因为当前正在执行的任务是由TR指示的,所以要把每个寄存器的快照保存到由TR指向的TSS中。这些寄存器包括:GS,FS,DS,SS,CS,ES,EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX,EFLAGS,EIP.
2. 处理器根据TSS选择子索引GDT,找到新任务的TSS描述符,进而找到新任务的TSS,从中恢复各个寄存器的内容,包括通用寄存器、EFLAGES、段寄存器、EIP、ESP、LDTR等。
3. TR指向新任务的TSS,处理器开始执行新的任务。

下图对理解这个过程很有帮助。

不过,上面的总结不够完整,还隐去了一些细节,比如权限的检查(以后的博文会提到)。

另外,新旧任务的TSS的B位,EFLAGS的NT位,任务链接域的变化也是需要关注的。好在作者已经总结成了表格,这里我们再次复习一下。

3.3 用户程序的执行与切换到程序管理器

用户代码比较简单。请注意最后一行

74         call far [fs:TerminateProgram]    

这句是通过调用门转到全局空间执行。

354  terminate_current_task:                   ;终止当前任务
355                                            ;注意,执行此例程时,当前任务仍在
356                                            ;运行中。此例程其实也是当前任务的
357                                            ;一部分
358         pushfd
359         mov edx,[esp]                      ;获得EFLAGS寄存器内容
360         add esp,4                          ;恢复堆栈指针
361
362         mov eax,core_data_seg_sel
363         mov ds,eax
364
365         test dx,0100_0000_0000_0000B       ;测试NT位
366         jnz .b1                            ;当前任务是嵌套的,到.b1执行iretd
367         mov ebx,core_msg1                  ;当前任务不是嵌套的,直接切换到
368         call sys_routine_seg_sel:put_string
369         jmp far [prgman_tss]               ;程序管理器任务
370
371  .b1:
372         mov ebx,core_msg0
373         call sys_routine_seg_sel:put_string
374         iretd

358~360:获得EFLAGS寄存器的值,值保存在EDX中;
365:测试EFLAGS的NT位。本实验的场景是,程序管理器可以用JMP指令或者CALL指令切换到用户任务。如果是前者,那么用户任务的NT=0,需要用JMP指令切换到程序管理器;如果是后者,那么用户任务的NT=1,需要用IRET指令返回到程序管理器。

3.4 程序管理器再次加载用户任务

因为之前程序管理器通过CALL切换到了用户任务,所以用户任务会通过IRET返回,所以第374行会执行。接下来又回到了程序管理器,从它中断的地方继续执行,也就是第952行。

51         ;重新加载并切换任务
952         mov ebx,prgman_msg2
953         call sys_routine_seg_sel:put_string
954
955         mov ecx,0x46
956         call sys_routine_seg_sel:allocate_memory
957         call append_to_tcb_link            ;将此TCB添加到TCB链中
958
959         push dword 50                      ;用户程序位于逻辑50扇区
960         push ecx                           ;压入任务控制块起始线性地址
961
962         call load_relocate_program

955~962:再次加载用户任务,依然是第50扇区的程序。这充分说明:一个程序可以对应着多个运行中的副本,或者说多个任务。

3.5 管理器通过JMP指令切换到用户任务

963
964         jmp far [es:ecx+0x14]              ;执行任务切换

3.6 用户程序通过JMP指令切换到管理器

因为用户任务是同一份代码,所以也会执行到365行。不同的是这个任务不是嵌套于程序管理器的,所以会执行369行,用JMP指令返回。

3.7 程序管理器停机

966         mov ebx,prgman_msg3
967         call sys_routine_seg_sel:put_string
968
969         hlt

这章的代码就说到这里。感谢关注!

任务切换——《x86汇编语言:从实模式到保护模式》读书笔记38相关推荐

  1. x86汇编语言从实模式百度云_Intel x86 CPU 32位保护模式杂谈之任务切换 上

    目录: 什么是任务 任务由什么组成 任务门描述符是什么东东?有了TSS描述符为什么要有任务门描述符? 参考文献 什么是任务 任务(task)是处理器可以分配.执行.挂起的工作单位,笔者认为和我们操作系 ...

  2. 处理器在实施任务切换时的操作——《x86汇编语言:从实模式到保护模式》读书笔记39

    处理器在实施任务切换时的操作--<x86汇编语言:从实模式到保护模式>读书笔记39 处理器可以通过以下四种方法实施任务切换: 1. call指令或者jmp指令的操作数是GDT内的某个TSS ...

  3. 任务切换的方法——《x86汇编语言:从实模式到保护模式》读书笔记37

    任务切换的方法--<x86汇编语言:从实模式到保护模式>读书笔记37 1. 中断门和陷阱门 在实模式下,内存最低端的1M是中断向量表,保存着256个中断处理过程的段地址和偏移.当中断发生时 ...

  4. 硬盘和显卡的访问与控制(一)——《x86汇编语言:从实模式到保护模式》读书笔记01

    本文是<x86汇编语言:从实模式到保护模式>(电子工业出版社)的读书实验笔记. 这篇文章我们先不分析代码,而是说一下在Bochs环境下如何看到实验结果. 需要的源码文件 第一个文件是加载程 ...

  5. 任务和特权级保护(三)——《x86汇编语言:从实模式到保护模式》读书笔记34

    任务和特权级保护(三)--<x86汇编语言:从实模式到保护模式>读书笔记34 5.2.7 在GDT中创建LDT描述符 处理器要求在GDT中安装每个LDT的描述符.当要使用这些LDT时,可以 ...

  6. 程序的加载和执行(五)——《x86汇编语言:从实模式到保护模式》读书笔记25

    程序的加载和执行(五)--<x86汇编语言:从实模式到保护模式>读书笔记25 前面几篇博文终于把代码分析完了.这篇就来说说代码的编译.运行和调试. 1.代码的编译及写入镜像文件 之前我们都 ...

  7. 程序的加载和执行(四)——《x86汇编语言:从实模式到保护模式》读书笔记24

    程序的加载和执行(四)--<x86汇编语言:从实模式到保护模式>读书笔记24 通过本文能学到什么? 怎样跳转到用户程序 用户程序通过调用内核过程完成自己的功能 怎样从用户程序返回到内核 接 ...

  8. 【OS修炼指南目录】----《X86汇编语言-从实模式到保护模式》读书笔记目录表

    学习交流加(可免费帮忙下载CSDN资源): 个人微信: liu1126137994 学习交流资源分享qq群1(已满): 962535112 学习交流资源分享qq群2: 780902027 本文是将个人 ...

  9. x86汇编语言从实模式百度云_x86汇编语言:从实模式到保护模式

    x86汇编语言:从实模式到保护模式2013年1月由电子工业出版社出版发行,总共6000行的源代码,全方位地向读者展现汇编语言程序设计之美.尽管汇编语言也是一种计算机语言,但却是与众不同的,与它的同类们 ...

最新文章

  1. python之路---装饰器函数
  2. mysql日常有哪些用_mysql日常笔记(持续更新)
  3. Appium 命令行安装教程
  4. ABAP入门程序,你会了嘛?
  5. 设计模式:代理模式是什么,Spring AOP还和它有关系?
  6. IDEA远程部署调试Java应用程序
  7. Java学习之数据类型的转换
  8. spring boot(一):Hello World
  9. Java 8 (5) Stream 流 - 收集数据
  10. 凸优化第二章凸集 2.5分离与支撑超平面
  11. 大学生python心得1000字_大学生读书心得1000字3篇
  12. dx11 将纹理保存到dds
  13. 《自拍教程74》Python 假装企业微信电脑在线并定时关机,骗老板的好方法!
  14. python实现误差逆传播算法
  15. javamail模拟邮箱功能--邮件删除-中级实战篇【邮件标记方法】(javamail API电子邮件实例)
  16. 郭店楚简——原简整理,文物出版社
  17. 先验概率和后验概率那点事儿
  18. nginx upstream 健康检查
  19. 实验吧CTF逆向题1000writeup
  20. Qt Creator打造VScode one dark pro主题配色

热门文章

  1. Python中的遇到的错误(持续更新)
  2. Adnroid提高效率之资源移动
  3. ALGO-117_蓝桥杯_算法训练_友好数
  4. 使用正則表達式对URL进行解析
  5. 尝试.Net Core—使用.Net Core + Entity FrameWork Core构建WebAPI(一)
  6. 线段树--codevs 1690 开关灯
  7. CentOS 6.5系统安装配置图解教程(详细图文)
  8. ChartDirector资料小结
  9. 超长数列中n个整数排序C++代码实现
  10. 转:c/c++ 运行库