CF卡上的Linux启动过程分析

2019-07-13 04:57发布


一个嵌入式linux操作系统可以简单的抽象为,引导程序bootloader、内核vmlinuz、文件系统filesystem。
Bootloader是系统加电后运行的第一段代码,一般它只在启动系统时非常短的时间按内运行。对于linux系统来说,这是至关重要的一步。在系统中,整个bootloader由系统中的bios和u盘中MBR(主引导扇区)的一段代码来共同完成引导任务。这里我们采用grub引导方式。系统先将BIOS检测到的MBR内容读取到RAM中,然后将系统控制权交给grub,最后由grub负责把要引导的操作系统的内核镜像读取到系统RAM中,然后跳转到内核的入口点。

vmlinuz是Linux 内核的镜像文件,可以被引导程序加载,从而启动Linux系统。

initrd的全称是boot loader initialized RAM disk,它是系统启动时所使用的根文件系统映像文件,这个文件系统中包含几个驱动模块,都是系统启动时所必须加载的,另外当我们需要加载其它的模块时,也可以放在其中。

一、引导程序Grub

机器加电启动后,BIOS开始检测系统参数,如内存的大小,日期和时间,磁盘设备以及这些磁盘设备用来引导的顺序,通常情况下,BIOS都是被配置成首先检查软驱或者光驱,然后再尝试从硬盘引导。如果在这些可移动的设备中,没有找到可引导的介质,那么BIOS通常是转向第一块硬盘最初的几个扇区,寻找用于装载操作系统的指令。装载操作系统的这个程序就是boot loader。

linux里面的bootloader通常是lilo或者grub,从Red Hat Linux 7.2起,GRUB取代LILO成为了默认的启动装载程序。那么启动的时候grub是如何被载入的呢?

grub有几个重要的文件,stage1,stage2,有时候还需要stage1.5。这些文件

一般都在/boot/grub文件夹下面。grub被载入通常包括以下几个步骤:

1、装载基本的引导装载程序(stage1)

stage1很小,只有512字节,

stage1通常位于主引导扇区里面,它的主要功能就是装载第二引导程序(stage2)。这主要是因为在主引导扇区中没有足够的空间用于其它东西, grub中stage2文件的大小是103.9K。

2. 装载第二引导装载程序(stage2)

这第二引导装载程序实际上是引出更高级的功能,以允许用户装载入一个特定的操作系统。在GRUB中,这步是让用户显示一个菜单或是输入命令。

上面还提到了stage1.5这个文件,它的作用是什么呢?在/boot/grub目录下可以看到有fat_stage_1.5  e2fs_stage_1.5 xfs_stage_1.5等等,很容易猜想stage1.5和文件系统有关系,有时候基本引导装载程序(stage1)不能识别stage2所在的文件系统分区,那么这时候就需要stage1.5来连接stage1和stage2了.因此对于不同的文件系统就会有不同的是stage1.5。但是对于我们做的grub好像stage1.5并不是很重要,因为我试过了,在没有stage1.5的情况下, 我把stage1安装在格式化为ext3的CF卡中,能够正常引导,并不需要e2fs_stage_1.5或者fat_stage_1.5。

我们的具体做法是把整个CF卡格式化为一个分区,文件系统为ext3格式,然后把stage1、stage2、grub.conf这几个启动的时候必须的文件拷贝到CF卡的指定目录下,然后进入grub使用一些命令将其安装到CF卡上。

二、内核配置

Linux内核所控制的东西非常广,从文件系统格式、程序开放、电源管理到用户的安全性等一大堆的项目,甚至连网络带宽的分配都在其中,由此可知内核的重要性。但是针对我们现在做的系统,在内核配置中我们主要对下面这些选项感兴趣

1、 Loadable module support  对模块的支持,这里面有三项:  Enable loadable module support:除非你准备把所有需要的内容都编译到内核里面,否则该项应该是必选的。

Set version information on all module symbols:表示该模块不跟内核一起发布,通常不选。

Kernel module loader:该选项表示内核可以实现模块加载的功能。Kernel程序可以在需要的时候自动调用模块,而在不用该功能的时候自动卸载该模块

2、Processor type and features

在它的下面,同样有很多的选项,但我们只关心Processor family:根据我

们自己的情况选择CPU类型。在我们的故障诊断仪上,经过试验证明选择386、486或586/K5/5x86/6x86/6x86MK都可以,但是选择Pentium-3/Celeron或者Pentium-4不行。

3、General setup

这里是对最普通的一些属性进行设置。这部分内容非常多,一般使用缺省设置就可以了。但是必须选上,因为里面有PCI总线支持,电源管理模式等的支持。

4、Block devices

在它的选项下,我们一定要选的是: RAM disk support:。

(65536)default ramdisk size Initial ramdisk(initrd)support

因为我们做的就是ram disk,所以我们必须把这些都选上,内核不支持的话在内核启动完后是不能加载根文件系统的。其中的65536K是我们在内存中开辟的根文件系统空间。这里就是64M,我们可以根据我们的需要进行调整。

5、Character devices

一些字符设备的支持,例如鼠标,虚拟终端的支持等,使用缺省的就可以了。 6、Filesystem

在这里主要是要把ext3文件支持,/proc文件系统支持选上,一般默认即可。因为我们在后面做出的文件系统镜像是ext3格式的,所以内核必须对此文件格式支持。/proc文件系统是linux提供给用户和系统进行交互的通道,也要选上。

另外second extended fs support是标准的linux文件系统,建议编译进内核。其它的文件系统类型我们可以根据自己的爱好进行选择。

7、Console drivers

因为我们还没有桌面系统,我们选择的是VGA text console, 如果没有选择这项的话,开机运行到下载内核时就停止了。

另外对于IDE的支持,我们在不选的情况下系统是可以正常启动和工作的。但是我们的系统只是工作在内存中,我们即使把要运行的程序放在其中,关机后什么都没有保留。所以我们要在系统启动起来后重新把CF卡挂载到系统中,然后把程序运行的结果都保存在CF卡上,这样即使关机CF卡上也已经保存了我们程序的运行结果。所以我们在系统中必须加上对IDE的支持。同理,假如我们的系统要支持USB设备时,我们应该在配置选项中选择支持USB和SCSI。也就是添加上usb的驱动。这里选择SCSI的原因是只有支持SCSI时在USB的配置选项中才会出现USB Mass storage support。

三、文件系统

我们的文件系统是通过busybox工具做出来的,busybox集成了linux常用的命令和工具。这些命令和工具我们都可以根据自己的情况进行选择。另外我们还可以选择是静态编译还是动态编译。这些选择都是通过配置界面进行的。它的配置界面和内核配置界面类似,配置方法也是一样的。使用的命令也是make menuconfig。我们做的时候选择了静态编译的方法,也就是我们在编译程序的时候,需要在参数中指定为静态编译。例如在编译hello.c程序时我们的命令是

#gcc –o hello –static hello.c

如果我们不用-static,那么我们在执行程序时就会出现错误。因为我们的文件系统中没有加上相应的库。当然我们也可以选择动态编译,然后在文件系统中把相应的库文件添加进去。

最终我们的文件系统是做成了ram disk镜像的形式。也就是initrd.img。

四、linux启动过程

BIOS在开机上电后寻找引导程序grub,然后grub引导加载内核,当grub加载内核时,内核会先在内存中制造出一个rootfs当作临时的空间供系统使用,接着kernel便会把我们做出来的文件系统镜像当作一个系统将其挂载到rootfs上激活。当系统镜像被激活后,它会找到并执行其中的linuxrc程序,linuxrc会按照其中的脚本文件/etc/initab执行,一直到系统启动完毕并出现shell命令行。

1、grub引导内核。

在我们前面制作grub时我们拷贝了一个grub.conf文件,它就是grub的配置文件,它的作用就是用来找到内核和根文件系统。它的内容如下:

timeout=10

title Red Hat Linux

root (hd0,0)

kernel  /boot/bzImage

initrd  /boot/initrd.img

timeout就是启动时的延时时间,title是启动画面上出现的操作系统名称。

root (hd0,0)

指示我们的系统在第一个硬盘的第一个分区上

kernel  /boot/bzImage

指示我们的内核文件所在的目录

initrd  /boot/initrd.img

指示我们的文件系统镜像所在的目录

2、linuxrc程序的执行

在前面我们说过,linuxrc程序按照脚本文件/etc/initab依次执行,根据这个脚本文件,在我们自己的系统中,它会首先执行/etc/init.d/rcS程序,该程序的内容如下:

#!bin/sh /bin/mount –a

它的意思是加载/etc/fstab下的所有文件。/etc/fstab下的内容如下: proc

/proc proc defaults 0 0

这里首先说下fstab文件格式  下面是/etc/fatab文件的一个示例行:

fs_spec  fs_file  fs_type  fs_options  fs_dump  fs_pass

/dev/hda1  /usb    ext3  defaults      0          0

简单的说,第一项是我们要挂载的设备文件描述符,第二项是要挂载到哪个目录下,第三项是我们设备的文件系统类型。后面三项对于我们来说一般是不变的。详细的说明可以看下面的描述:

例如在开机启动时,我们要将我们的CF卡自动挂载到系统中去,我们就在fstab文件中增加如上实例中的内容。

这样我们的CF卡在开机启动时就自动挂载到了系统中,但是自动运行我们自己的程序该怎么办呢?我们应该注意到在执行linuxrc程序时首先执行的是/etc/init.d/rcS中的内容,刚才我们的挂载就是其中的一个小程序。所以我们完全可以在其中增加开机时我们需要执行的其它程序,比如说我们有一个可执行二进制文件hello,我们就可以在其中增加这个语句: ./usb/hello

其中usb是我们CF卡的挂载目录,我们的二进制可执行程序hello就位于这个目录。

到此为止,我们的linux操作系统开机运行,自动加载CF卡,自动运行程序就完成了。