編譯aarch64 Linux內核並基於qemu運行
- 2021 年 7 月 9 日
- 筆記
- Linux buildroot qemu module, 總結
核心流程
首先,本文主要講述如何編譯Linux
內核並在qemu
虛擬機上運行。這裡針對的架構是aarch64
。
本文的實驗平台是Ubuntu 16.04
。
為了達成目標,我們需要有qemu
、buildroot
和linux
安裝包或源碼。
首先確保qemu-system-aarch64
命令可用,可以通過在命令行執行qemu-system-aarch64 --version
判斷。
下載buildroot
源碼,鏈接見下文平台工具。假設其絕對路徑保存在變數BUILD_ROOT_PATH
中。執行以下命令
cd $BUILD_ROOT_PATH
make menuconfig
在彈出的配置介面中,設置Target option ---> Target Architecture
為AArch64 (little endian)
;設置Toolchain ---> Toolchain type
為External toolchain
,這時我們可以看到Toolchain ---> Toolchain
的值為linaro AArch64 xxxx.xx
;設置System configuration ---> Enable root login with password
開啟,並設置System configuration ---> Root password
為xxxx
(任意的你喜歡的密碼);設置System configuration ---> Run a getty (login prompt) after boot ---> TTY port
的值為ttyAMA0
(這一條非常重要,不然虛擬機可能啟動不了);設置Target packages ---> Show packages that are also provided by busybox
開啟;設置Target packages ---> Debugging, profiling and benchmark ---> strace
開啟;設置Filesystem images ---> cpio the root filesystem
開啟。
在配置完成之後,執行
make
注意:這裡可能需要配置wget
代理。
生成的rootfs.cpio
在目錄$BUILD_ROOT_PATH/output/images
下面。
下載Linux
內核源碼,鏈接見下文平台工具。假設其絕對路徑保存在變數LINUX_KERNEL_PATH
中。執行以下命令
cd $LINUX_KERNEL_PATH
ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make defconfig
vim .config
在打開的文件中,找到CONFIG_CMDLINE
這個配置選項,設置其值為console=ttyAMA0
;找到CONFIG_INITRAMFS_SOURCE
這個配置選項,設置其值為$BUILD_ROOT_PATH/output/images/rootfs.cpio
(注意,這裡要自己展開變數BUILD_ROOT_PATH
);設置CONFIG_DEBUG_INFO
配置項為y
。
配置結束後,執行以下命令
ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make -j16
執行結束後,我們可以看到生成了一些文件,其中包括$LINUX_KERNEL_PATH/vmlinux
和$LINUX_KERNEL_PATH/arch/arm64/boot/Image
在當前目錄創建一個shell
腳本,避免重複輸入指令。其文件名為start.sh
,其內容為
qemu-system-aarch64 -machine virt -cpu cortex-a57 \
-machine type=virt -nographic -smp 1 \
-m 2048 \
-kernel ./arch/arm64/boot/Image \
--apend "console=ttyAMA0" \
$1 $2
執行./startup.sh
,這是可以用qemu
啟動linux
內核。在進入命令行之前,需要輸入buildroot login:
的值,其值為root
,然後需要輸入Password:
,這是前文構建rootfs.cpio
的時候,配置項System configuration ---> Root password
的值。然後就可以進入命令行執行以下常用命令了。(注意,需要先cd /
)
如果要退出qemu
,可以先按Ctrl + A
,然後按X
。
為了在主機和qemu
虛擬機之間共享文件,我們可以創建一個目錄,其絕對路徑為SHARED_FILE_PATH
。然後執行以下命令
cd $BUILD_ROOT_PATH
vim .config
修改BR2_ROOTFS_OVERLAY
配置項的值為$SHARED_FILE_PATH
(注意,自行展開變數)。
保存後執行以下命令重新創建 rootfs.cpio
。
rm $BUILD_ROOT_PATH/output/images/rootfs.*
make
然後需要重新編譯內核,即
cd $LINUX_KERNEL_PATH
ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make -j16
依然通過./start.sh
啟動虛擬機跑linux
內核,進入命令行後,執行cd /; ls
,我們可以看到$SHARED_FILE_PATH
目錄下的文件。
重新執行./start.sh -s -S
進入qemu
的調試狀態,然後開一個新的shell
,輸入命令
cd $LINUX_KERNEL_PATH
aarch64-linux-gnu-gdb ./vmlinux -ex "target remote :1234"
現在,可以像以往一樣使用gdb
進行調試了……
下面介紹如何編譯一個linux
內核模組。
cd $SHARED_FILE_PATH
vim hello.c
hello.c
的內容為
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
int helloinit(void)
{
printk(KERN_DEBUG "hello world !!\n");
return 0;
}
void helloexit(void)
{
printk(KERN_DEBUG "goodbye world !!\n");
}
module_init(helloinit);
module_exit(helloexit);
MODULE_LICENSE("GPL");
然後在當前目錄創建Makefile
內容如下
ifneq (${KERNELRELEASE},)
obj-m := hello.o
else
KERNEL_SOURCE := $LINUX_KERNEL_PATH # 注意自行展開變數LINUX_KERNEL_PATH
PWD := $(shell pwd)
default:
${MAKE} -C ${KERNEL_SOURCE} M=${PWD} modules
clean:
${MAKE} -C ${KERNEL_SOURCE} M=${PWD} clean
endif
然後執行交叉編譯命令
ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make
OK,重新編譯rootfs.cpio
和linux
內核,然後運行qemu
。在進入linux
命令行後,執行以下命令
cd /
insmod hello.ko
dmesg | tail # 可以看到列印資訊 hello world !!
rmmod hello.ko
dmesg | tail # 可以看到列印資訊 goodbye world !!
相關經驗
Linux Kernel
- 使用
qemu
並開啟gdb server
功能之後,在gdb
窗口輸入b start_kernel
,進入最初的內核初始化函數。
平台工具
參考
- Starting Linux kernel exploration
- Debugging an ARM64 linux kernel using QEMU
- Writing kernel modules
- Debugging Kernel and Modules using GDB