製作最小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指令碼中預設大量可能的裝置節點: