Linux内核学习-Linux系统的初始化(二)

来源:互联网 发布:偏头痛物理疗法知乎 编辑:程序博客网 时间:2024/05/11 03:59

了解计算机开机加电到系统启动的过程。

        为了向前兼容,使得旧代码可以运行在新的芯片中,现有的计算机一般都是由实模式开始。然后转成保护模式。

稍微带点历史信息:Intel处理器生产的8086CPU, 总线16位。地址总线20位。可寻址1M。 当初Intel本意是设计16位的处理器,但是正常寻址空间才2的16次方 = 64KB。 为了更大的寻址空间。 需要对16位的总线进行映射。 为了支持16位映射到20位地址空间,才新增了4个寄存器,CS代码段,DS数据库,ES其他,SS堆栈段。这样一个物理地址就变成了

段地址:段内偏移量。   段地址经过左移4位再加上段内偏移量就得到了真实的20位物理地址。

这种方式可以寻址的最大地址就是:0xFFFF:0xFFFF。 寻址空间为: 0x00000~~~~~~0x10FFEF。 地址总线20位,物理地址空间是0x00000~~~0xFFFFF。 超出的部分即

0x100000~~0x10FFEF自动映射到真实物理地址空间的0x00000处。 即对2的20次方求模运算后进行地址映射。


        实模式:只能访问1MB的地址空间。但是访问的都是真实物理地址,即实际地址模式。 而且无法对内存加以保护。任何进程都可以修改寄存器指令来获取任意一个段地址。在任意64KB段起始地址的连续地址空间进行访问。可以直接软件访问BIOS及硬件,没有硬件支持的分页机制和实时多任务概念。


后来80386问世,32位的CPU登上的历史舞台。IA-32时代。为了向前兼容,使得旧的软件可以运行在新的硬件上。在段寄存器(CS,DS,SS,ES)基础上新增通用段寄存器FS和GS。新增这两个寄存器不仅可以起到辅助ES寄存器的作用, 还可以限制内存访问,事实上保护模式的根本是GDT,即全局描述符。段的信息(基地址,界限,属性等)保存在段描述符表中,除了GDT,还有LDT,即一个特定程序的私有内存段的描述符。当程序运行在不同的特权等级下,FS和GS指向GDT的值也不一致。可以通过工具查看程序再R0和R3下段寄存器的值来进行对比。

保护模式:在保护模式中,段寄存器的功能也发生了变化,从一个段基址(实模式下)转变成一个指向段描述符的指针(其实是索引值,16位的寄存器只有2个字节,无法存储段描述符)。当发出一条访问内存的指令时, 不再像实模式那样,直接用段基址左移后加上指令中的偏移量进行物理地址的访问。 而是先判断指令类型,然后根据指令类型(CS,DS等)去获取对应(CS,DS等)段寄存器中的指针,即拿到段描述符里的 内容,从段描述符中可以获取到(1)段的基址;(2)段的长度,判断偏移量是否越界;(3)访问权限,指令是否越权; 然后通过段基址和偏移量得到一个虚拟地址。再通过虚拟地址得到线性地址再转换成物理地址进行访问(查询页表)。 其实就是逻辑地址等于线性地址,每个段(内核代码段,内核数据,用户代码段,用户数据段)都是以0x00000000起始的,长度4G。 但是线性地址不一定等于物理地址,如果没有分页,则线性地址就是物理地址, 如果分页了,则需要查询页表进行物理地址的转换。 具体内容可以查看内存管理部分。

为什么上面要讲实模式和保护模式呢,这是因为一个计算机的加电开机启动是从实模式和保护模式转换的一个过程。

我们平常运行一个软件都是双击运行,那么操作系统运行之前需要谁来对它进行双击这个操作呢, 答案就是BIOS, BIOS自身的启动无法通过软件途径解决,所以它是存储在主板上一块小的ROM中,CPU中的硬件逻辑在当加电的一瞬间,就强行把CS的值置为0xF000,IP的值置为0xFFF0, 这样CS:IP的值就是0xFFFF0这个位置。实模式下地址范围是0x00000~0xFFFFF,所以BIOS所在的ROM就在内存中实模式下最大的寻址范围的旁边。此时CS:IP指的地址位置仅仅16个字节,此处只能存储一个跳转指令,用于指向BIOS程序入口地址,开启POST(Power On Self Test),这中间设计自检过程,电压稳定后的某些操作。

在POST结束后,BIOS程序在内存最开始的位置0x00000~0x003FF构建中断向量表,后面紧挨着BIOS数据区,然后就是中断服务器程序。关于BIOS程序如何构建的,如何安排内存空间加载的,没有详细信息。这部分待续,POST代码存储位置?如何加载执行?

  POST自检完成后,BIOS构建中断服务,然后触发CMOS设置,这时CPU收到int 0x19中断,该中断服务程序就是启动加载程序的入口地址。主要目的就是根据CMOS设置的启动设备,找到该设备,然后加载第一个扇区到内存(即运行自举程序)。


附注:这中间还有几个疑问? 1.BIOS程序是存储在ROM里的,该ROM里的代码如何加载到内存里的?如果该ROM是否是内存组成的一部分,还是独立的一块芯片。BIOS是先进行加电自检还是先把自身代码加载到内存中?如果先加电自检,那么POST自检代码如何加载运行的?如果先把BIOS自身代码加载到内存中,又怎么加电自检的,加电自检也要检查自身内存啊?先有鸡先有蛋啊。。。。额。。。