在Bootsect.s中设置的根文件系统设备号其实只是初始值,不起作用,仅仅为保存根文件系统设备号的值在Bootsect.s的编译后文件的508,509处预留了空间。而在最后用工具程序Build将所有内核有效部分组合起来时,还要对根文件系统设备号进行最后的处理。
ROOT_DEV = 0x306;指定根文件系统设备是第2个硬盘的第1个分区。这是Linux老式的硬盘命名方式,具体值的含义如下:
设备号=主设备号*256 +次设备号(也即dev_no = (major<<8) + minor),其中主设备号:
1-内存,2-磁盘,3-硬盘,4-ttyx,5-tty,6-并行口,7-非命名管道。
硬盘的逻辑设备号(主设备号为3):
逻辑设备号 |
对应设备文件 |
说明 |
0x300 |
/dev/hd0 |
代表整个第1个硬盘 |
0x301 |
/dev/hd1 |
表示第1个硬盘的第1个分区 |
0x302 |
/dev/hd2 |
表示第1个硬盘的第2个分区 |
0x303 |
/dev/hd3 |
表示第1个硬盘的第3个分区 |
0x304 |
/dev/hd4 |
表示第1个硬盘的第4个分区 |
0x305 |
/dev/hd5 |
代表整个第2个硬盘 |
0x306 |
/dev/hd6 |
表示第2个硬盘的第1个分区 |
0x307 |
/dev/hd7 |
表示第2个硬盘的第2个分区 |
0x308 |
/dev/hd8 |
表示第2个硬盘的第3个分区 |
0x309 |
/dev/hd9 |
表示第2个硬盘的第4个分区 |
软盘的逻辑设备号:
(主设备号为2,次设备号=type * 4 + nr,其中nr为0-3分别对应软驱A、B、C、D;type是软驱的类型2:1.2MB,7:1.44MB等)。
逻辑设备号 |
对应设备文件 |
说明 |
0x021C |
/dev/PS0 |
1.44MB A驱动器,major = 2; minor = 7 * 4 + 0 = 28。 |
0x0208 |
/dev/at0 |
1.2MB A驱动器,major = 2;minor = 2 * 4 + 0 = 8。 |
从117行开始,判断根设备号是否已经被定义,如果没有定义,则以当前引导软驱的设备号为根文件系统设备号。因此通过取每磁道扇区数来判断当前的引导软驱的设备号是否合法(见123行),如果合法,则将当前引导软驱的设备号为根文件系统设备号。
3.5英寸,18扇区的软盘:2*80*18*512B = 1.44MB
Bootsect.s文件被编译以后,产生的bin文件为512 Bytes,其中508,509字节保存的为根设备号。
Build工具程序对根设备号的处理,是通过判断入口参数信息来设置根文件系统设备号的。如下:
下面为入口参数的几种情况:
第一种情况:
其中蓝色方框之中ROOT_DEV为主Makefile文件中给定的根设备号的初始值。
红色方框为make调用Build工具程序的执行结果。共有五个参数,其中最后一个参数为1FLOPPY。[X]表示参数序号。如第一种情况下有五个参数。
主Makefile文件中给定的ROOT_DEV的初始值。 |
表示第几种情况。 |
通过Make来调用Build工具程序时给定的参数列表。 tools/build boot/bootsect boot/setup tools/kernel $(ROOT_DEV) > Image |
(主设备号,次设备号) |
第三种情况:
总结:如果ROOT_DEV的初始值中带“#”,则调用如下的命令(摘自主Makefile文件):
tools/build boot/bootsect boot/setup tools/kernel$(ROOT_DEV) > Image
中的最后一个根设备号参数(红色的)将忽略,此时主设备号、次设备号分别等于一个给定的缺省值,如以上第三种情况。如果不带“#”,则按给定的根设备号初始值来进行判断:如果等于FLOPPY,则主设备号、次设备号均为0,如以上第二种情况;如果不等于FLOPPY,则通过系统调用stat以及给定的根设备号初始值来取得主设备号、次设备号,如以上第一种情况。
在操作系统成功引导以后,Bootsect被加载到0x90000处,所以从0x90000 + 508 = 0x901FC处即可获得根文件系统设备号的值。在main.c中的main()函数的第一行即是通过如下方式来取根文件系统设备号的值:ROOT_DEV = ORIG_ROOT_DEV,其中ORIG_ROOT_DEV即为0x901FC。
设置根文件系统设备号的初始值,要以根文件系统所在的物理位置为根据。
因为Linux当初是在Minix1.5.10操作系统的扩展版本Minix-i386上交叉编译开发的。并且当初Linus是将Linux的原始根文件系统放在第2块硬盘的第一个分区上的,所以在主Makefile文件中ROOT_DEV = /dev/hd6。并且在Bootsect.s中,给定ROOT_DEV = 0x306;在Build.c中给定的缺省的主设备号(DEFAULT_MAJOR_ROOT)为3,缺省的次设备号(DEFAULT_MINOR_ROOT)为6。
如果将gcc 1.40编译环境放到Liunx0.11中,如《Liunx内核完全注释》提供的http://oldlinux.org/Linux.old/bochs/linux-0.11-devel-040329.zip开发包,其根文件系统所在位置为第1块硬盘的第一个分区,所以在主Makefile文件中ROOT_DEV = /dev/hd1。并且在Bootsect.s中,给定ROOT_DEV=0x301;在Build.c中给定的缺省的主设备号(DEFAULT_MAJOR_ROOT)为3,缺省的次设备号(DEFAULT_MINOR_ROOT)为1。
如果在Rethat 9中编译Linux 0.11,则假定实际运行过程中根文件系统所在位置为第1块硬盘的第一个分区,因为Build工具程序是在Redhat中运行的,所以通过系统调用stat以及给定的根设备号初始值来取得主设备号、次设备号,其中的根设备号初始值必须是在Redhat中有效的设备文件,而在Redhat 9中第1块硬盘的第一个分区的设备文件为:/dev/hda1。因此,在主Makefile文件中ROOT_DEV = /dev/hda1。并且在Bootsect.s中,给定ROOT_DEV = 0x301;在Build.c中给定的缺省的主设备号(DEFAULT_MAJOR_ROOT)为3,缺省的次设备号(DEFAULT_MINOR_ROOT)为1。
如果假定实际运行过程中根文件系统所在位置为软盘,因此,在主Makefile文件中ROOT_DEV = #floppy。并且在Bootsect.s中,给定ROOT_DEV = 0x306;在Build.c中给定的缺省的主设备号(DEFAULT_MAJOR_ROOT)为2,缺省的次设备号(DEFAULT_MINOR_ROOT)为0x1D。因为在主Makefile文件中ROOT_DEV = #floppy,前面带有“#”,所以Build工具程序将用缺省的主设备号2、次设备号0x1D来设置根文件系统设备号。最后系统运行时将提示插入根文件系统所在的软盘。