【操作系统】1、操作系统启动

先提炼一下本文中心内容:

操作系统启动——1、把操作系统的代码加载到内存; 2、初始化。

几个重要部分和流程的概述(名词、简写后续介绍,省略了一些细节):

(1)CPU进入BIOS,CS:IP指向0xFFFF0,检查设备,之后取出磁盘中第一个磁道第一个扇区——boot/bootsect,并将其放入0x90000

(2)boot/bootsect把磁盘中的boot/setup载入内存地址0x7C00处,再挪到0x90200处,屏幕上加载开机的LOGO,载入磁盘中的system至内存0x10000处

(3)setup读取PC机器系统的数据,比如光标位置,内存大小,硬盘参数等等, 放到0x90000处(覆盖了bootsect),开启保护模式

(4)执行system模块(有多个部分, 后面介绍), 进入main.c

 

进入正文:

当我们的个人电脑,也就是PC加电,CPU开始工作开始,这里插一句,按照冯诺依曼提出的存储程序的思想,CPU工作可以简单的归结为取指-执行。

那么从CPU开始,CPU自动进入实模式(也就是内存地址就是真实的物理地址,虽然会经过段基址和段偏移的计算)。

CPU首先寻址0xFFFF0,这是ROM BIOS映射区,BIOS全称Basic Input/Output System,也就是基础读写系统。

CPU进入了BIOS,BIOS会帮助我们检查RAM(内存条),I/O设备(显示器,软硬磁盘,键盘),所以开机时你可以看见你的这些设备响一下或者亮那么一下。BIOS还为我们提供了操作系统完全运行起来前的一些基本中断(我们要利用这些中断去操作I/O设备)。

紧接着BIOS会从磁盘的0磁道0扇区读入一个扇区(512B)到内存——boot/bootsect,boot顾名思义就是系统启动区,而读入的这个bootsect,就是boot的启动区。

bootsect会被读到0x7C00(31KB处)的地方,然后它再将自己整体挪到0x90000(576KB处)的地方。

紧接着bootsect读入BOOT的下一个模块,boot/setup, 这个模块大小为2KB,也就是紧接着boot/bootsect的四个扇区,并把它读到bootsect的后面(0x90200处),读完并检查完成之后,就会输出神奇的“Loading System ...”给用户,而与之对应的,Windows则是输出我们开篇的那个神秘的Windows LOGO。

在输出完后,bootsect就干它刚刚输出的那句话的事,加载系统,也就是读入系统的主模块,真正的操作系统所在的模块,System模块,并把它读到0x10000处,由于System模块不大于512KB也就是16进制的0x80000字节大小,所以它并不会覆盖到boot/bootsect(0x90000处开始)。

在读完System并检查完后,boot/bootsect就完成了它光荣的使命,把控制权转交给了boot/setup。

控制权来到了boot/setup,boot/setup是一个操作系统加载程序,首先它会利用BIOS提供的中断读取PC机器系统的数据,比如光标位置,内存大小,硬盘参数等等。并把这些数据放到0x90000的位置上,就是bootsect所在的位置,因为它没用了,所以它会被这些数据所覆盖掉。这些参数会被操作系统的许多相关程序所使用,比如驱动程序。

然后setup程序会将刚刚放在从0x10000处起的System模块整块向下挪动,挪到0x00000处,也就是内存的初始地址处。

setup紧接着开始着手进入保护模式,其中包含了加载中断描述符寄存器(idtr)和全局描述符表(gdtr),并临时设置了中断描述符表(IDT)和全局描述符表(GDT),并在GDT中设置了当前内核代码段的描述符和数据段的描述符。设置好这些后,最后修改机器状态字的保护模式标志(表示当前机器是实模式还是保护模式的标志)进入保护模式(32位/64位)。

至于什么是实模式什么是保护模式,取决于CPU的工作方式,实模式是直接寻址,它的寻址格式是:(段基址:段偏移量)。可见,实模式的"实"更多地体现在其地址是真实的物理地址。

它被设计出来是因为早期的16位机器,而现在的机器大多是32位和64位,因此需要更加灵活的寻址方式。而保护模式是间接寻址,GDT表就是用来替代原来的段基址的,至于深入这个话题,需要到后面的文章(文件、内存管理)。

                  

boot/setup程序执行完了以后,就开始执行system模块了,而执行这个模块是完全在保护模块下的,此时的内存映像如上图。

首先执行的是system中的head,它处于内存中绝对地址的0x00000处,而head模块在编译前是属于boot的,编译后会被跟其他system程序链接在一起。而head的功能比较单一,首先是加载各个数据段寄存器,重新设置中断描述符表(idt)和全局描述符表(gdt)。

接着设置管理内存的分页处理机制(这个至关重要),将页目录表放在绝对物理地址0x00000处,也就是本程序的位置,会覆盖掉head程序。

最后,利用返回指令将预先放置在堆栈中的/init/main.c程序入口地址弹出,去执行main()程序。此时,内存映像如下图。

 

 

main.c跟其他程序的main方法一样,是操作系统的主函数,进入了main.c就等同于进入了操作系统,main.c会初始化并启动各种各样的线程,检查内存,中断设备等等,并将他们初始化为表或者其他数据结构。而操作系统管理硬件凭借的就是:数据结构+算法。

开机后操作系统从硬盘到启动起来的全过程就是这样。

参考资料:
1、https://zhuanlan.zhihu.com/p/360772405
2、https://blog.csdn.net/weixin_42174342/article/details/84036599?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_ecpm_v1~rank_v31_ecpm-2-84036599.pc_agg_new_rank&utm_term=%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E4%BD%8D%E7%BD%AE&spm=1000.2123.3001.4430

 

 

 

 

 

posted @ 2022-02-17 11:20  鱼儿冒个泡  阅读(337)  评论(0)    收藏  举报