Windows 版本
下载 QEMU
官网 下载页 提供了 x64 位 Windows QEMU 下载;
下载安装时,只用选择 qemu-system-arm 即可;
接着添加安装路径 D:\Program Files\qemu
到系统全局环境变量 Path 即可;
查看支持仿真的信息
1
2
3
4
5
# 查看支持仿真的终端板(machines)
qemu-system-arm.exe -M help
# 查看支持仿真的设备(输入、显示等)
qemu-system-arm.exe -device help
仿真 mcimx6ul-evk
运行 mcimx6ul-evk(空程序)
注意这样运行没有卵用,只是看看能运行;
1
2
3
4
# 弹出 qemu 的控制台窗口(还是字符界面)
qemu-system-arm.exe -M mcimx6ul-evk
# 无图形窗口
qemu-system-arm.exe -M mcimx6ul-evk -nographic
Linux 版本
下载 QEMU 源码
官网 下载页 提供了 5.0.0 的源码;
编译 QEMU
安装依赖:
1
2
3
sudo apt install pkg-config
sudo apt install libglib2.0-dev
sudo apt install libpixman-1-dev
接下来进入源码目录,按需编译即可,直接 ./configure
会生成编译全部架构的配置,没有必要;
如下两个架构选择需要的一个即可;
1
2
3
4
# 32位arm配置
./configure --target-list=arm-softmmu --audio-drv-list=
# aarch64配置
./configure --target-list=aarch64-softmmu
进行编译(建议加 -j4
等并行编译):
1
make
生成的目标文件在 arm-softmmu/qemu-system-arm
1
2
# 链接到 bin 目录
sudo ln -sf $(pwd)/arm-softmmu/qemu-system-arm /bin/qemu-system-arm
简单验证
查看版本:
1
2
3
jerry@CLOU-PC ~ → qemu-system-arm --version
QEMU emulator version 5.0.0
Copyright (c) 2003-2020 Fabrice Bellard and the QEMU Project developers
简单运行(空程序):
1
qemu-system-arm -M vexpress-a9 -nographic
按下 Ctrl 键和 A 键,然后释放这两个键,再按 X 键即可退出 QEMU;
运行 versatilepb
PB926EJ-S 是开发板型号,主控芯片是 arm926ejs;
部分资源地址如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
Ethernet Interface FPGA PIC 25, SIC 25 0x10010000–0x1001FFFF 64KB
===
Vectored Interrupt Controller (PIC) Dev. chip - 0x10140000–0x1014FFFF 64KB
===
Timer modules 0 and 1 interface Dev. chip PIC 4 0x101E2000–0x101E2FFF 4KB
(Timer 1 starts at 0x101E2020)
Timer modules 2 and 3 interface Dev. chip PIC 5 0x101E3000–0x101E3FFF 4KB
(Timer 3 starts at 0x101E3020)
===
UART 0 Interface Dev. chip PIC 12 0x101F1000–0x101F1FFF 4KB
===
UART 1 Interface Dev. chip PIC 13 0x101F2000–0x101F2FFF 4KB
===
1.1 编写一个裸机程序
startup.S 如下:
.global _Reset
_Reset:
ldr sp, =stack_top
bl c_entry
b .
test.c 如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
volatile unsigned int *const UART0DR = (unsigned int *)0x101f1000;
void print_uart0(const char *s)
{
while (*s) {
*UART0DR = (unsigned int)(*s);
s++;
}
}
void c_entry()
{
print_uart0("Hello World\n");
}
test.lds(设置程序入口,栈起始地址等)如下:
ENTRY(_Reset)
SECTIONS
{
. = 0x10000;
.startup . : { startup.o(.text) }
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss COMMON) }
. = ALIGN(8);
. = . + 0x1000;
stack_top = .;
}
1.2 编译上面的程序
1
2
3
4
arm-linux-gnueabi-as -mcpu=arm926ej-s -g startup.S -o startup.o
arm-linux-gnueabi-gcc -c -mcpu=arm926ej-s -g test.c -o test.o
arm-linux-gnueabi-ld -T test.lds test.o startup.o -o test.elf
arm-linux-gnueabi-objcopy -O binary test.elf test.bin
1.3 使用 qemu 运行上面的程序
1
qemu-system-arm -M versatilepb -m 128M -nographic -kernel test.bin
运行 vexpress-a9
介绍
vexpress(Versatile Express Family)是 ARM 推出的开发板,主要是为了方便 SOC 厂商设计、验证和测试 SOC 芯片设计;
官网资料已丢失,建议参考 github-LKDemo 进行实验;
1. 1 下载 uboot2017.11-rc4
1.2 编译 uboot
自行下载 4.9.4编译器 arm-linux-gnueabi-
1
2
make vexpress_ca9x4_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
在 uboot 工程根目录生成了 u-boot
、u-boot.bin
等目标文件;
大概 u-boot
是 qemu 使用的,u-boot.bin
是烧写到目标终端上的;
1.3 运行 u-boot
1
2
3
4
5
qemu-system-arm \
-M vexpress-a9 \
-nographic \
-m 512M \
-kernel u-boot
仿真结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
U-Boot 2017.11-rc4 (Jul 09 2020 - 09:56:58 +0800)
DRAM: 512 MiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC: MMC: 0
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: smc911x-0
Hit any key to stop autoboot: 0
=>
=> version
U-Boot 2017.11-rc4 (Jul 09 2020 - 09:56:58 +0800)
arm-linux-gnueabi-gcc (Linaro GCC 4.9-2017.01) 4.9.4
GNU ld (Linaro_Binutils-2017.01) 2.24.0.20141017 Linaro 2014_11-3-git
=>
2.1 下载 linux-5.7.7
2.2 编译 linux
安装依赖:
1
sudo apt install flex bison
进行编译:
注意
export xxx=yyy
后不要有空格;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-
# 生成 .config 配置文件
make vexpress_defconfig
# 编译内核
make zImage
# [可选]编译模块
make modules
# 编译设备树
make dtbs
会生成 arch/arm/boot/zImage
内核文件;
会生成 arch/arm/boot/dts/vexpress-v2p-ca9.dtb
设备树文件;
3.1 下载 buildroot-2020.05
3.2 构建 rootfs
安装依赖:
1
sudo apt install unzip
图形化配置生成 .config
配置文件:
1
make menuconfig
Target options 按照以下配置:
-
Target Architecture:目标架构,这里选择 ARM(little endian),ARM小端模式;
-
Target Binary Format:二进制格式为 ELF;
-
Target Architecture Variant:架构体为 cortex-A9;
-
Target ABI:应用程序二进制接口,为EABI;
-
Floating point strategy:浮点数的策略,选择为 Soft float;
注意 qemu 仿真都需要选软浮点;
非仿真情况下,如终端支持硬浮点,就选择硬浮点;
-
ARM instruction set:arm 汇编指令集,选择 ARM;
Build options 是下载和编译用到的选项,一般默认就好;
Toolchain 是工具链选项:
- Toolchain type:编译工具链选择
external toolthain
; - Toolchain:选择
Custom toolchain
; - Toolchain origin:选择
Pre-installed toolchain
; - Toolchain path:填入
/home/jerry/public/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi
,也就是交叉编译器所在根文件夹; - Toolchain prefix:填入
$(ARCH)-linux-gnueabi
; - External toolchain gcc version 选择交叉编译工具的 gcc 版本;
- External toolchain kernel headers series 百度教你选择,也可随便选择,报错后会提示正确的版本;
- External toolchain C library:选择 glibc/eglibc;
- Toolchain has SSP support? 一般选 glibc 后自动勾选。如未请手动勾选,否则 glibc 报错;
System configuration 是文件系统设置项:
-
Root FS skeleton 默认即可;
-
System hostname:填写
myhost
; -
System banner:填写
Welcome to jerry's host
; -
Init system:填写
BusyBox
;各个初始化系统的区别看:这篇文章;
-
/dev management:选择
Dynamic using devtmpfs + eudev
;mdev 和 eudev 区别请百度,也建议先百度一下再选适合的;
-
Path to the permission tables:一定填写
system/device_table_dev.txt
; -
Root password:是 root 账户的密码。默认登录 root 账户,如果为空,那么登录就不需要密码;
-
Run a getty (login prompt) after boot:
-
TTY port:配置为 ttyAMA0
这个需要确定调试串口在 kernel 上对应的设备节点;
vexpress-a9 默认是 ttyAMA0;
-
Baudrate:配置为 115200
-
Filesystem images 文件系统镜像相关设置项:
- ext2/3/4 root filesystem:选择 ext3;
以上完成后,进行编译:
1
make
- 编译后生成 tar 文件:
output/image/rootfs.tar
(默认配置了 tar 打包,可自行二次打包) - 编译后生成 ext3 文件:
output/image/rootfs.ext3
(QEMU 仿真的目标文件系统镜像)
4. 运行 kernel + 文件系统
先将 zImage、vexpress-v2p-ca9.dtb、rootfs.ext3 拷贝到同一目录,接着执行以下命令运行 kernel + 文件系统(SD卡):
1
2
3
4
5
6
7
8
qemu-system-arm \
-nographic \
-M vexpress-a9 \
-m 512M \
-kernel zImage \
-dtb vexpress-v2p-ca9.dtb \
-sd rootfs.ext3 \
-append "root=/dev/mmcblk0 rw console=ttyAMA0"
运行成功的结果:
1
2
3
4
5
6
Welcome to jerry's host
myhost login: root
Password:
#
# pwd
/root
5. 运行 kernel + ramfs
让我们制作最简 ramfs 镜像:
-
创建 hello.c 文件
1 2 3 4 5 6 7 8
#include <stdio.h> void main(){ printf("================\n"); printf("Hello ramfs\n"); printf("================\n"); fflush(stdout); while(1); }
-
静态编译 hello.c
1
arm-linux-gnueabi-gcc hello.c -o hello -static
-
创建 ramfs 镜像文件 —— rootfs
给 cpio 传递文件名打包到 rootfs 中;
如果需要文件夹打包,可用:
find . | cpio -o --format=newc > rootfs
1
echo ./hello | cpio -o --format=newc > rootfs
接着将 zImage、vexpress-v2p-ca9.dtb、rootfs 拷贝到同一目录,然后执行以下命令运行 kernel + ramfs:
其中
-initrd
用于指定 ramfs 镜像文件,qemu 会自动将系统拷贝到内存中(对应设备 /dev/ram0 或者 /dev/ram);
-append
中的rdinit
指定初始程序,如果没有指定默认会去找/init
;
1
2
3
4
5
6
7
8
qemu-system-arm \
-nographic \
-M vexpress-a9 \
-m 512M \
-kernel zImage \
-dtb vexpress-v2p-ca9.dtb \
-initrd rootfs \
-append "root=/dev/ram rdinit=/hello console=ttyAMA0"
运行成功的结果:
1
2
3
4
Run /hello as init process
================
Hello ramfs
================
chroot+qemu-user-static 仿真各平台程序
安装 qemu-user-static
1
sudo apt install qemu-user-static
1.1 创建 hello.c 文件
1
2
3
4
5
6
7
8
#include <stdio.h>
void main(){
printf("================\n");
printf("Hello\n");
printf("================\n");
fflush(stdout);
while(1);
}
1.2 调试 x86_64 版本的 hello
编译 hello.c 为 x86_64 版本
1
gcc -g hello.c -o hello
使用 chroot+qemu-x86_64-static 调试 hello,其中 gdbserver 的端口是 1234;
1
2
3
4
cp /usr/bin/qemu-x86_64-static .
# 下面的命令怎么看:sudo chroot <dir> <cmd...>
# 制作 rootfs 时常用的命令:sudo chroot <rootfs_dir> ./usr/bin/bash 进入根文件系统用 apt 安装软件包
sudo chroot . ./qemu-x86_64-static -g 1234 ./hello
接着使用 gdb 调试 hello:
1
2
3
4
gdb hello
(gdb) target remote :1234
(gdb) b main
(gdb) r
1.3 调试 arm 版本的 hello
编译 hello.c 为 arm 版本
1
arm-linux-gnueabi-gcc hello.c -o hello
使用 chroot+qemu-arm-static 调试 hello,其中 gdbserver 的端口是 1234;
1
2
3
cp /usr/bin/qemu-arm-static .
# 下面的命令怎么看:sudo chroot <dir> <cmd...>
sudo chroot . ./qemu-arm-static -g 1234 ./hello
接着使用 arm-linux-gnueabi-gdb 调试 hello:
1
2
3
4
arm-linux-gnueabi-gdb hello
(gdb) target remote :1234
(gdb) b main
(gdb) r