编译2022年最新的Linux kernel、U-Boot和BusyBox rootfs源码,并用QEMU模拟器运行
作者 | 将狼才鲸 |
---|---|
创建日期 | 2022-11-26 |
- Gitee源码和工程地址:才鲸嵌入式 / 嵌入式QEMU教程
- CSDN文章地址:项目介绍:嵌入式QEMU教程
-
前提:编译U-Boot和Linux kernel源码时,源码版本、PC主机Linux系统版本、交叉编译器版本都有影响,最好按照网上教程中相同的版本来尝试,要不然经常会遇到编译时遇到了问题,但又搜不到解决方法的尴尬局面。
-
必须在Linux系统中编译(如Ubuntu),不能在MSYS2中编译。
1)直接编译Linux源码并运行
1、编译U-Boot并在QEMU中运行
-
网上能搜到的QEMU + U-Boot已有的示例都是使用的ARM官方的开发板配置:如vexpress_ca9x4_defconfig、qemu_arm_vexpress_defconfig、versatile_defconfig,第一阶段我也使用相同的配置,后续我会在树莓派2b的硬件上尝试。
-
编译好的u-boot文件我已经放在另一个仓库中,地址为:https://gitee.com/langcai1943/linux_kernel_u-boot_busybox_code_comments/tree/develop/bin/v1.0.0
-
当前硬件为ARM Versatile™ Express开发板系列的CoreTile Express主板。
- 开发板资料:express_ca9x4 uboot分析
-
我使用最新版本的U-Boot官方源码,系统使用的是VMware Player Ubuntu18.04。当前下载的U-Boot版本是v2023.01-rc2,地址:Gitee 极速下载 / u-boot Prepare v2023.01-rc2,文件有33M,要查看所有版本的话则进入https://gitee.com/mirrors/u-boot/tags
- 当前VM Player最新的版本是17,https://customerconnect.vmware.com/en/downloads/info/slug/desktop_end_user_computing/vmware_workstation_player/17_0 ,但我因为之前已经安装了16,所以就用这个。没用过VM的建议先用VMware Workstation的破解版,网上的教程更多,但是Player和VM的使用方法是一样的,如果遇到了问题可以直接按VM搜到的解决办法来处理。
- 我在32位Ubuntu16.04上编译最新的U-Boot有报错,中文和外文网站搜索都未解决问题,见于16.04的版本官方也早已不支持了,现在重装为64位的Ubuntu18.04
- Ubuntu下载请找国内源下载,16.04是最后一个提供32位系统的版本,不用配置32位的依赖库。
-
参考网址
-
如果使用虚拟机,则下载安装VMware Player,过程略。
-
下载并安装64位Ubuntu 18.04,因为我的笔记本电脑是2012年买的,配置不行,所以我在虚拟机中用老系统能跑的比较快;Ubuntu 18.04系统会持续支持到2028年,不用担心里面的软件过时。
- 不要从Ubuntu官方下载,从各种大学的镜像中下载,速度会更快,我下载的地址是 ubuntu-18.04.6-desktop-amd64.iso,如果要下载其它的版本,如Ubuntu 22.04,则进入http://mirrors.ustc.edu.cn/ubuntu-releases/ 对应的文件夹中,下载.iso文件;不管是Intel芯片还是AMD芯片,iso的文件尾都是amd64.iso,都可以用。
- 虚拟机中安装Ubuntu18.04的过程略;为了在命令行中进入桌面方便,我选择先安装英文系统,然后再安装中文输入法;安装要花几十分钟,安装的过程中要不联网,否则安装的过程中会更新程序,速度非常慢。
- 如果你用的笔记本,Ubuntu18虚拟机中使用不了触摸板的手势功能,不能双指滚动,忍耐一下。
- Ubuntu18.04选了中文之后,默认的软件源为国内源,但还是需要指定为具体的哪个源,例如指定阿里云的源;更换国内源后更新一下系统。
- 不要按屏幕下方VMware的提示使用CD的方式安装安装VMware Tools,而要在Ubuntu中用命令行直接安装;这样才能全屏和与Windows拖动文件;安装过程略。
- 如果安装系统时选择的是英语,则安装中文输入法。
-
参考网址:
-
从ARM官网下载最新的,在64位PC上使用的32位ARM交叉编译工具,下载速度比较慢。
- (未使用)下载地址:[arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz](https://developer.arm.com/-/media/Files/downloads/gnu/11.3.rel1/binrel/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz)
- 这是最新版本的查看地址:https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
- (使用)!注意!后面编译BusyBox时我发现最新版的ARM交叉编译器会报错,新版本编译器编译kernel和U-Boot都没问题。我又装回了这个老版本,10.2版本编译器ARM官方下载地址:gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf.tar.xz
- (未使用)或者从Linaro上下载当前最新的稳定版本,下载地址:gcc-linaro-12.2.1-2022.11-x86_64_arm-linux-gnueabihf.tar.xz
- Linaro的下载速度也很慢;暂时没找到国内提供的下载镜像。
-
解压交叉编译器,然后在Linux系统中输出芯片架构和交叉编译工具名称的环境变量和交叉编译工具的路径
# 因为我当前不编译Linux PC下的程序,所以我直接将整个环境都配成交叉编译的
export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabihf-
# 增加交叉编译器的路径,修改成你自己解压的路径
export PATH=$PATH:/home/jim/Desktop/tools/arm-gnu-toolchain-11.3/bin
- 编译U-Boot:
- make vexpress_ca9x4_defconfig
- make -j4
- 编译U-Boot时报错发现未安装而需要安装的软件:
- sudo apt-get install make
- sudo apt-get install gcc
- sudo apt-get install bison
- sudo apt-get install flex
- sudo apt-get install libssl-dev
- 如果lib/display_options.c:59:9: 编译器内部错误: 非法指令报错时将该行改成:
unsigned long d = 1000000000;//1e9;
- 编译完成后会在uboot源码目录下生成u-boot文件,将其用QEMU运行即可。
- 编译好的u-boot文件我已经放在另一个仓库中,地址为:https://gitee.com/langcai1943/linux_kernel_u-boot_busybox_code_comments/tree/develop/bin/v1.0.0
jim@DESKTOP-SVP3BEM MSYS /d
$ qemu-system-arm -M vexpress-a9 -m 256 -kernel u-boot --nographic
U-Boot 2023.01-rc2 (Nov 25 2022 - 17:27:26 +0800)
DRAM: 256 MiB
WARNING: Caches not enabled
Core: 18 devices, 10 uclasses, devicetree: embed
Flash: 64 MiB
MMC: mmci@5000: 0
Loading Environment from Flash... *** Warning - bad CRC, us
ing default environment
......
2、编译Linux kernel
-
如果要编译用于BCM2836或ARM CoreTile Express开发板的Linux kernel,则必须要在Linux环境如Ubuntu中编译。一是因为编译过程中有各种依赖库;二是因为kernel源码中有三个以aux命名的文件,这个文件名在Windows环境中不允许存在,在Windows中解压或者拷贝kernel源码时都会报错;如果一定要在Windows下的MinGW中编译,网上找不到任何教程,你可以在kernel源码中强行修改aux文件名和对应的Kconfig、Makefile后,并安装各种依赖库,只能自行尝试;在MSYS2中安装各种依赖库软件也是需要自行摸索的,应该很少有教程。
- 不要在Windows下git clone kernel源码后再拷贝到Linux系统中编译,会丢失软连接,导致dt-bindings/pinctrl/xxx.h文件明明有,但是链接器提示找不到文件的报错,该问题很难解决。
- (使用)Linux kernel官方源码中也支持BCM2835/6/7和ARM CoreTile Express,源码查看路径为https://gitee.com/mirrors/linux_old1 ;我当前使用Linux官方最新的源码,下载路径为v6.1-rc6。整个仓库带所有Git历史的源码有好几G,如果用git clone的方式拉代码,中间时间比较久,一旦中间网络中断,则无法恢复,需要重新clone;推荐直接下载zip压缩包,这样只有250M。
- (当前不使用)树莓派官方提供了从Linux kernel中派生的源码,但是版本比kernel官方低很多,路径为https://github.com/raspberrypi/linux 。
- 编译好的zImage和vexpress-v2p-ca9.dtb文件我已经放在另一个仓库中,地址为:https://gitee.com/langcai1943/linux_kernel_u-boot_busybox_code_comments/tree/develop/bin/v1.0.0
-
Ubuntu主机和交叉编译工具可以直接用上面U-Boot同样的环境,下面介绍的是32位Ubuntu16.04下使用的交叉编译工具;Linux kernel在此环境下也能编译通过。
- 这是在32位Ubuntu16.04下编译kernel的步骤,可以不看,后面有64位Ubuntu18.04中编译的介绍。
- 因为我虚拟机中的64位Ubuntu18.04系统运行起来很慢,所以我最终都会在Ubuntu16.04中编译内核。
- (使用)Linaro旧版本的地址支持32位主机的工具下载:https://releases.linaro.org/components/toolchain/binaries ,这里面Linaro gcc的最新版本是7.5.0;因为我虚拟机中安装的是32位的Ubuntu 16.04系统,32位的系统可以省去在64位系统中安装32位编译所需环境的步骤,所以我使用gcc-linaro-7.5.0-2019.12-i686_arm-linux-gnueabihf.tar.xz
- (不使用)树莓派官方也提供了交叉编译工具:https://github.com/raspberrypi/tools ,但是比ARM官方或者Linaro官方的编译器版本要低。下载解压后,BCM2836能用的交叉编译工具的目录在 ./arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/;注意:这只能编译U-Boot、Linux kernel和Linux应用,不能编译ARM裸机程序;但是该编译器编译最新的Linux kernel源码会报错。
- 如果用Linux官方的kernel源码,则不能使用树莓派的交叉编译工具:
- Linux kernel源码的下载路径:https://gitee.com/mirrors/linux_old1/tree/v6.1-rc4
- 先在Linux系统环境中修改芯片类型和编译器名称:
# 因为我当前不编译Linux PC下的程序,所以我直接将整个环境都配成交叉编译的
export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabihf-
# 增加交叉编译器的路径,修改成你自己解压的路径
export PATH=$PATH:/home/jim/Desktop/tools/arm-gnu-toolchain/bin
* 再 make bcm2835_defconfig
* 当前Linux kernel源码要求最低的gcc版本为Minimum GCC version: 5.1.0,而树莓派提供的版本为4.8.3,版本太低。
- (不使用)ARM官网的交叉编译工具,当前只支持64位主机下的软件:https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
- 当前ARM gcc的版本是12.2.0,arm官网从从2016年的GCC6开始只提供64位Linux的交叉编译器可执行文件
- (不使用)Linaro gcc交叉编译器,最新的gcc版本是11.3,当前只支持64位主机下的下载地址:https://snapshots.linaro.org/gnu-toolchain/11.3-2022.06-1/arm-linux-gnueabihf/
- 安装了Ubuntu 16.04 32位系统,在里面下载了Linux kernel源码,安装了Linaro gcc7.5.0交叉编译器后
- make bcm2835_defconfig 生成.config,源码里 没有BCM2836的默认配置,只有2835的,先用这个,然后再在里面改。
- make menuconfig 打开kernel配置界面。
- 在kernel字符配置界面中:System type --> Platform selection 取消armv6的选择,只保留armv7;
- make 因为之前已经配置了ARCH和CROSS_COMPILE变量(也可以只在kernel .config或者Makefile中指定这两个环境变量),直接make ,如果你不是虚拟机,可以make -j8,8核并行编译,加快编译速度;编译时间比较久,可能要几分钟到几十分钟;要生成uImage的话要指定地址,例如make uImage LOADADDR=0x8000,生成的uImage在arch/arm/boot/中。
- 如果遇到编译报错,提示某些.h文件找不到,则一般是电脑上没安装对应的库;将报错信息百度,按照搜到的文章安装缺少的库,再重新编译即可。
- 设备树在2011年3月在从Linux kernel源码3.1版本中正式替代寄存器头文件。
- .dtsi设备树文件中只有各个模块的起始寄存器地址,没有每个寄存器详细的描述,而每个模块的寄存器定义和偏移则在每个驱动的源文件中,不会有一个统一的.h头文件包含了所有的寄存器地址定义。
- 设备树添加之前的2.6.xx版本中,能在/arch/arm/plat-xxx和/arch/arm/mach-xxx中看到芯片的所有模块的寄存器基地址,和模块中所有寄存器的头文件宏定义。例如:https://gitee.com/mirrors/linux_old1/blob/v3.0/arch/arm/mach-bcmring/include/mach/csp/mm_addr.h ,https://gitee.com/mirrors/linux_old1/blob/v3.0/arch/arm/include/asm/hardware/dec21285.h 和 https://gitee.com/mirrors/linux_old1/blob/v3.0/arch/arm/mach-bcmring/include/mach/reg_umi.h 等。
- 下面是在64位Ubuntu 18.04中编译Linux kernel的步骤
- 编译好的zImage和vexpress-v2p-ca9.dtb文件我已经放在另一个仓库中,地址为:https://gitee.com/langcai1943/linux_kernel_u-boot_busybox_code_comments/tree/develop/bin/v1.0.0
- 交叉编译环境保持和上面编译U-Boot时相同
# 因为我当前不编译Linux PC下的程序,所以我直接将整个环境都配成交叉编译的
export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabihf-
# 增加交叉编译器的路径,修改成你自己解压的路径
export PATH=$PATH:/home/jim/Desktop/tools/arm-gnu-toolchain/bin
-
下载最新的Linux kernel源码:v6.1-rc4
-
编译:
- make vexpress_defconfig
- make zImage dtbs -j4
-
安装过程中遇到了报错,需要安装依赖库:
- sudo apt-get install g++
- sudo apt-get install libmpc-dev
- 将arch/arm/boot/zImage和arch/arm/boot/dts/vexpress-v2p-ca9.dtb拷贝出来
-
运行:
- qemu-system-arm -M vexpress-a9 -m 256M -nographic -kernel zImage -dtb vexpress-v2p-ca9.dtb
- 能正常运行,但是会提示没有文件系统
- 编译好的zImage和vexpress-v2p-ca9.dtb文件我已经放在另一个仓库中,地址为:https://gitee.com/langcai1943/linux_kernel_u-boot_busybox_code_comments/tree/develop/bin/v1.0.0
-
运行效果:
jim@DESKTOP-SVP3BEM MSYS /d/1_git/cj-security-camera/linux
$ qemu-system-arm -M vexpress-a9 -m 256M -nographic -kernel zImage -dtb vexpress-v2p-ca9.dtb
Booting Linux on physical CPU 0x0
Linux version 6.1.0-rc6 (jim@jim) (arm-none-linux-gnueabihf-gcc (Arm GNU Toolchain 11.3.Rel1) 11.3.1
20220712, GNU ld (Arm GNU Toolchain 11.3.Rel1) 2.38.20220708) #1 SMP Fri Nov 25 23:17:29 CST 2022
CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
OF: fdt: Machine model: V2P-CA9
Memory policy: Data cache writeback
Reserved memory: created DMA memory pool at 0x4c000000, size 8 MiB
OF: reserved mem: initialized node vram@4c000000, compatible id shared-dma-pool
cma: Reserved 16 MiB at 0x6f000000
Zone ranges:
Normal [mem 0x0000000060000000-0x000000006fffffff]
Movable zone start for each node
Early memory node ranges
node 0: [mem 0x0000000060000000-0x000000006fffffff]
Initmem setup node 0 [mem 0x0000000060000000-0x000000006fffffff]
CPU: All CPU(s) started in SVC mode.
......
---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) ]---
- 参考网址
2、Busybox生成文件系统需要的系统应用程序和制作根文件系统
-
MSYS2中的QEMU不能引导文件系统(未尝试去查找解决该问题),在Linux下运行QEMU能正常引导。
- 在Ubuntu下安装QEMU:sudo apt install qemu-system-arm
-
从官网下载最新的BusyBox发布版本:busybox-1.35.0.tar.bz2
- 如果想要尝试最新的未形成版本的源码,则下载 busybox-snapshot.tar.bz2
-
因为BusyBox源码更新较慢,ARM最新的编译器11.3编译BusyBox报错无法解决,所以我改用老版本的编译器,能编译通过
-
10.2版本编译器ARM官方下载地址:gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf.tar.xz
- 解压后需要重新输出编译器路径:
-
交叉编译环境的配置方法和上面编译U-Boot时相同
# 因为我当前不编译Linux PC下的程序,所以我直接将整个环境都配成交叉编译的
export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabihf-
# 增加交叉编译器的路径,修改成你自己解压的路径
export PATH=$PATH:/home/jim/Desktop/tools/gcc-arm-10.2/bin
# 如果之前以及输出了别的版本gcc的路径,则需重新注销或者重启Ubuntu后再执行上面的步骤
- 编译:
- make menuconfig
- 设置 Build Options 开启静态编译(提示: 可使用 / 搜索
static
)- 在第一行Settings —>上回车,在滚动到中间位置,找到 [ ] Build static binary (no shared libs)并按空格,让括号内多一个星号表示选中,再按两次Esc,在弹出框中按回车保存配置
- make -j4
- make install
- 编译过程中报错时需要安装的依赖库
- sudo apt install libncurses5-dev
-
以下内容无效。以下为尝试解决最新的ARM GCC编译器编译时的问题,但最终失败,但保留重新编译安装coreutils工具集的步骤:
-
遇到报错无法解决:
coreutils/dd.c: 在函数‘dd_output_status’中:
coreutils/dd.c:123:21: 编译器内部错误: 非法指令
123 | #define G (*(struct globals*)bb_common_bufsiz1)
| ^~~~~~~
coreutils/dd.c:192:29: 附注: in expansion of macro ‘G’
192 | seconds = (now_us - G.begin_time_us) / 1000000.0;
| ^
free(): invalid next size (fast)
editors/awk.c: 在函数‘next_token’中:
editors/awk.c:1121:17: 编译器内部错误: 已放弃
1121 | debug_printf_parse("%s: using concat-inserted token\n", __func__);
| ^~~~~~~~~~~~~~~~~~
- 重新编译安装coreutils也无法解决报错的问题:
- sudo apt install git
- git clone git://git.sv.gnu.org/coreutils
- 编译步骤参考:coreutils.git/plain/README
- 注释掉
export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabihf-
export PATH=$PATH:/home/jim/Desktop/tools/arm-gnu-toolchain-11.3/bin
- 然后登出系统(注销),再重新登入(或者重启也可以),去掉当前环境中的交叉编译环境变量
- 进入coreutils目录
- ./bootstrap 运行要一会儿,且没有打印提示,可以通过看自己CPU占用率来判断是否结束
- 执行时报错,则:
- sudo apt-get install autoconf
- sudo apt-get install autopoint
- sudo apt-get install gperf
- sudo apt-get install texinfo
- ./configure
- make CFLAGS=‘-w’ -j4
- sudo make install
- 重新编译Busybox仍然报错。
- 以上内容无效。
已在BusyBox源码文件夹下生成了_install目录,里面有板子上能用到的各种系统命令
制作根文件系统:
mkdir my_mnt
dd if=/dev/zero of=rootfs.img bs=1024 count=16384 # 创建 16MB 虚拟磁盘
mkfs.ext2 rootfs.img # 格式化成 ext2 格式文件系统
sudo mount -o loop rootfs.img my_mnt # 将镜像文件和块设备关联并挂载设备到my_mnt
sudo cp -r _install/* my_mnt # 将 BUsybox 所有生成的程序拷贝到根目录
# 创建4个tty设备(c代表字符设备,4是主设备号,1~4分别是次设备号)
sudo mkdir -p my_mnt/dev
sudo mknod my_mnt/dev/tty1 c 4 1
sudo mknod my_mnt/dev/tty2 c 4 2
sudo mknod my_mnt/dev/tty3 c 4 3
sudo mknod my_mnt/dev/tty4 c 4 4
# 创建终端
sudo mknod -m 666 my_mnt/console c 5 1
sudo umount my_mnt
- 将生成的rootfs.img拷贝Ubuntu桌面
- 将之前的u-boot和vexpress-v2p-ca9.dtb拷贝到Ubuntu桌面
- 编译好的rootfs.img、zImage和vexpress-v2p-ca9.dtb文件我已经放在另一个仓库中,地址为:https://gitee.com/langcai1943/linux_kernel_u-boot_busybox_code_comments/tree/develop/bin/v1.0.0
- 在Ubuntu桌面上打开终端
- 在Ubuntu终端中执行 qemu-system-arm -M vexpress-a9 -m 256M -nographic -kernel zImage -dtb vexpress-v2p-ca9.dtb -sd rootfs.img -append “root=/dev/mmcblk0 rw console=ttyAMA0”
- 可以看到效果:
jim@jim:~/Desktop/usr$ qemu-system-arm -M vexpress-a9 -m 256M -nographic -kernel zImage -dtb vexpress-v2p-ca9.dtb -sd rootfs.img -append "root=/dev/mmcblk0 rw console=ttyAMA0"
WARNING: Image format was not specified for 'rootfs.img' and probing guessed raw.
Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
Specify the 'raw' format explicitly to remove the restrictions.
pulseaudio: set_sink_input_volume() failed
pulseaudio: Reason: Invalid argument
pulseaudio: set_sink_input_mute() failed
pulseaudio: Reason: Invalid argument
Booting Linux on physical CPU 0x0
Linux version 6.1.0-rc6 (jim@jim) (arm-none-linux-gnueabihf-gcc (Arm GNU Toolchain 11.3.Rel1) 11.3.1 20220712, GNU ld (Arm GNU Toolchain 11.3.Rel1) 2.38.20220708) #1 SMP Fri Nov 25 23:17:29 CST 2022
CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
OF: fdt: Machine model: V2P-CA9
Memory policy: Data cache writeback
Reserved memory: created DMA memory pool at 0x4c000000, size 8 MiB
OF: reserved mem: initialized node vram@4c000000, compatible id shared-dma-pool
cma: Reserved 16 MiB at 0x6f000000
Zone ranges:
Normal [mem 0x0000000060000000-0x000000006fffffff]
Movable zone start for each node
Early memory node ranges
node 0: [mem 0x0000000060000000-0x000000006fffffff]
Initmem setup node 0 [mem 0x0000000060000000-0x000000006fffffff]
CPU: All CPU(s) started in SVC mode.
percpu: Embedded 15 pages/cpu s30612 r8192 d22636 u61440
Built 1 zonelists, mobility grouping on. Total pages: 65024
Kernel command line: root=/dev/mmcblk0 rw console=ttyAMA0
printk: log_buf_len individual max cpu contribution: 4096 bytes
printk: log_buf_len total cpu_extra contributions: 12288 bytes
printk: log_buf_len min size: 16384 bytes
printk: log_buf_len: 32768 bytes
printk: early log buf free: 14944(91%)
......
can't run '/etc/init.d/rcS': No such file or directory
Please press Enter to activate this console.
/ # ls
bin dev linuxrc lost+found sbin usr
/ #