使用 linux kernel +busybox 定製linux系統

寫在開頭:

本來是想使用linux kernel +busybox 製作一個教程的,後來快要結束的時候,死活找不到硬盤,我瞭解很多文章都有類似的,但是沒有談到硬盤找不到問題,最後歷經艱辛,終於把問題解決了,成功啟動一個趕緊的的linux 小系統。

目的:

瞭解linux的啟動過程

主要內容:

1. grub 是啟動程序的bootloader

2. linux-kernel 是linux的開源內核

3. busybox 是linux的工具集合


啟動順序:

grub-> bzimage > initrd > init > chroot sbin/init (從內存鏡像轉換車工rootfs)> /etc/inittab > fstab>etc/init.d/rcS


實驗環境:

操作系統(編譯使用): CentOS 7.4

Kernel 版本 :5.5.2


1. 編譯linux kernel


1) 下載及解壓:

https://www.kernel.org/

目前最新版本5.5.2

https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.5.2.tar.xz

複製文件到 /usr/src/linux-5.5.2.tar.xz

解壓 tar -xvf linux-5.5.2.tar.xz

2)編譯linux kernel:

<code>yum install ncusres-devel # 按照需要編譯的一些包cd /usr/src/linux-5.5.2  # 切換到linux源代碼目錄make menuconfig   #配置內核編譯內容,配置一些信息 ,由於是演示,默認就可以了make -j4 #執行多cpu方式編譯midir /usr/src/modulesmake modules_install INSTALL_MOD_PATH=/usr/src/modules #將modules安裝在這裡/<code>


2. 編譯busybox

1) 下載及解壓:

https://busybox.net/

目前最新版本1.31.1

https://busybox.net/downloads/busybox-1.31.1.tar.bz2

複製文件到 /usr/src/busybox-1.31.1.tar.bz2

解壓 tar -jxvf busybox-1.31.1.tar.bz2

2) 編譯busybox

<code>yum install glibc-static # 按照需要編譯的靜態庫包 cd /usr/src/busybox-1.31.1 # 切換到busybox源代碼目錄 make menuconfig # 配置 Settings->Build Options->Build static binary make install/<code>


3. 根據busybox 製作initrd.gz文件

<code>make /usr/src/initrd # 創建初始化目錄 cd /usr/src/initrd # 進入工作目錄 cp /usr/src/busybox-1.31.1/_install/* -a . #複製所有busybox文件 mkdirprocsysmnt/sysrootdevtmpetc-pv #創建必要的目錄 mknod dev/console c 5 1 # 創建console設備 mknod dev/null c 1 3 # 創建null設備rm linuxrc # 刪除軟連接,這個文件沒啥用看著不舒服而已 touch init # 創建init 引導程,具體內容見下面信息 chmod +x init # 設置可運行程序find . | cpio -H newc --quiet -o | gzip -9 > /usr/src/initrd.gz #打包initrd/<code>


init 文件內容:

<code>#!/bin/shecho "Mounting proc and sys..."  #下面兩句有順序問題,特別奇怪,具體沒有深入研究mount -t sysfs sysfs /sysmount -t proc proc /proc   echo "Detect and export hardware infomation..."mdev -s  echo "Mount real rootfs to /mnt/sysroot..."mount -t ext4 -o ro /dev/sda2 /mnt/sysroot  echo "Switch to real rootfs..."exec chroot /mnt/sysroot /sbin/init/<code>


4. 根據linux kernel 編譯輸出整理成 vmlinuz

<code>cp /usr/src/linux-5.5.2/arch/x86/boot/bzImage /usr/src/vmlinuz #複製內核/<code>


5. 根據busybox 製作rootfs 系統真正的linux目錄

<code>make /usr/src/sysroot #創建工作目錄cd sysroot #進入工作目錄cp /usr/src/busybox-1.31.1/_install/* -a . #複製所有busybox文件rm linuxrc # 刪除軟連接,這個文件沒啥用看著不舒服而已# 創建目錄mkdir dev var sys mnt etc proc lib home tmp root bootmkdir var/{log,run,lock}mkdir lib/modulesmknod dev/console c 5 1 # 創建console設備mknod dev/null c 1 3 # 創建null設備vim etc/inittab #創建rootfs啟動文件,內容見下圖vim etc/init.d/rcS #創建啟動腳本chmod +x rcSvim etc/fstab #當執行mount -a 的時候就會執行這個文件裡的掛載/<code>


inittab 文件內容:

<code>::sysinit:/etc/init.d/rcS::askfirst:-/bin/sh::ctrlaltdel:/sbin/reboot::shutdown:/bin/umount -a -r::restart:/sbin/init/<code>

rcS 文件內容:

<code>#!/bin/shecho -e "Welcome To My Linux"echo "Remount the rootfs..."mount -t ext4 -o remount,rw /dev/sda2 /echo "Detect and export hardware infomation..."mdev -secho "Mount the other filesystem...fstab"mount -a/<code>


fstab

<code># device        mount-point             type    options       dump fscksysfs           /sys                    sysfs   defaults        0   0  proc            /proc                   proc    defaults        0   0  /dev/sda1       /boot                   ext4    defaults        0   0  /dev/sda2       /                       ext4    defaults        1   1  /<code>


6. 經過上面的步驟已經實現了 vmlinuz(linux 內核) initrd.gz(內存系統盤) sysroot (真正的linux rootfs系統) 都已經準備好了,接下來開始準備一塊磁盤。

通過virtual box 創建一塊sata磁盤10G 並分成兩個區.

<code>[root@centos ~]# lsblkNAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTsda           8:0    0  100G  0 disk ├─sda1        8:1    0    1G  0 part /boot└─sda2        8:2    0   99G  0 part   ├─cl-root 253:0    0   50G  0 lvm  /  ├─cl-swap 253:1    0    2G  0 lvm  [SWAP]  └─cl-home 253:2    0   47G  0 lvm  /homesdb           8:16   0   10G  0 disk sr0          11:0    1 1024M  0 rom###############################################[root@centos ~]# fdisk /dev/sdb  #開始格式化Welcome to fdisk (util-linux 2.23.2).Changes will remain in memory only, until you decide to write them.Be careful before using the write command.Device does not contain a recognized partition tableBuilding a new DOS disklabel with disk identifier 0x3f5d5436.Command (m for help): nPartition type:   p   primary (0 primary, 0 extended, 4 free)   e   extendedSelect (default p): pPartition number (1-4, default 1): 1First sector (2048-20971519, default 2048): 2048Last sector, +sectors or +size{K,M,G} (2048-20971519, default 20971519): +5GPartition 1 of type Linux and of size 5 GiB is setCommand (m for help): nPartition type:   p   primary (1 primary, 0 extended, 3 free)   e   extendedSelect (default p): pPartition number (2-4, default 2): First sector (10487808-20971519, default 10487808): Using default value 10487808Last sector, +sectors or +size{K,M,G} (10487808-20971519, default 20971519): Using default value 20971519Partition 2 of type Linux and of size 5 GiB is setCommand (m for help): pDisk /dev/sdb: 10.7 GB, 10737418240 bytes, 20971520 sectorsUnits = sectors of 1 * 512 = 512 bytesSector size (logical/physical): 512 bytes / 512 bytesI/O size (minimum/optimal): 512 bytes / 512 bytesDisk label type: dosDisk identifier: 0x3f5d5436   Device Boot      Start         End      Blocks   Id  System/dev/sdb1            2048    10487807     5242880   83  Linux/dev/sdb2        10487808    20971519     5241856   83  LinuxCommand (m for help): wThe partition table has been altered!Calling ioctl() to re-read partition table.Syncing disks.[root@centos ~]# /<code>


開始掛載分好區的盤,並將文件複製到這兩分區中,第一個分區定義為boot,第二個分區定義為sysroot ;


<code>mkdir /mnt/boot /mnt/sysroot # 在centos系統上創建兩個目錄[root@centos src]# lsblk  # 查看剛剛分好區的sdb 盤NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTsda           8:0    0  100G  0 disk ├─sda1        8:1    0    1G  0 part /boot└─sda2        8:2    0   99G  0 part   ├─cl-root 253:0    0   50G  0 lvm  /  ├─cl-swap 253:1    0    2G  0 lvm  [SWAP]  └─cl-home 253:2    0   47G  0 lvm  /homesdb           8:16   0   10G  0 disk ├─sdb1        8:17   0    5G  0 part └─sdb2        8:18   0    5G  0 part sr0          11:0    1 1024M  0 rom [root@centos mnt]# mkfs.ext4 /dev/sdb1 #創建文件系統格式mke2fs 1.42.9 (28-Dec-2013)Filesystem label=OS type: LinuxBlock size=4096 (log=2)Fragment size=4096 (log=2)Stride=0 blocks, Stripe width=0 blocks327680 inodes, 1310720 blocks65536 blocks (5.00%) reserved for the super userFirst data block=0Maximum filesystem blocks=134217728040 block groups32768 blocks per group, 32768 fragments per group8192 inodes per groupSuperblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736Allocating group tables: done                            Writing inode tables: done                            Creating journal (32768 blocks): doneWriting superblocks and filesystem accounting information: done [root@centos mnt]# mkfs.ext4 /dev/sdb2mke2fs 1.42.9 (28-Dec-2013)Filesystem label=OS type: LinuxBlock size=4096 (log=2)Fragment size=4096 (log=2)Stride=0 blocks, Stripe width=0 blocks327680 inodes, 1310464 blocks65523 blocks (5.00%) reserved for the super userFirst data block=0Maximum filesystem blocks=134217728040 block groups32768 blocks per group, 32768 fragments per group8192 inodes per groupSuperblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736Allocating group tables: done                            Writing inode tables: done                            Creating journal (32768 blocks): doneWriting superblocks and filesystem accounting information: done [root@centos mnt]# blkid/dev/sda1: UUID="cbf299b0-d76d-4efe-8643-c900502683d4" TYPE="xfs" /dev/sda2: UUID="L416ib-7Z3D-rtXt-FqTb-ChsW-j6zH-heeuF2" TYPE="LVM2_member" /dev/mapper/cl-root: UUID="12c02980-3012-4884-8a7d-437195398fdb" TYPE="xfs" /dev/mapper/cl-swap: UUID="c4ea26e2-7424-4a52-aa34-8d9fb4f3fbd2" TYPE="swap" /dev/mapper/cl-home: UUID="7be941f2-fcf6-44b7-b673-f999f1c876b0" TYPE="xfs" /dev/sdb1: UUID="78df7716-e32f-421e-a756-8fe89407e9ec" TYPE="ext4" /dev/sdb2: UUID="c905f4d2-ae58-41f8-85e6-69d1f0237ad2" TYPE="ext4" [root@centos mnt]# [root@centos mnt]# mount /dev/sdb1 /mnt/boot[root@centos mnt]# mount /dev/sdb2 /mnt/sysroot[root@centos mnt]# df -hFilesystem           Size  Used Avail Use% Mounted on/dev/mapper/cl-root   50G   27G   24G  53% /devtmpfs             910M     0  910M   0% /devtmpfs                920M     0  920M   0% /dev/shmtmpfs                920M  8.5M  912M   1% /runtmpfs                920M     0  920M   0% /sys/fs/cgroup/dev/sda1           1014M  185M  830M  19% /boot/dev/mapper/cl-home   47G   33M   47G   1% /hometmpfs                184M     0  184M   0% /run/user/0/dev/sdb1            4.8G   20M  4.6G   1% /mnt/boot/dev/sdb2            4.8G   20M  4.6G   1% /mnt/sysroot/<code>


開始複製之前編譯好的文件

<code>cp /usr/src/vmlinuz /mnt/boot/  #linux kernelcp /usr/src/initrd.gz /mnt/boot/ #ramdisk 內存鏡像(來自於busybox改造)cp -a /usr/src/sysroot/* /mnt/sysroot/ #系統目錄集合(來自於busybox改造)[root@centos /]# tree mnt -L 2mnt├── boot│   ├── initrd.gz│   └── vmlinuz└── sysroot    ├── bin    ├── boot    ├── dev    ├── etc    ├── home    ├── lib    ├── mnt    ├── proc    ├── root    ├── sbin    ├── sys    ├── tmp    ├── usr    └── var/<code>


7. 安裝grub引導程序到sdb1中


<code>yum install grub2-install #由於centos7以後採用的是grub2 所以直接安裝了這個[root@centos mnt]# grub2-install --boot-directory=/mnt/boot /dev/sdb #安裝到boot目錄下Installing for i386-pc platform.Installation finished. No error reported.[root@centos boot]# lltotal 9248drwxr-xr-x. 5 root root    4096 Feb  6 08:25 grub2-rw-r--r--. 1 root root 1484989 Feb  6 08:03 initrd.gz-rw-r--r--. 1 root root 7975904 Feb  6 08:04 vmlinuz[root@centos boot]#grub2-mkconfig -o /mnt/boot/grub2/grub.cfg #為了方便我採用了先根據系統自動生成,然後再編輯這個文件[root@centos boot]# vim /mnt/boot/grub2/grub.cfg #編輯內容見下圖,去掉很多用不到的內容/<code>


grub.cfg 文件內容,僅僅保留了幾個核心的信息


<code># relay displayset timeout=5# entrymenuentry 'My Linux' {        insmod gzio        insmod part_msdos        insmod xfs        set root='hd0,msdos1'        linux16 /vmlinuz root=/dev/sda2         initrd16 /initrd.gz}/<code>


8. 通過virtual 將剛剛創建的虛擬硬盤加載進來,並啟動虛擬機。。。開始見證奇蹟的時候。


使用 linux kernel +busybox 定製linux系統


歡迎界面出現,成功引導系統。


使用 linux kernel +busybox 定製linux系統


出錯啦

估計猜測分析:

由於系統啟動的時候需要掛載/dev/sda2 這塊真正的rootfs 系統,可是在加載內存鏡像initrd.gz 後,想啟動掛載rootfs的時候,找不到硬盤分區了。

這裡有個我們打包的時候,在涉及 第三方模塊如ext4 驅動的時候,是沒有打包到內核中的,但是默認是支持擴展掛載的,所以採用修改initrd.gz 這個文件,這個時候就需要用到modules了(前面只是生成了,還沒有用到,所以需要先把這個modules打包進initrd.gz中,讓他能找到ext4驅動)

同時也順便把rootfs 的目錄中也一併處理成鏡像的樣子。

sysroot 和initrd 兩個目錄一樣操作:

<code>cd /mnt/sysrootcp -a /usr/src/modules/lib usr/ #複製modules進入這個文件夾mkdir usr/lib64 #創建空文件夾,只是為了規範一點ln -s usr/lib64 lib64ln -s usr/lib lib#initrd 同樣操作cd /usr/src/initrdcp -a /usr/src/modules/lib usr/ #複製modules進入這個文件夾mkdir usr/lib64 #創建空文件夾,只是為了規範一點ln -s usr/lib64 lib64ln -s usr/lib lib# 重新生成initrd.gz 由於模塊我沒有精簡所以耗時比較久find . | cpio -H newc --quiet -o | gzip -9 > /usr/src/initrd.gz# 替換 舊的initrd.gzcp initrd.gz /mnt/boot//<code>


通過修改init文件,我雖然進去了鏡像系統,但是由於始終沒有找到硬盤,導致rootfs沒有能進入,也請各位大神幫忙解開這個結,我不知道哪裡出了問題。


開始修改 init 不進行rootfs轉換,直接進入內存系統:

<code>#!/bin/shecho "Mounting proc and sys..."mount -t sysfs sysfs /sysmount -t proc proc /proc   echo "Detect and export hardware infomation..."mdev -s  exec /bin/sh把項目兩句話註釋掉,改成直接執行 exec /bin/sh 作為主進程echo "Mount real rootfs to /mnt/sysroot..."#mount -t ext4 -o ro /dev/sda2 /mnt/sysroot  echo "Switch to real rootfs..."# exec chroot /mnt/sysroot /sbin/init/<code>


這個時候內存系統進去了:


使用 linux kernel +busybox 定製linux系統


使用 linux kernel +busybox 定製linux系統


但是根本但是在/dev/ 下根本沒有sdaX的硬盤分區。

首先驅動也是有的,通過grub也是能看到的。

<code>cat /proc/filesystems/<code>
使用 linux kernel +busybox 定製linux系統


進入剛剛啟動時候的grub界面,是能看到硬盤分區的:


使用 linux kernel +busybox 定製linux系統


使用 linux kernel +busybox 定製linux系統

終極解決:

---硬盤找不到的問題已經解決,補充進去:

通過修改配置linux kernel 已經解決硬盤找不到的問題:

Device Drivers > SCSI device Support >SCSI Disk Support

SCSI generic support


使用 linux kernel +busybox 定製linux系統

以上通過修改內核kernel配置後,重新編譯覆蓋/boot/vmlinuz 文件後,再次啟動,終於見到了完美的結局,找到了硬盤,並且成功從內存鏡像加載到了rootfs磁盤系統目錄,大功告成!!!


使用 linux kernel +busybox 定製linux系統

後語:

本來在做這個實驗的時候,做到了內存的啟動,死活不知道為啥硬盤沒找到,搞了僅兩天時間,沒有找到原因,最終偶然的機會,我整理了下思路,既然磁盤沒有找到,那應該是modules沒有,但是我將所有modules加入到initrd.gz的時候發現打完包後的initrd.g又太大了,所以這種思路我就直接放棄了,我就通過重新修改linux 內核,直接將ext4相關的配置打在了鏡像裡面,這樣文件就不大了,而硬盤找不到的原因呢,由於我採用的是virtubalbox 所以是sata硬盤的scsi ,然後我就到device driver下看了下scsi的加載與搜索情況,發現有個配置沒有配置上,於是我就配置上了,並重新打包,再次啟動的時候奇蹟出現了,終於找到了硬盤。

寫這篇文章也是在非常時期的無聊之作,希望對大家瞭解linux的原理有所幫助。


分享到:


相關文章: