该OS课程全部基于X86(64),因此后文CPU特指X86(_64)的CPU,AMD64位于灰色区域。
按照 CPU 功能升级迭代的顺序,CPU 的工作模式有实模式、保护模式、长模式,基本属于历史包袱。
题外话:说到这里,英特尔在“中国情人节”发布了X86s的白皮书,这里的s是简化Simplification的意思,如果86s普及,那么os启动和程序启动都会有巨大的变化。墙裂看看老狼的回答,很厉害的BIOS/UEFI专家:从技术角度来如何评价这个intel推出的X86S架构?产品能否大范围推广? – 知乎 (zhihu.com)现在还不是很懂,至少16bit的保护模式肯定是从X86s移除了。
在这里,我们先学习一下实模式的相关信息。
这是16位实模式寄存器

那么16位实模式是怎样访问内存的呢?采用的是分段管理模型,这里

地址 = CS(段寄存器)*16+ IP(程序指针寄存器)
1.为啥是*16,因为左移4位,2的4次方就是16。
2.为啥是左移4位,本来寄存器16位,左移4位就刚好20位,和地址总线宽度一致。具体可以看一下王爽的汇编语言。
现在可以16位hello word来考古了
data SEGMENT ;定义一个数据段存放Hello World!
hello DB 'Hello World!$' ;注意要以$结束
data ENDS
code SEGMENT ;定义一个代码段存放程序指令
ASSUME CS:CODE,DS:DATA ;告诉汇编程序,DS指向数据段,CS指向代码段
start:
MOV AX,data ;将data段首地址赋值给AX
MOV DS,AX ;将AX赋值给DS,使DS指向data段
LEA DX,hello ;使DX指向hello首地址
MOV AH,09h ;给AH设置参数09H,AH是AX高8位,AL是AX低8位,其它类似
INT 21h ;执行DOS中断输出DS指向的DX指向的字符串hello
MOV AX,4C00h ;给AX设置参数4C00h
INT 21h ;调用4C00h号功能,结束程序
code ENDS
END start
最后INT就是中断啦。
补充几个个小知识:硬件中断是异步异常 软件中断是同步异常。
为了实现中断,就需要在内存中放一个中断向量表,这个表的地址和长度由 CPU 的特定寄存器 IDTR 指向。实模式下,表中的一个条目由代码段地址和段内偏移组成。
“上面说的是 BIOS 在填写中断向量表,那该表是谁创建的呢?答案就是 CPU 原生支持的,不用谁负责创建。之前我曾说过,软件是靠硬件来运行的,软件能实现什么功能,很大程度上取决于硬件提供了哪些支持。软件中只要执行int中断向量号, CPU 便会把向量号当作下标,去中断向量表中定位中断处理程序井执行。”——《操作系统真象还原》
更多关于段寄存器可以看一下这个博客8086汇编 段寄存器 – kevin.Xiang – 博客园 (cnblogs.com)
还有这个一口气看完45个寄存器,CPU核心技术大揭秘 – 轩辕之风 – 博客园 (cnblogs.com)
下面就可以进入保护模式了
由于 CPU 的扩展导致了 32 位的段基地址和段内偏移,还有一些其它信息,所以 16 位的段寄存器肯定放不下。放不下就要找内存借空间,然后把描述一个段的信息封装成特定格式的段描述符,放在内存中,其格式如下。


上图为全局段描述符表
后续持续更新本课内容,毕竟本课太过于硬核。
最后评论结尾,也确实把我触动了。
看了今天的课程和同学们的留言让我百感交集。 人的一生时间有限,无法什么都做到极致。但在摸索的过程是可以什么都去碰一下,才知道自己喜欢什么。我以为我不是那么喜欢计算机。我不是本科,是念电机工程的,已算是很相近的,比起念化学或是文史哲商等。但我仍然用了一堵高墙将自己围住,说自己不是纯正计算机本科的。 二十年前刚开始工作时有机会接触8051控制器,是用8051的汇编代码,花了不少时间把中断、寄存器研究过、因为8051只有8位元,相对简单,但没有操作系统,我开始对操作系统有兴趣,就开始自学x86的操作系统,买书来看,但真的看不懂,当时也没有互联网上这么多讯息,还买了minix的书来看,英文的书有多了一层外文的障碍,因为工作忙,也没实际用到,就这么放下了。 最近看到老师的这专烂,让我想到之前放弃了的操作系统的学习。 老师讲的实在太好了,给100个赞都不够。因为他是亲身实践过,而且表达力极佳。 过去不懂的,开始有一点看得懂了。但是真的是单纯因为老师讲的好我才看得懂吗? 看到底下很多同学的留言,让我想起二十年前的自己。 这过程有点像是小学的数学学不明白,到了中学再回头看,竞然明白了。 其实是自己的理解增加了,我不想用聪明这个字,会误导很多人。 纠结在自己有没有天份。 我很认同老师在底下同学留言的回覆。 “不需要前置的知识”,”多看几遍”,”如果看到一个新东西 ,不要在意它叫什么,它叫什么都可以,而是要在意它是干什么的,它有什么作用。有了整体思路,再去扣细节。” 也不存在着需要什么条件,常常就是这种条件,自己把自己绊住了, 以为自己没有达到,就放弃了。或是就转移目标去完成那个条件,而忘了回来原来的操作系统的学习。 很多时候困难全是自己想出来的。觉得难,这是很正常的。 不必要对自己太严苛。可以稍微休息一下(我说稍微不是二十年),做一下别的事,再回来。 每个人的情况都不一定,没有一个固定的方法或是习惯,只有问你自己。 因为太难就放弃,那就太可惜了。可以慢一点没关系,不要放弃。 想想自己为什么来上这个课,想要从这个课得到什么? 如果是加薪,升官,学分或是为了下一门课会不会压力很大? 如果只是因为好奇,这看起来还挺有趣,想了解一下,会让你更挺得住这些困难。 因为有这些难点本来就很正常,克服了,弄懂了一个信心就会增加,就会继续前进, 如果一开始不去克服那个难点,选择逃避或是绕路,那永远就是在原地打转。 如果这一篇让你觉得鸡汤或是说教,那不是我的本意。只是将自己过去有感而发写下的。我也还在学习。 谢谢老师带来亲身实践后这么精彩的课程,也谢谢同学们对我的启发,共勉之~
作者回复: 你好,这个评论让我感到震撼,想必老哥之前也是认真研究过操作系统的人,才会有如此深刻的体会。一定是走了很多路才会有这样的启发和经验,我写这门的定位就是实战可能和学究派不同,我不讲虚的,只有让别人写出操作系统 ,这门课才达到了目标,也是对诸多同学的一个交付,谢谢你!
这名同学的解释也是很精辟:
这篇文章信息量很大,但是问题比较简单,我先回答一下问题吧。 实模式下的寻址空间跟地址总线的个数是密切相关的,早期的 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 的这群挖坑师给乐坏了。
该回答充分解释了英特尔屎山是怎么来的,X86s是怎么来的,笑死。
Views: 102