1. 程式人生 > >製作最小linux核心(2)

製作最小linux核心(2)

    製作最小linux核心(1) 一文中定製了一個小型核心,當重啟系統載入小型核心後,往螢幕上輸出"Hello world"。說實話,這樣的OS並沒有什麼作用,至少得有個能和使用者互動的介面吧?本文將繼續定製核心,以實現這個目的。要實現這個目的需要2部分支援:1.繼續配置核心選項以完善核心功能;2.為initrd.img增加新功能。

    1.先來完成第一部分,在這步中需要加入以下核心選項:

1.1.配置核心支援netlink。後面initrd.img中要通過udevd來動態載入模組,udevd需要這項支援:
執行make menuconfig-"Networking support"-"Networking options"-將"Unix domain sockets"編譯進核心

    

1.2.配置核心支援inotify。udev使用inotify檢測udev規則檔案是否發生變化:

執行make menuconfig-"File systems"-將"inotify support for userspace"編譯進核心


1.3.配置核心支援shell指令碼。initrd.img中將執行shell指令碼:

執行make menuconfig-"Executable file formats/Emulations"-將"Kernel support for scripts starting with #!"編譯進核心


1.4.配置核心支援ramfs。udev掛載系統時需要用到ramfs:

執行make menuconfig-"ubuntu supplied Third-party" device drivers-將"Aufs"編譯進核心;勾選"Aufs"核心項後,會出現Ramfs,同時將Ramfs(initramfs/rootfs)編譯進核心


至此,核心新特性部分新增完畢,重新編譯核心,並將bzImage拷貝到/boot下

$make all -j4
$sudo cp arch/x86/boot/bzImage /boot
    2.再來準備第二部分,定製initrd.img。initrd.img中包含了大量的工具,從頭開始編譯這些工具不是很方便,為此我找了個替代的方法:將/boot目錄下ubuntu發行版的initrd.img拷貝出來,剔除一些不需要的工具和指令碼,然後重新打包做成initrd.img並拷貝回/boot目錄。看過前一篇文章的讀者一定了解這個背景知識----initrd.img其實是經過gz壓縮的cpio包。因此只要將initrd.img檔案重新命名為initrd.cpio.gz就能還原出其中的檔案。下圖是解壓發行版ubuntu自帶的initrd.img檔案後得到的目錄結構和init檔案的內容:

圖片中init指令碼實現的功能很複雜:它實現了CDROM/網路/磁碟等多種啟動方式,此外還載入了大量的驅動。這些對於我來說是不必要的,所以我對init檔案做了瘦身,僅僅啟動udev守護程式以及udev執行時需要掛載的sysfs/proc/ramfs等檔案系統

#!/bin/sh

[ -d /dev ] || mkdir -m 0755 /dev #如果/dev目錄不存在則建立 下同
[ -d /sys ] || mkdir /sys
[ -d /proc ] || mkdir /proc
[ -d /tmp ] || mkdir /tmp
[ -d /run ] || mkdir /run
export PATH=/bin 
mount -t devtmpfs -o mode=0755 udev /dev #掛載各類udev依賴的檔案系統
mount -t sysfs -o nodev,noexec,nosuid sysfs /sys
mount -t proc -o nodev,noexec,nosuid proc /proc
[ -e /dev/console ] || mknod -m 0600 /dev/console c 5 1 #如果不存在/dev/console裝置節點則建立 下同
[ -e /dev/null ] || mknod /dev/null c 1 3
mount -n -t ramfs ramfs /run
echo > /sys/kernel/uevent_helper #uevent_helper是核心與使用者層用於互動uevent事件的檔案
/lib/systemd/systemd-udevd --daemon --resolve-names=never #啟動udev守護程式
udevadm trigger --action=add #udevadm trigger 請求核心對全部裝置模擬一遍熱拔插
udevadm settle #上面的命令是個非同步呼叫過程,settle使得指令碼暫停執行,直到核心完成熱拔插過程
exec /bin/sh #啟動互動式sh

完成以上操作後在init同層目錄下執行打包命令用以製作initrd.img

$find .|cpio -o -H newc|gzip -3 > ../initrd.img  
$sudo cp ../initrd.img /boot 

最後,定製結束後我們看下引導新核心的執行截圖:

系統引導到busybox生成的shell中,而不是先前單調的輸出Hello world:


執行命令,可以看到根檔案系統的結構


由於udev動態產生了裝置節點,因此不需要再init指令碼中預設大量可能的裝置節點: