Linux內核開發_3_busybox

Busybox簡介

busybox是一個開源項目,集合了Linux的常用命令,且體積非常小,一般被用於嵌入式Linux上。

busybox在編寫初期的思想就是簡潔,小巧,強悍,並且設計時從系統資源考慮,節省內存,動態編譯busybox工具包總大小才幾百kb,如果是靜態編譯則才1MB左右,非常適合用於嵌入式開發,與發行版不同,發行版使用的不是busybox,一些流行發行版一般使用的都是GNU fileutils、shellutils,這些工具鏈裏包含了對文件,還有一些shell支持的命令,就是我們常用的ls之類的命令,都屬於GNU的開源項目。

下載Busybox

你可以在它的官網下載到有關Busybox的所有開源版本的源代碼:

https://busybox.net/downloads/

將Busybox製作成根文件系統

前幾篇文章講了如何使用Initramf作爲根文件系統,但是效果並不能達到我們的要求,這篇文章使用busybox做一個完整的根文件系統,並且不將它作爲臨時根文件系統,而是把它當作一個實際根文件系統,供Linux內核使用。

根文件系統簡述

在Linux中,根文件系統就是Linux下“/”目錄,Linux把文件系統掛載到這個目錄下,這個目錄下一般擁有Linux運行時需要的一些設備文件,如塊設備,tty,字符設備文件等。

編譯Busybox

這裏我下載的是1.27.0版本的

wget https://busybox.net/downloads/busybox-1.27.0.tar.bz2

這裏跟大家說一個tar解壓命令的小技巧,原本這種解壓我們需要使用對應的選項,二次解壓後才能得到原文件,這裏我們不需要指定這些,tar命令會自動幫我們分析

tar -xf busybox-1.27.0.tar.bz2

-x是解壓的意思,-f是文件的意思,我們不需要指定解壓格式,tar會自動幫我們分析

busybox目錄結構說明:

applets

主要是實現applets框架的文件

applets_sh

一些有用的腳本,例如:dos2unix、unix2dos等

archival

與壓縮有關的命令源文件,例如:bzip2、gzip等

configs

自帶的一些默認配置文件

console-tools

與控制檯相關的一些命令,例如:setconsole

coreutils

常用的核心命令,例如:cat、rm等

editors

常用的編輯命令,例如:vi、diff等

findutils

用於查找的命令,例如:find、grep等

init

init進程的實現源文件

networking

與網絡相關的命令,例如:telnetl、arp等

shell

與shell相關的實現,例如:ash、msh等

util-linux

Linux下常用的命令,主要是與文件系統相關的,例如:mkfs_ext2等


配置busybox

和Linux一樣,busybox使用menuconfig配置,可以在裏面去裁剪一些不需要的模塊,這裏我們使用這個命令然後選擇靜態編譯,因爲在我們編譯的Linux內核裏,並不自帶GLIBC庫

sudo make menuconfig

選擇“Busybox Setting"

選擇”Build BusyBox as a static binary(no shared libs)” 按下“Y”

然後保存退出,使用make install編譯

sudo make install

編譯完成後會生成很多目錄,其中_install目錄裏就是我們需要的bin文件,除了bin文件還包含了一些根文件系統所具備的一些設備文件

使用ls命令查看一下:

包含了一些基本的文件目錄,如usr,bin這些Linux內核運行時的一些目錄,當然,只有這些目錄是不能算上一個完整的根文件系統目錄的,還需要/dev /tty等目錄。

創建文件系統

busybox編譯完成了,上面也說了_install文件夾下的所有文件,要被拿來製作成文件系統,那麼怎麼製作呢?

很簡單,在Linux上如果要對軟盤或者U盤進行操作,那麼就需要掛載,這裏我們可以使用dd命令先創建一個軟盤,作爲我們的根文件系統的鏡像文件,然後將它掛載到一個目錄下,最後我們把busybox下_install目錄copy到鏡像文件掛載的目錄下,這樣鏡像文件裏就有了一個基礎根文件系統所需要的設備文件目錄,然後在卸載掛載,這樣一個文件系統的鏡像就已經制作完成了。

實踐:

1.創建鏡像文件

dd if=/dev/zero of=rootfs.img bs=4096 count=1024

這裏我們創建一個4MB大小的鏡像文件

然後使用ext3格式格式化這個鏡像文件,前幾篇文章說過,Linux子系統VFS負責與文件系統進行交互,但是VFS只認特定的格式,如NFS,EXT等,所以這裏我們格式化一下,注意如果你的Linux內核不支持ext3,需要在make menuconfig時,選擇file system裏把這一選項按下Y,否則VFS會報內核恐慌

mkfs.ext3 rootfs.img

創建一個目錄作爲掛載點:

mkdir rootfs

掛載:

sudo mount -o loop rootfs.img rootfs/

將busybox下的_install文件夾下的所有文件copy過來

sudo cp -a ../busybox-1.27.0/_install/* rootfs/.

ls看一下:

除了這些文件以外,我們還需要三個設備文件dev proc sys

這裏介紹一些這三個文件的作用:

/sys/ 用於管理存儲文件,文件相關管理 的,sys是運行在內存中的
/proc 用於管理進程,是對進程管理,運行的進程參數管理的
/dev 存放各種設備節點,除了設備節點還會存儲socket,管道文件

這些是Linux內核運行時需要的三個設備節點,這裏我們創建出來,具體這些文件的作用,我後面在寫文件系統組成時會詳細講解,目前各位只需要知道這些文件在運行時,會被Linux內核裏的一些文件管理系統掛載到上面去

注意這些文件需要創建在rootfs文件夾下哦

cd rootfs
sudo  mkdir dev proc sys
cd ..

基本一個文件系統的基礎已經搭好了,那麼這樣我們就可以卸載掛載了,然後把這個掛載目錄刪除或者不刪除都可以

sudo umount rootfs

那麼到這一步,基本上一個簡單的根文件系統已經搭好了,可以用作嵌入式,或者amd都可以。

運行

使用qemu指定我們的硬盤路徑,然後模擬運行:

qemu-system-x86_64 -kernel /usr/src/linux-4.10.15/arch/x86/boot/bzImage\
                   -hda rootfs.img \
                   -append "root=/dev/sda init=/bin/ash"

這裏來解釋一下選項:

-hda 是指定硬盤文件

-append 這個選項不用多說了,第一篇文章有說過,這裏說一下里面的運行

root=/dev/sda 這個是指定根文件系統掛載點,大家有沒有發現其實我們剛剛創建時,只是創建了一個dev目錄,但是並沒有創建sda這個目錄,這個不用擔心,因爲Linux內核運行時會在自動創建設備文件,並將文件系統掛載到這些文件上,這個sda就是文件系統掛載目錄,這個設備文件必須指定爲sda,經過測試結果是這樣,查的資料是這個設備文件是指整個硬盤,還有sda1,sda2這些是指硬盤下的分區,至於更詳細的資料,還在查閱讀內核代碼中。

最後面,的init可以不用指定,這個就是在根文件目錄下的bin下找一個可執行文件,如果不指定的話Linux內核會自動尋找幾個常用的init

這幾行代碼是位於Linux內核init/main.c文件下的kernel_init函數下,它會去依次使用try_to_run_init_process函數來調用不同的初始化函數,如果你的根文件系統下有對應的文件就ok,如果沒有則會引起內核恐慌,找不到init程序。

與Linux2.6內核不同的是Linux2.6使用的是init_post,這個函數會發生兩次調用,第一次是進入到init_post,完成相關初始化後在去依次創建這些進程。

但是到了我們所使用的內核時,只會發生一次函數調用,初始化前面就已經被完成了,就只會發生調用創建進程的函數,可以說得上是運行速度和資源上的提升了。

因爲在內核裏,一切都最好按照一個整體來設計,這樣就可以省去不必要的接口調用,等函數調用時發生的堆棧保護等問題。

所以這也是爲什麼可以在Linux內核裏看到大量的內聯函數的原因。

運行結果:

注意運行後要按兩下回車,因爲運行時init已經打印出數據來了,但是Linux內核的一些工作是後續完成的,也會打印出來,會導致你可能看不到“#”這個輸入交互字符,建議按兩下回車,刷一下緩衝流,有的時候這會讓人覺得是不是運行沒有成功,哈哈我就是。

添加自己的調試程序

這裏教大家一個小技巧,比如我寫了一個調試程序,那麼我想調試它怎麼辦?

我們可以先掛載鏡像文件,然後把我們的文件打包到bin目錄下就可以了,不過打包的文件要靜態編譯,這一點在第一章已經說過了,這裏就不多說啦。

先隨便寫一個文件:

vim test.c
#include <stdio.h>

int main(){
    printf("test!");
    return 0;
}

gcc靜態編譯:

gcc -static -o test test.c

然後掛載一下鏡像文件,在把test copy進去

sudo mount -o -loop rootfs.img rootfs
sudo cp test rootfs/bin/

然後運行,Linux內核時到bin目錄下執行即可

記得把鏡像文件分配大一點哦,不然會出現 No space left on device的錯誤。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章