Qemu模拟ARM

Sunmy Lv5

Qemu是一款开源免费的仿真软件,跟VMware station类似,可以仿真一台虚拟的电脑,然后在这个电脑上安装各种操作系统、运行各种应用程序。Qemu和VMware station不同的是,除了可以仿真一台电脑外,它还支持仿真一系列嵌入式开发板(支持ARM、MIPS、RISC-V等各种架构),模拟的开发板支持各种外设:串口、LCD、网卡、USB、SD卡等,可以在这个开发板上运行U-boot+Linux+Rootfs。对于缺少开发板学习嵌入式、研究U-boot、Linux内核的朋友,可以考虑使用qemu来搭建一块虚拟的开发板,方便快捷、经济实惠

环境搭建

开发环境介绍

名称 版本 工具包
操作系统 Ubuntu2204
Qemu 6.2.0
交叉编译工具链 11.4.0
Linux内核 5.10.186
U-boot 2022.07-rc3
busybox 1.36.1

Ubuntu22.0切换软件源

1
2
3
4
5
6
7
8
9
10
11
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
sudo vi /etc/apt/sources.list

# 将sources.list替换为以下内容
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse

# 更新软件源列表并升级已安装的软件包
sudo apt update

配置安装交叉编译环境

1
2
3
sudo apt install -y gcc-arm-linux-gnueabi
sudo apt install -y g++-arm-linux-gnueabi
sudo apt install -y build-essential openssh-server vim net-tools flex bison libncurses-dev libssl-dev u-boot-tools

搭建qemu运行环境

1
2
3
4
5
6
7
8
9
10
11
12
# qemu依赖包
sudo apt-get -y install zlib1g-dev
sudo apt-get -y install libglib2.0-0
sudo apt-get -y install libglib2.0-dev
sudo apt-get -y install libtool
sudo apt-get -y install libsdl1.2-dev
sudo apt-get -y install libpixman-1-0
sudo apt-get -y install libpixman-1-dev
sudo apt-get -y install autoconf

# 安装qemu
sudo apt install -y qemu-system

检查环境搭建是否成功

交叉编译工具链

1
2
3
4
5
6
7
8
9
10
sun@ldspdvs:~$ arm-linux-gnueabi-gcc -v
Using built-in specs.
COLLECT_GCC=arm-linux-gnueabi-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/arm-linux-gnueabi/11/lto-wrapper
Target: arm-linux-gnueabi
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 11.4.0-1ubuntu1~22.04' --with-bugurl=file:///usr/share/doc/gcc-11/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-11 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --disable-libquadmath-support --enable-plugin --with-system-zlib --enable-libphobos-checking=release --without-target-system-zlib --enable-multiarch --disable-sjlj-exceptions --with-specs='%{mfloat-abi=hard:-march=armv7-a -mcpu=generic-armv7-a -mfloat-abi=hard}' --with-arch=armv5t --with-float=soft --disable-werror --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=arm-linux-gnueabi --program-prefix=arm-linux-gnueabi- --includedir=/usr/arm-linux-gnueabi/include --with-build-config=bootstrap-lto-lean --enable-link-serialization=2
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)
sun@ldspdvs:~$

虚拟开发板QEMU

1
2
3
4
sun@ldspdvs:~$ qemu-system-arm --version
QEMU emulator version 6.2.0 (Debian 1:6.2+dfsg-2ubuntu6.16)
Copyright (c) 2003-2021 Fabrice Bellard and the QEMU Project developers
sun@ldspdvs:~$

编译Linux内核

建立workspace工作空间

1
sudo mkdir -p /home/workspace/objects

获取Linux内核源码

1
2
cd /home/workspace
sudo wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.186.tar.xz

解压Linux内核源码

1
sudo tar -xvf linux-5.10.186.tar.xz

编译Linux内核源码

进入源码根目录

1
cd linux-5.10.191

创建automake_arm32.sh(笔者的电脑是12核CPU所以采用-j12进行编译,读者编译过程中可根据实际情况进行调整)

1
2
3
4
5
6
7
8
9
sun@ldspdvs:/home/workspace/linux-5.10.186$ sudo touch automake_arm32.sh
sun@ldspdvs:/home/workspace/linux-5.10.186$ sudo chmod 777 automake_arm32.sh
sun@ldspdvs:/home/workspace/linux-5.10.186$ vim automake_arm32.sh

# 在automake_arm32.sh中填入以下内容
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- vexpress_defconfig O=../objects/vexpress-v2p-ca9
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig O=../objects/vexpress-v2p-ca9
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j12 O=../objects/vexpress-v2p-ca9
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- LOADADDR=0x60003000 uImage -j12 O=../objects/vexpress-v2p-ca9

运行automake_arm32.sh编译

1
./automake_arm32.sh

编译过程可能出现以下界面,即menuconfig,目前阶段不关注,按两下Esc退出这个界面继续编译即可

image.png

在Qemu试运行Linux内核源码

进入objects目录

1
cd /home/workspace/objects

创建qemu-start-vexpress-a9.sh

1
2
3
4
5
6
7
8
9
10
sun@ldspdvs:/home/workspace/objects$ sudo touch qemu-start-vexpress-a9.sh
sun@ldspdvs:/home/workspace/objects$ sudo chmod 777 qemu-start-vexpress-a9.sh
sun@ldspdvs:/home/workspace/objects$ vim qemu-start-vexpress-a9.sh

#! /bin/sh
qemu-system-arm -M vexpress-a9 \
-m 512M \
-kernel vexpress-v2p-ca9/arch/arm/boot/zImage \
-dtb vexpress-v2p-ca9/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
-nographic

Linux内核启动过程会打印大量信息,最后因为没挂载根文件系统导致

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.10.186 #7
Hardware name: ARM-Versatile Express
[<8010f264>] (unwind_backtrace) from [<8010afb4>] (show_stack+0x10/0x14)
[<8010afb4>] (show_stack) from [<80881254>] (dump_stack+0x94/0xa8)
[<80881254>] (dump_stack) from [<8087d0b4>] (panic+0x124/0x32c)
[<8087d0b4>] (panic) from [<80b017a8>] (mount_block_root+0x1e8/0x26c)
[<80b017a8>] (mount_block_root) from [<80b01aec>] (prepare_namespace+0x150/0x18c)
[<80b01aec>] (prepare_namespace) from [<80885f8c>] (kernel_init+0x8/0x118)
[<80885f8c>] (kernel_init) from [<80100148>] (ret_from_fork+0x14/0x2c)
Exception stack(0x810b9fb0 to 0x810b9ff8)
9fa0: 00000000 00000000 00000000 00000000
9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
9fe0: 00000000 00000000 00000000 00000000 00000013 00000000
---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) ]---

挂载根文件系统

文件系统首先是内核启动时所mount的第一个文件系统,内核代码映像文件保存在根文件系统中,而系统引导启动程序会在根文件系统挂载之后从中把一些基本的初始化脚本和服务等加载到内存中去运行。本节将介绍如何编译和制作Linux最小系统的根文件系统,并通过sd卡或者nfs挂载根文件系统。

编译、安装根文件系统

下载并解压busybox源码

1
2
3
cd /home/workspace
sudo wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
sudo tar -xvf busybox-1.36.1.tar.bz2

自动编译脚本

制作automake_arm32.sh自动编译脚本

1
2
3
4
5
6
7
8
9
10
11
12
cd busybox-1.36.1
sun@ldspdvs:/home/workspace/busybox-1.36.1$ sudo touch automake_arm32.sh
sun@ldspdvs:/home/workspace/busybox-1.36.1$ sudo chmod 777 automake_arm32.sh
sun@ldspdvs:/home/workspace/busybox-1.36.1$ vim automake_arm32.sh


# 在automake_arm32.sh中添加下列代码
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- clean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j12
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- CONFIG_PREFIX=../objects/rootfs-arm32 install

编译过程中会出现menuconfig界面,需要将“Settings->Build Options->Build static binary”选上

image-1.png

补充根文件夹系统

busybox编译完成后,只是初步具有了维持linux操作系统基本运行所需的可执行文件,还有设备节点、动态链接库、引导启动相关代码、用户相关信息等,需要根据开发板自身的特性做定制和适配,接下来将适配vexpress-a9开发板补充根文件系统相关内容

进入根文件系统目录

1
cd /home/workspace/objects/rootfs-arm32

创建设备节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sun@ldspdvs:/home/workspace/objects/rootfs-arm32$ sudo mkdir dev
sun@ldspdvs:/home/workspace/objects/rootfs-arm32$ sudo mknod -m 666 dev/tty1 c 4 1
sudo mknod -m 666 dev/tty2 c 4 2
sudo mknod -m 666 dev/tty3 c 4 3
sudo mknod -m 666 dev/tty4 c 4 4
sudo mknod -m 666 dev/console c 5 1
sudo mknod -m 666 dev/null c 1 3
sun@ldspdvs:/home/workspace/objects/rootfs-arm32$ ll dev
总计 8
drwxr-xr-x 2 root root 4096 1月 21 23:12 ./
drwxr-xr-x 6 root root 4096 1月 21 23:12 ../
crw-rw-rw- 1 root root 5, 1 1月 21 23:12 console
crw-rw-rw- 1 root root 1, 3 1月 21 23:12 null
crw-rw-rw- 1 root root 4, 1 1月 21 23:12 tty1
crw-rw-rw- 1 root root 4, 2 1月 21 23:12 tty2
crw-rw-rw- 1 root root 4, 3 1月 21 23:12 tty3
crw-rw-rw- 1 root root 4, 4 1月 21 23:12 tty4
sun@ldspdvs:/home/workspace/objects/rootfs-arm32$

安装动态链接库

1
2
sun@ldspdvs:/home/workspace/objects/rootfs-arm32$ sudo mkdir lib
sun@ldspdvs:/home/workspace/objects/rootfs-arm32$ sudo cp -d /usr/arm-linux-gnueabi/lib/*.so* ./lib

配置初始化进程rcS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
sudo mkdir -p etc/init.d
sudo touch etc/init.d/rcS
sudo chmod 777 etc/init.d/rcS
vim etc/init.d/rcS

# 在rcS中填入以下内容
#!/bin/sh
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export LD_LIBRARY_PATH=/lib:/usr/lib
/bin/mount -n -t ramfs ramfs /var
/bin/mount -n -t ramfs ramfs /tmp
/bin/mount -n -t sysfs none /sys
/bin/mount -n -t ramfs none /dev
/bin/mkdir /var/tmp
/bin/mkdir /var/modules
/bin/mkdir /var/run
/bin/mkdir /var/log
/bin/mkdir -p /dev/pts
/bin/mkdir -p /dev/shm
/sbin/mdev -s
/bin/mount -a
echo "-----------------------------------"
echo "*****welcome to vexpress board*****"
echo "-----------------------------------"

配置文件系统fstab

1
2
3
4
5
6
7
8
9
10
11
12
13
14
sudo touch etc/fstab
sudo chmod 777 etc/fstab
vim etc/fstab

# 在fstab中填入以下内容
proc /proc proc defaults 0 0
none /dev/pts devpts mode=0622 0 0
mdev /dev ramfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev/shm tmpfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
tmpfs /mnt tmpfs defaults 0 0
var /dev tmpfs defaults 0 0
ramfs /dev ramfs defaults 0 0

配置初始化脚本

1
2
3
4
5
6
7
8
9
10
sudo touch etc/inittab
sudo chmod 777 etc/inittab
vim etc/inittab

# 在inittab中输入以下内容
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r

配置环境变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sudo touch etc/profile
sudo chmod 777 etc/profile
vim etc/profile

# 在profile中添加以下内容
#!/bin/sh
USER="root"
LOGNAME=$USER
# export HOSTNAME=vexpress-a9
export HOSTNAME=`cat /etc/sysconfig/HOSTNAME`
export USER=root
export HOME=root
export PS1="[$USER@$HOSTNAME:\w]\#"
PATH=/bin:/sbin:/usr/bin:/usr/sbin
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
export PATH LD_LIBRARY_PATH

增加主机名

1
2
3
4
5
6
sudo mkdir etc/sysconfig
sudo chmod 777 etc/sysconfig
vim etc/sysconfig/HOSTNAME

# 在HOSTNAME中添加以下内容
vexpress-a9

创建其他文件夹

1
sudo mkdir mnt proc root sys tmp var

查看创建的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sun@ldspdvs:/home/workspace/objects/rootfs-arm32$ ll
总计 56
drwxr-xr-x 14 root root 4096 1月 21 23:24 ./
drwxr-xr-x 4 root root 4096 1月 21 23:09 ../
drwxr-xr-x 2 root root 4096 1月 21 23:09 bin/
drwxr-xr-x 2 root root 4096 1月 21 23:12 dev/
drwxr-xr-x 4 root root 4096 1月 21 23:23 etc/
drwxr-xr-x 2 root root 4096 1月 21 23:14 lib/
lrwxrwxrwx 1 root root 11 1月 21 23:09 linuxrc -> bin/busybox*
drwxr-xr-x 2 root root 4096 1月 21 23:24 mnt/
drwxr-xr-x 2 root root 4096 1月 21 23:24 proc/
drwxr-xr-x 2 root root 4096 1月 21 23:24 root/
drwxr-xr-x 2 root root 4096 1月 21 23:09 sbin/
drwxr-xr-x 2 root root 4096 1月 21 23:24 sys/
drwxr-xr-x 2 root root 4096 1月 21 23:24 tmp/
drwxr-xr-x 4 root root 4096 1月 21 23:09 usr/
drwxr-xr-x 2 root root 4096 1月 21 23:24 var/
sun@ldspdvs:/home/workspace/objects/rootfs-arm32$

通过SD卡挂载根文件系统

自动打包脚本

编译安装完成后,进入object目录,并制作自动打包脚本makefs-arm32.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cd /home/workspace/objects
sudo mkdir /mnt/rootfs
sudo chmod 777 /mnt/rootfs

sudo touch makefs-arm32.sh
sudo chmod 777 makefs-arm32.sh
vim makefs-arm32.sh

# 在makefs-arm32.sh中添加下列代码
dd if=/dev/zero of=rootfs-arm32.ext3 bs=1M count=64
mkfs.ext3 rootfs-arm32.ext3
sudo mount -t ext3 rootfs-arm32.ext3 /mnt/rootfs -o loop
sudo cp -rf rootfs-arm32/* /mnt/rootfs/
sudo umount /mnt/rootfs/

运行自动打包脚本makefs-arm32.sh,运行完成后将在objects目录下生成一个rootfs-arm32.ext3文件,将作为外设sd卡加入到开发板上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
sun@ldspdvs:/home/workspace/objects$ ll
总计 20
drwxr-xr-x 4 root root 4096 1月 21 23:31 ./
drwxr-xr-x 5 root root 4096 1月 21 23:04 ../
-rwxrwxrwx 1 root root 202 1月 21 23:32 makefs-arm32.sh*
drwxr-xr-x 14 root root 4096 1月 21 23:24 rootfs-arm32/
drwxr-xr-x 21 root root 4096 1月 21 22:57 vexpress-v2p-ca9/
sun@ldspdvs:/home/workspace/objects$ sudo ./makefs-arm32.sh
记录了64+0 的读入
记录了64+0 的写出
67108864字节(67 MB,64 MiB)已复制,0.0487807 s,1.4 GB/s
mke2fs 1.46.5 (30-Dec-2021)
丢弃设备块: 完成
创建含有 16384 个块(每块 4k)和 16384 个 inode 的文件系统

正在分配组表: 完成
正在写入 inode表: 完成
创建日志(1024 个块): 完成
写入超级块和文件系统账户统计信息: 已完成

sun@ldspdvs:/home/workspace/objects$ sudo chmod 777 rootfs-arm32.ext3
sun@ldspdvs:/home/workspace/objects$ ll
总计 21108
drwxr-xr-x 4 root root 4096 1月 21 23:34 ./
drwxr-xr-x 5 root root 4096 1月 21 23:04 ../
-rwxrwxrwx 1 root root 202 1月 21 23:32 makefs-arm32.sh*
drwxr-xr-x 14 root root 4096 1月 21 23:24 rootfs-arm32/
-rwxrwxrwx 1 root root 67108864 1月 21 23:34 rootfs-arm32.ext3*
drwxr-xr-x 21 root root 4096 1月 21 22:57 vexpress-v2p-ca9/
sun@ldspdvs:/home/workspace/objects$

挂载根文件系统

修改qemu-start-vexpress-a9.sh

1
2
3
4
5
6
7
8
9
10
11
sun@ldspdvs:/home/workspace/objects$ vim qemu-start-vexpress-a9.sh 

# 将qemu-start-vexpress-a9.sh修改为以下内容
#! /bin/sh
qemu-system-arm -M vexpress-a9 \
-m 512M \
-kernel vexpress-v2p-ca9/arch/arm/boot/zImage \
-dtb vexpress-v2p-ca9/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
-nographic \
-append "root=/dev/mmcblk0 rw console=ttyAMA0" \
-sd rootfs-arm32.ext3

出现下述内容代表启动成功

image-3.png

通过NFS挂载根文件系统

在进行软件调试的过程中,我们经常需与开发板交换文件,或者直接修改板子上的配置文件,如果使用SD卡挂载根文件系统,则每次进行文件交换都需要重启操作系统。为了提高开发效率,我们可以通过NFS共享主机上的根文件系统给开发板,实现在主机上修改完善代码并编译后,直接在开发板上运行,无缝对接。

安装NFS服务器

安装

1
sudo apt install -y nfs-kernel-server

配置

1
2
3
4
5
6
7
8
sudo mkdir -p /sync/rootfs
sudo chmod 777 /etc/exports
sudo vim /etc/exports

# 在/etc/exports文件中添加以下内容
/sync/rootfs *(rw,sync,no_root_squash,no_subtree_check)

# !!!注意上述内容应严格按照格式输入,不能随意增减空格!!!

重启NFS服务器

1
2
sudo /etc/init.d/rpcbind restart
sudo /etc/init.d/nfs-kernel-server restart

将安装好的根文件系统拷贝到/sync/rootfs内

1
2
3
cd /home/workspace/objects/rootfs-arm32
sudo cp -rf * /sync/rootfs/
sudo chmod 777 -R /sync/rootfs

内核NFS兼容问题

为解决Linux内核与NFS服务器的兼容问题,目前有两种方案供读者参考,实在不行可以把两种都用上

重新编译内核,并在menuconfig下开启NFS4支持

位置:File System -> Network File Systems->NFS client support for NFS version 4

设置Ubuntu2204,使之兼容NFS-V2和NFS-V3并增加调试功能

1
2
3
4
5
6
7
8
9
sudo vim /etc/default/nfs-kernel-server

# 将nfs-kernel-server文件内的RPCSVCGSSDOPTS属性修改如下:
RPCSVCGSSDOPTS="--nfs-version 2,3,4 --debug --syslog"


# 修改后重启NFS服务器
sudo /etc/init.d/rpcbind restart
sudo /etc/init.d/nfs-kernel-server restart

测试NFS挂载根文件系统

配置主机网桥(其中eth0是Ubuntu系统的网卡,根据实际调整)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
sudo apt install -y uml-utilities bridge-utils

sudo vim /etc/network/interfaces

# 修改interfaces文件如下
auto lo
iface lo inet loopback

auto eth0

auto br0
iface br0 inet dhcp
bridge_ports eth0
====================================================================================
sun@ldspdvs:/home/workspace/objects/rootfs-arm32$ ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.58.146 netmask 255.255.255.0 broadcast 192.168.58.255
inet6 fe80::d763:3d05:1073:739c prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:f3:7c:aa txqueuelen 1000 (以太网)
RX packets 272895 bytes 394360550 (394.3 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 14324 bytes 1257519 (1.2 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (本地环回)
RX packets 464 bytes 44975 (44.9 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 464 bytes 44975 (44.9 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

sun@ldspdvs:/home/workspace/objects/rootfs-arm32$ sudo vim /etc/network/interfaces
sun@ldspdvs:/home/workspace/objects/rootfs-arm32$ cat /etc/network/interfaces
auto lo
iface lo inet loopback

auto ens33

auto br0
iface br0 inet dhcp
bridge_ports ens33
sun@ldspdvs:/home/workspace/objects/rootfs-arm32$

创建tap0网卡,用于连接qemu虚拟开发板

1
2
sudo tunctl -u root -t tap0
sudo ifconfig tap0 172.16.16.10 promisc up

创建qemu-start-vexpress-a9-nfs.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cd /home/workspace/objects
sudo touch qemu-start-vexpress-a9-nfs.sh
sudo chmod 777 qemu-start-vexpress-a9-nfs.sh
vim qemu-start-vexpress-a9-nfs.sh

# 在qemu-start-vexpress-a9-nfs.sh内添加以下内容
sudo qemu-system-arm \
-M vexpress-a9 \
-m 512M \
-kernel vexpress-v2p-ca9/arch/arm/boot/zImage \
-dtb vexpress-v2p-ca9/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
-net tap,ifname=tap0,script=no,downscript=no \
-net nic,macaddr=00:16:3e:00:00:01 \
-nographic \
-append "root=/dev/nfs rw nfsroot=172.16.16.10:/sync/rootfs,proto=tcp,nfsvers=3,nolock init=/linuxrc console=ttyAMA0 ip=172.16.16.20" \


sun@ldspdvs:/home/workspace/objects$ sudo ./qemu-start-vexpress-a9-nfs.sh

启动成功后如下所示

image-2.png

通过U-boot引导加载内核

编译安装U-boot

下载解压U-boot源码

1
2
3
cd /home/workspace
wget https://ftp.denx.de/pub/u-boot/u-boot-2022.07-rc3.tar.bz2
tar -xvf u-boot-2022.07-rc3.tar.bz2

制作automake_arm32.sh

1
2
3
4
5
6
7
8
9
10
cd u-boot-2022.07-rc3
vim automake_arm32.sh

# 在automake_arm32.sh中添加下列代码
# !/bin/bash
# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- clean
# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- mrproper
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- vexpress_ca9x4_defconfig O=../objects/u-boot-arm
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig O=../objects/u-boot-arm
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j12 O=../objects/u-boot-arm

运行automake_arm32.sh编译安装U-Boot

1
./automake_arm32.sh

出现下述内容证明U-Boot编译完毕

7.png

配置主机tftp服务器

安装tftp服务器

1
sudo apt-get install tftp-hpa tftpd-hpa xinetd

配置tftp路径文件

1
2
3
4
5
6
7
8
9
10
sudo mkdir -p /sync/tftp
sudo chmod 777 /sync/tftp
sudo touch /etc/default/tftpd-hpa
sudo vim /etc/default/tftpd-hpa

# 在tftpd-hpa文件下添加以下内容
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/sync/tftp" #该路径即为tftp可以访问到的路径
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"

重启tftp服务器

1
sudo /etc/init.d/tftpd-hpa restart

系统开机自动tftp服务

1
2
3
4
systemctl enable tftpd-hpa.service
tftpd-hpa.service is not a native service, redirecting to systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable tftpd-hpa
jcrj@SQA-JCRJ-01:~/qemu_arm_a9/workspace/u-boot-2022.07-rc3$

将设备树和Linux内核文件拷贝到tftp目录下

1
2
3
cd /home/workspace/objects
sudo cp vexpress-v2p-ca9/arch/arm/boot/dts/vexpress-v2p-ca9.dtb /sync/tftp/
sudo cp vexpress-v2p-ca9/arch/arm/boot/uImage /sync/tftp/

虚拟主机网络配置,创建tap0网卡,用于连接qemu虚拟开发板

此处已在测试NFS挂载根文件系统中设置过

1
2
sudo tunctl -u root -t tap0
sudo ifconfig tap0 172.16.16.10 promisc up

试运行U-boot

创建qemu-start-uboot-arm32-uboot-manual.sh脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
cd /home/workspace/objects
sudo touch qemu-start-uboot-arm32-uboot-manual.sh
sudo chmod 777 qemu-start-uboot-arm32-uboot-manual.sh
vim qemu-start-uboot-arm32-uboot-manual.sh

# 在qemu-start-uboot-arm32.sh内添加以下代码
sudo qemu-system-arm \
-M vexpress-a9 \
-m 512M \
-kernel u-boot-arm/u-boot \
-net tap,ifname=tap0,script=no,downscript=no \
-net nic,macaddr=00:16:3e:00:00:01 \
-nographic \

运行脚本

1
./qemu-start-uboot-arm32.sh

出现以下界面,说明运行成功(注意在Hit any key to stop autoboot出现时按任意键进入命令行)

8.png

在U-Boot命令行下输入以下代码,尝试引导内核

1
2
3
4
5
6
7
8
9
setenv bootargs 'root=/dev/nfs rw nfsroot=172.16.16.10:/sync/rootfs,proto=tcp,nfsvers=3,nolock init=/linuxrc console=ttyAMA0 ip=172.16.16.20'
setenv ipaddr 172.16.16.20
setenv serverip 172.16.16.10
setenv netmask 255.255.0.0
saveenv

tftp 60003000 uImage
tftp 60500000 vexpress-v2p-ca9.dtb
bootm 60003000 - 60500000

实际

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
jcrj@SQA-JCRJ-01:~/qemu_arm_a9/workspace/objects$ sudo ./qemu-start-uboot-arm32-uboot-manual.sh 


U-Boot 2022.07-rc3 (Jan 22 2024 - 13:51:57 +0800)

DRAM: 512 MiB
WARNING: Caches not enabled
Core: 19 devices, 10 uclasses, devicetree: embed
Flash: 64 MiB
MMC: mmci@5000: 0
Loading Environment from Flash... *** Warning - bad CRC, using default environment

In: serial
Out: serial
Err: serial
Net: eth0: ethernet@3,02000000
Hit any key to stop autoboot: 0
=> setenv bootargs 'root=/dev/nfs rw nfsroot=172.16.16.10:/sync/rootfs,proto=tcp,nfsvers=3,nolock init=/linuxrc console=ttyAMA0 ip=172.16.16.20'
=> setenv ipaddr 172.16.16.20
=> setenv serverip 172.16.16.10
=> setenv netmask 255.255.0.0
=> saveenv
Saving Environment to Flash... Error: start and/or end address not on sector boundary
Error: start and/or end address not on sector boundary
Failed (1)
=>
=>
=> tftp 60003000 uImage
smc911x: detected LAN9118 controller
smc911x: phy initialized
smc911x: MAC 00:16:3e:00:00:01
Using ethernet@3,02000000 device
TFTP from server 172.16.16.10; our IP address is 172.16.16.20
Filename 'uImage'.
Load address: 0x60003000
Loading: #################################################################
#################################################################
#################################################################
#################################################################
#################################################################
########
27.6 MiB/s
done
Bytes transferred = 4886088 (4a8e48 hex)
smc911x: MAC 00:16:3e:00:00:01
=> tftp 60500000 vexpress-v2p-ca9.dtb
smc911x: detected LAN9118 controller
smc911x: phy initialized
smc911x: MAC 00:16:3e:00:00:01
Using ethernet@3,02000000 device
TFTP from server 172.16.16.10; our IP address is 172.16.16.20
Filename 'vexpress-v2p-ca9.dtb'.
Load address: 0x60500000
Loading: #
6.8 MiB/s
done
Bytes transferred = 14171 (375b hex)
smc911x: MAC 00:16:3e:00:00:01
=> bootm 60003000 - 60500000
## Booting kernel from Legacy Image at 60003000 ...
Image Name: Linux-5.10.186
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 4886024 Bytes = 4.7 MiB
Load Address: 60003000
Entry Point: 60003000
Verifying Checksum ... OK
## Flattened Device Tree blob at 60500000
Booting using the fdt blob at 0x60500000
Loading Kernel Image
Loading Device Tree to 7fb1d000, end 7fb2375a ... OK

Starting kernel ...

Booting Linux on physical CPU 0x0
Linux version 5.10.186 (jcrj@SQA-JCRJ-01) (arm-linux-gnueabi-gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #3 SMP Mon Jan 22 13:46:34 CST 2024
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
OF: fdt: Ignoring memory block 0x80000000 - 0x80000004
........
........
Freeing unused kernel memory: 1024K
Run /linuxrc as init process
-----------------------------------
*****welcome to vexpress board*****
-----------------------------------
device eth0 entered promiscuous mode

Please press Enter to activate this console.
[root@vexpress-a9:/]#

出现下面界面证明引导成功

6.png

固化U-boot环境变量

在试运行过程中,需要输入代码修改U-boot的环境变量,如果每次启动都需要如此,则太过麻烦。真实开发板由于内置了NAND/MMC Flash,修改后的环境变量可以使用saveenv保存下来,但是我们这部分还没有把NAND/MMC相关支持完全做好。因此需要在U-boot源码上做一些修改,将环境变量固化下来。

修改配置文件

1
2
3
4
5
cd /home/workspace/u-boot-2022.07-rc3
vim configs/vexpress_ca9x4_defconfig

# 将CONFIG_BOOTCOMMAND的值修改为:
CONFIG_BOOTCOMMAND="tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb;setenv bootargs 'root=/dev/nfs rw nfsroot=172.16.16.10:/sync/rootfs,proto=tcp,nfsvers=3,nolock init=/linuxrc ip=172.16.16.20 console=ttyAMA0';bootm 0x60003000 - 0x60500000;"

修改后如下所示

9.png

修改头文件

// 在vexpress_common.h文件末尾#endif之前添加以下代码:

1
2
3
4
5
6
vim include/configs/vexpress_common.h

// 在vexpress_common.h文件末尾#endif之前添加以下代码:
#define CONFIG_IPADDR 172.16.16.20
#define CONFIG_NETMASK 255.255.0.0
#define CONFIG_SERVERIP 172.16.16.10
1
2
3
4
5
6
7
8
9
10
11
12
jcrj@SQA-JCRJ-01:~/qemu_arm_a9/workspace/u-boot-2022.07-rc3$ pwd
/home/jcrj/qemu_arm_a9/workspace/u-boot-2022.07-rc3
jcrj@SQA-JCRJ-01:~/qemu_arm_a9/workspace/u-boot-2022.07-rc3$ vim include/configs/vexpress_common.h
jcrj@SQA-JCRJ-01:~/qemu_arm_a9/workspace/u-boot-2022.07-rc3$
jcrj@SQA-JCRJ-01:~/qemu_arm_a9/workspace/u-boot-2022.07-rc3$ tail -6 include/configs/vexpress_common.h
/* Net Settings */
#define CONFIG_IPADDR 172.16.16.20
#define CONFIG_NETMASK 255.255.0.0
#define CONFIG_SERVERIP 172.16.16.10

#endif /* VEXPRESS_COMMON_H */
jcrj@SQA-JCRJ-01:~/qemu_arm_a9/workspace/u-boot-2022.07-rc3$

重新编译U-Boot

1
2
cd /home/workspace/u-boot-2022.07-rc3
./automake_arm32.sh

编译完成后,进入Objects目录运行U-boot

1
2
cd /home/workspace/objects
./qemu-start-uboot-arm32.sh

运行结果应该与手动引导一致

其他辅助优化功能

虚拟开发板连接互联网

修改rootfs根文件系统

进入根文件系统目录

1
cd /home/workspace/objects/rootfs-arm32

开发板指定DNS服务器

1
2
3
4
5
6
touch etc/resolv.conf
chmod 777 etc/resolv.conf
vim etc/resolv.conf

# 在resolv.conf文件内添加以下内容
nameserver 114.114.114.114

开发板初始化规则配置

1
2
3
4
5
vim etc/init.d/rcS

# 在rcS文件末尾添加以下内容
ifconfig eth0 172.16.16.20 promisc up
route add default gw 172.16.16.10 dev eth0

将修改后的根文件系统拷贝到 /sync/rootfs内

1
2
3
cd /home/workspace/objects/rootfs-arm32
sudo cp -rf * /sync/rootfs/
sudo chmod 777 -R /sync/rootfs

修改主机配置

虚拟开发板访问互联网,不仅需要修改开发板相关配置文件,同时也需要对主机进行进一步操作,包括开启IP转发、配置静态路由、配置iptable规则等。

主机开启IP转发

主机配置tap虚拟网卡

运行脚本

U-boot+emmc启动

在第四部分《通过U-boot引导加载内核》中,我们发现U-boot的环境变量修改后无法保存,需要修改源代码来固化环境变量,对启动参数的修改造成了不便。因此本节将继续深入探讨如何将U-boot的环境变量存储在emmc内,同时使用emmc存储Linux内核、设备树以及根文件系统,并在此基础上尝试引导启动最小Linux操作系统。

制作emmc镜像文件

本节制作的emmc镜像文件共256MB,分为两个部分,第一部分存放uImage和dtb,大小为32MB,第二部分存放根文件系统,大小为224MB。

创建挂载路径

1
2
sudo mkdir /mnt/rootfs
sudo mkdir /mnt/uboot

创建自动打包脚本

将/home/workspace/objects下makefs-arm32.sh的内容替换为以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
cd /home/workspace/objects
vim makefs-arm32.sh

# 将makefs-arm32.sh的内容替换为以下内容
dd if=/dev/zero of=rootfs-arm.ext3 bs=1M count=256

echo "hard disk partition!"
sgdisk -n 0:0:+32M -c 0:uboot rootfs-arm.ext3
sgdisk -n 0:0:0 -c 0:rootfs rootfs-arm.ext3
sgdisk -p rootfs-arm.ext3

echo "mount loop device!"
LOOPDEV=`losetup -f`
echo $LOOPDEV
sudo losetup $LOOPDEV rootfs-arm.ext3
sudo partprobe $LOOPDEV
sudo losetup -l
ls -l /dev/loop*

echo "format disk to ext3"
echo ${LOOPDEV}p1
echo ${LOOPDEV}p2
sudo mkfs.ext3 ${LOOPDEV}p1
sudo mkfs.ext3 ${LOOPDEV}p2
sudo mount -t ext3 ${LOOPDEV}p1 /mnt/uboot -o loop
sudo mount -t ext3 ${LOOPDEV}p2 /mnt/rootfs -o loop
sudo cp -rf rootfs-arm32/* /mnt/rootfs/
sudo cp vexpress-v2p-ca9/arch/arm/boot/dts/vexpress-v2p-ca9.dtb /mnt/uboot/
sudo cp vexpress-v2p-ca9/arch/arm/boot/uImage /mnt/uboot/
sudo umount /mnt/rootfs/
sudo umount /mnt/uboot/
sudo losetup -d $LOOPDEV

运行自动打包脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
jcrj@SQA-JCRJ-01:~/qemu_arm_a9/workspace/objects$ sudo ./makefs-arm32.sh 
记录了256+0 的读入
记录了256+0 的写出
268435456字节(268 MB,256 MiB)已复制,0.18134 s,1.5 GB/s
hard disk partition!
Creating new GPT entries in memory.
Setting name!
partNum is 0
Warning: The kernel is still using the old partition table.
The new table will be used at the next reboot or after you
run partprobe(8) or kpartx(8)
The operation has completed successfully.
Setting name!
partNum is 1
Warning: The kernel is still using the old partition table.
The new table will be used at the next reboot or after you
run partprobe(8) or kpartx(8)
The operation has completed successfully.
Disk rootfs-arm.ext3: 524288 sectors, 256.0 MiB
Sector size (logical): 512 bytes
Disk identifier (GUID): 3C81BB8A-E76E-49AF-B920-1DC5B7EF6B72
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 524254
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)

Number Start (sector) End (sector) Size Code Name
1 2048 67583 32.0 MiB 8300 uboot
2 67584 524254 223.0 MiB 8300 rootfs
mount loop device!
/dev/loop15
NAME SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE DIO LOG-SEC
/dev/loop1 0 0 1 1 /var/lib/snapd/snaps/bare_5.snap 0 512
/dev/loop8 0 0 1 1 /var/lib/snapd/snaps/gnome-42-2204_141.snap 0 512
/dev/loop15 0 0 0 0 /home/jcrj/qemu_arm_a9/workspace/objects/rootfs-arm.ext3 0 512
/dev/loop6 0 0 1 1 /var/lib/snapd/snaps/gnome-3-38-2004_143.snap 0 512
/dev/loop13 0 0 1 1 /var/lib/snapd/snaps/snapd-desktop-integration_83.snap 0 512
/dev/loop4 0 0 1 1 /var/lib/snapd/snaps/core22_858.snap 0 512
/dev/loop11 0 0 1 1 /var/lib/snapd/snaps/snapd_19457.snap 0 512
/dev/loop2 0 0 1 1 /var/lib/snapd/snaps/core20_2105.snap 0 512
/dev/loop0 0 0 1 1 /var/lib/snapd/snaps/core20_1974.snap 0 512
/dev/loop9 0 0 1 1 /var/lib/snapd/snaps/gtk-common-themes_1535.snap 0 512
/dev/loop7 0 0 1 1 /var/lib/snapd/snaps/gnome-42-2204_120.snap 0 512
/dev/loop14 0 0 1 1 /var/lib/snapd/snaps/code_149.snap 0 512
/dev/loop5 0 0 1 1 /var/lib/snapd/snaps/firefox_2987.snap 0 512
/dev/loop12 0 0 1 1 /var/lib/snapd/snaps/snapd_20671.snap 0 512
/dev/loop3 0 0 1 1 /var/lib/snapd/snaps/core22_1033.snap 0 512
/dev/loop10 0 0 1 1 /var/lib/snapd/snaps/snap-store_959.snap 0 512
brw-rw---- 1 root disk 7, 0 1月 22 08:56 /dev/loop0
brw-rw---- 1 root disk 7, 1 1月 22 08:56 /dev/loop1
brw-rw---- 1 root disk 7, 10 1月 22 08:56 /dev/loop10
brw-rw---- 1 root disk 7, 11 1月 22 08:56 /dev/loop11
brw-rw---- 1 root disk 7, 12 1月 22 08:56 /dev/loop12
brw-rw---- 1 root disk 7, 13 1月 22 08:56 /dev/loop13
brw-rw---- 1 root disk 7, 14 1月 22 08:56 /dev/loop14
brw-rw---- 1 root disk 7, 15 1月 22 14:57 /dev/loop15
brw-rw---- 1 root disk 259, 3 1月 22 14:57 /dev/loop15p1
brw-rw---- 1 root disk 259, 4 1月 22 14:57 /dev/loop15p2
brw-rw---- 1 root disk 7, 16 1月 22 14:56 /dev/loop16
brw-rw---- 1 root disk 7, 2 1月 22 08:56 /dev/loop2
brw-rw---- 1 root disk 7, 3 1月 22 08:56 /dev/loop3
brw-rw---- 1 root disk 7, 4 1月 22 08:56 /dev/loop4
brw-rw---- 1 root disk 7, 5 1月 22 08:56 /dev/loop5
brw-rw---- 1 root disk 7, 6 1月 22 08:56 /dev/loop6
brw-rw---- 1 root disk 7, 7 1月 22 08:56 /dev/loop7
brw-rw---- 1 root disk 7, 8 1月 22 08:56 /dev/loop8
brw-rw---- 1 root disk 7, 9 1月 22 08:56 /dev/loop9
crw-rw---- 1 root disk 10, 237 1月 22 08:56 /dev/loop-control
format disk to ext3
/dev/loop15p1
/dev/loop15p2
mke2fs 1.46.5 (30-Dec-2021)
丢弃设备块: 完成
创建含有 8192 个块(每块 4k)和 8192 个 inode 的文件系统

正在分配组表: 完成
正在写入 inode表: 完成
创建日志(1024 个块): 完成
写入超级块和文件系统账户统计信息: 已完成

mke2fs 1.46.5 (30-Dec-2021)
丢弃设备块: 完成
创建含有 57083 个块(每块 4k)和 57088 个 inode 的文件系统
文件系统 UUID:3e290f2c-d621-4fd0-bb3a-f25fd0dbcd64
超级块的备份存储于下列块:
32768

正在分配组表: 完成
正在写入 inode表: 完成
创建日志(4096 个块): 完成
写入超级块和文件系统账户统计信息: 已完成

jcrj@SQA-JCRJ-01:~/qemu_arm_a9/workspace/objects$

将生成一个256MB大小的镜像文件rootfs-arm.ext3

5.png

修改U-boot环境变量的保存位置

上一小节生成的emmc镜像分为两部分,我们把环境变量存储在第一部分最后256KB的位置,以保证它不会与Linux内核和设备树互相干扰。

重新编译U-boot

1
2
cd /home/workspace/u-boot-2022.07-rc3
./automake_arm32.sh

在menuconfig界面设置环境变量存储设备,以及环境变量在设备中的具体位置和大小。由于需要将环境变量存储在emmc镜像的第一个分区的最后256KB位置,所以环境变量的设备号为emmc0,分区号为0,偏移量为0x02000000-0x00040000=0x01FC0000,大小为0x00040000。

menuconfig设置路径为:Environment->Environment in an MMC device

image.png

修改后,按两下Esc,保存配置,退出menuconfig,等待U-boot编译完成

加载U-boot修改环境变量

创建自动运行脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cd /home/workspace/objects
sudo touch qemu-start-uboot-arm32-emmc.sh
sudo chmod 777 qemu-start-uboot-arm32-emmc.sh
vim qemu-start-uboot-arm32-emmc.sh

# 在qemu-start-uboot-arm32-emmc.sh文件内添加以下内容
#!/bin/bash
sudo tunctl -u root -t tap0
sudo ifconfig tap0 172.16.16.10 promisc up
sudo route add -net 172.16.0.0 netmask 255.255.0.0 dev tap0
sudo iptables -t nat -A POSTROUTING -s 172.16.0.0/16 -o eth0 -j MASQUERADE
sudo netfilter-persistent save
sudo qemu-system-arm \
-M vexpress-a9 \
-m 512M \
-kernel u-boot-arm/u-boot \
-net tap,ifname=tap0,script=no,downscript=no \
-net nic,macaddr=00:16:3e:00:00:01 \
-nographic \
-sd rootfs-arm.ext3

运行脚本,在自动挂载倒计时结束前按任意键进入命令行模式

可以看到此时emmc镜像仍未存储环境变量,加载的是默认变量

1.png

在U-boot命令行中输入以下命令设置环境变量

1
2
3
setenv bootargs 'root=/dev/mmcblk0p2 rw console=ttyAMA0,38400n8'
setenv bootcmd "load mmc 0:1 0x60003000 uImage;load mmc 0:1 0x60500000 vexpress-v2p-ca9.dtb;bootm 0x60003000 - 0x60500000;"
saveenv

2.png

保存成功后,重新启动U-boot

3.png

4.png

问题及解决方案

Ubuntu2204网卡丢失

查看本地IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
jcrj@SQA-JCRJ-01:~$ ifconfig
br-593cc1b66d28: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.18.0.1 netmask 255.255.0.0 broadcast 172.18.255.255
ether 02:42:e2:a9:db:58 txqueuelen 0 (以太网)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:43ff:fef5:b4a2 prefixlen 64 scopeid 0x20<link>
ether 02:42:43:f5:b4:a2 txqueuelen 0 (以太网)
RX packets 369 bytes 25324 (25.3 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 250 bytes 26842 (26.8 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (本地环回)
RX packets 1798 bytes 133078 (133.0 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1798 bytes 133078 (133.0 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

veth948b02a: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::44a5:58ff:fe17:3f7c prefixlen 64 scopeid 0x20<link>
ether 46:a5:58:17:3f:7c txqueuelen 0 (以太网)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 83 bytes 9130 (9.1 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

vethde0c1ce: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::3415:67ff:feac:e7a6 prefixlen 64 scopeid 0x20<link>
ether 36:15:67:ac:e7:a6 txqueuelen 0 (以太网)
RX packets 27 bytes 1774 (1.7 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 84 bytes 7704 (7.7 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

vethf73e2dc: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::243b:61ff:fea8:8b5b prefixlen 64 scopeid 0x20<link>
ether 26:3b:61:a8:8b:5b txqueuelen 0 (以太网)
RX packets 13 bytes 1098 (1.0 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 27 bytes 3260 (3.2 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

vethfdaf20c: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::acb4:8fff:fe32:f35a prefixlen 64 scopeid 0x20<link>
ether ae:b4:8f:32:f3:5a txqueuelen 0 (以太网)
RX packets 13 bytes 1098 (1.0 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 27 bytes 3260 (3.2 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
ether 52:54:00:90:4b:76 txqueuelen 1000 (以太网)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0


jcrj@SQA-JCRJ-01:~$


查看本地网卡设备名

可以看到本地网卡设备信息为logical name: eno1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
jcrj@SQA-JCRJ-01:~$ sudo lshw -c network
[sudo] jcrj 的密码:
*-network DISABLED
description: Ethernet interface
product: Ethernet Connection (17) I219-V
vendor: Intel Corporation
physical id: 1f.6
bus info: pci@0000:00:1f.6
logical name: eno1
version: 11
serial: ec:d6:8a:be:bd:27
capacity: 1Gbit/s
width: 32 bits
clock: 33MHz
capabilities: pm msi bus_master cap_list ethernet physical tp 10bt 10bt-fd 100bt 100bt-fd 1000bt-fd autonegotiation
configuration: autonegotiation=on broadcast=yes driver=e1000e driverversion=6.5.0-14-generic firmware=2.3-4 latency=0 link=no multicast=yes port=twisted pair
resources: irq:125 memory:80a00000-80a1ffff
jcrj@SQA-JCRJ-01:~$

重启网络服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 停止服务
jcrj@SQA-JCRJ-01:~$ sudo service NetworkManager stop
# 删除文件
jcrj@SQA-JCRJ-01:~$ sudo rm /etc/NetworkManager/NetworkManager.state
rm: 无法删除 '/etc/NetworkManager/NetworkManager.state': 没有那个文件或目录
# 修改配置文件
# 将NetworkManager.conf 中的managed=false改为managed=true保存
jcrj@SQA-JCRJ-01:~$ sudo vim /etc/NetworkManager/NetworkManager.conf
jcrj@SQA-JCRJ-01:~$
jcrj@SQA-JCRJ-01:~$ cat /etc/NetworkManager/NetworkManager.conf
[main]
plugins=ifupdown,keyfile

[ifupdown]
managed=true

[device]
wifi.scan-rand-mac-address=no
jcrj@SQA-JCRJ-01:~$
jcrj@SQA-JCRJ-01:~$ sudo service NetworkManager start
jcrj@SQA-JCRJ-01:~$

Tftp使用

基本信息

设备名称 IP 属性 备注
SQA-JCRJ-01 172.16.16.10 server tap0: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST> mtu 1500 inet 172.16.16.10 netmask 255.255.0.0 broadcast 172.16.255.255 inet6 fe80::ec13:32ff:fe7e:70ba prefixlen 64 scopeid 0x20<link> ether ee:13:32:7e:70:ba txqueuelen 1000 (以太网) RX packets 51 bytes 3314 (3.3 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 110 bytes 9805 (9.8 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
vexpress-a9 172.16.16.20 client eth0 Link encap:Ethernet HWaddr 00:16:3E:00:00:01 inet addr:172.16.16.20 Bcast:172.16.255.255 Mask:255.255.0.0 UP BROADCAST RUNNING PROMISC MULTICAST MTU:1500 Metric:1 RX packets:76 errors:0 dropped:17 overruns:0 frame:0 TX packets:51 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:5668 (5.5 KiB) TX bytes:3314 (3.2 KiB) Interrupt:26

Server -> Client

Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
jcrj@SQA-JCRJ-01:/sync/tftp$ cat server-client.txt 
server to client
tftp> ?
tftp-hpa 5.2
Commands may be abbreviated. Commands are:

connect connect to remote tftp
mode set file transfer mode
put send file
get receive file
quit exit tftp
verbose toggle verbose mode
trace toggle packet tracing
literal toggle literal mode, ignore ':' in file name
status show current status
binary set mode to octet
ascii set mode to netascii
rexmt set per-packet transmission timeout
timeout set total retransmission timeout
? print help information
help print help information
tftp> q

Client

tftp -g -r 远程目标文件 远程地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@vexpress-a9:/tmp]#tftp
BusyBox v1.36.1 (2024-01-19 17:01:13 CST) multi-call binary.

Usage: tftp [OPTIONS] HOST [PORT]

Transfer a file from/to tftp server

-l FILE Local FILE
-r FILE Remote FILE
-g Get file
-p Put file
-b SIZE Transfer blocks in bytes
[root@vexpress-a9:/tmp]#
[root@vexpress-a9:/tmp]#ls
a.txt v.txt
[root@vexpress-a9:/tmp]#tftp -g -r server-client.txt 172.16.16.10
server-client.txt 100% |********************************| 17 0:00:00 ETA
[root@vexpress-a9:/tmp]#ls
a.txt server-client.txt v.txt
[root@vexpress-a9:/tmp]#cat server-client.txt
server to client
[root@vexpress-a9:/tmp]#

Client -> Server

Client

1
2
3
4
5
6
7
8
9
10
[root@vexpress-a9:/tmp]#vim clent-server.txt
[root@vexpress-a9:/tmp]#ls
a.txt clent-server.txt server-client.txt v.txt
[root@vexpress-a9:/tmp]#cat clent-server.txt
client server
[root@vexpress-a9:/tmp]#tftp -p -r client_server.txt -l client-server.txt 172.16
.16.10
client_server.txt 100% |********************************| 14 0:00:00 ETA
[root@vexpress-a9:/tmp]#

Server

1
2
3
4
5
jcrj@SQA-JCRJ-01:/sync/tftp$ ls
a.txt client_server.txt server-client.txt uImage vexpress-v2p-ca9.dtb v.txt
jcrj@SQA-JCRJ-01:/sync/tftp$ cat client_server.txt
client server
jcrj@SQA-JCRJ-01:/sync/tftp$

离线安装软件包

官方网址

https://ubuntu.pkgs.org/

GCC

MAKE

SSH

  • 标题: Qemu模拟ARM
  • 作者: Sunmy
  • 创建于 : 2024-01-22 21:25:23
  • 更新于 : 2025-06-29 21:05:24
  • 链接: https://ldspdvsun.github.io/cmchvp8fn0009h0gbaiwn9tep/
  • 版权声明: 版权所有 © Sunmy,禁止转载。
评论
目录
Qemu模拟ARM