交叉編譯busybox和Linux kernel 并在qemu上運行

轉(zhuǎn)載請注明出處

原文地址: http://www.itdecent.cn/p/5aaea4d41aa6

@簡書

@earth_xmx

翻譯部分

原文地址https://jasonblog.github.io/note/arm_emulation/compiling_linux_kernel_for_qemu_arm_emulator.html

上一次,我編譯了無操作系統(tǒng)的ARM程序(bare-metal ARM programs)和U-boot. 本節(jié),我們將在ARM平臺上編譯一個 linux kernel. 由于我沒有真實的ARM設(shè)備, 所以本節(jié)我用QEMU模擬ARM設(shè)備。

linux內(nèi)核代碼和QEMU都支持VersatilePB平臺。所以,我選擇VersatilePB作為測試平臺。交叉編譯工具鏈,我選擇 CodeSourcery ARM EABI toolchain.

內(nèi)核代碼可以從 http://kernel.org 上下載. 我選擇最新的版本(version 2.6.33)并且解壓縮到想關(guān)的目錄。

在內(nèi)核根代碼中執(zhí)行:

make ARCH=arm versatile_defconfig

上面的命令,使用了預(yù)定義的配置(arch/arm/configs/versatile_defconfig)。 這個配置讓內(nèi)核在VersatilePB板子上正常運行。執(zhí)行上面的命令后,會把versatilepb的默認配置寫入到根目錄下的 .config 文件中。另外,執(zhí)行如下命令在.config 的基礎(chǔ)上進行微調(diào)配置。

make ARCH=arm menuconfig

我移除了模塊支持,并且打開了EABI支持(同時支持 old ABI)。對于使用 CodeSourcery 交叉編譯工具編譯出的程序,其要想正常運行。這個選項必須要打開。

執(zhí)行如下命令,進行編譯。

make ARCH=arm CROSS_COMPILE=arm-none-eabi- all

如果使用GNU/Linux 工具鏈,應(yīng)該執(zhí)行如下進行編譯:

make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- all

上面便于命令結(jié)束且沒有報錯的時候,會在 arch/arm/boot 下生成了一個 叫 zImage的文件。這個文件可以被 QEMU使用。

qemu-system-arm -M versatilepb -m 128M -kernel zImage

上面的命令:QEMU將執(zhí)行zImage。內(nèi)核會顯示很多的啟動信息。最后會顯示它找不到文件系統(tǒng)。所以,我們下一步創(chuàng)建一個簡單的文件系統(tǒng)。此文件系統(tǒng)僅包含一個"Hello world"可執(zhí)行程序。

#include <stdio.h>

void main() {
  printf("Hello World!\n");
  while(1);
}

注意:程序最后要使用無限循環(huán)保證程序不退出。因為 linux 內(nèi)核執(zhí)行的第一個程序后,內(nèi)核期望地一個程序永遠都不結(jié)束,不然會包 kernel panic錯誤。

arm-none-linux-gnueabi-gcc -static    test.c   -o test

上面的命令會創(chuàng)建一個靜態(tài)鏈接的二進制程序(靜態(tài)代表其依賴的所有庫都鏈接到一個單一的可執(zhí)行程序里面了)。下面就可以創(chuàng)建文件系統(tǒng)了。

echo test | cpio -o --format=newc > rootfs

cpio 工具會從標準輸入中讀取一系列文件列表,并且會在標準輸出中輸出一個格式為newc的歸檔文件。我們這里把標準輸出重定向到一個名為 rootfs的文件中。newc文件系統(tǒng)格式,是linux內(nèi)核能夠直接識別的文件系統(tǒng)。(而ext4這樣的文件系統(tǒng),需要內(nèi)核加載相應(yīng)的模塊才能識別。)rootfs文件是一個文件系統(tǒng)的鏡像文件,其中只包含一個文件(test可執(zhí)行文件)。 QEMU可以把 rootfs文件傳給內(nèi)核(傳入機制以后再說)。通過下面的命令啟動內(nèi)核。

qemu-system-arm -M versatilepb -m 128M -kernel zImage -initrd rootfs -append
"root=/dev/ram rdinit=/test"
#include <stdio.h>

void main() {
  printf("Hello World!\n");
  while(1);
}

實踐部分

下面的實踐在 ubuntu 22.04 中進行。上面原文的作者大概是在2010年左右整理出來的教程?,F(xiàn)在都2022年了。希望可以按照他的教程,完成內(nèi)核的編譯與運行。

先下載 linux 內(nèi)核源碼,我這里選擇的是2.6.34.1 跟原文有點小差別。

wget https://mirrors.edge.kernel.org/pub/linux/kernel/v2.6/linux-2.6.34.1.tar.bz2
tar xf linux-2.6.34.1.tar.bz2

如果下載失敗,可以打開上面的網(wǎng)址,找一個差不多的內(nèi)核應(yīng)該也行。
部分
下載安裝交叉編譯工具鏈并配置(參考文章:https://developer.ridgerun.com/wiki/index.php/Code_Sourcery_ARM_toolchain_2011.09

wget https://sourcery.mentor.com/public/gnu_toolchain/arm-none-linux-gnueabi/arm-2011.09-70-arm-none-linux-gnueabi.bin
chmod +x arm-2011.09-70-arm-none-linux-gnueabi.bin
## 安裝依賴:
sudo apt install lib32z1  ## 32位lib,如果是ubuntu其他版本,可能是安裝其他包,請自行搜索解決。

## 執(zhí)行安裝程序(如果執(zhí)行失敗,請查看終端輸出的錯誤log,然后解決)
./arm-2011.09-70-arm-none-linux-gnueabi.bin
## 一路按照提示,安裝完成。

安裝完后配置環(huán)境變量:(我的安裝目錄為~/CodeSourcery/)

export PATH=$PATH:~/CodeSourcery/Sourcery_CodeBench_Lite_for_ARM_GNU_Linux/bin
list.png

編譯內(nèi)核

編譯內(nèi)核之前,先安裝依賴

sudo apt install make
sudo apt install gcc
sudo apt install libncurses5-dev 

編譯內(nèi)核: step1: 先使用versatile的默認配置去寫入.config文件

cd linux-2.6.39.2/
make ARCH=arm versatile_defconfig

step2: 使用menuconfig 調(diào)整.config文件使內(nèi)核支持 EABI

make ARCH=arm menuconfig

移除模塊支持

menu1.png

在 Kernel Features 中打開 EABI支持

menu2.png

step3: 編譯

make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- all

編譯的時候會報一個錯誤:

err1.png

這里的解決辦法是 kernel/timeconst.pl 的373 行做如下修改

correct1.png

然后重新執(zhí)行上面的編譯命令。編譯成功后會在 源碼目錄下 arch/arm/boot/下面生成一個叫做 zImage的文件。這個就是內(nèi)核文件了。

下面使用qemu啟動內(nèi)核了。

安裝 qemu

sudo apt install qemu-system-arm 

啟動內(nèi)核

qemu-system-arm -M versatilepb -m 128M -kernel zImage

應(yīng)看到如下啟動信息

qemu-no-rootfs.png

可以看到最后有一行打印了 not syncing: VFS: unable to mount root fs on unkown ....

下面創(chuàng)建內(nèi)核要啟動的第一個進程 init

#include <stdio.h>

void main() {
  int num = 1;
  for (num = 1; num <= 10; ++num)
    printf("Hello World![num=%d]\n", num);
    
  while(1);
}

編譯并制作rootfs

arm-none-linux-gnueabi-gcc -static init.c -o init
echo init | cpio -Hnewc -o > rootfs.img

重新啟動內(nèi)核

qemu-system-arm -M versatilepb -m 128M -kernel arch/arm/boot/zImage  -initrd ../test/rootfs.img -append "rdinit=/init"

可以看到如下

qemu-init.png

至此,我們已經(jīng)完成了上面的教程。下面額外添加編譯busybox到rootfs中去。

busybox編譯到initrd中

下載busybox 源碼

https://www.busybox.net/downloads/busybox-1.20.0.tar.bz2
tar xf busybox-1.20.0.tar.bz2

編譯busybox源碼

cd busybox-1.20.0
make ARCH=arm defconfig ## 使用默認配置
make ARCH=arm menuconfig ## 打開靜態(tài)編譯選項,把busybox編譯成static形勢,如同上面的init程序。
### Busybox Settings -> Build Options -> Build BusyBox as a static binary (no shared libs) 
## 不打開的話一會還要拷貝動態(tài)鏈接庫到rootfs中,就比較麻煩。
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- install #編譯源碼

上述編譯如果沒有錯誤的話,會在 busybox源碼目錄下生成一個 _install 的目錄。

制作 rootfs

cd _install
find . | cpio -Hnewc -o | gzip -9 > ../rootfs.img.gz
## rootfs.img.gz 文件保存在 busybox-1.20.0 下面了。

使用qemu加載啟動

qemu-system-arm -M versatilepb -m 128M -kernel arch/arm/boot/zImage  -initrd ../busybox-1.20.0/rootfs.img.gz -append "rdinit=/bin/sh"

將會看到如下:

qemu-busybox.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容