同步操作将从 才鲸嵌入式/嵌入式QEMU教程 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
作者 | 将狼才鲸 |
---|---|
创建日期 | 2022-11-14 |
软硬件资源 | 详情 | 备注 |
---|---|---|
QEMU BCM2836芯片模拟器 | 900MHz 4核 ARM Cortex-A7 CPU, VideoCore IV 双核 GPU (2D 3D显示加速, 视频编解码), 1GB 内存, 100M以太网, HDMI显示, USB2.0 x 4, SD卡, 音频输出, GPIO, 摄像头输入, 液晶屏接口, 串口, SPI, I2C等嵌入式通用模块 | 树莓派2B同款硬件 |
硬件模块测试用例:raspi3-tutorial | 裸机程序,包含让CPU运行的空程序、串口打印、屏幕图像输出、屏幕文字输出、读写SD卡、bootloader | 树莓派3B同款硬件BCM2837,在仓库根目录raspi3-tutorial文件夹中, 开箱即用, 直接make, 直接在QEMU中运行 |
裸机项目 | 汇编boot,串口打印,......进行中...... | 树莓派2B同款硬件BCM2836 |
RTOS项目 | ......未开始...... | |
Linux项目 | uboot编译运行,Linux和根文件系统编译运行 | ARM CoreTile Express开发板 |
使用的开源库 |
作为一名嵌入式软件工程师,我想自己从头开始做一个实际的嵌入式产品;结合自己工作中接触过的技术,我希望最终的项目中有通信、GUI、音视频编码、音视频解码功能的设备。
创建这个仓库的目的,一是记录自己学习到的技术,防止时间久了忘记;二是给其他也想要做一个实际嵌入式项目的人一个参考,最好是能开箱即用,能看到产品的效果,然后能方便的阅读源码和注释,知晓原理,而不用自己去一步步搭建环境;搭环境是很痛苦的,往往遇到一个问题跨不过去,又没人指导,然后就不得不放弃了。
我不使用具体的开发板,而是使用QEMU模拟器;原因一就是上面“第2条前言”所描述的通用和开箱即用,因为不同的开发板太多了,开发板也很贵,真的没必要让看这个工程的人还去花钱买块板子,板子买回来很大的概率也是吃灰。原因二是我自己也从来没买过开发板,也不喜欢在开发板上频繁下载调试程序,很慢也很烦,一般纯逻辑的模块我会先用gcc或者模拟器验证好,然后再上板子调试。原因三是芯片原厂开发芯片开发包时,芯片还没设计好的初期也会先使用模拟器,不过他们完整的模拟器代码并没有流传出来而已。
在硬件选型的过程中,其实我最中意的是瑞芯微的芯片,但无奈他们家的产品在QEMU模拟器中并不支持;然后我查看了QEMU支持的所有嵌入式芯片,发现除了Intel、AMD,其它的芯片都不支持其中的显示加速、音视频编解码(一开始我以为QEMU对博通VideoCore GPU会支持,后面发现只是模拟了核间通信,但此时我已经做完了这个项目的准备工作了),有些芯片仅仅只支持了不加速的液晶屏显示、触摸屏、音频解码,还有些芯片只支持了串口、GPIO、SPI、I2C等基础的外设。阴差阳错间,我选择了树莓派。
树莓派不是最理想的选项,最新的几款树莓派芯片都是64位的ARM;嵌入式当前流行32位CPU,所以我选择树莓派32位CPU的老版本;而且树莓派所使用的博通芯片的手册还是不公开的,能找到的资料也少,这对嵌入式开发很不利,但还好基本的外设寄存器地址还是能找到的,网上也能找到一些底层开发的教程;我刚毕业时也用过博通BCM2042和BCM20730蓝牙芯片,对博通也不是两眼一抹黑;尽管困难重重,但也要慢慢解决问题。
其它带有GPU的MCU芯片还有RK3399、RV1126、RK3588、RK3288、Exynos4412、DM6446等;全志的资料不公开,和博通一样,只面向大客户公开资料,所以也放弃使用全志芯片;海思的芯片也没找到模拟器,也就不用了。
一些带2D显示加速和音视频编解码模块的嵌入式开发板信息:
首先,需要Linux或者Windows MinGW等环境,如果你是第一次使用Linux,则不应该摸索Windows下的MinGW环境,这应该是对Linux已经很熟悉之后才做的事,因为在里面装软件很麻烦;你应该直接使用Ubuntu或其它Linux发行板,推荐在Windows下使用VMware虚拟机安装Ubuntu;具体的过程略。
Ubuntu下安装QEMU,这也等同于准备好了一块硬件开发板,过程略。
Ubuntu下安装ARM交叉编译工具,过程略。
编译程序,运行程序。
如果你以前用过树莓派,那么请忘掉它,我们按照嵌入式的模式来。
写树莓派的底层程序,并不能像8051或普通MCU芯片一样,使用汇编,从零地址开始的复位中断开始写,能够控制芯片上电后执行的第一条指令;因为树莓派上电后是芯片里面的GPU先开始运行,并且这部分代码是不公开的,GPU底层的寄存器介绍也是不公开的,只能加载官方提供的GPU的驱动;GPU上电后再引导ARM CPU运行。
但其实如果不是在芯片原厂,一般嵌入式开发人员也不需要知道芯片开发包里面的boot是如何实现的,编译器里面的C标准库是如何实现的,中断向量表和堆栈是如何分配的,各个驱动模板是如何实现的,操作系统是怎么移植的;能用就行。
QEMU可以在Windows下安装,也可以在Linux下安装。
参考网址:
树莓派交叉编译工具可以在Windows下安装,也可以在Linux下安装。
参考网址:
软件名 | 版本 | 作用 | 特点 |
---|---|---|---|
MSYS | MSYS,MSYS2 | Linux命令行终端:Shell,Bash | 没有在Windows下编译Linux程序的工具集,会自带已经被MinGW编译好的一些包;脱胎于Cygwin,但容量更小;MSYS2是因为MSYS常年不更新而新组的的一个项目;MSYS2安装完后的文件名为msys64,你可以将你安装好之后的msys64文件夹打包发给别人,这样别人无安装就可以用了,只是容量有点大,几十G |
MinGW | MinGW32,MinGW64 | 一组编译工具链 | 编译后生成的是纯粹的Windows程序;它自带的命令行终端很难用也不全,要和MSYS2终端配合使用;MinGW64是因为MinGW32常年不更新而新组的的一个项目 |
Cygwin | Cygwin | 编译工具+命令行 | 有模拟层,将Linux API转成Windows API再执行程序,效率低,容量大,速度慢,2010年左右在Windows下搭建交叉编译环境时还多用它;要运行纯粹的Linux程序时也用它 |
因为我已经有了MSYS2环境,可以在里面直接安装QEMU;你下载Windows版本的QEMU单独安装,也是走的MSYS2+MinGW这一套,只是和Git一样,它们都是在自己的软件安装包自带了精简版的MinGW环境。
我们不需要用MinGW64或者MinGW32编译QEMU,我们只安装已经编译好的QEMU软件;网上没搜到MSYS2中安装QEMU的教程,但是我们知道MSYS2中的所有软件都在packages.msys2.org/repos 、 MSYS2 Base Packages 和 MSYS2 Packages中有描述。
在https://packages.msys2.org/base 中能找到mingw-w64-qemu;在https://packages.msys2.org/package/ 中能找到mingw-w64-x86_64-qemu;在https://packages.msys2.org/package/mingw-w64-x86_64-qemu?repo=mingw64 中能找到/mingw64/bin/qemu-system-aarch64.exe、/mingw64/bin/qemu-system-arm.exe,也能找到安装方法:pacman -S mingw-w64-x86_64-qemu;我当前使用的是Build Date: 2022-10-10 20:19:53,Installed Size: 768.72 MB,实际安装完后有2G。
查看是否安装成功:进入cd /mingw64/bin/ 然后./qemu-system-arm.exe --version查看版本号;后续还需要设置环境变量,这里暂略。
能看到输出信息:
jim@DESKTOP-SVP3BEM MSYS /mingw64/bin
$ ./qemu-system-arm.exe --version
QEMU emulator version 7.1.0
Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers
一些工具介绍:
但也不在ARM官方下载,我们在MSYS2中同样也能找到:在https://packages.msys2.org/base 中能搜到mingw-w64-arm-none-eabi-gcc和mingw-w64-arm-none-eabi-gdb
如果有需要,你也可以安装用于64位ARM的交叉编译工具。
MSYS2安装make
参考网址:
export PATH=$PATH:/mingw64/bin
export PATH=$PATH:/mingw32/bin/gcc-linaro-7.5.0-2019.12-i686-mingw32_aarch64-linux-gnu/bin
echo $PATH
源码我已经拷贝到msys64中,并且已经改了Makefile,能直接编译和运行,同时修改过以后的源码我也会在本仓重新上传
源码路径 ~/raspi3-tutorial/01_bareminimum,也就是/home/jim/raspi3-tutorial/01_bareminimum,也就是D:\msys64\home\jim\raspi3-tutorial\01_bareminimum,后面所有的示例路径我都采用第一种写法。
进入目录 cd ~/raspi3-tutorial/01_bareminimum
编译 make
运行 make run
make run能运行,是因为在Makefile里面写了命令 qemu-system-aarch64 -M raspi3b -kernel kernel8.img -d in_asm
01_bareminimum用例是一个空程序,所以QEMU里面什么都不会显示,其它用例的效果我会再后面展示。
参考网址:
树莓派有关裸机编程的教程很少,我只找到了几个英文教程和几篇中文博客:
参考网址:
树莓派里面有GPU和ARM CPU,GPU先上电运行,然后再引导ARM运行
树莓派的GPU底层固件(Bootloader)是闭源的,但可以在此基础上引导自己的U-Boot、Linux kernel,也可以不用U-Boot和Linux,直接引导裸机程序或者RTOS;这种引导方式和Xilinx ZYNQ类似,ARM和FPGA一个先启动一个后启动。
一些其它的树莓派嵌入式相关的开源仓库:
(1) 运行在 Raspberry Pi 上的小型嵌入式系统
(2) 一些在 Raspberry Pi 上可以嵌入在其他系统中的运行库
(3) 以及其他一些基于 Raspberry Pi 裸机开发例子:
用例名称 | 作用 | 备注 |
---|---|---|
00_crosscompiler | 文档,只是描述编译器相关的内容 | |
01_bareminimum | 空程序,在汇编中死循环,只是为了验证编译器和模拟器安装正确,能够编译和运行 | |
02_multicorec | 写汇编boot,并引导C语言main函数运行 | |
03_uart1 | 串口打印Hello world,从MSYS2控制台输出 | |
04_mailboxes | CPU和GPU邮箱通信,通信成功后打印串口号 | |
05_uart0 | 串口收发回环 | |
06_random | 打印随机数 | |
07_delays | 延时后打印 | |
08_power | 关机与重启 | |
09_framebuffer | 从屏幕显示未压缩的图片 | |
0A_pcscreenfont | 从屏幕显示点阵字库文字 | |
0B_readsector | 读SD卡扇区 | |
0C_directory | 读SD卡文件夹 | |
0D_readfile | 读SD卡文件 | |
0E_initrd | 根文件系统 | |
0F_executionlevel | 获取当前程序级别 | |
10_virtualmemory | MMU虚拟内存映射 | |
11_exceptions | 测试异常中断 | |
12_printf | 测试printf输出 | |
13_debugger | gdb调试输出 | |
14_raspbootin64 | 一个简单的bootloader | |
15_writesector | 写SD卡 |
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/03_uart1
$ make
rm kernel8.elf *.o >/dev/null 2>/dev/null || true
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c start.S -o start.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c main.c -o main.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c uart.c -o uart.o
aarch64-linux-gnu-ld -nostdlib -nostartfiles start.o main.o uart.o -T link.ld -o kernel8.elf
aarch64-linux-gnu-objcopy -O binary kernel8.elf kernel8.img
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/03_uart1
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio
Hello World!
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/04_mailboxes
$ make
rm kernel8.elf *.o >/dev/null 2>/dev/null || true
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c start.S -o start.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c main.c -o main.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c mbox.c -o mbox.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c uart.c -o uart.o
aarch64-linux-gnu-ld -nostdlib -nostartfiles start.o main.o mbox.o uart.o -T link.ld -o kernel8.elf
aarch64-linux-gnu-objcopy -O binary kernel8.elf kernel8.img
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/04_mailboxes
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio
My serial number is: 0000000000000000
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/05_uart0
$ make
rm kernel8.elf *.o >/dev/null 2>/dev/null || true
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c start.S -o start.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c main.c -o main.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c mbox.c -o mbox.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c uart.c -o uart.o
aarch64-linux-gnu-ld -nostdlib -nostartfiles start.o main.o mbox.o uart.o -T link.ld -o kernel8.elf
aarch64-linux-gnu-objcopy -O binary kernel8.elf kernel8.img
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/05_uart0
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
My serial number is: 0000000000000000
aaaaddddd
asdfasfsafsa
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/07_delays
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
Waiting 1000000 CPU cycles (ARM CPU): OK
Waiting 1000000 microsec (ARM CPU): OK
Waiting 1000000 microsec (BCM System Timer): OK
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/08_power
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
1 - power off
2 - reset
Choose one: 2
1 - power off
2 - reset
Choose one: 1
1 - power off
2 - reset
Choose one:
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/08_power
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/0F_executionlevel
$ jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/0F_executionlevel
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
Current EL is: 00000001
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/11_exceptions
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
Synchronous: Data abort, same EL, Translation fault at level 2:
ESR_EL1 0000000096000006 ELR_EL1 0000000000080CC4
SPSR_EL1 00000000200003C4 FAR_EL1 FFFFFFFFFF000000
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/11_exceptions
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/12_printf
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
Hello World!
This is character 'A', a hex number: 7FFF and in decimal: 32767
Padding test: '00007FFF', ' -123'
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/12_printf
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/13_debugger
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
Synchronous: Breakpoint instruction
> run
x0: 000000000008EF7C x1: 0000000000000301 x2: 0000000000000070
x3: 000000000000000B x4: 0000000000024000 x5: 0000000000000000
x6: 0000000000000000 x7: 0000000000000000 x8: 0000000000000000
x9: 0000000000000000 x10: 0000000000000000 x11: 0000000000000000
x12: 0000000000000000 x13: 0000000000000000 x14: 0000000000000000
x15: 0000000000000000 x16: 0000000000000000 x17: 0000000000000000
x18: 0000000000000000 x19: 0000000000000000 x20: 0000000000000000
x21: 0000000000000000 x22: 0000000000000000 x23: 0000000000000000
x24: 0000000000000000 x25: 0000000000000000 x26: 0000000000000000
x27: 0000000000000000 x28: 0000000000000000 x29: 000000000007FFF0
x30: 000000000008EF7C elr_el1: 8EF7C spsr_el1: 600003C4
esr_el1: F2000000 far_el1: 0
sctlr_el1: 30D00800 tcr_el1: 0
>
发布时间 | 名称 | 芯片 | 外设 |
---|---|---|---|
2011-12 | Raspberry Pi Model B | BCM2835 ARM1176JZF-S 700MHz 512M | 有网口、无WiFi和蓝牙 |
2014-7-14 | Raspberry Pi Model B+ | 同上,BCM2835 ARM1176JZF-S 700MHz 512M | 同上 |
2014-11-11 | Raspberry Pi Model A+ | 同上,BCM2835 ARM1176JZF-S 700MHz 512M | 无网口、WiFi和蓝牙 |
2015-02-02 | Raspberry Pi 2 Model B | BCM2836 ARM Cortex-A7 900MHz 4核 1G | 有网口、无WiFi和蓝牙 |
2015-11-26 | Raspberry Pi Zero | BCM2835 ARM11 1GHz DDR512M | 无网口、WiFi和蓝牙 |
2016-02-29 | Raspberry Pi 3 Model B | BCM2837 ARM Cortex-A53 1.2GHz 64位4核 1GB | 有网络、WiFi和蓝牙 |
2017-3-1 | Raspberry Pi Zero W | BCM2835 ARM11 1GHz 512M | 无网口,有WiFi和蓝牙 |
2018-3-4 | Raspberry Pi 3 Model B+ | BCM2837 ARM Cortex-A53 1.2GHz 64位4核 1GB | 有网络、WiFi和蓝牙 |
2018-11-15 | Raspberry Pi 3 Model A+ | BCM2837B0 ARM Cortex-A53 1.4GHz 64位4核 1GB | 无网络、有WiFi和蓝牙 |
2019-06-24 | Raspberry Pi 4 Model B | BCM2711 ARM Cortex-A72 1.5GHz 64位4核 8GB | 有网络、WiFi、蓝牙 |
参考资料:
我使用32位ARM Cortex-A7 4核的BCM2836芯片,该芯片的参数如下;2836的文档是以2835为基础的,所以也要看2835的文档:
芯片的Boot
参考资料:
模块名称 | 描述 | 备注 |
---|---|---|
GPU | VideoCore IV,支持OpenGL ES 2.0,1080p 30帧 H.264和MPEG-4解码 | |
HDMI | HDMI音频视频输出 | |
USB | 4个USB 2.0,Core和Phy用的是Synopsys IP,该模块被GPU所拥有 | |
SD EMMC | 支持MultiMedia和SD卡 | |
以太网 | 100M | |
定时器 | 1个64位定时器,2个32位定时器 | |
Mailbox | GPU和CPU核间通信 | |
中断控制 | GPU中断和ARM中断 | |
UART | 两个串口 | |
SPI | SPI1、SPI2 | |
BSC(I2C) | Broadcom Serial Controller (BSC),BSC0~2三个,I2C | |
DMA | 数据快速搬运,16个通道 | |
GPIO | 54个IO口 | |
I2S PCM | 音频输入输出 | |
PWM | Pulse Width Modulator | |
SPI | SPI总线 |
Boot流程介绍:
几个对裸机编程有帮助的教程:
参考网址:
https://github.com/raspberrypi 里有树莓派的一些仓库集合,有用的一些仓库有:
文件夹 | 文件名 | 作用 | 描述 |
---|---|---|---|
arch | 硬件相关源码的文件夹 | ||
samples | 单元测试用例所在的文件夹 | 验证某项功能是否已实现 | |
samples/01_asm_boot | BCM2836的汇编boot和串口输出 | ||
…… |
#include "hw/char/pl011.h"
#include "hw/char/bcm2835_aux.h"
#include "hw/display/bcm2835_fb.h"
#include "hw/dma/bcm2835_dma.h"
#include "hw/intc/bcm2835_ic.h"
#include "hw/misc/bcm2835_property.h"
#include "hw/misc/bcm2835_rng.h"
#include "hw/misc/bcm2835_mbox.h"
#include "hw/misc/bcm2835_mphi.h"
#include "hw/misc/bcm2835_thermal.h"
#include "hw/misc/bcm2835_cprman.h"
#include "hw/misc/bcm2835_powermgt.h"
#include "hw/sd/bcm2835_sdhost.h"
#include "hw/gpio/bcm2835_gpio.h"
#include "hw/timer/bcm2835_systmr.h"
前提:编译U-Boot和Linux kernel源码时,源码版本、PC主机Linux系统版本、交叉编译器版本都有影响,最好按照网上教程中相同的版本来尝试,要不然经常会遇到编译时遇到了问题,但又搜不到解决方法的尴尬局面。
必须在Linux系统中编译(如Ubuntu),不能在MSYS2中编译。
网上能搜到的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主板。
我使用最新版本的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
参考网址
如果使用虚拟机,则下载安装VMware Player,过程略。
下载并安装64位Ubuntu 18.04,因为我的笔记本电脑是2012年买的,配置不行,所以我在虚拟机中用老系统能跑的比较快;Ubuntu 18.04系统会持续支持到2028年,不用担心里面的软件过时。
参考网址:
从ARM官网下载最新的,在64位PC上使用的32位ARM交叉编译工具,下载速度比较慢。
解压交叉编译器,然后在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
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
......
如果要编译用于BCM2836或ARM CoreTile Express开发板的Linux kernel,则必须要在Linux环境如Ubuntu中编译。一是因为编译过程中有各种依赖库;二是因为kernel源码中有三个以aux命名的文件,这个文件名在Windows环境中不允许存在,在Windows中解压或者拷贝kernel源码时都会报错;如果一定要在Windows下的MinGW中编译,网上找不到任何教程,你可以在kernel源码中强行修改aux文件名和对应的Kconfig、Makefile后,并安装各种依赖库,只能自行尝试;在MSYS2中安装各种依赖库软件也是需要自行摸索的,应该很少有教程。
Ubuntu主机和交叉编译工具可以直接用上面U-Boot同样的环境,下面介绍的是32位Ubuntu16.04下使用的交叉编译工具;Linux kernel在此环境下也能编译通过。
# 因为我当前不编译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,版本太低。
# 因为我当前不编译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
编译:
安装过程中遇到了报错,需要安装依赖库:
运行:
运行效果:
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) ]---
MSYS2中的QEMU不能引导文件系统(未尝试去查找解决该问题),在Linux下运行QEMU能正常引导。
从官网下载最新的BusyBox发布版本:busybox-1.35.0.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后再执行上面的步骤
static
)
以下内容无效。以下为尝试解决最新的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__);
| ^~~~~~~~~~~~~~~~~~
export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabihf-
export PATH=$PATH:/home/jim/Desktop/tools/arm-gnu-toolchain-11.3/bin
已在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
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
/ #
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。