环境
主机ubuntu版本: 20.04
qemu模拟处理器:ARM64
Linux内核版本:https://www.kernel.org/ 最新版
step1:安装编译工具链
sudo apt-get install gcc-aarch64-linux-gnu sudo apt-get install libncurses5-dev build-essential git bison flex libssl-dev
查看版本号
leon@leon:~/work$ aarch64-linux-gnu-gcc -v Using built-in specs. COLLECT_GCC=aarch64-linux-gnu-gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/aarch64-linux-gnu/9/lto-wrapper Target: aarch64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-10ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libquadmath --disable-libquadmath-support --enable-plugin --enable-default-pie --with-system-zlib --without-target-system-zlib --enable-libpth-m2 --enable-multiarch --enable-fix-cortex-a53-843419 --disable-werror --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=aarch64-linux-gnu --program-prefix=aarch64-linux-gnu- --includedir=/usr/aarch64-linux-gnu/include Thread model: posix gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu1)
step2:安装qemu
2.1ubuntu仓库安装
sudo apt-get install qemu-system-arm
查看版本:
leon@leon:~/work$ qemu-system-aarch64 --version QEMU emulator version 4.2.1 (Debian 1:4.2-3ubuntu6.16) Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers leon@leon:~/work$
从源码安装
wget https://download.qemu.org/qemu-4.1.0.tar.xz tar xvJf qemu-4.1.0.tar.xz cd qemu-4.1.0/ ./configure make -j 8 sudo make install qemu-system-aarch64 --version
step3:制作根文件系统rootfs
3.1 下载busybox源码:
官网:http://busybox.net/downloads/下载最新版本即可,这里
tar jxvf busybox-1.33.1.tar.bz2
3.2 配置busybox
指定编译工具
export ARCH=arm64 export CROSS_COMPILE=aarch64-linux-gnu-
打开静态库编译选项
make menuconfig Settings ---> [*] Build static binary (no shared libs)
如果报错:
<command-line>: fatal error: curses.h: No such file or directory compilation terminated.
安装ncurses库
sudo apt-get install libncurses5-dev libncursesw5-dev
PS:编译过程报错的话,把相应项去掉即可;
编译完成,在busybox生成_install目录
【文章福利】小编推荐自己的Linux内核技术交流群:【 865977150】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!
3.4 补充rootfs目录结构
(1) 根目录添加etc、dev和lib目录
etc目录:
leon@leon:~/work/Linux/busybox-1.33.1/_install$ ls bin linuxrc sbin usr leon@leon:~/work/Linux/busybox-1.33.1/_install$ mkdir etc dev lib leon@leon:~/work/Linux/busybox-1.33.1/_install$ ls bin dev etc lib linuxrc sbin usr leon@leon:~/work/Linux/busybox-1.33.1/_install$
在etc分别创建文件:
leon@leon:~/work/Linux/busybox-1.33.1/_install/etc$ cat profile #!/bin/sh export HOSTNAME=myQEMU export USER=root export HOME=/home export PS1="[$USER@$HOSTNAME \W]\# " PATH=/bin:/sbin:/usr/bin:/usr/sbin LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH export PATH LD_LIBRARY_PATH
leon@leon:~/work/Linux/busybox-1.33.1/_install/etc$ cat fstab #device mount-point type options dump fsck order proc /proc proc defaults 0 0 tmpfs /tmp tmpfs defaults 0 0 sysfs /sys sysfs defaults 0 0 tmpfs /dev tmpfs defaults 0 0 debugfs /sys/kernel/debug debugfs defaults 0 0 kmod_mount /mnt 9p trans=virtio 0 0
leon@leon:~/work/Linux/busybox-1.33.1/_install/etc$ cat inittab ::sysinit:/etc/init.d/rcS ::respawn:-/bin/sh ::askfirst:-/bin/sh ::ctrlaltdel:/bin/umount -a -r
指定挂载的文件系统
leon@leon:~/work/Linux/busybox-1.33.1/_install/etc/init.d$ cat rcS mkdir -p /sys mkdir -p /tmp mkdir -p /proc mkdir -p /mnt /bin/mount -a mkdir -p /dev/pts mount -t devpts devpts /dev/pts echo /sbin/mdev > /proc/sys/kernel/hotplug mdev -s leon@leon:~/work/Linux/busybox-1.33.1/_install/etc/init.d$
dev目录:
leon@leon:~/work/Linux/busybox-1.33.1/_install/dev$ sudo mknod console c 5 1 leon@leon:~/work/Linux/busybox-1.33.1/_install/dev$ sudo mknod null c 1 3 leon@leon:~/work/Linux/busybox-1.33.1/_install/dev$
lib目录:拷贝lib库,支持动态编译的应用程序运行
leon@leon:~/work/Linux/busybox-1.33.1/_install/lib$ cp /usr/aarch64-linux-gnu/lib/*.so* -a . leon@leon:~/work/Linux/busybox-1.33.1/_install/lib$ ls ld-2.31.so libdl-2.31.so libnsl.so libnss_nisplus-2.31.so libSegFault.so ld-linux-aarch64.so.1 libdl.so libnsl.so.1 libnss_nisplus.so libstdc++.so.6 libanl-2.31.so libdl.so.2 libnss_compat-2.31.so libnss_nisplus.so.2 libstdc++.so.6.0.28 libanl.so libgcc_s.so.1 libnss_compat.so libnss_nis.so libthread_db-1.0.so libanl.so.1 libgomp.so.1 libnss_compat.so.2 libnss_nis.so.2 libthread_db.so libasan.so.5 libgomp.so.1.0.0 libnss_dns-2.31.so libpcprofile.so libthread_db.so.1 libasan.so.5.0.0 libitm.so.1 libnss_dns.so libpthread-2.31.so libtsan.so.0 libatomic.so.1 libitm.so.1.0.0 libnss_dns.so.2 libpthread.so libtsan.so.0.0.0 libatomic.so.1.2.0 liblsan.so.0 libnss_files-2.31.so libpthread.so.0 libubsan.so.1 libBrokenLocale-2.31.so liblsan.so.0.0.0 libnss_files.so libresolv-2.31.so libubsan.so.1.0.0 libBrokenLocale.so libm-2.31.so libnss_files.so.2 libresolv.so libutil-2.31.so libBrokenLocale.so.1 libmemusage.so libnss_hesiod-2.31.so libresolv.so.2 libutil.so libc-2.31.so libm.so libnss_hesiod.so librt-2.31.so libutil.so.1 libc.so libm.so.6 libnss_hesiod.so.2 librt.so libc.so.6 libnsl-2.31.so libnss_nis-2.31.so librt.so.1 leon@leon:~/work/Linux/busybox-1.33.1/_install/lib$
step4 编译内核
(1)下载代码:
#我从torvalds的仓库fork了一个分支,方便自己添加注释笔记 git clone https://github.com/luteresa/linux.git
(2) 指定编译工具:
export ARCH=arm64 export CROSS_COMPILE=aarch64-linux-gnu-
配置内核:这里采用ARM公司提供的Versatile Express开发平台模拟;
sudo cp ../busybox-1.33.1/_install/ ./_install_arm64 -a cp arch/arm/configs/vexpress_defconfig .config make menuconfig
添加hotplug支持:
Device Drivers -> Generic Driver Options -> Support for uevent helper (/sbin/hotplug) path to uevent helper
添加initramfs的支持:
General setup ---> [*]Initial RAM filesystem and RAM disk(initramfs/initrd) support(_install_arm64) Initramfs souce file(s)
内核页分别配置为
Kernel Features ---> Page size(4KB) ---> Virtual address space size(48-bit)--->
编译:
make all -j8
在内核根目录下添加共享目录
mkdir kmodules
启动Linux:
qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -m 1024 -smp 4 -kernel arch/arm64/boot/Image --append "rdinit=/linuxrc root=/dev/vda rw console=ttyAMA0 loglevel=8" -nographic --fsdev local,id=kmod_dev,path=$PWD/kmodules,security_model=none -device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount
- cpu指定模拟的cpu为 cortex-a57
- m 1024 指定内存大小为1G
- smp4指定模拟的系统为4核处理器
- kernel指定启动的内核镜像
- append指定传递的命令行参数
后面的选项指定共享目录已经使用的9P协议。
如果报类似错:
qemu-system-aarch64: rom check and register reset failed
大概率是qemu版本问题,换个版本,可以从源码直接编译;经测试
ubuntu18.04用qemu-4.1.0可以正常工作;
ubuntu20.04用apt安装即可;
wget https://download.qemu.org/qemu-4.1.0.tar.xz tar xvJf qemu-4.1.0.tar.xz cd qemu-4.1.0 ./configure make -j 8 编译完安装: sudo make install 默认编译支持很多个平台
报错:
mount: mounting debugfs on /sys/kernel/debug failed: No such file or directory
内核配置加上CONFIG_DEBUG_FS=y :
Kernel hacking ---> Generic Kernel Debugging Instruments ---> [*] Debug Filesystem
step5: 使用模拟磁盘
上述initramfs的方式,将根文件系统打包到内核源码,运行时都是在内存中,可以操作,但系统重启就会丢失,下面用模拟磁盘方式挂载根文件系统。制作磁盘文件:
dd if=/dev/zero of=rootfs_ext4.img bs=1M count=1024 mkfs.ext4 rootfs_ext4.img mkdir -p tmpfs sudo mount -t ext4 rootfs_ext4.img tmpfs/ -o loop sudo cp -af _install_arm64/* tmpfs/ sudo umount tmpfs chmod 777 rootfs_ext4.img
rootfs_ext4.img就是即将用来挂载的磁盘,再次启动内核:
qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -m 1024 -smp 4 -kernel arch/arm64/boot/Image --append "noinitrd root=/dev/vda rw console=ttyAMA0 loglevel=8" -nographic -drive if=none,file=rootfs_ext4.img,id=hd0 -device virtio-blk-device,drive=hd0 --fsdev local,id=kmod_dev,path=$PWD/kmodules,security_model=none -device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount
传递给内核的命令行参数变化了,添加了noinitrd选项,这样就会挂载我们自己的模拟磁盘。
[root@myQEMU ]# df -mh Filesystem Size Used Available Use% Mounted on /dev/root 975.9M 12.8M 895.9M 1% / tmpfs 496.1M 0 496.1M 0% /tmp tmpfs 496.1M 0 496.1M 0% /dev kmod_mount 981.8G 32.5G 899.4G 3% /mnt [root@myQEMU ]#
这样在文件系统的读写,就会存在磁盘,重启后,数据不会丢失。
step6: qemu与主机ubuntu文件共享
前面已经支持了主机和qemu上的系统共享目录,这个目录就是kmodules目录:通过mount可以查看被挂载到了qemu上的系统的/mnt目录下
[root@myQEMU mnt]# mount /dev/root on / type ext4 (rw,relatime) proc on /proc type proc (rw,relatime) tmpfs on /tmp type tmpfs (rw,relatime) sysfs on /sys type sysfs (rw,relatime) tmpfs on /dev type tmpfs (rw,relatime) kmod_mount on /mnt type 9p (rw,sync,dirsync,relatime,access=client,trans=virtio) devpts on /dev/pts type devpts (rw,relatime,mode=600,ptmxmode=000)
在ubuntu的kmodules目录,创建一个文件hello.c
#include <stdio.h> int main(int argc, char **argv) { printf("Hello World,Qemu!\n"); return 0; }
在qemu查看
[root@myQEMU mnt]# cat /proc/cpuinfo > cpu.txt [root@myQEMU mnt]# cat hello.c #include <stdio.h> int main(int argc, char **argv) { printf("Hello World,Qemu!\n"); return 0; } random: fast init done [root@myQEMU mnt]#
在ubuntu编译
aarch64-linux-gnu-gcc hello.c
在qemu运行
[root@myQEMU mnt]# ./a.out Hello World,Qemu! [root@myQEMU mnt]#
可见,在共享目录,可以执行含动态库的应用程序;
step7:内核模块测试:
Makefile文件
step7:内核模块测试: Makefile文件,
驱动测试文件module_test.c
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> static int __init module_test_init(void) { printk("---module_test_init\n"); return 0; } static void __exit module_test_exit(void) { printk("---module_test_exit\n"); } module_init(module_test_init); module_exit(module_test_exit); MODULE_LICENSE("GPL");
在ubuntu上交叉编译
leon@leon:~/work/Linux/linux/kmodules$ make make -C ~/work/Linux/linux M=/home/leon/work/Linux/linux/kmodules modules make[1]: Entering directory '/home/leon/work/Linux/linux' CC [M] /home/leon/work/Linux/linux/kmodules/module_test.o MODPOST /home/leon/work/Linux/linux/kmodules/Module.symvers CC [M] /home/leon/work/Linux/linux/kmodules/module_test.mod.o LD [M] /home/leon/work/Linux/linux/kmodules/module_test.ko make[1]: Leaving directory '/home/leon/work/Linux/linux' leon@leon:~/work/Linux/linux/kmodules$
在qemu加载驱动
[root@myQEMU mnt]# insmod module_test.ko ---module_test_init. [root@myQEMU mnt]# rmmod module_test ---module_test_exit. [root@myQEMU mnt]#
可见,内核模块正常运行了。
step8:gdb调试
安装arm-none-eabi-gdb
sudo apt-get install gdb-multiarch
qemu模拟端启动内核:
qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -m 1024 -smp 4 -kernel arch/arm64/boot/Image --append "rdinit=/linuxrc root=/dev/vda rw console=ttyAMA0 loglevel=8" -nographic --fsdev local,id=kmod_dev,path=$PWD/k_shared,security_model=none -device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount -S -s
X86启动gdb:
$ gdb-multiarch --tui vmlinux
(gdb)target remote localhost:1234 //通过1234端口远程连接到qemu端 (gdb)b start_kernel //在内核的start_kernel设置断点 (gdb)c
gdb接管linux内核,在断点处(start_kernel)暂停,即可通过gdb来调试内核。
用Eclipse可视化环境,单步调试Linux内核
目的:通过可视化环境,单步调试linux内核
开发环境:ubuntu20.04
安装java环境
Eclipse运行依赖jave环境;
sudo apt install openjdk-13-jre
安装Eclipse-CDT
官网:http://www.eclipse.org/cdt/
配置Eclipse-CDT
(1)创建工程
在Eclipse菜单选择File->New->Project,选择Makefile Project with Exiting Code,即可创建一个新工程;
(2)配置调选项
选择Eclipse菜单中的Run->Debug Configurations, 弹出Debug configurations
(3)debugger选项卡,配置
Debugger:gdbserver
GDB debugger:gdb-multiarch
进行单步调试Linux内核
主机端运行qemu仿真系统
qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -m 1024 -smp 1 -kernel arch/arm64/boot/Image --append "rdinit=/linuxrc root=/dev/vda rw console=ttyAMA0 loglevel=8" -nographic --fsdev local,id=kmod_dev,path=$PWD/k_shared,security_model=none -device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount -S -s
启动Eclipse,选择Run->Debug History, 在Debugger Console选项卡输入file vmlinux导入调试文件的符号表;输入set architecture aarch64命令,设定GDB支持ARM64架构:
配置完成,便可在Eclipse可视化环境,进行linux内核单步调试;
Eclipse比GDB命令直观很多,可以方便查看参数,局部变量,寄存器值等;
精品文章推荐阅读: