打印
[应用相关]

【转】Linux利器:QEMU!用它模拟开发板能替代真开发板?

[复制链接]
2697|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
QEMU,搞嵌入式开发的一定不陌生,最近各大群里都讨论疯了,说它是Linux利器一点也不夸张。它是一款知名的而且开源的模拟器(官网:https://www.qemu.org/),它能在 X86 PC 上运行(其实它也可以在你的 Arm 开发板上运行,我们今天先不讨论这种场景),能够模拟 Arm、MIPS、RISC-V 等各种 CPU 和开发板,以及 网卡、声卡、键盘、sdcard、emmcusb等各种外设。
你可以把它当作一块召之即来的开发板,在上面运行 U-Boot、Linux Kernel、甚至 Ubuntu 等各种软件和操作系统。
有时候我们想体验一下 mainline 上最新的 U-Boot 或者 Linux Kernel,可是却发现手边没有合适的板子,或者手边的板子搭载的 U-Boot 和 Linux Kernel 版本都比较低,这时候 QEMU 可以帮你迅速实现这一愿望。

使用特权

评论回复
沙发
问天少年|  楼主 | 2022-4-28 22:44 | 只看该作者
QEMU安装我们安装的是 Arm 版本的 QEMU,如果直接在 Ubuntu 上用sudo apt install qemu-system-arm命令安装的话,得到的 QEMU 版本比较旧,最好直接通过源码去编译。
我在 Ubuntu 18.04 系统上发现系统默认安装的 QEMU 在图形模式(不带 -nographic 参数)下无法启动。
参考上面步骤编译成功后,得到:qemu-system-arm和qemu-system-aarch64。前者用来模拟 32 位的 Arm cpu,比如 Arm9 /Arm11、 Cortex-A7/A9/A15 。后者用来模拟 64 位的 Arm cpu,比如 Arm Cortex A53,A57。
可以用qemu-system-arm -machine help命令来查看所支持的开发板:
是不是有很多熟悉的开发板都在里面,i.MX、EXYNOS 这些知名的芯片都有包含。
这里我们使用 vexpress-a9 这款开发板。vexpress-a9 是 Arm 公司自己设计的一款 4 核 Cortex-A9 开发板,U-Boot、Linux Kernel 和 QEMU 对这款开发板都做了完整的支持。

使用特权

评论回复
板凳
问天少年|  楼主 | 2022-4-28 22:45 | 只看该作者
编译U-Boot
第一步:U-Boot 代码下载:

git clone https://gitlab.denx.de/u-boot/u-boot.git
下载完后,可以看到 configs 目录下有针对这款开发板的配置文件:



vexpress_ca9x4_defconfig

使用特权

评论回复
地板
问天少年|  楼主 | 2022-4-28 22:46 | 只看该作者
第二步:编译

make vexpress_ca9x4_defconfig
make CROSS_COMPILE=arm-linux-gnueabihf- all
最终编译生成 elf 格式的可执行文件 u-boot 和纯二进制文件u-boot.bin,其中 QEMU 可以启动的为 elf 格式的可执行文件 u-boot。

使用特权

评论回复
5
问天少年|  楼主 | 2022-4-28 22:47 | 只看该作者
编译Buildroot启动一个 Arm Linux 系统,一般都要必须的三件套:Bootloader、Linux Kernel、rootfs(根文件系统)。在很久以前,制作 rootfs 是一件很麻烦的事情:交叉编译 busybox,然后手动建立标准的 Linux 系统目录,再把编译 busybox 生成的各种文件和库拷贝过来。如果还需要其他的模块,再交叉编译。如果交叉编译的某个模块依赖其他的库,还想要办法解决这个依赖关系。最后还要手动建立设备节点,设置对应的权限。一步一步做下去,任意一个环节都不能出错。否则启动的时候不知道会遇到什么莫名其妙的问题。
Buildroot 项目出现之后,如同它的 Slogan:MakingEmbedded Linux Easy,构建 rootfs 就变得轻松了许多,用一个群友的话说:
自从用了buildroot,我就告别了刀耕火种的野蛮生活。那种文件系统自己定制,需要任何工具都要自己下源码交叉编译然后被各种库问题搞的焦头烂额的时代一去不复返了。



使用特权

评论回复
6
问天少年|  楼主 | 2022-4-28 22:48 | 只看该作者
代码下载:

git clone git://git.buildroot.net/buildroot
Buildroot 代码仓库默认只包含一个编译框架,所以代码量很小,下载起来很快。真正构建 rootfs需要的各种代码包是根据你的配置选项,在编译的时候才开始下载的。

使用特权

评论回复
7
问天少年|  楼主 | 2022-4-28 22:49 | 只看该作者
配置:Buildroot 提供了和 U-Boot、Linux Kernel 等主流开源项目一样的 menucoinfig 配置接口,可以通过make help来查询所支持的各种命令: 开发者只要执行make menuconfig命令,就能通过这个熟悉的界面去选择自己需要的各种组件,定制自己的 rootfs:首先要配置的是 Target options 选项: 大部分 Arm 都是小端模式,所以选上 little endian 。这款开发板的 CPU 是 cortex-A9。我们将使用 Linaro GCC 进行编译,Linaro 的 GCC 默认都打开了 hardfloat 的支持,所以选上 VFP extension 和 EABIhf

使用特权

评论回复
8
问天少年|  楼主 | 2022-4-28 22:51 | 只看该作者
Build options选项:





第一个选项是设置最后生成的配置文件的保存路径,buildroot 可以针对不同的板子生成特定的 defconfig 文件,默认保存在 configs 目录下。
自己修改各项配置后,执行make savedefconfig命令,就会生成新的 defconfig 文件: 下次编译之前,可以直接执行make ca9_mini_defconfig命令来加载已有的配置。 第二个选项设置 buildroot 下载的各种第三方包的存储路径,默认在 dl 目录下:

使用特权

评论回复
9
问天少年|  楼主 | 2022-4-28 22:54 | 只看该作者
设置 Toolchain




因为这里使用电脑上自己安装的 toolchain,所以我们这里选 External toolchainCustom toolchain然后在 Toolchain path 中填写 toolchian 在电脑上安装的位置,如果不知道具体位置,用which命令查看:
另外要注意 Toolchain prefix 这个前缀别写错。设置 toolchain 的版本和用来编译这个 toolchain 的内核头文件的内核的版本:Toolchain 的版本我们根据 Toolchain 的名字或者通过arm-linux-gnueabihf-gcc  -v 命令就可以查到。编译 Toolchain 的内核头文件对应的内核的版本是什么呢?我们在这个选项上敲 h 键,会看到下面的帮助选项: 原来这个版本可以在 toolchain 里面的 version.h 这个文件查到:打开这个文件:
arm-linux-gnueabihf/libc/usr/include/linux/version.h
263680 对应的十六进制为 0x40600,右移 16 位,得到的版本号为 4。这就是上面 4.0.x 的由来。这里也教给了大家一个小窍门:当我们在 make menuconfig 做配置的时候,如果遇到了看不懂的选项,直接在这个选项上敲 h 键,会看到一些有用的帮助信息,对这个选项做进一步解释。因为 vexpress_a9 内核启动的控制台的名字叫做 ttyAMA0,所以我们还要在 :System configuration->Run a getty(login prompt) after boot选项中配置 TTY Port 为 ttyAMA0。否则文件系统挂载后无法进入控制台。

我们把编译的 rootfs 以 initramfs 的形式和 Linux Kernel 链接在一起,为了让根文件系统镜像尽量小,可以对文件系统采用 lz4 压缩,所以 Filesystem images 还要做如下配置:


到这里一个最精简的 buildroot 已经配置完成。如果还需要其他的命令或者工具,可以在 Target Packages 下面开启:

如果你需要的某个模块,buildroot 里面没有,还可以自己添加:



比如加入上面这个补丁,就可以让 buildroot 在编译的时候自动下载 https://github.com/rockchip-linux/io.git 并编译。退出执行make命令开始编译。Buildroot 编译的过程中会自动通过网络下载需要的各种包,所以要保证网络畅通。编译完成后输入信息如下图:


使用特权

评论回复
10
问天少年|  楼主 | 2022-4-28 22:56 | 只看该作者
编译Linux Kernel
1)代码下载

git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
Linux mainline 已经有了对 vexpress_a9 这块板子的支持:


这里面的 ca 就是 Cortex-a 的简写,所以 ca9 就是 Cortex-A9,ca15 就是 Cortex-A15.2)配置把前面 buildroot 编译的 rootfs.cpio.lz4 拷贝到 linux kernel 根目录下:
cp../buildroot/output/images/rootfs.cpio.lz4 .
make ARCH=arm vexpress_defconfig
执行make ARCH=arm menuconfig命令,我们修改一些基本的配置:
General setup->Initramfs source file处填写 rootfs.cpio.lz4, 就是我们前面从 Buildroot 拷贝过来的 rootfs,这里面我们把它和内核编译在一起,当然,rootfs也可以单独作为一个文件,放在独立的分区去加载,这种方式我们可以留在以后去尝试。

使用特权

评论回复
11
问天少年|  楼主 | 2022-4-28 22:57 | 只看该作者
在 Kernel hacking->printk and dmesg options选项中选中第一项,这样打印的内核 log 前面会附带有时间戳信息,比较好看。
退出,保存,然后编译:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-  -j8
编译完成。

使用特权

评论回复
12
问天少年|  楼主 | 2022-4-28 22:59 | 只看该作者
本帖最后由 问天少年 于 2022-4-28 23:01 编辑

启动QEMU前面说了,QEMU 可以模拟 sd 卡等外设。我们就把编译好的固件放在一个模块的 sdcard 上,让 QEMU 从这张模拟的 sd 卡上启动 Linux 系统: 制作 sd 卡镜像,并将它格式化成 fat 格式:

dd if=/dev/zero of=sd.img bs=4096 count=4096
mkfs.vfat sd.img
把编译好的 kernel zImage 和 dtb 文件拷贝到 sd.img 中

sudo mount sd.img /mnt/ -o loop,rw
sudo cp arch/arm/boot/zImage /mnt/
sudo cp arch/arm/boot/dts/vexpress-v2p-ca9.dtb /mnt/
sudo umount /mnt
启动 QEMU

sudo qemu-system-arm -M vexpress-a9 -m 512M -kernel ../uboot-imx/u-boot-nographic  -sd sd.img

-M 参数指定启动的板子为 vexpress-a9。
-m 指定这块板子的内存为 512MB。
-kernel 指定 QEMU 启动时首先执行的程序,我们这里指定为前面编译好的 u-boot 可以执行文件。
-sd 参数指定前面制作的 sd.img。
因为我们这里是从命令行启动,所以加了 nographic 参数。
可以看到 u-boot 已经顺利启动并进入命令,下面我们来启动 Linux Kernel。

使用特权

评论回复
13
问天少年|  楼主 | 2022-4-28 23:03 | 只看该作者
首先通过 fatload 命令把 sd.img 里面的 zImage 和 dtb 文件读到开发板的内存中:

fatload mmc 0:0 0x62008000 zImage
fatload mmc 0:0 0x64008000 vexpress-v2p-ca9.dtb
这里面的 0x62008000 和 0x64008000 分别对应 zImage 和 dtb 文件在内存中的加载地址,这两个地址是怎么来的呢:在 Linux Kernel 中,有如下定义: 这个 textofs 定义的就是 Linux kernel zImage 执行地址对应的内存偏移地址,默认偏移为 0x8000。在 u-boot 命令行中输入bdinfo命令,可以查到这块开发板内存的起始地址: 可以看到这块开发板的内存其实地址为 0x60000000,所以对应内核的起始地址为:0x62008000dtb 的加载地址没有特别的要求,一般注意和 Linux Kernel Image 避开,不要重叠即可。 通过 bootz 命令启动 Linux Kernel:
bootz 0x62008000 - 0x64008000 启动到最后输入root就可以进入命令行控制台。到这里,我们就顺利的在 QEMU 上把 Arm linux 运行起来了。

使用特权

评论回复
14
Uriah| | 2022-10-8 10:14 | 只看该作者

一般要进行内存优化,尽量提高内存的使用效率

使用特权

评论回复
15
Bblythe| | 2022-10-8 13:13 | 只看该作者

访问时采用不同的指令,所以并不会占用 RAM 空间

使用特权

评论回复
16
Pulitzer| | 2022-10-8 16:12 | 只看该作者

51 单片机不使用线性编址

使用特权

评论回复
17
Clyde011| | 2023-7-1 07:15 | 只看该作者

主从定时器门控的方式

使用特权

评论回复
18
万图| | 2023-7-1 09:11 | 只看该作者

中断计数的方式实现简

使用特权

评论回复
19
Uriah| | 2023-7-1 10:14 | 只看该作者

当PWM频率较高时,频繁的中断将影响程序运行的效率

使用特权

评论回复
20
帛灿灿| | 2023-7-1 12:10 | 只看该作者

都可以产生指定个数的PWM脉冲

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

57

主题

405

帖子

1

粉丝