提要
linux的啟動過程,包括BIOS的加電自檢POST,拷貝MBR的資訊(啟動BootLoader),載入核心,掛載根檔案安系統這幾大步熟悉grub的話會知道linux啟動時grub中有三項:root,kernel,initrd。其三項的作用分別是:
1.指定核心所在的目錄
2.指定核心的名稱,以及掛載根目錄的方式,還有向核心傳遞一定的參數
3.initrd實際就是個小的linux系統,在一般的系統中initrd的作用是:啟動一個很小的linux用來掛載真實的linux。
今天的目的就是從核心開始,打造一個屬於自己的linux。
環境:Ubuntu13.04 gcc4.7.3
相關的準備工作:
核心的編譯
qemu的安裝
製作根系統目錄1)建立init程式 首先建立一個init.c檔案,代碼如下:
#include<stdio.h>int main(){ printf("Welcome! My student No. is sa*****310.\n"); return 0;}
靜態編譯成一個可執行檔。gcc -static -o init init.c2)建立引導根目錄映像終端運行:dd if=/dev/zero of=initrd.img bs=4096 count=1024mkfs.ext3 initrd.img
有提示,輸入y。
關於dd
dd 是 Linux/UNIX 下的一個非常有用的命令,作用是用指定大小的塊拷貝一個檔案,並在拷貝的同時進行指定的轉換。
文法:dd [選項]
if =輸入檔案(或裝置名稱)。
of =輸出檔案(或裝置名稱)。
ibs = bytes 一次讀取bytes位元組,即讀入緩衝區的位元組數。
...
3)建立rootfs目錄,並掛載mkdir rootfs
sudo mount -o loop initrd.img rootfs
4)在rootfs中添加一些檔案將init拷貝到initrd4M.img的目標根目錄下(因為linux啟動後期會在根目錄中尋找一個應用程式來運行,在根目錄下提供init是一種可選方案)
cp init rootfs/
準備dev目錄:
sudo mkdir rootfs/dev
linux啟動過程中會啟用console裝置:
sudo mknod rootfs/dev/console c 5 1
另外需要提供一個linux根裝置,我們使用ram:
sudo mknod rootfs/dev/ram b 1 0
sudo umount rootfs
至此,一個包含簡單應用程式的根目錄initrd4M.img映像就準備好。mknod 用於製作字元或塊相關檔案
用qemu跑一下:qemu -kernel ../linux-3.9.2/arch/x86/boot/bzImage -initrd initrd.img -append "root=/dev/ram init=/init"
整合busybox
busybox簡介
BusyBox 是一個整合了一百多個最常用linux命令和工具的軟體。BusyBox 包含了一些簡單的工具,例如ls、cat和echo等等,還包含了一些更大、更複雜的工具,例如grep、find、mount以及telnet。有些人將 BusyBox 稱為 Linux 工具裡的瑞士軍刀。簡單的說BusyBox就好像是個大工具箱,它整合壓縮了 Linux 的許多工具和命令,也包含了 Android 系統的內建的shell。
BusyBox 將許多具有共性的小版本的UNIX工具結合到一個單一的可執行檔。這樣的集合可以替代大部分常用工具比如的GNU fileutils , shellutils等工具,BusyBox提供了一個比較完善的環境,可以適用於任何小的或嵌入式系統。
下載源碼:http://www.busybox.net/
這裡選擇1.20穩定版。
解壓,終端進入目錄執行:
make menuconfig
勾選下面的選項:
Build Options
Build BusyBox as a static binary (no shared libs)
這個選項是一定要選擇的,這樣才能把busybox編譯成靜態連結的可執行檔,運行時才獨立於其他函數庫.否則必需要其他庫檔案才能運行,在單一個linux核心不能使他正常工作.
現在直接make的話會報錯:‘RLIMIT_FSIZE’ undeclared
論壇上的回答是沒有包含 sys/resource.h,則在include/libbb.h 中添加:
#include <sys/resource.h>
接下來執行:
#編譯busybox
make
#安裝busybox
make install
安裝好之後在檔案夾下出現一個_install檔案夾,編譯完成。
下面來整合根檔案系統。
建立一個檔案夾,終端cd進去,將之前的initrd.img拷貝進來。
#建立檔案夾
mkdir rootfs
#掛載鏡像
sudo mount -o loop initrd.img rootfs/
#將busybox添加進來
cd ../busybox-1.20.2/
sudo make CONFIG_PREFIX=../Opuntu/rootfs/ install
#查看rootfs中結構
cd ../Opuntu
ls rootfs
#卸載分區
sudo umount rootfs/
運行命令時注意目錄結構!
linux的系統下的目錄都是幹嘛的?
linux下的檔案結構,看看每個檔案夾都是幹嗎用的
/bin 二進位可執行命令
/dev 裝置特殊檔案
/etc 系統管理和設定檔
/etc/rc.d 啟動的設定檔和指令碼
/home 使用者主目錄的基點,比如使用者user的主目錄就是/home/user,可以用~user表示
/lib 標準程式設計庫,又叫動態連結共用庫,作用類似windows裡的.dll檔案
/sbin 系統管理命令,這裡存放的是系統管理員使用的管理程式
/tmp 公用的臨時檔案儲存體點
/root 系統管理員的主目錄(呵呵,特權階級)
/mnt 系統提供這個目錄是讓使用者臨時掛載其他的檔案系統。
...
最後產生的 initrd.img檔案就是根檔案系統了!
#qemu測試
qemu -kernel ../linux-3.9.2/arch/x86/boot/bzImage -initrd initrd.img -append "root=/dev/ram init=/bin/sh"
裝載好之後可以在qemu中運行busybox的命令,效果如下:
整合grub
關於Grub
GNU GRUB(簡稱“GRUB”)是一個來自GNU項目的多作業系統啟動程式。GRUB是多啟動規範的實現,它允許使用者可以在電腦內同時擁有多個作業系統,並在電腦啟動時選擇希望啟動並執行作業系統。GRUB可用於選擇作業系統分區上的不同核心,也可用於向這些核心傳遞啟動參數。
首先來測試一下grub.
從ftp://alpha.gnu.org/gnu/grub/下載GRUB Legacy的最後一個版本0.97的編譯好的檔案grub-0.97-i386-pc.tar.gz.
解壓之後中端cd進去,執行下面的命令。
#建立磁碟片映像:
dd if=/dev/zero of=boot.img bs=512 count=2880
#在boot.img中安裝grub:
sudo losetup /dev/loop0 boot.img
sudo dd if=./grub-0.97-i386-pc/boot/grub/stage1 of=/dev/loop0 bs=512 count=1
sudo dd if=./grub-0.97-i386-pc/boot/grub/stage2 of=/dev/loop0 bs=512 seek=1
sudo losetup -d /dev/loop0
在qemu中測試是否可以進入grub
qemu -fda boot.img
OK.
接下來將grub,kernel,busybox一起整合,離勝利只還有一步 - - 。
先你自己發行版取一個庫一些的名字,比如Opuntu...(Opensuse+ubuntu),建立一個以它命名的檔案夾。
#拷貝boot.img到目前的目錄
sudo cp ../grub-0.97-i386-pc/boot.img ./
#建立rootfs檔案夾
mkdir rootfs
#建立一個32M的磁碟鏡像檔案
dd if=/dev/zero of=/dev/zero of=Opuntu.img bs=4096 count=8192
#給磁碟映像分區
fdisk -C 16065 -H 255 -S 63 Opuntu.img
解釋:設定Opuntu.img的磁頭數為255、磁軌數為16065、扇區數為63,同時給磁碟分割。
這裡我們只分一個區,並設定該分區為引導分區。如下:
#格式化分區
sudo losetup -o 1048576 /dev/loop0 Opuntu.img
sudo mkfs.ext3 -m 0 /dev/loop0
解釋:我們把前面的2048個扇區(0~2047)作為開機磁區使用,格式化分區從第2048個扇區開始,所以1048576=2048*512
#拷貝之前做好的initrd.img和bzImage.img到rootfs
sudo mount /dev/loop0 rootfs/
sudo cp ../linux-3.9.2/arch/x86/boot/bzImage ./rootfs/
sudo cp ../rootfs/initrd.img ./rootfs/
#添加grub
sudo mkdir rootfs/boot
sudo mkdir rootfs/boot/grub
sudo cp ../grub-0.97-i386-pc/boot/grub/* ./rootfs/boot/grub
sudo vi ./rootfs/boot/grub/menu.lst
內容:
default 0timeout 30title linux on 32M.imgroot (hd0,0)kernel (hd0,0)/bzImage root=/dev/ram init=/bin/ashinitrd (hd0,0)/initrd.img
#卸載磁碟鏡像
sudo umount rootfs
sudo losetup -d /dev/loop0
#利用grub啟動磁碟片,在硬碟映像上添加grub功能
qemu -boot a -fda boot.img -hda Opuntu.img
執行圖中的兩步(注意空格):
運行成功之後,Opuntu.img就是我們的最終成果了,整合了busybox,grub,linux kernel3.92!
qemu -hda Opuntu.img
用qemu跑起來:
參考:
鳥哥私房菜 第二十二章:開關機流程與loader
製作可用grub引導Linux系統的磁碟映像檔案 - http://blog.sina.com.cn/s/blog_70dd169101013gcw.html
詳細講解Linux啟動流程及啟動用到的設定檔及指令碼 - http://guodayong.blog.51cto.com/263451/1168731