操作系统实战 45 讲
彭东
网名 LMOS,Intel 傲腾项目关键开发者
65203 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 60 讲
尝尝鲜:从一个Hello到另一个Hello (2讲)
特别放送 (1讲)
操作系统实战 45 讲
15
15
1.0x
00:00/00:00
登录|注册

05 | CPU工作模式:执行程序的三种模式

切换到长模式
中断
段描述符
寄存器
切换到保护模式
中断
段选择子
段描述符
特权级
寄存器
中断
访问内存
寄存器
思考题
长模式
保护模式
实模式
CPU工作模式

该思维导图由 AI 生成,仅供参考

你好,我是 LMOS。
我们在前面已经设计了我们的 OS 架构,你也许正在考虑怎么写代码实现它。恕我直言,现在我们还有很多东西没搞清楚。
由于 OS 内核直接运行在硬件之上,所以我们要对运行我们代码的硬件平台有一定的了解。接下来,我会通过三节课,带你搞懂硬件平台的关键内容。
今天我们先来学习 CPU 的工作模式,硬件中最重要的就是 CPU,它就是执行程序的核心部件。而我们常用的电脑就是 x86 平台,所以我们要对 x86 CPU 有一些基本的了解。
按照 CPU 功能升级迭代的顺序,CPU 的工作模式有实模式保护模式长模式这几种工作模式下 CPU 执行程序的方式截然不同,下面我们一起来探讨这几种工作模式。

从一段死循环的代码说起

请思考一下,如果下面这段应用程序代码能够成功运行,会有什么后果?
int main()
{
int* addr = (int*)0;
cli(); //关中断
while(1)
{
*addr = 0;
addr++;
}
return 0;
}
上述代码首先关掉了 CPU 中断,让 CPU 停止响应中断信号,然后进入死循环,最后从内存 0 地址开始写入 0。你马上就会想到,这段代码只做了两件事:一是锁住了 CPU,二是清空了内存,你也许会觉得如果这样的代码能正常运行,那简直太可怕了。
不过如果是在实模式下,这样的代码确实是能正常运行。因为在很久以前,计算机资源太少,内存太小,都是单道程序执行,程序大多是由专业人员编写调试好了,才能预约到一个时间去上机运行,没有现代操作系统的概念。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

CPU工作模式的演变及特点 本文详细介绍了CPU的工作模式,包括实模式、保护模式和长模式。实模式下,CPU执行程序简单,不加区分地执行指令和访问内存,适用于资源有限的场景。保护模式通过扩展寄存器位宽和引入特权级等机制,实现对指令和资源的访问控制和内存保护。在保护模式下,CPU引入了控制寄存器和段描述符等新概念,提供更加灵活和安全的程序执行环境。文章还介绍了长模式(AMD64),包括寄存器和段描述符的特点。长模式弱化段模式管理,只保留了权限级别的检查,忽略了段基址和段长度,而地址的检查则交给了MMU。 切换到长模式的步骤包括准备长模式全局段描述符表、准备长模式下的MMU页表、加载GDTR寄存器、开启长模式和进行跳转。切换到长模式和切换保护模式的流程相似,但需要注意同时开启保护模式和分页模式。最后,文章提出了思考题,引导读者思考实模式下能寻址多大的内存空间。 总的来说,本文通过详细介绍CPU工作模式的演变和特点,为读者提供了对计算机CPU工作原理的重要参考价值。文章内容涵盖了实模式、保护模式和长模式的特点及切换步骤,对于系统开发人员和对CPU工作模式感兴趣的读者具有较高的技术含量和参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《操作系统实战 45 讲》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(163)

  • 最新
  • 精选
  • Geek_a5edac
    置顶
    之前看过深入理解linux内核,但缺少模型上的分析,从书本从头看到尾反反复复最终似懂非懂,看了该系列整体上清晰多了,有了比较清晰的知识结构。而且因为之前有了解过相关概念,所以看此篇很快,倒没啥压力了哈哈

    编辑回复: 6666,很高兴对你有帮助!看得出你的功底很扎实,继续加油

    2021-05-30
    2
    7
  • Freddy
    置顶
    这节CPU三种工作模式,确实信息量比较大; 第一遍扫完后,发现好多细节都没有太懂; 第二遍精读,每句话,每个图,每行代码都一一理解后,再往下进行,龟速,需要很好的耐心,中间偶尔还要停顿信息,放松下大脑。这一边用了2-3个小时; 现在终于有感觉了; 看到长模式下,段描述符中不在有段基地址和段内偏移,就会去想那如何用段描述符定位内存中的数据呢? 这时就想到了操作系统里面的页面。。。 果然下面的文字就提到了MMU和TLB 激活了我多年没有用过的操作系统课知识点

    作者回复: 你好,是的,你学习方法很好。值得点赞和推广

    2021-05-26
    16
  • Vic
    置顶
    看了今天的课程和同学们的留言让我百感交集。 人的一生时间有限,无法什么都做到极致。但在摸索的过程是可以什么都去碰一下,才知道自己喜欢什么。我以为我不是那么喜欢计算机。我不是本科,是念电机工程的,已算是很相近的,比起念化学或是文史哲商等。但我仍然用了一堵高墙将自己围住,说自己不是纯正计算机本科的。 二十年前刚开始工作时有机会接触8051控制器,是用8051的汇编代码,花了不少时间把中断、寄存器研究过、因为8051只有8位元,相对简单,但没有操作系统,我开始对操作系统有兴趣,就开始自学x86的操作系统,买书来看,但真的看不懂,当时也没有互联网上这么多讯息,还买了minix的书来看,英文的书有多了一层外文的障碍,因为工作忙,也没实际用到,就这么放下了。 最近看到老师的这专烂,让我想到之前放弃了的操作系统的学习。 老师讲的实在太好了,给100个赞都不够。因为他是亲身实践过,而且表达力极佳。 过去不懂的,开始有一点看得懂了。但是真的是单纯因为老师讲的好我才看得懂吗? 看到底下很多同学的留言,让我想起二十年前的自己。 这过程有点像是小学的数学学不明白,到了中学再回头看,竞然明白了。 其实是自己的理解增加了,我不想用聪明这个字,会误导很多人。 纠结在自己有没有天份。 我很认同老师在底下同学留言的回覆。 "不需要前置的知识","多看几遍","如果看到一个新东西 ,不要在意它叫什么,它叫什么都可以,而是要在意它是干什么的,它有什么作用。有了整体思路,再去扣细节。" 也不存在着需要什么条件,常常就是这种条件,自己把自己绊住了, 以为自己没有达到,就放弃了。或是就转移目标去完成那个条件,而忘了回来原来的操作系统的学习。 很多时候困难全是自己想出来的。觉得难,这是很正常的。 不必要对自己太严苛。可以稍微休息一下(我说稍微不是二十年),做一下别的事,再回来。 每个人的情况都不一定,没有一个固定的方法或是习惯,只有问你自己。 因为太难就放弃,那就太可惜了。可以慢一点没关系,不要放弃。 想想自己为什么来上这个课,想要从这个课得到什么? 如果是加薪,升官,学分或是为了下一门课会不会压力很大? 如果只是因为好奇,这看起来还挺有趣,想了解一下,会让你更挺得住这些困难。 因为有这些难点本来就很正常,克服了,弄懂了一个信心就会增加,就会继续前进, 如果一开始不去克服那个难点,选择逃避或是绕路,那永远就是在原地打转。 如果这一篇让你觉得鸡汤或是说教,那不是我的本意。只是将自己过去有感而发写下的。我也还在学习。 谢谢老师带来亲身实践后这么精彩的课程,也谢谢同学们对我的启发,共勉之~

    作者回复: 你好,这个评论让我感到震撼,想必老哥之前也是认真研究过操作系统的人,才会有如此深刻的体会。一定是走了很多路才会有这样的启发和经验,我写这门的定位就是实战可能和学究派不同,我不讲虚的,只有让别人写出操作系统 ,这门课才达到了目标,也是对诸多同学的一个交付,谢谢你

    2021-05-26
    16
    225
  • neohope
    置顶
    稍微总结一下: 1、x86 CPU的位数越来越高,从16到32到64,每次进步都尽量的去兼容了之前的CPU架构,所以: A、16位时寻址能力不足,所以要借助额外的寄存器进行1M空间的寻址;32位时,每个程序都有自己独立的4G寻址空间,操作系统用低位的1G-2G,其余留给用户程序;64位后,暂时就遇不到寻址能力不足的事情了; B、前一代的寄存器尽量保留,不够用就扩展新的 C、寄存器的长度升级后,其低位可以兼容上一代的寄存器 2、CPU同时在安全性上也要提升,从只有实模式【可以随意执行全部CPU指令,内存可以直接通过物理地址访问,随意访问随意读写】,到了32的保护模式【将指令划分为ring0到ring3,CPU指令不是你想调用就能调用;内存不是你想访问就能访问,首先CPU要允许,而且操作系统允许】,而64的长模式在安全方面与32并没有本至区别; 3、从实模式到保护模式,访问内存时,需要访问的地址变大了,需要控制的内容变多了,于是引入了段描述符,所有的段描述符组成了描述符表,包括唯一的全局描述符GDT和多个局部描述符号LDT。GDT是操作系统特供,要重点关注。CPU寻址的时候,要通过段寄存器+GDTR寄存器定位到的内存中的描述符,判断是否允许访问。然后,再根据段描述符中地址进行访问。 4、同时内存中内存管理有段、页、段页三种常用模式。一般在应用层,程序员感受不太到,操作系统全给咱们做完了。 5、中断,其实是通过硬件或软件方式告诉CPU,来执行一段特殊的代码。比如咱们键盘输入,就是通过硬件中断的方式,告知操作系统的。在实模式下,中断是直接执行的。但到了保护模式和长模式下,就要特权级别校验通过才能执行,所以引入了中断门进行控制。在ring3调用中断一般是要通过操作系统切换到内核态ring0进行的,与内存类似,要通过中断向量表,确认中断门中权限是否允许,然后定位到指定代码执行。 6、BIOS引导后,系统直接进入最简单、特权最大的实模式;而后告知CPU,切换到保护模式,并运行在ring0。后续的用户进程,一般就在ring3,想执行特权指令要通过操作系统来执行。

    编辑回复: 很感谢你的分享和总结,66666~

    2021-05-23
    4
    155
  • 李军
    置顶
    汇编看不懂,还有x86平台也不懂,请问可以从哪里入手下?

    编辑回复: 小编指路,根据群聊分享,汇编可以参考《汇编程序设计》(王爽)。 不用太过担心,汇编只占很少一部分,先理解课程整体思路。另外,你现在不理解具体寄存器的细节,也不会影响对整个课程的学习,别慌。

    2021-05-19
    5
    2
  • 李军
    置顶
    搞java的我,表示没看懂

    编辑回复: 如果看到一个新东西 ,不要在意它叫什么,它叫什么都可以,而是要在意它是干什么的,它有什么作用。有了整体思路,再去扣细节。

    2021-05-19
    10
    59
  • pedro
    置顶
    这篇文章信息量很大,但是问题比较简单,我先回答一下问题吧。 实模式下的寻址空间跟地址总线的个数是密切相关的,早期的 x86 物理机,虽然寄存器是 16 位,但是地址总线却有 20 根,根据计算 2^20 = 1M,寻址空间肯定得有 1M 啊,但是寄存器只有 16 位,即 2^16,没有这么大的空间啊,臣妾办不到啊~ 那怎么办呢?聪明的 intel 工程师(挖坑师)想到了一个办法,即段寄存器左移 4 位,然后加上另外一个通用寄存器的值就可以组合出这个 20 位了,即 2^16 * 2^4 + 2*16,哦嚯一下子组装出来了。 这样 20 根地址总线都用上了,得到了 1M 的寻址空间,可把工程师给乐坏了。 但是,后面的事情大家都知道了,16 位不够了,32 位也不够了,在 64 位的情况下,完全不用考虑地址空间的大小问题了,变成了内存不够的问题了,而这个时候,保护模式下的虚拟地址映射又完美解决了这个问题(虚拟地址后面有),哟嚯,又把 intel 的这群挖坑师给乐坏了。

    作者回复: 哈哈

    2021-05-19
    24
    167
  • 云师兄
    置顶
    内容硬核,已啃三遍!

    作者回复: 坚持 就会 明白 不错哦

    2021-05-19
    12
  • 马杰
    看到后面,回头再看一遍,记点笔记。 实模式,保护模式,长模式,逐渐演进 1、实模式: (1)代码段地址+左移4位+ IP = 取指 数据段+左移4位+ 通用寄存器值 = 数据地址 栈段SS+左移4位 + SP = 栈地址 (2)实模式中断: 中断号+ IDTR 寄存器(指向中断表的地址和长度) ---> 根据中断号,找到中断表中的对应条目 ---> 解析出中断函数基地址填充CS、中断函数偏移填充IP ---> 响应中断。 2、保护模式: (1)保护模式寄存器:通用寄存器,IP,SP 16位->32位。添加了EFLAGS cpu标志寄存器和几个cpu控制寄存器。 CS DS SS 中改为存放内存段的索引,用于寻找内存中的段描述符。 (2)保护模式下,R0 -- R3的特权级别访问。通过内存中存放64位段描述符实现特权划分,段地址寻址。 CS | DS | SS (段描述符索引)+ GDTR(指向全局段描述符表基地址) -- > 找到段描述符 --> 解析代码段还是数据段,地址,访问权限 其中影子寄存器 : 通过硬件实现,是段描述符的高速缓存, 防止反复读内存,提高效率。 权限问题:当前执行程序的CS RPL、SS RPL = CPL, 要访问的段描述符中拿到DPL, CPL > DPL 禁止程序访问目标段, CPL <= DPL , 可以访问 (3)保护模式的平坦模型: 段基址为0,段长度为4G的特殊段管理模式,规避历史原因导致的分段模型缺陷。 (4)保护模式中断:中断号+ IDTR 寄存器(指向中断表) ---> 根据中断号,找到中断表指向的内存中的中断门描述符 ---> 中断门和中断描述符中段选择子的权限检查--> 中断门描述符中目标代码段选择子填充CS, 目标代码段偏移填充EIP ---> 响应中断。 权限问题:当前CPL小于等于中断门DPL,才可进中断门,当前CPL,大于段选择子的DPL,则设置CPL=段选择子DPL。 例:当前运行代码CPL=R3级别,遇R3中断门进门,执行特权级中断程序R0,此时CRL=R0。 (5) 切换保护模式: 准备全局描述附表GDT, GDTR指向GDT, 设置CR0开启保护模式, 执行长跳转,CPU根据8索引值索引GDT中第二条数据,加载CS 3、长模式: (1)寄存器扩展到64位 (2)长模式段描述符, L=1,D/B=0 时是64 位代码段, L , D/B, 无效是数据段 (3)长模式中断:中断们描述符比保护模式多了8字节64位,用于存放64位的目标代码段偏移多出来的高32位。 其他中断过程同保护模式。 (4)长模式切换:准备长模式全局段描述符表, 准备长模式下的MMU页表,开启分页模式 CR3指向页表物理地址 GDTR指向全局段描述符表 IA32_EFER寄存器第8位开启长模式,CR0寄存器= 0x31开启保护模式和分页模式 进行跳转,索引GDT, 加载 CS 段寄存器,刷新其影子寄存器 (5)长模式弱化段模式管理,只保留了权限级别的检查,忽略了段基址和段长度,而地址的检查则交给了 MMU,分页管理。

    作者回复: 对的,总结到位

    2021-07-14
    4
    26
  • 尼欧
    建議大家讀讀李忠老師的《穿越計算機的迷霧》,學習一點硬件原理,對後續學習會有很大幫助。很薄的小冊子,三兩天就能讀完。

    作者回复: 66666 这个不错

    2021-05-19
    4
    23
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部