linux 内核代码学习(十)--Linux内核启动和文件系统

前面第九章介绍了linux内核+文件系统从软盘启动的几种方式:1、从软盘直接启动的linux,软盘上包括内核及简单文件系统;2、从软盘直接启动的linux,将内核与文件系统分别放置在一张软盘上;3、Grub做为引导程序,软盘上包括内核及简单文件系统;4、用sysLinux引导,软盘上包括内核及简单文件系统。本章介绍的linux内核+文件系统从软盘启动的方式的特点是:Grub做为引导程序,分为两张软盘启动,第一张软盘包括grub、内核、简单文件系统、以及一个自己编写的readkey程序;第二张软盘包括一个完整的文件系统;系统启动过程中通过readkey程序提示插入第二张软盘,并通过第一张软盘中的简单文件系统将第二张软盘中的文件系统解压,切换到第二张软盘的完整文件系统,释放第一张软盘的简单文件系统;这种方式可以完成更复杂的启动,可以自己DIY自己的linux,进一步可以制作自己的linux发行版。

为了方便理解这个例子,先介绍目录结构如下:
/home/mygrub
  ├─bootldr/
  │ ├─grub/
  │ ├─kernel/
  │ │ ├─images/
  │ │ └─linux-2.4.20/
  │ └─initrd/ 
       │   ├─mkinitrd.sh
  │   ├─local/
  │   └─ramdisk/
  ├─rootfs/
  │ ├─mkrootfs.sh
  │ ├─ramdisk/
  │ └─local/
  └─lib/
使用Grub做为引导程序,并使用initrd(初始RAM磁盘)来辅助Linux的启动。两张软盘分别命名为bootldr盘和rootfs盘,在bootldr盘中内容为grub、内核、initrd;rootfs盘中是压缩过的根文件系统。系统启动时bootldr盘的Grub定位并执行内核,然后内核解开initrd,并执行linuxrc文件(这需要在grub.conf配置文件中设置初始化参数init=/linuxrc rw),这个文件负责提示用户更换rootfs盘并将其中内容解压至内存中,然后执行刚刚解压的init(注意此时的init在第二张盘文件系统中)继续启动过程。

一、第一张bootldr盘的制作
插入一张软盘,然后将其格式化,然后加载到/mnt/floppy
mke2fs -m 0 /dev/fd0
mount -t ext2 /dev/fd0 /mnt/floppy -o loop
在其中创建/boot/grub目录
mkdir -p /mnt/floppy/boot/grub
将系统中/boot/grub下的device.map, stage1, stage2 复制到/mnt/floppy/boot/grub中,
cp /boot/grub/stage1 /mnt/floppy/boot/grub
cp /boot/grub/stage2 /mnt/floppy/boot/grub
grub
在 grub> 提示符处,输入:
grub> root (fd0)
grub> setup (fd0)
grub> quit
cp /boot/grub/grub.conf /mnt/floppy/boot/grub

编辑grub.conf, 内容如下:
timeout 10
default 0
title XB_Linux (2.4.20-8)
  root (fd0)
  kernel /boot/bzImage ro root=/dev/ram0 init=/linuxrc rw ##必须指定启动参数init=/linuxrc rw,否则会报错提示说init程序多次调用,导致文件系统初始化不完善。见内核文档initrd.txt详细说明
  initrd /initrd.gz
然后制作grub.conf的link文件menu.lst
ln -s /mnt/floppy/boot/grub/grub.conf /mnt/floppy/boot/grub/menu.lst
这样grub就被安装到bootldr盘上了。

没有配置启动参数的时候,会有init多次调用的提示,导致第二张盘中的文件系统中的/etc/目录下的初始化文件不能执行,比如fstab、inittab。 

二、定制Linux内核:由于软盘大小的限制,内核应尽可能只包含必要的一些支持,对于本文中的例子一定要选上initrd支持。比如如果做为系统修复盘的话,必要的支持包括:IDE,PCI,和需要的文件系统类型等等就可以了,而没有必要网络支持,当然,如果做为路由器或者防火墙的话,网络支持是必要的,而其他的可相应的删除掉。
  #make [xconfig | menuconfig | config]
  #make bzImage
  如果添加了模块的支持,还需要
  #make modules
  之后就得到了内核镜像bzImage。如果bzImage的大小超出了软盘的限制,就需要重新再来配置一下。将编译好的bzImage放到bootldr盘的根目录下,如果把bzImage改了名字,要注意与grub.conf中的名字一致。
cp /mnt/hgfs/linux-2.4.20/arch/i386/boot/bzImage /mnt/floppy/boot/
umount /mnt/floppy/

三、制定initrd
  在initrd/local目录下建立bin, dev, etc, lib, proc, sysroot, usr目录。其中dev目录下包括必要的设备文件,
比如tty, ram, console,fd0等等,
mknod dev/tty c 5 0
mknod dev/ram0 b 1 0
mknod dev/console c 5 1
mknod dev/null c 1 3
 bin中必要的可执行文件有gzip,chroot, cp, cpio, dd, echo, mount, pivot_root,readkey, sh, test等。Busybox提供了其中大部分。 gzip, dd, cpio用来解压缩第二张软盘上的内容,chroot,pivot_root用来转换根目录。
cp /home/xb/busybox-1.00/_install/bin/busybox  bin/
ln -s busybox gzip
ln -s busybox chroot
ln -s busybox cp
ln -s busybox cpio
ln -s busybox dd
ln -s busybox echo
ln -s busybox mount
ln -s busybox pivot_root
ln -s busybox sh
ln -s busybox ls
因为我的busybox编译的时候用的是默认的sysinit script:
#define INIT_SCRIPT  "/etc/init.d/rcS"    /* Default sysinit script. */
而我们的initrd软盘中并没有/etc/init.d/目录及rcS脚本文件,因此我们在grub配置文件中配置了启动参数init=/linuxrc rw,这样内核就会直接执行简单文件系统根目录下的linuxrc文件。

[root@localhost initrd]# cat local/linuxrc
#!/bin/sh

#把sysroot目录mount到一块内存上,并建立tmpfs文件系统。
echo "Mounting new root filsystem ..."
mount tmpfs /sysroot -t tmpfs
cd /sysroot

#下面的readkey是一个很简单的程序,当启动过程执行到这里的时候暂停,等待换入第二章软盘,然后#接受任意键输入继续执行启动过程,要注意的是最好使用静态链接。
echo " "
echo -en "Insert the second disk and press ANY key..."
readkey > /dev/null
echo " "

#将第二章软盘上的内容解压到sysroot目录(内存)中。
echo "Loading root-archive from floppy ..."
dd if=/dev/fd0 bs=1k | gzip -d | cpio -idv
#下面将initrd中的文件copy到sysroot/bin目录下,这样可以把根文件系统中一部分内容放到initrd(第##一张软盘)中,因为软盘容量有限,当第一张软盘空间有剩余,而第二章软盘空间紧张的时候这会非常##有用。
echo "Copying:"
for file in gzip chroot cp cpio echo readkey; do
echo -en " "; echo -n $file
cp /bin/$file ./bin/$file
done
#下面将/目录设定为当前目录,即sysroot,并执行刚刚从rootfs盘中解压出来的init。
echo " "
echo "Pivoting / ..."
pivot_root . mnt/initrd
echo "Starting init process..."
exec chroot . /sbin/init <dev/console >/dev/console 2>&1
echo -en"Something went wrong ..."
/bin/sh || /mnt/initrd/bin/sh
[root@localhost initrd]#

当initrd所有必须的文件都放到bootldr/initrd/local目录下之后,进入到bootldr/initrd目录,就可以执行bootldr/initrd/mkinitrd.sh来创建initrd镜像文件。mkinitrd.sh的内容为:
#!/bin/sh
  mount -t ext2 /dev/fd0 /mnt/floppy
  rm -f /mnt/floppy/initrd.gz
  rm -f initrd.gz
  取4M大小的内存块格式化为ext2格式,并将其mount到bootldr/initrd/ramdisk上。
  dd if=/dev/zero of=/dev/ram9 bs=1k count=4096
  mke2fs -m 0 /dev/ram9
  mount -t ext2 /dev/ram9 ramdisk/
  把local中的文件复制到ramdisk目录中,也就是那块内存中。
  cp -R local/* ramdisk/
  umount ramdisk
  将内存中的内容压缩为initrd.gz,并复制到bootldr盘中
  dd if=/dev/ram9 bs=1k | gzip -v9 > initrd.gz
  cp initrd.gz /mnt/floppy/
  umount /mnt/floppy
  这样,bootldr盘就完成了。

 [root@localhost xb]# cat readkey.c
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>

#if 0
// 定义按键值
#define KEY_ESC 0x1b  
// 定义readkey函数
int readkey(void) {
    struct termios oldattr, newattr;
    int ch;  
    // 获取当前终端设置
    tcgetattr(0, &oldattr);
    newattr = oldattr;
    // 设置非回显模式
    newattr.c_lflag &= ~(ECHO | ICANON);
    tcsetattr(0, TCSANOW, &newattr);  
    // 读取键盘输入
    ch = getchar();  
    // 恢复原来的终端设置
    tcsetattr(0, TCSANOW, &oldattr);  
    return ch;
}  
int main() {
    int key;  
    printf("Press a key, and then press Enter: ");
    fflush(stdout); // 清空输出缓冲区  
    key = readkey();  
    if (key == KEY_ESC) {
        printf("You pressed the ESC key.\n");
    } else {
        printf("You pressed the '%c' key.\n", key);
    }  
    return 0;
}
#endif
 
int main()
{
    struct termios oldattr, newattr;
    int ch;  
    // 获取当前终端设置
    tcgetattr(0, &oldattr);
    newattr = oldattr;
    // 设置非回显模式
    newattr.c_lflag &= ~(ECHO | ICANON);
    tcsetattr(0, TCSANOW, &newattr);  
    // 读取键盘输入
    ch = getchar();  
    // 恢复原来的终端设置
    tcsetattr(0, TCSANOW, &oldattr);  
    return ch;
}
四、定制根文件系统
  一个根文件系统需要包含支持Linux系统运行的所有文件。通常包括:
  基本的文件系统结构
  基本的目录: /dev, /proc, /bin, /sbin, /etc, /usr, /tmp,/mnt,/mnt/initrd等。
  基本的工具: sh, ls, cp, cd, mv等。
  基本的配置文件: rc, inittab, fstab等。
  设备: /dev/hd*, /dev/tty*, /dev/fd0, /dev/ram*, /dev/console等.
  基本的运行库。
  Busybox和Tinylogin是在嵌入式系统上常用的工具包,它们包含了上面提到的常用的工具和目录结构等,而且经过重新改写后所生成的代码比普通的Linux系统上的工具要小的多。编辑Busybox的Config.h文件,选择自己需要的工具。修改Busybox和Tinylogin的Makefile文件,制定它们使用静态链接方式(DOSTATIC=true),这样就不需要在生成的系统中添加运行库了。将编译好的Busybox和Tinylogin文件放到rootfs/local中。

对于tinylogin,操作和busybox完全相同。也要静态编译,然后把login,passwd,adduser等帐户管理的工具建立和tinylogin的链接即可。需要注意的是有些工具是在sbin当中的,所以也可以把tinylogin拷到 sbin目录下,bin下的工具要想链接到tinylogin,可以如下操作:

ln –s tinylogin ../bin/login

有些bin和sbin下的工具是busybox和tinylogin中所没有的,必须从完整的系统中拷过来,例如在这个系统中,由于选择vi时编译出错,所以vi是直接从主盘上拷过来的,而且必须把这个工具使用的相应的库也拷到lib下面。如使用ldd vi,就可以看到vi使用了哪些库,然后把这些库拷到/mnt/lib下就可以了。Tinylogin目前已经整合到busybox中了。

https://tinylogin.busybox.net/

     

在rootfs/local中在自己创建下面几个目录:dev/, tmp/, etc/, proc/可以将系统中/dev下的设备复制到这个目录下,只需要复制必要的就可以了,例如:
  #cp -dpR /dev/tty[0-9]    rootfs/local/dev
  #cp -dpR /dev/ram*       rootfs/local/dev
  但是要注意一定要包含必要的接各设备/dev/console, /dev/kmem, /dev/mem, /dev/tty, /dev/ram0,/dev/null等。etc/目录下包含了目标系统运行所必须的配置文件,它包括的内容依赖于目标系统所要运行的程序。最低限度,它包括下面几个文件:inittab、rc、fstab、passwd、group、shadow、termcap等。做为init进程的参数,inittab可以非常简单,仅需要包括下面几行即可:
[root@localhost local]# cat etc/inittab
::sysinit:/etc/init.d/rcS
::askfirst:/bin/sh
#::askfirst:/bin/login
#tty2::askfirst:/bin/login
#tty3::askfirst:/bin/login
#tty4::askfirst:/bin/login
#::ctrlaltdel:/sbin/reboot
#::restart:/sbin/init
#::shutdown:/bin/umount -a -r
#::shutdown:/sbin/swapoff -a

将::askfirst:/bin/login替换为::askfirst:/bin/sh,否则会出现如下面的问题,不能进入到linux环境中:

其中sysinit指明系统初始化脚本rc。rc所包含内容也可以非常少:
  #!/bin/sh
  /bin/mount -av
  /bin/umount /mnt/initrd
  /bin/hostname papaya
fstab的内容为:
  none/procprocdefaults0 0
  none/tmptmpfsdefaults0 0
  其他的配置文件可以从原来的系统中获得,然后修剪掉不必要的内容即可。现在在/rootfs中已经包含了运行一个最低限度Linux系统所必须的所有文件和工具,下面需要将它们压缩成一个文件系统了。插入rootfs软盘并执行rootfs/mkrootfs.sh
  #!/bin/sh
  rm -f rootfs.cpio.bz2
  dd if=/dev/zero of=/dev/ram0 bs=1k count=4096
  mke2fs /dev/ram0
  mount -t ext2 /dev/ram0 ramdisk/
  cp -R local/* ramdisk/
  cd ramdisk/
  find . -depth -print | cpio -o > ../rootfs.cpio
  cd ..
  gzip -v9 rootfs.cpio
  umount ramdisk
  dd if=rootfs.cpio.gz of=/dev/fd0 bs=1k
  OK,rootfs盘也完成了

 五、在vmware虚拟机中的测试效果

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值