和菜鸟一起学linux内核之引导启动篇

注:以下大部分内容摘自linux内核编程入门篇和linux内核完全注释

 

对于linux的整个体系结构有了一定的了解,看了每个目录的文件整体概要,那么就

可以开始看内核的源码了,首先那便是引导启动了。


关于磁道,扇区等信息

在这有必要讲一下磁道和扇区等。

1、扇区:不是扇形的,即不是两个半径之间的区域,而是个四边形:两个半径为两边,两个大小同心圆作为两外两边。 

2、磁道 :磁道不是线性的,而是个区域,有两个大小同心圆组成

3、 柱面:不是面而是号码相同的多个磁道组成的柱体 

4、 磁头数:因为磁盘的双面存储性,使得计算时用磁头数而没有用盘片数 

可以说:扇区是硬盘分割的最小单位。

存储容量=磁头数*磁道(柱面)数*每道扇区数*每扇区字节数 

_______________________________|----- 磁道的总字节数--------|      

 ________________|-------磁盘一个盘面的总字节数----------------|

 __________|----- 磁盘容量(磁头数个盘面)--------------------|

 

关于8086寄存器

汇编代码是基于8086的,所以先了解了这些寄存器,然后再看代码会更好些。

1、数据寄存器,一般称之为通用寄存器组

8086 有8个8位数据寄存器,

这些8位寄存器可分别组成16位寄存器:

AH&AL=AX:累加寄存器,常用于运算;

BH&BL=BX:基址寄存器,常用于地址索引;

CH&CL=CX:计数寄存器,常用于计数;

DH&DL=DX:数据寄存器,常用于数据传递。

 

2、地址寄存器/段地址寄存器

为了运用所有的内存空间,8086设定了四个段寄存器,专门用来保存段地址:

CS(Code Segment):代码段寄存器;

DS(Data Segment):数据段寄存器;

SS(Stack Segment):堆栈段寄存器;

ES(Extra Segment):附加段寄存器。

当一个程序要执行时,就要决定程序代码、数据和堆栈各要用到内存的哪些位置,通过设定段寄存器CS,DS,SS来指向这些起始位置。

通常是将DS固定,而根据需要修改CS。所以,程序可以在可寻址空间小于64K的情况下被写成任意大小。所以,程序和其数据组合起来的大小,限制在DS 所指的64K内,这就是COM文件不得大于64K的原因。

 

3:特殊功能的寄存器

IP(Instruction Pointer):指令指针寄存器,与CS配合使用,可跟踪程序的执行过程;

SP(Stack Pointer):堆栈指针,与SS配合使用,可指向目前的堆栈位置。

BP(Base Pointer):基址指针寄存器,可用作SS的一个相对基址位置;

SI(Source Index):源变址寄存器可用来存放相对于DS段之源变址指针;

DI(Destination Index):目的变址寄存器,可用来存放相对于 ES 段之目的变址指针。

还有一个标志寄存器FR(FlagRegister)有以下九个有意义的标志:

OF: 溢出标志位OF用于反映有符号数加减运算所得结果是否溢出。如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值被置为1,否则,OF的值被清为0.

DF: 方向标志DF位用来决定在串操作指令执行时有关指针寄存器发生调整的方向。

IF:  中断允许标志IF位用来决定CPU是否响应CPU外部的可屏蔽中断发出的中断请求。但不管该标志为何值,CPU都必须响应CPU外部的不可屏蔽中断所发出的中断请求,以及CPU内部产生的中断请求。具体规定如下:

(1)、当IF=1时,CPU可以响应CPU外部的可屏蔽中断发出的中断请求;

(2)、当IF=0时,CPU不响应CPU外部的可屏蔽中断发出的中断请求。

TF: 状态控制标志位是用来控制CPU操作的,它们要通过专门的指令才能使之发生改变

SF: 符号标志SF用来反映运算结果的符号位,它与运算结果的最高位相同。在微机系统中,有符号数采用补码表示法,所以,SF也就反映运算结果的正负号。运算结果为正数时,SF的值为0,否则其值为1。

ZF: 零标志ZF用来反映运算结果是否为0。如果运算结果为0,则其值为1,否则其值为0。在判断运算结果是否为0时,可使用此标志位。

AF: 下列情况下,辅助进位标志AF的值被置为1,否则其值为0:

(1)、在字操作时,发生低字节向高字节进位或借位时;

(2)、在字节操作时,发生低4位向高4位进位或借位时。

PF: 奇偶标志PF用于反映运算结果中“1”的个数的奇偶性。如果“1”的个数为偶数,则PF的值为1,否则其值为0。

CF: 进位标志CF主要用来反映运算是否产生进位或借位。如果运算结果的最高位产生了一个进位或借位,那么,其值为1,否则其值为0。)

 

关于BIOS启动过程

1、 对计算机硬件执行一系列的测试,用来监测现在都有什么设备以及这些设备是否正常工作。这个阶段通常称为POST(Power-on self-test,上电自检)。这个阶段中,会显示一些信息,例如BIOS版本号。

2、 初始化硬件设备。这个阶段在现代基于PCI的体系结构中相当重要,因为它可以保证所有的硬件设备操作不会引起IRQ线与I/O端口的冲突。在本阶段的最后,会显示系统中所有安装的所有PCI设备的一个列表。

3、 搜索一个操作系统来启动。实际上,根据BIOS的设置,这个过程可能要试图访问系统中软盘、硬盘和CD-ROM的第一个扇区(引导扇区)。

4、 只要找到一个有效的设备,就把第一个扇区的内容拷贝到RAM中从物理地址0x00007c00开始的位置,然后跳转到这个地址处,开始执行刚才装载进来的代码。

 

下面看下BIOS的中断,具体功能太多了,等调用了可以去查看。

00h  被零除

01h  单步

02h  不可屏中断(NMI)

03h  断点

04h  溢出

05h  屏幕打印

06--07h   保留

________________________________________

08h  日时钟中断

09h  键盘中断

0Ah 保留/8259A从片中断

0Bh  串行口2中断

0Ch 串行口1中断

0Dh 硬盘(XT)/并行口2中断

0Eh  软盘中断

0Fh  打印机/并行口1中断

________________________________________

10h  视频显示I/O

11h  设备配置检测

12h  内存容量检测

13h 磁盘I/O

14h  串行通信I/O

15h  盒带(PC)/多功能

16h  键盘I/O

17h  打印机I/O

18h  ROM-BASIC

19h  自举程序

1Ah 时钟I/O

1Bh  Ctrl-Break中止

1Ch 时钟控制

1Dh 视频初始化参数表

1Eh  软盘参数表

1Fh  图形显示扩展字符表

________________________________________

20h  程序终止退出

21h 系统功能调用

22h  程序结束地址

23h  Ctrl-C处理

24h  严重错误处理

25h  磁盘扇区读

26h  磁盘扇区写

27h  程序终止驻留

28h  键盘空闲处理

29h  快速字符输出

2Ah 保留

________________________________________

2B--2Dh  保留

2Eh  命令执行处理

2Fh  多路中断,共享

________________________________________

30--31h   远转移至INT 21h入口

32--3Fh   保留

________________________________________

40h  软盘I/O

41h  硬盘机1基数表

42--45h   保留

46h  保留

47--5Bh   保留

5Ch 硬盘机2基数表

5D--6Fh  保留

________________________________________

70h  实时钟中断

71h  改向0Ah号中断

72h  保留给IRQA

73h  保留给IRQB

74h  保留给IRQC

75h  协处理器中断

76h  硬盘中断

77h  保留给IRQF

________________________________________

78--7Fh   保留

________________________________________

80--F0h   BASIC使用区

________________________________________

F1--FFh  保留

 

关于bootsect.s

bootsect.s代码是磁盘引导块程序,驻留在磁盘中的第一个扇区中(引导扇区,0磁道(柱面),0磁头,第1扇区)。在我们的电脑上电后。。。。。

1、首先ROM BIOS自检,引导扇区由BIOS加载到内存0x7c00处(如果是嵌入式设备的话,一般都是上电后,由bootloader中加载内核代码到内存的);

2、然后将自己移动到内存0x90000处,该程序主要作用是首先将setup模块从磁盘加载到内存紧接着bootsect的后面位置(0x90200)。

3、然后利用BIOS中断0x13取磁盘参数表中当前启动引导盘的参数,接着在屏幕上显示“loadingsystem..”字符串。

4、再将system模块从磁盘上加载到内存0x10000开始的地方。随后确定根文件系统的设备号,若没有指定,则根据所保存的引导盘的每磁道扇区数判别出盘的类型和种类并保存到其设备号于root_dev(引导块的0x508地址处)。

5、最后长跳转到setup程序开始处(0x90200)执行setup程序。


       而在多系统引导的时候,我们经常看到的grub,就类似替代了bootsect的功能使命。

 

关于setup.s

Setup程序的作用主要是利用ROM BIOS中断读取机器系统数据,并将这些数据保存到0x90000开始的位置,其读取并保留的参数如下表所示:


1、 setup程序将system模块0x10000--0x8fffff整块向下移动到内存绝对地址0x00000处。

2、 加载中断描述符表寄存器(idtr)和全局描述表寄存器(gdtr)。

3、 开启A20地址线

4、 重新设置两个中断控制芯片8259A,将硬件中断号重新设置为0x20—0x2f

5、 设置CPU的控制寄存器CR0(机器状态字),进入32位保护模式运行

6、 跳转到位于system模块最前面部分的head.s程序继续运行。

 

关于head.s

       head.s程序编译后,被连接成system模块的最前面部分。从这里开始内核完全都是在保护模式下运行了。功能如下:

1、加载各个数据段寄存器,重新设置中断描述符表,共256项,并使各个表项均指向一个只报错误的哑中断程序。

2、重新设置全局描述符表。

3、使用物理地址0与1M开始处的内容相比较,检测A20地址线是否开启。

4、测试PC机是否含有数字协处理器芯片,并在控制器CR0中设置相应的标志位。

5、设置管理内存的分页处理机制,将页目录表放在绝对物理地址0开始处,紧随后面放置共可寻址16MB内存的4个页表,并分别设置它们的表项。

6、利用返回指令将预先放置在堆栈中的/init/main.c程序的入口地址弹出,去运行main()程序。

 

原文地址:https://www.cnblogs.com/wuyida/p/6300005.html