系统初始化 —— 上电
2019-04-14 12:35发布
生成海报
读内核源代码是一件很有意思的事。它像一条线,把操作系统,编译原理,汇编语言,计算机组成原理,C 语言,数据结构与算法,计算机系统结构等等计算机的基础课程串起来。而分析linux的启动很重要,因为牵涉到硬件的初始化和内核各模块初始化环境的搭建,所以我们就针对linux/arch/x86下的代码,对从打开PC电源到屏幕上出现shell环境,来对整个Linux的初始化过程进行一个全方位的分析,希望能有帮助,不足之处,还请各位网友不吝赐教。
1 引子
目前,市面上的大多数计算机系统的内存都是“随机性”的:一旦关机断电,存储在内存中的信息、连同操作系统本身都会丢失。所以,必须把操作系统(内核)的程序存储在某种永久性的介质中,使得开机加电时有一个从不挥发介质装入操作系统、并转入运行的过程,这个过程就叫做“引导”(bootload,或boot),也称为“自举”。
我们只关注x86体系的这个过程,CPU所在的主板会有一个特殊的硬件电路在CPU的RESET引脚上产生一个电平。这时,CPU处于实地址模式中,并开始自检,自检的最后一个步骤是把一些寄存器(如cs和eip)设置成固定值。我们知道,实模式下的寻址方法是16位段寄存器左移4位加上16位偏移构成具有能寻址1MB能力的20位地址。所以,刚开始时,复位输入提供一种初始化的硬件手段:标志寄存器设为0xuuuu0002(u代表未定义,实模式下9位标志可用,这里是奇偶标志为1);指令指针eip设为0x0000fff0,CS寄存器设为0xf000;DS、SS、ES、FS和GS寄存器都设为0x0000,指令队列清空。
CPU在识别出Reset信号后把数据总线设在高阻状态,地址线强行设为1。由于清空中断标志是初始化的一部分,外部中断被禁止。因为代码段寄存器为0xf000,指令指针为0x0000fff0,地址线A20-A31全部是1,从而复位后实模式程序从地址0xfffffff0开始(注意,只用于实模式高地址位忽略,从地址0xffff0开始)。该地址处可以包含一条转移指令跳到启动程序处。
那么,这段程序要有多大呢?这就要看具体的设计了。在早期的计算机中这段程序般都很小,例如2K字节或者史小,甚至于只有几条指令(我们的胡希明老同志回忆起70年代中美建交后进入中国的NOVA机,由此而来的国产机名为DJS-130,操作系统为RTOS,引导程序只有13条指令,当时称初始引导13条,亦称手拨13条。13条指令执行结果是通过光电读入机把存放在穿孔纸带上的RTOS执行码装入内存)。这是因为早期的PROM或EPROM的容量都很小,并且其目的和功能也很单一。
我们在“PC存储器”一篇博文中讲到,ROM和RAM扩展成一个整体的内存系统,这个ROM的地址是32位的,况且开机时CPU只运行在实模式下,高12位全被置1那么线性地址0xffff0对应的物理地址就是0xfffffff0,定位到这个ROM。ROM中所存放的程序集在80x86体系中通常叫做基本输入/输出系统(Basic Input/Output System, BIOS),因为它包括几个中断驱动的低级过程。比如,执行INT 10H,就是显示服务,10H是中断类型号,在运行以下流程:
(SP)←(SP) - 2 ;SP - 2
((SP+1),(SP))←(PSW) ;标志位寄存器内容进栈
IF←0, TF←0 ;清除中断和陷阱标志
(SP)←(SP) - 2 ;SP - 2
((SP+1),(SP))←(CS) ;CS入栈
(SP)←(SP) – 2 ;SP - 2
((SP+1),(SP))←(IP) ;IP入栈
(IP)←(TYPE*4) ;取中断服务程序偏移地址,这里的TYPE是10H
(CS)←(TYPE*4 + 2) ;取中断服务程序段地址,这里的TYPE是10H
…… ;开始执行位于ROM的BIOS中断服务程序
(SP)←(SP) + 2 ;SP + 2
(IP)←((SP-1),(SP)) ;IP出栈
(SP)←(SP) + 2 ;SP + 2
(CS)←((SP-1),(SP)) ;CS出栈
IF←1, TF←1 ;设置中断和陷阱标志
(SP)←(SP) + 2 ;SP + 2
(PSW)←((SP-1),(SP)) ;标志位寄存器内容出栈
不管Linux、MS-DOS还是Windows,在启动时,都要通过这些过程对计算机硬件设备初始化。Linux一旦进入了保护模式,就不再使用BIOS,而是为计算机上的每个硬件设备提供各自的设备驱动程序。
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮