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

不想错过我的推送,记得右上角-查看公众号-设为星标,摘下星星送给我!

QEMU,搞嵌入式开发的一定不陌生,最近各大群里都讨论疯了,说它是Linux利器一点也不夸张。它是一款知名的而且开源的模拟器(官网:https://www.qemu.org/),它能在 X86 PC 上运行(其实它也可以在你的 Arm 开发板上运行,我们今天先不讨论这种场景),能够模拟 Arm、MIPS、RISC-V 等各种 CPU 和开发板,以及 网卡、声卡、键盘、sdcard、emmc、usb等各种外设。

你可以把它当作一块召之即来的开发板,在上面运行 U-Boot、Linux Kernel、甚至 Ubuntu 等各种软件和操作系统。

有时候我们想体验一下 mainline 上最新的 U-Boot 或者 Linux Kernel,可是却发现手边没有合适的板子,或者手边的板子搭载的 U-Boot 和 Linux Kernel 版本都比较低,这时候 QEMU 可以帮你迅速实现这一愿望。

我是Andy, Linux内核开发者。现从事Arm芯片上Linux 系统移植和优化工作,并向 u-boot 和 linux kernel开源社区贡献了大量补丁。从 Cortex-M3 到 Arm64,RT-Thread 到 Linux kernel, hack 不止,其乐无穷。受达尔闻邀约为嵌入式开发爱好者分享这篇好文,更多我的文章,可以关注我的公众号:HackforFun

接下来我带领大家一起来感受一下QEMU的强大和乐趣:手把手教你在 Ubuntu 系统中通过 QEMU 来运行基于 Arm CPU 的Linux系统吧。

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 对这款开发板都做了完整的支持。

编译U-Boot

第一步:U-Boot 代码下载:

git clone https://gitlab.denx.de/u-boot/u-boot.git

下载完后,可以看到 configs 目录下有针对这款开发板的配置文件:

vexpress_ca9x4_defconfig

第二步:编译

make vexpress_ca9x4_defconfig
make CROSS_COMPILE=arm-linux-gnueabihf- all

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

编译 Buildroot

启动一个 Arm Linux 系统,一般都要必须的三件套:Bootloader、Linux Kernel、rootfs(根文件系统)。

在很久以前,制作 rootfs 是一件很麻烦的事情:交叉编译 busybox,然后手动建立标准的 Linux 系统目录,再把编译 busybox 生成的各种文件和库拷贝过来。如果还需要其他的模块,再交叉编译。如果交叉编译的某个模块依赖其他的库,还想要办法解决这个依赖关系。最后还要手动建立设备节点,设置对应的权限。一步一步做下去,任意一个环节都不能出错。否则启动的时候不知道会遇到什么莫名其妙的问题。

Buildroot 项目出现之后,如同它的 Slogan:MakingEmbedded Linux Easy,构建 rootfs 就变得轻松了许多,用一个群友的话说:

自从用了buildroot,我就告别了刀耕火种的野蛮生活。那种文件系统自己定制,需要任何工具都要自己下源码交叉编译然后被各种库问题搞的焦头烂额的时代一去不复返了。

◆ 代码下载:

git clone git://git.buildroot.net/buildroot

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

◆ 配置:

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

交叉编译工具 Linaro GCC 的安装可以参考前面的文章:一次搞定 Arm Linux 交叉编译。

Build options选项:

第一个选项是设置最后生成的配置文件的保存路径,buildroot 可以针对不同的板子生成特定的 defconfig 文件,默认保存在 configs 目录下。

自己修改各项配置后,执行make savedefconfig命令,就会生成新的 defconfig 文件:

下次编译之前,可以直接执行make ca9_mini_defconfig命令来加载已有的配置。

第二个选项设置 buildroot 下载的各种第三方包的存储路径,默认在 dl 目录下:

设置 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 编译的过程中会自动通过网络下载需要的各种包,所以要保证网络畅通。

编译完成后输入信息如下图:

编译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也可以单独作为一个文件,放在独立的分区去加载,这种方式我们可以留在以后去尝试。

 

在 Kernel hacking->printk and dmesg options选项中选中第一项,这样打印的内核 log 前面会附带有时间戳信息,比较好看。

退出,保存,然后编译:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-  -j8

编译完成。

如果在编译 Linux kernel 或者 u-boot 的过程中,遇到什么错误,可以参考我之前的文章:LinuxKernel 和 U-Boot 编译的那些事。

启动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。

首先通过 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,所以对应内核的起始地址为:0x62008000

dtb 的加载地址没有特别的要求,一般注意和 Linux Kernel Image 避开,不要重叠即可。

通过 bootz 命令启动 Linux Kernel:

bootz 0x62008000 - 0x64008000

 

启动到最后输入root就可以进入命令行控制台。

到这里,我们就顺利的在 QEMU 上把 Arm linux 运行起来了。

QEMU 能否完全替代开发板?

QEMU 是一个模拟器,它和真正的开发板还是有一定的区别:

它无法完全模拟真实的硬件行为,也很难模拟一个 gpio 让你去拉高拉低或去点一个 led 灯,又或者去模拟 dram,一个 LCD 接口,让你去接一个显示屏….看起来它不能模拟的东西太多了,那它到底有什么用呢?

它的强项是模拟实现那些不涉及具体硬件外设的场景,比如:

你想快速体验一下最新的 u-boot 和 linux kernel,它拿过来就能跑。

你想在 Arm 上运行 Ubuntu、Debian 这些时髦的 Linux 发行版,用它就行。

你想研究u-boot 或者 linux kernel 的启动流程,它也很合适。我有时候在具体的开发板上移植 Linux 内核的时候,发现某个流程跑的很异常,我又不确定正常的流程是什么样的时候,我就直接拿 QEMU 来跑一下做对比。

你想了解文件系统的挂载过程,它很合适。

你想学习 Arm 汇编,完全可以在 QEMU 上跑,配合 GDB 就能单步调试啦。

你想学习 Linux 设备树,它可以拿来做实验….

再或者你想编译某个开源的项目在 Arm 开发板上运行,而交叉编译比较困难,就可以考虑直接在 QEMU 上运行一个 Arm Ubuntu 来编译,也许会简单很多。

假设你以前一直玩单片机、做硬件,也想体验下 Arm Linux 开发,用 QEMU 试试再适合不过了。用在对的场景,QEMU 就是一款召之即来的利器!

END

  推荐阅读:

    专辑|Linux文章汇总

    专辑|程序人生

    专辑|C语言

嵌入式Linux

微信扫描二维码,关注我的公众号 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/467216.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CPU怎么认识代码的?

# 语言这个东西?首先说明下,我们正常使用的python、C、C语言等等,我们自己能读得懂的语言,包括汇编语言,CPU都是不认识的,CPU 只认识一种语言,那就是 机器语言,也就是我们很多人&…

节日才需要快乐吗?

---- 当然需要天天快乐2020年的国庆和中秋是挺特别的,也是国庆,也是中秋,而且今天还能看NBA总决赛助兴。这么愉快的节日,祝我们的国家繁荣昌盛,国泰民安,也祝大家中秋快乐,当然中秋后也需要快乐…

我在富士康13年

以下是一个读者朋友的日记---- ???? 有点恨铁不成钢的感觉这个读者跟我一样的年纪,都是89年,好吧,说到这里突然觉得又马上要老一岁了,因为小云跟我说,我马上就要过生日了,我从来就记不清自己的生日&…

域名服务器的配置文档,dns域名服务器的配置

dns域名服务器的配置 内容精选换一换使用mount命令挂载文件系统到云服务器,云服务器系统提示timed out。原因1:网络状态不稳定。原因2:网络连接异常。原因3:云服务器DNS配置错误,导致解析不到文件系统的域名&#xff0…

广东阳西的小城生活

国庆放假,回小云老家,广东阳江阳西县。我们是昨天下午5点出发,晚上11点到家,刚好错开拥堵高峰,不过在沿江高速上川岛附近还是遇到了交通堵塞,一直缓缓前行,等到我们通过那个事故点的时候&#x…

10.5 0819吉米牛逼

吉米真牛逼,这场比赛热火赢得漂亮,没有阿德巴约,没有德拉季奇的情况下,吉米硬生生把自己变成了詹姆斯。右侧45度拿球,突破顶着老詹急停跳投,又一次在老詹面前拿下两分,马上回防,面对…

既生Flash,又何生EEPROM?

我们正常编译生成的二进制文件,需要下载烧录到单片机里面去,这个文件保存在单片机的ROM中,ROM这个名称指的是「read only memory」的意思,所有可以完成「read only memory」这种特性的存储介质都可以称为ROM,我们一般使…

文本或代码中 \n 和 \r 的区别

我们使用printf打印时基本都会用到 \n 和 \r 之类控制字符,比如:printf("hello world!\r\n");那你知道这些 \n 和 \r 的区别吗?# 关于「 \n 」 和「 \r 」在ASCII码中,我们会看到有一类不可显示的字符,叫控制…

中兴5G和展锐原厂芯片开发,怎么选?

最近跟一个读友聊天,谈到的还是offer选择的问题,我觉得讨论这个问题比讨论技术问题更加重要「特别是刚出校门的学生,选择一个好的行业比刚毕业的薪资重要」。当然了,肯定有人跟我说我不务正业,整天瞎BB,好的…

40张动图揭示各种传感器工作原理!

应变加速度感应器▼称重式料位计▼电子皮带秤重示意图▼电子吊车秤▼荷重传感器用于测量汽车衡的原理▼荷重传感器的应用▼TiO2氧浓度传感器结构及测量电路▼布料张力测量及控制原理▼直滑式电位器控制气缸活塞行程▼电位器式传感器▼陶瓷湿度传感器▼多孔性氧化铝湿敏电容原理…

lpad与rpad

--lpad(str, n, [pad_str])--rpad(str, n, [pad_str])-- 如果n<length(str),则显示substr(str,1,n)-- 否则&#xff0c;分别从左边和右边使用pad_str进行填充-- 其中n表示最后输出结果字符串的长度-- 如果pad_str为空&#xff0c;则用空格来填充select lpad(abc,2,#) from d…

git log 你学废了吗?

# 前言Git 是一个工具&#xff0c;用来管理代码的东西&#xff0c;要是Git 使用不好&#xff0c;确实还是挺尴尬的&#xff0c;我今晚看了个文章&#xff0c;发现Git log 是的玄机都还很多。比如这样的# git log --help如果觉得git 还不会用&#xff0c;可以看看git log --help…

别错过校招

我不是很想讨论这个问题&#xff0c;也没有想过我现在要用这个话题做文章的标题&#xff0c;这篇文是提醒准备毕业的同学们&#xff0c;校招非常重要。今天晚上&#xff0c;一个微信好友问「发哥&#xff0c;我现在研究生毕业&#xff0c;但是自己的基础非常不好&#xff0c;也…

spring集成 log4j + slf4j

以maven web项目为例&#xff0c; 首先、在pom文件引入相关依赖&#xff0c;如下&#xff08;spring官网文档有介绍&#xff09;&#xff1a; <dependencies><!-- spring 相关 --><dependency><groupId>org.springframework</groupId><artifa…

90后中国程序员“黑吃黑”博彩网站,半年获利256万,判刑11年半

一个90后程序员&#xff0c;在短短两年的时间里&#xff0c;非法控制67万台计算机&#xff0c;还利用漏洞“黑吃黑”博彩网站&#xff0c;半年从中获利256万余元……近期&#xff0c;浙江省杭州市西湖区人民法院对这起黑客大案进行了一审宣判。法院以诈骗罪、非法控制计算机信息…

用一张图片告诉你芯片设计

#推荐阅读专辑|Linux文章汇总专辑|程序人生专辑|C语言嵌入式Linux微信扫描二维码&#xff0c;关注我的公众号

【学习总结】Markdown 使用的正确姿势

参考资料&#xff1a; Learning-Markdown 入门参考 注&#xff1a;原博可能对GitHub中的Markdown格式更适用。ps&#xff1a;在王熊猫的GitHub里也有相关格式的攻略&#xff0c;可一并参考学习。关于表情的cheatsheet ? &#xff08;似乎不太好&#xff0c;哈哈&#xff09;1、…

MTK 平台TP调试遇坑

#前言最近在调试我们项目上的TP驱动&#xff0c;奈何一直不能使用&#xff0c;而且这个项目的硬件确定是没有问题的「这个是前提」&#xff0c;我们在软件上提升了SDK基线&#xff0c;在之前的基线版本上软件是没有问题的。然后我就赶紧检查了两个方面确定TP的供电是不是正常的…

51nod 1379 索函数

Fib[0]0,Fib[1]1,Fib[n]Fib[n-1]Fib[n-2] if n>1. 定义索函数Sor(n)Fib[0]| Fib[1] |Fib[2]|…|Fib[n]. 给定整数n&#xff0c;要求计算Sor(n)%1,000,000,007(1e97). Input第1行&#xff1a;给出一个整数T&#xff0c;表示有T组数据。(1<T<10000) 第2行到T1行&#xf…

昨天小米股价大涨的背后:UWB芯片到底是个什么鬼?

小米10月12日发布了“一指连”小米UWB技术。小米称该技术赋予手机与智能设备空间感知能力&#xff0c;手机指向设备即可定向操控&#xff0c;使小米在“通往未来之路上再迈一步”。来源&#xff1a;腾讯自选股受此消息利好&#xff0c;截止10月12日收盘&#xff0c;小米集团港股…