前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >操作系统启动篇--01

操作系统启动篇--01

作者头像
大忽悠爱学习
发布2022-07-12 15:51:46
6100
发布2022-07-12 15:51:46
举报
文章被收录于专栏:c++与qt学习c++与qt学习

操作系统启动篇--01


本系列参考哈工大MOOC整理而来


计算机起源

从白纸到图灵机

计算机怎么工作? 说到底就是一个计算模型

1936年,英国数学家A.C.图灵提出了一种模型

在这里插入图片描述
在这里插入图片描述

此时的控制器还无法自动进行计算,而是通过提前做法结果集映射,通过查表快速计算出的结果


从图灵机到通用图灵机

在这里插入图片描述
在这里插入图片描述
  • 只会做一道菜的厨师没有竞争力,一个能看懂菜谱并按照菜谱制作菜的厨师才有竞争力
  • 普通的图灵机就像看不懂菜谱的厨师,只会做番茄炒蛋。
  • 而通用图灵机则是能够读懂菜谱的厨师,可以读取读取不同的菜谱,制作出不同的菜肴
  • 而菜谱则对应计算机世界中的程序,通过载入不同的程序,从而去解释执行不同的程序,获得不同的效果

最后总结出来的思想就是大名鼎鼎的冯诺依曼思想


从通用图灵机到计算机

一个伟大的发明: 冯·诺依曼存储程序思想

  • 存储程序的主要思想:将程序和数据存放到计算机内部的存储器中,计算机在程序 的控制下一步一步进行处理
  • 计算机由五大部件组成:输入设备、输出设备、存储器、运算器、控制器
在这里插入图片描述
在这里插入图片描述

程序其实是由一堆指令组成的,因此程序载入后的解释执行的过程,其实总结就是四个字: “取指执行”


打开电源,计算机执行的第一句指令什么?

上面说了,计算机本质就是取指执行,那么计算机一插上电,就应该去取指执行才对,而去哪里取指令,这个由CS段寄存器和IP寄存器的初始值决定。

在这里插入图片描述
在这里插入图片描述

ROM只读存储器中的代码是生产过程中直接写入的,因此刚插上电的时候,内存中唯一有代码的也是这块区域,因此CS和IP的初始值默认也是被设置为了执行该块代码区域的起始位置。

BIOS和DOS中断例程的安装过程

BIOS主要负责对硬件系统检测和初始化程序。

初始化程序将建立BIOS所支持的中断向量,即将BIOS提供的中断例程的入口地址登记在中断向量表中。(不清楚看上面汇编链接)

硬件系统检测和初始化完成后,调用int19h进行操作系统的引导,即去将磁盘0磁道0扇区读入0x7c00处,然后将CS和IP位置重新指向操作系统的代码起始处。(计算机交给操作系统来管理)

0磁道0扇区是操作系统的引导扇区,一共512字节


0x7c00处存放的代码

  • 就是从磁盘引导扇区读入的那512个字节
  • 引导扇区就是启动设备的第一个扇区,开机时按住del键可进入 启动设备设置界面,可 以设置为光盘启动!
  • 启动设备信息被设置在CMOS中…,CMOS: 互补金属氧化物半导 体(64B-128B)。用来存储实 时钟和硬件配置信息。

操作CMOS RAM芯片

  • 因此,硬盘的第一个扇区上存放着开机 后执行的第一段我们可以控制的程序

引导扇区代码: bootsect.s

在这里插入图片描述
在这里插入图片描述

把一开始从引导扇区读入的512个字节挪动到0x9000:0x000处,肯定是为了腾出0x07c0:0x0000这段空间来干别的事情。

代码语言:javascript
复制
     ip   cs
jmpi go,INITSEG

jmpi会重新设置cs:ip,相当于不是段内跳转,而是段间跳转,这里是跳到了0X9000处go地址标记处继续执行


jmpi go, INITSEG

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

0x13中断会将setup处的四个扇区读入到0x9000:0x0200(512)处,即上面转移位置后的引导扇区后面


读入setup模块后: ok_load_setup

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这一部分主要做了两件事:

  1. 读取内存处指定位置保存的开启界面数据,打在屏幕上
  2. 继续读取system模块

read_it —> 读入system模块

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

最后,就是将system模块的代码读进内存,然后引导扇区程序执行结束,下面转入执行setup

代码语言:javascript
复制
jmpi 0,SETUPSEG

system模块被读取到了0x1000处

最后引导扇区执行结束后,设置ip=0,cs=SETUPSEG,SETUPSEG=0x9020,即setup扇区内存开始的地址

在这里插入图片描述
在这里插入图片描述

操作系统启动

setup模块,即setup.s

根据名字就可以想到: setup将完成OS启动前的设置

在这里插入图片描述
在这里插入图片描述
  • 通过15号中断,读入扩展内存大小到0x90002处,操作系统需要知道当前PC机物理内存大小

intel刚出来的时候,只有1M内存,因此把1M以后的内存称为扩展内存

在这里插入图片描述
在这里插入图片描述

将system模块移动到0地址处,读取到0x9000处结束

  • 将操作系统的代码移动到0地址开始处,然后我们的应用程序代码就都放在操作系统代码上面去执行

将system模块移动到0地址处,而引导模块和setup模块不需要移动是因为这两个模块一旦读取完毕后,就没用了,后面由system模块进行管理


进入保护模式

上面setup模块读取完相关硬件参数然后将System模块移动到0地址处后,下面还需要做一件事,就是进入保护模式。

在这里插入图片描述
在这里插入图片描述

所谓进入保护模式: 主要是指setup模块最后执行的jmpi 0 8跳转指令。

大家猜猜这个跳转指令究竟会跳转到哪里呢?

  • 相信大家都能说出来,是跳转到system模块去执行,但是如果按照默认的cs<<4+ip的话,会跳转到80处,但是这可不是system模块的起始地址处,显然是一个非法地址,这样跳转只会导致死机。

操作系统必须严格按照顺序读取,先引导模块,再是setup模块,最后读取ststem模块,一旦读取过程中有一点偏差,就会死机

既然我们按照默认的cs:ip规则推导出来是死机的结果,显然这里一定存在猫腻,可能是cs:ip的寻址规则发生的改变,那么到底是不是这样呢?

  • 寻址方式发生改变

cs<<4+ip -->最大达到20位地址,最大访问地址空间为1M。

但是,这里内存为4G,因此16位机已经无法满足需求了,需要切换到32位模式。

如何切换到32位机呢? ---->那我们需要思考16位机和32位机的本质区别是什么

32位模式也叫做保护模式

  • 本质区别是对cs:ip的解释方式不一样,16位机情况下,会将cs:ip解释为cs<<4+ip
  • 32位机模式下,对应的解释程序需要用另外一条电路来实现,其实切换就是通过下面这条指令完成的
代码语言:javascript
复制
将cro赋值为1,即开启了保护模式
mov ax,#0x0001 mov cro,ax
在这里插入图片描述
在这里插入图片描述

保护模式下的地址翻译和中断处理

gdt是用硬件来实现的,主要追求的是块,此时cs不再是左移4位产生一个地址,而是选择子。

以前cs里面存放的是代码段地址,而现在存放的是查表的下标,真正的段基址,存放在表项中。

因此上面cs为8是选择下标为8的表项,然后让该表项中存放的段基址和偏移地址ip相加,得到一个32的物理地址。

但是,查表之前,必须保证表中存放好了相关的段基址,否则不就查不到了,这个存放的问题下面会进行解答.

在这里插入图片描述
在这里插入图片描述

中断程序也是改为去查询IDT表,和GDT实现原理一样。


将system移到0地址处…

  • 如果学习过x86汇编的小伙伴,肯定会产生疑问说,0地址处不应该用来存放中断向量表吗? 覆盖了0地址处的内容,后面的中断程序查表怎么搞呢?

上面提到了,查询GDT表之前,需要先初始化该表,确保相关段基址已经保存好了,那么具体的初始化过程如下:

在这里插入图片描述
在这里插入图片描述

gdt表通过上面一番操作就已经初始化好了,再回顾一下上面那条jmpi指令:

在这里插入图片描述
在这里插入图片描述

此时jmpi 0,8 ,这里cs为8,会跳到GDT表的第2行。


jmpi 0,8 //gdt中的8

在这里插入图片描述
在这里插入图片描述

GDT表项每个字节的含义如上,通过对比,可以得知,最终CS的值为0,加上偏移地址ip的值同样为0,因此最终是跳转到了0地址处,即system模块的开始处执行。


跳到system模块执行…

在这里插入图片描述
在这里插入图片描述

我们知道操作系统0磁道0扇区一定是存放Boot扇区的代码,如果不是的话,那么一上来尝试去读取的时候就会产生不可预料的结果。

Boot扇区读取结束后,会去读取setup扇区的内容,最后是system扇区。

操作系统是由一堆源码组合而成的,但是只有在确保其组成是有序并且符合规定的,才能确保操作系统的正常运行。

但是如何确保大型软件的合成结构的呢? —> makefile

对于操作系统而言,除了要编写操作系统源码之外,还需要去编写操作系统的控制代码,即makefile.

在这里插入图片描述
在这里插入图片描述

将操作系统的一堆源代码交给makefile编译成一个Image镜像,然后放入0磁道0扇区中。

然后就是从0磁道0扇区开始去读取,完成操作系统的初始化和启动过程。

在这里插入图片描述
在这里插入图片描述

makefile是一种树状结构,其中各个父子模块之间存在大量依赖关系,makefile就是通过这些依赖关系来确保系统结构的正确性。

对于System模块来说,他会将他所依赖的模块都链接起来,组成system模块的内容。

对于system模块中依赖的各个模块而言,他们又会依赖其他子模块,例如: head.o模块会依赖head.s子模块。

system是由一堆.c文件组成的,这些.c文件经过链接后会形成一堆.o文件,这些.o文件链接起来组成system模块.

当boot,setup和system模块都组装好后,通过tools/build组成一个镜像.

而对于system模块而言,head.s是其第一部分的代码。


head.s //一段在保护模式下运行的代码

在这里插入图片描述
在这里插入图片描述

关于汇编…head.s的汇编和前面不一样?

在这里插入图片描述
在这里插入图片描述

after_page_tables //设置了页表之后

在这里插入图片描述
在这里插入图片描述

虽然说main函数返回时,操作系统会进入死机状态,但实际上main函数永远都不会返回,因为操作系统需要一直处于运行状态。


进入main函数

在这里插入图片描述
在这里插入图片描述

main函数是不会退出返回的,上面给出的main代码还少了两句,具体可以参考linux 0.11源码。


看一看mem_init…

这里我们来看看内存的初始化都干了啥

在这里插入图片描述
在这里插入图片描述

mem_init方法负责初始化相关内存页表,这里end_mem参数是setup阶段拿到的内存大小,该内存大小会存入90002的位置,而这里end_num实际就是该处的地址值。

将没有使用过的内存全部置空,而上面从0地址处开始使用过的一段内存就是上面移动到0地址处的system模块,也就是操作系统代码


小结

计算机启动读取BIOS,BIOS会去读取0磁道0扇区的boot扇区到内存中,boot扇区将setup模块和system模块读入内存。

setup模块获取到相关参数后启动保护模式。

head初始化gdt,idt表等,然后调用main函数

main函数负责初始化相关组件。

总结一句话: 先把操作系统从磁盘读入内存,然后再初始化,主要是建立相关数据结构,让操作系统知道硬件的样貌

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-07-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 操作系统启动篇--01
  • 计算机起源
    • 从白纸到图灵机
      • 从图灵机到通用图灵机
        • 从通用图灵机到计算机
        • 打开电源,计算机执行的第一句指令什么?
          • 0x7c00处存放的代码
            • 引导扇区代码: bootsect.s
              • jmpi go, INITSEG
              • 读入setup模块后: ok_load_setup
              • read_it —> 读入system模块
          • 操作系统启动
            • setup模块,即setup.s
              • 进入保护模式
                • 保护模式下的地址翻译和中断处理
                  • 将system移到0地址处…
                    • jmpi 0,8 //gdt中的8
                      • 跳到system模块执行…
                        • head.s //一段在保护模式下运行的代码
                          • 关于汇编…head.s的汇编和前面不一样?
                            • after_page_tables //设置了页表之后
                              • 进入main函数
                                • 看一看mem_init…
                                  • 小结
                                  领券
                                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档