基于QEMU的嵌入式模拟开发环境搭建

【目录】

@[toc] 本文档主要介绍了如何编译安装QEMU仿真软件、安装交叉编译环境、编译及用QEMU加载调试u-boot、编译及用QEMU加载Linux内核,如何制作Linux跟文件系统及用通过QEMU用SD卡、tftp、NFS、flash等不同的方式加载u-boot、Linux内核、Linux根文件系统。并在Linux根文件系统正常加载给出了一个简单的测试程序的编译、执行过程。由于在嵌入式系统设计过程中通常需要使用交叉调试的方式进行程序调试,最后介绍了如何编译交叉调试所用的gdb、gdbserver,并用一个实例演示了如何使用gdbserver进行交叉调试。 本文档所使用的各软件版本:
  • Linux操作系统 Ubuntu 20.04
  • QEMU emulator version 8.2.50
  • gcc version 9.4.0 Target:x86_64-gnu-linux
  • arm-linux-gnueabihf- gcc version 9.4.0 host=x86_64-linux-gnu --target=arm-linux-gnueabihf
  • u-boot u-boot-2023.10
  • busybox busybox-1.36.1
  • gdb gdb-13.1
    文档是对在“干净的”Ubuntu系统上构建开发环境过程的记录,其中穿插了部分错误的解决方法,使得文档组织看起来比较零散。个人觉得这可以对于嵌入式系统开发入门者在使用Linux系统时,解决问题提供思路。因此未对文档结构进行重新组织。

一、QEMU安装

1.简易安装

Ubuntu或Debian下可使用如下命令安装
sudo apt-get install qemu-system安装全系统仿真器
sudo apt-get install qemu-user-static安装Linux二进制仿真器
其他操作系统可参考QEMU官方网站
以上安装QEMU版本较低,不推荐

2.源码编译安装

1)在github上克隆最新版本QEMU源码

dev@Ubuntu:~$ git clone https://github.com/qemu/qemu.git

2)配置QEMU编译

参考qemu目录下的README.rst

mkdir build
cd build
sudo ../configure
sudo make

提示缺少Python 3.8.10,并有如下提示:(Hint: Debian puts ensurepip in its python3-venv package.)

3)按照提示安装python环境

sudo apt-get install python3-venv
再次运行../configure提示ERROR: Cannot find Ninja

4)使用源码安装Ninja

在工作目录下运行如下命令
git clone https://github.com/ninja-build/ninja.git克隆Ninja最新源码
参考ninja目录下的README.md文件
./configure.py --bootstrap
提没有c++编译器,ubuntu默认未安装gcc、g++,安装。
重新编译ninja,编译完成后将其拷贝至/usr/bin/ 目录
sudo cp ninja /usr/bin/

或者使用sudo apt-get install ninja-build 直接安装
本次编译采用了直接安装版本成功。编译版本报错(多规则定义错误),网上已有反馈,是版本1.20 ninja的BUG。

5)重新编译QEMU

依次出现如下提示:

 ERROR: Dependency "glib-2.0" not found
 ERROR: Program 'flex' not found or not executable
 ERROR: Program 'bison' not found or not executable

依次运行如下命令安装

 sudo apt-get install libglib2.0-0 libglib2.0-dev
 sudo apt-get install flex
 sudo apt-get install bison

6)重新配置、编译、安装

sudo ../configure
suo make -j4
sudo make install 

7)测试

运行qemu-system-aarch64 -version
显示如下信息:

QEMU emulator version 8.2.50 (v8.2.0-924-gbd2e12310b)
Copyright (c) 2003-2023 Fabrice Bellard and the QEMU Project developers

具体版本信息因版本而异,说明QEMU安装成功

3、基于源码安装QEMU小结

# 下载源码
git clone https://github.com/qemu/qemu.git
或者 wget https://download.qemu.org/qemu-8.2.0.tar.xz
# 解压
tar vxJf qemu-8.2.0.tar.xz
# 安装配置、暗转依赖库
sudo apt-get install python3-venv ninja-build
sudo apt-get install libglib2.0-0 libglib2.0-dev flex bison
# 建立编译目录
mkdir build
cd build
# 配置
sudo ../configure
# 编译
suo make -j4
# 安装
sudo make install 

【返回目录】

二、安装交叉编译环境

目前GNU工具链构建非常成熟,如无特殊需求建议直接安装交叉编译工具。如要自己构造交叉编译工具,请参考其他相关文章
Linux下gcc交叉编译工具链制作实例详细总结

1、安装

sudo apt-get install gcc-arm-linux-gnueabi*

2、验证安装结果

dpkg -l gcc-arm-linux-gnueabi*
显示安装信息
安装了arm-linux-gnueabi 和 arm-linux-gnueabihf 两个交叉编译器
ABI: 二进制应用程序接口(Application Binary Interface (ABI) for the ARM Architecture)
EABI: Embedded ABI

3、交叉编译器 arm-linux-gnueabi 和 arm-linux-gnueabihf 的区别

两个交叉编译器分别适用于 armel 和 armhf 两个不同的架构,armel 和 armhf 这两种架构在对待浮点运算采取了不同的策略(有 fpu 的 arm 才能支持这两种浮点运算策略)。
这两个编译器只是在处理是 gcc 的选项 -mfloat-abi 的默认值不同。
gcc 的选项 -mfloat-abi 有三种值 soft、softfp、hard(其中后两者都要求arm 里有 fpu 浮点运算单元,soft 与后两者是兼容的,但 softfp 和 hard 两种模式互不兼容):

  • soft: 不用fpu进行浮点计算,即使有fpu浮点运算单元也不用,而是使用软件模式。
  • softfp: armel架构(对应的编译器为 arm-linux-gnueabi-gcc )采用的默认值,用fpu计算,但是传参数用普通寄存器传,这样中断的时候,只需要保存普通寄存器,中断负荷小,但是参数需要转换成浮点的再计算。
  • hard: armhf架构(对应的编译器 arm-linux-gnueabihf-gcc )采用的默认值,用fpu计算,传参数也用fpu中的浮点寄存器传,省去了转换,性能最好,但是中断负荷高。

【返回目录】

三、编译u-boot

如果不调试u-boot这一部分可以暂时跳过

1、下载u-boot

根据需要选择u-boot版本,使用如下命令下载

wget https://ftp.denx.de/pub/u-boot/u-boot-2023.10.tar.bz2

2、解压u-boot

tar jvxf u-boot-2023.10.tar.bz2

3、配置、编译u-boot

有关u-boot配置编译及注意问题可参考u-boot目录下的READMD文件。u-boot/configs/ 下列出了u-boot支持的所有开发板,可以根据自己项目的需要选择配置文件。
本文档参考了网上大量关于使用QEMU建立vexpress-a9的示例,本文档也采用vexpress-a9开发板的默认配置vexpress_ca9x4_defconfig

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

编译过程中提示fatal error: openssl/evp.h:没有那个文件或目录,是由于没有OpenSSL 库,安装即可sudo apt-get install libssl-dev
编译生成 elf 格式的可执行文件 u-boot 和纯二进制文件u-boot.bin,其中 QEMU 可以启动的为 elf 格式的可执行文件 u-boot 。

4、运行qemu加载u-boot

qemu-system-arm -M vexpress-a9 -kernel u-boot -nographic -m 512M
  • -M vexpress-a9 模拟vexpress-a9开发
  • -M ?參数来获取该qemu支持的全部开发板
  • -m 512M 单板执行物理内存512M
  • -nographic 不使用图形化界面,仅仅使用串口

qemu退出方法:Ctrl + a,然后按 x 键
出现u-boot启动界面,说明u-boot运行成功。
在Hit any key to stop autoboot 提示时按任意键,可以进入u-boot命令行状态

5、安装多体系结构支持的gdb

sudo apt-get install gdb-multiarch
启动qemu加载u-boot并开启gdbserver

 sudo qemu-system-arm -M vexpress-a9 -kernel u-boot -nographic -m 512M -gdb tcp::1234 -S
  • -S让QEMU开机后由gdb控制,即暂停CPU直到触发gdb命令启动运行。

另外开启一个终端运行以下命令
gdb-multiarch u-boot -ex "target remote localhost:1234"
可以开始跟踪u-boot启动过程了,QEMU为调试u-boot、Linux内核提供了极大的便利,通过使用gdb的跟踪过程,有利于大家对u-boot、Linux内核源码的理解。

6、基于源码编译u-boot小结

#下载源码
wget https://ftp.denx.de/pub/u-boot/u-boot-2023.10.tar.bz2
# 解压u-boot
tar jvxf u-boot-2023.10.tar.bz2
#配置支持的目标板
make vexpress_ca9x4_defconfig
# 编译
make CROSS_COMPILE=arm-linux-gnueabihf- all

【返回目录】

四、编译内核

1、下载Linux内核

内核版本根据自己的需要选择,一般不要选择最新版本。linux内核官方
https://mirror.bjtu.edu.cn/kernel/linux/kernel/v5.x/linux-5.10.tar.xz

2、解压内核

tar vxf linux-5.10.tar.xz

3、生成vexpress开发板的config文件

清除所有配置信息、中间编译结果
make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm clean

make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm vexpress_defconfig
第一次实验时不建议对开发板的默认配置进行修改,以后根据需要可以使用make menuconfig对配置进行修改

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
make clean
make vexpress_defconfig
make menuconfig
make -j4

4、编译内核

1)编译32位内核

make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm
编译成功后最后几行的输出信息要记住,后面要用到

 Kernel: arch/arm/boot/zImage is ready
 DTC     arch/arm/boot/dts/vexpress-v2p-ca5s.dtb
 DTC     arch/arm/boot/dts/vexpress-v2p-ca9.dtb
 DTC     arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dtb
 DTC     arch/arm/boot/dts/vexpress-v2p-ca15_a7.dtb
 LDS     scripts/module.lds
 MODPOST Module.symvers

2)编译64位内核

make ARCH=arm64 vexpress_defconfig CROSS_COMPILE=aarch64-linux-gnu-

make ARCH=arm64 menuconfig CROSS_COMPILE=aarch64-linux-gnu-

make ARCH=arm64 Image -j8 CROSS_COMPILE=aarch64-linux-gnu-

生成的内核镱像位于arch/arm/boot/Image

5、用qemu仿真内核

qemu-system-arm -M vexpress-a9 -m 512M -kernel arch/arm/boot/zImage -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic -append "console=ttyAMA0"
  • -kernel arch/arm/boot/zImage 内核镜像路径
  • -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb 设备树路径(必须加入)
  • -append “console=ttyAMA0” 内核启动參数。这里告诉内核vexpress串口设备是哪个tty。
    注意:上一命令中的 内核镜像、设备树文目录根据实际情况调整

正确的显示结果,显示编译内核的版本,并在最后一行提示end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block无文件系统

6、基于源码编译Linux内核小结

# 下载Linux内核
https://mirror.bjtu.edu.cn/kernel/linux/kernel/v5.x/linux-5.10.tar.xz
# 解压内核
tar vxf linux-5.10.tar.xz
# 清除所有配置信息、中间编译结果
make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm clean
# 生成特定目标板(vexpress开发板)的config文件
make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm vexpress_defconfig
# 编译
make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm

【返回目录】

五、制作根文件系统

内核在启动之后、执行到最后步骤时,需要挂载根文件系统,然后执行文件系统中指定的执行程序。

1、下载busybox

wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2

2、解压

tar jvxf busybox-1.36.1.tar.bz2
关于busybox的使用说明请参见解压目录下的README

3、编译、安装

关于makefile文件各选项的简单说明可以参考解压目录下的Makefile.help文件
make defconfig 使.config为最大配置
编译
make CROSS_COMPILE=arm-linux-gnueabihf-

安装
make install CROSS_COMPILE=arm-linux-gnueabihf-

安装完成后,会在busybox目录下生成_install目录,该目录下的程序就是开发板运行所需的命令

4、形成根文件目录结构

先在主机环境下,形成目录结构,里面存放的文件和目录与开发板上运行所需要的目录结构完全一样。

1)创建rootfs目录

mkdir -p rootfs/{dev,etc/init.d,lib,proc,sys,tmp,root,var,mnt}

  • -p:需要时创建目标目录的上层目录,但即使这些目录已存在也不当作错误处理

2)把busybox中的文件复制到rootfs根目录

sudo cp busybox/_install/* -r rootfs/

  • -r:递归复制目录及其子目录内的所有内容

3)将交叉编译工具链中的库文件复制到rootfs根目录的lib文件夹

sudo cp -P /usr/arm-linux-gnueabihf/lib/* rootfs/lib/

  • -P:保持指定的属性(默认:模式,所有权,时间戳),如果可能保持附加属性:上下文、链接、xattr 等

4)创建需要的设备节点

sudo mknod rootfs/dev/tty1 c 4 1
sudo mknod rootfs/dev/tty2 c 4 2
sudo mknod rootfs/dev/tty3 c 4 3
sudo mknod rootfs/dev/tty4 c 4 4
sudo mknod -m 666 rootfs/dev/console c 5 1
sudo mknod -m 666 rootfs/dev/null c 1 3

5)配置初始化进程rcS

mkdir -p etc/init.d
touch etc/init.d/rcS
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 "*******XDUCS vexpress board********"
echo "-----------------------------------"

6)配置文件系统fstab

touch etc/fstab
vim etc/fstab

# 在fstab中填入以下内容
#<device> <mont-point> <type>  <options>     <dump>  <fsck order>
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

7)配置初始化脚本

touch 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

8)配置环境变量

touch 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

9)增加主机名

mkdir etc/sysconfig
vi etc/sysconfig/HOSTNAME

# 在HOSTNAME中添加以下内容
vexpress

5、制作跟文件系统镜像

制作根文件系统镜像 根文件系统镜像就相当于一个硬盘,就是把上面rootfs根目录中的所有文件复制到这个硬盘中。有两种不同的方法

1)第一种方法使用Linux命令

  • 生成一个64M的空文件
    此时的rootfs的大小大约30M,简单实验这个镜像文件足够用,后期可以根实际需要调整)
    dd if=/dev/zero of=a9rootfs.ext3 bs=1M count=64
  • 格式化成ext3文件系统
    mkfs.ext3 a9rootfs.ext3
  • 挂载该文件系统
    sudo mkdir /mnt/tmpfs
    sudo mount -t ext3 a9rootfs.ext3 /mnt/tmpfs/ -o loop
  • 将rootfs下的内容拷贝至镜像文件
    sudo cp -r rootfs/* /mnt/tmpfs/
  • 卸载镜像文件系统
    sudo umount /mnt/tmpfs
  • qemu启动虚拟机运行
    qemu-system-arm -M vexpress-a9 -m 512M -kernel zImage -dtb vexpress-v2p-ca9.dtb -nographic -append "root=/dev/mmcblk0 rw console=ttyAMA0" -sd a9rootfs.ext3
    
    参数说明:
  • -sd a9rootfs.ext3 参数 挂载根文件系统为sd卡 文件名为a9rootfs.ext3

启动最后显示如下信息

EXT4-fs (mmcblk0): mounting ext3 file system using the ext4 subsystem
random: fast init done
EXT4-fs (mmcblk0): mounted filesystem with ordered data mode. Opts: (null)
VFS: Mounted root (ext3 filesystem) on device 179:0.
Freeing unused kernel memory: 1024K
Run /sbin/init as init process
random: crng init done
Please press Enter to activate this console. 
[root@vexpress ]#

恭喜,已经成功的启动了Linux内核并加载了文件系统!!!

2)第二种方法使用qemu提供的命令

  • 生成64M的磁盘镜像
    qemu-img create -f raw disk.img 64M
  • 将磁盘镜像转换为ext4文件系统
    mkfs -t ext4 disk.img
  • 将rootfs目录复制到磁盘镜像中
    sudo mount -t ext4 disk.img /mnt/tmpfs/ -o loop
    sudo cp -r rootfs/* /mnt/tmpfs/
    sudo umount /mnt/tmpfs 
    
  • 检查磁盘镜像文件
    file disk.img
  • qemu启动虚拟机运行
 qemu-system-arm -M vexpress-a9 -m 512M -kernel zImage -dtb  vexpress-v2p-ca9.dtb -nographic -append "root=/dev/mmcblk0 rw console=ttyAMA0" -sd disk.img

【返回目录】

六、验证交叉编译工具正确可用

1、在主机环境下编写C语言程序mfloat.c并编译

#include<stdio.h>
#define PI 3.14159265
          
/*
* QEMU测试程序,测试交叉工具链配置是否成功
* 测试使用不同的交叉编译工具是否影响程序的正常执行
* 分别使用:
*          arm-linux-gnueabi-gcc
*          arm-linux-gnueabihf-gcc
* 在宿主机上进行编译,看在目标机上是否能正常执行
* 目标目前使用的是gnueabihf的lib库
*/
int main(int argc, char ** argv)
{
    int i;
    double d_area, d_perimeter, d_radius;
    d_radius = 3;
      
    for(i=1; i<100000; i++){
        d_perimeter = 2 * PI * (d_radius * i);
        d_area = PI * (d_radius * i) * (d_radius *i);
    }//end for 测试不同浮点运算效率
  
    printf("The Radius is %f, Perimeter is:%f, Area is:%f\n",\
            d_radius*i, d_perimeter, d_area);
  
    printf("Hello World!!!\n");
  
    return 0;
}

使用两种不同编译工具进行编译
arm-linux-gnueabihf-gcc mfloat.c -o mfloat-hf
arm-linux-gnueabi-gcc mfloat.c -o mfloat

2、挂载镜像文件并将编译好的程序拷贝至镜像文件

步骤与拷贝跟文件系统相同以后不再重复

 sudo mount -t ext4 disk.img /mnt/tmpfs/ -o loop
 sudo cp src/mfloat/mfloat* /mnt/tmpfs/root/
 sudo umount /mnt/tmpfs 

3、启动虚拟机并在虚拟机中执行编译好的程序

启动虚拟机命令同上略。
在虚拟机中运行测试程序

time ./mfloat
The Radius is 300000.000000, Perimeter is:1884936.740444, Area is:282737683661.504395
Hello World!!!
real	0m 0.05s
user	0m 0.03s
sys	0m 0.00s
[root@vexpress ~]# time ./mfloat-hf
The Radius is 300000.000000, Perimeter is:1884936.740444, Area is:282737683661.504395
Hello World!!!
real	0m 0.02s
user	0m 0.01s
sys	0m 0.00s

结果表明,两种编译工具编译完的程序皆能正常运行,hf的浮点运算效率更高。
【返回目录】

七、通过NFS挂载根文件系统

以下的第七、八、九、十部分介绍了其他不同的u-boot、内核及文件系统的加载方式,供有不同实际开发需求的读者选择。作为嵌入系统程序开发常用通过NFS挂载文件系统的方法。
在上面的软件调试的过程中,经常需与开发板交换文件,或者直接修改板子上的配置文件,用SD卡挂载根文件系统,则每次进行文件交换都需要重启操作系统。为了提高开发效率,可以通过NFS共享主机上的根文件系统给开发板,实现在主机上修改完善代码并编译后,直接在开发板上运行,无缝对接。

1、安装NFS服务

sudo apt install nfs-kernel-server

2、配置

sudo mkdir -p /mnt/rootfs
sudo vim /etc/exports

# 在/etc/exports文件中添加以下内容
/mnt/rootfs *(rw,sync,no_root_squash,no_subtree_check)
# !!!注意上述内容应严格按照格式输入,不能随意增减空格!!!

#解决内核NFS兼容问题
sudo vim /etc/default/nfs-kernel-server

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

3、重启nfs服务器

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

4、将安装好的根文件系统拷贝到/mnt/rootfs/

sudo cp -rf rootfs/* /mnt/rootfs/
sudo chmod 777 -R /mnt/rootfs

5、配置主机网桥(其中ens33是Ubuntu系统主网卡)

#安装主机网络工具并查看主机网卡名、IP地址等信息
sudo apt-get install net-tools
ifconfig

sudo apt install uml-utilities bridge-utils
sudo vim /etc/network/interfaces

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

auto ens33

auto br0
iface br0 inet dhcp
bridge_ports ens33

6、创建tap0网卡用以链接虚拟开发板

sudo tunctl -u root -t tap0

#设置本机虚拟网卡IP地址,并启动
sudo ifconfig tap0 172.16.16.10 promisc up

7、启动qemu

sudo qemu-system-arm -M vexpress-a9 -m 512M -kernel zImage -dtb 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:/mnt/rootfs,proto=tcp,nfsvers=3,nolock init=/linuxrc console=ttyAMA0 ip=172.16.16.20"

参数说明

  • nfsroot=172.16.16.10:/mnt/rootfs 本机nfs服务器IP地址
  • ip=172.16.16.20 设置目标板IP地址

【返回目录】

八、通过u-boot加载kernel+fs的SD镜像启动

1、编译内核生成uImage

sudo cp u-boot/tools/mkimage /usr/local/bin/
make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm uImage LOADADDR=0x60003000 –j4

Image、zImage、uImage之间的区别

  • Image:内核映像文件,大约为4M;
  • zImage:内核的一种映像压缩文件,不到2M;内核编译(make)之后会生成Image和zImage;
  • uImage:u-boot专用的映像文件,它是在zImage之前加上一个长度为64字节的“头”,说明这个内核的版本、加载位置、生成时间、大小等信息,在0x40之后与zImage没有任何区别。

2、制作包含内核与文件系统的镜像

 #创建一个SD镜像
 dd if=/dev/zero of=uboot.disk bs=1M count=64
 #创建一个放内核文件的分区大小为16M
 sgdisk -n 0:0:+16M -c 0:kernel uboot.disk
 #将剩余的空间创建一个放根文件系统的分区
 sgdisk -n 0:0:0 -c 0:rootfs uboot.disk 
 #显示分区信息
 sgdisk -p uboot.disk
 
 #显示一个空的loop文件
 losetup -f
 #将SD镜像挂载到上面命令显示的空loop设备上
 sudo losetup /dev/loop12 uboot.disk
 #将指定设备的分区变化通知操系统
 sudo partprobe /dev/loop12
 # 使用上面的命令将uboot.disk挂载到loop设备上时,
 # 在运行partprobe命令有可能会报错,
 # 原因一般为losetup -f显示的设备可能不是可用的设备

 # 可以使用以下命令代替:
 sudo losetup -fP --show uboot.disk

 ls /dev/loop12*
 #格式化分区 为了和后面u-boot相关设置兼容建议文件格式为ext3
 sudo mkfs.ext3 /dev/loop12p1
 sudo mkfs.ext3 /dev/loop12p2
 #挂载
 sudo mkdir /mnt/p1
 sudo mkdir /mnt/p2

 sudo mount -t ext3 /dev/loop12p1 /mnt/p1/
 sudo mount -t ext3 /dev/loop12p2 /mnt/p2/ 
 #拷贝内核、设备树、根文件系统到镜像文件相应分区
 sudo cp uImage /mnt/p1/
 sudo cp vexpress-v2p-ca9.dtb /mnt/p1/
 sudo cp -r rootfs/* /mnt/p2/
 #卸载
 sudo umount /mnt/p1 /mnt/p2
 sudo losetup -d /dev/loop12

3、启动qemu

qemu-system-arm -M vexpress-a9 -m 512M -smp 1 -nographic -kernel u-boot -sd uboot.disk

4、在u-boot启动界面配置u-boot参数

#查看挂载的磁盘
part list mmc 0
#查看磁盘内容
ls mmc 0:1
ls mmc 0:2
# 从SD开加载内核、设备树到指定内存区
load mmc 0:1 0x60003000 uImage
load mmc 0:1 0x60800000 vexpress-v2p-ca9.dtb

设置bootargs

setenv bootargs 'root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait earlycon console=ttyAMA0 init=/linuxrc ignore_loglevel'

启动内核

bootm 0x60003000 - 0x60800000

5、u-boot启动参数bootarg、bootcmd的修改

文件为u-boot下源码include/configs/vexpress_ca9x4_defconfig
增加内容

#define CONFIG_BOOTCOMMAND  "load mmc 0:1 0x60003000 uImage;"\
"load mmc 0:1 0x60800000 vexpress-v2p-ca9.dtb;"\
"setenv bootargs 'root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait earlycon console=ttyAMA0 init=/linuxrc ignore_loglevel';"\
"bootm 0x60003000 - 0x60800000;"

6、有关u-boot启动内核命令

1)bootz

bootz 命令用于启动 zImage 镜像文件, bootz 命令格式如下:
bootz [addr [initrd[:size]] [fdt]]

  • addr: Linux 镜像文件在 DRAM 中的地址;
  • [initrd[:size]]:initrd 是 initrd 文件在DRAM 中的地址,如果不使用 initrd 的话使用 ‘-’ 代替即可;
  • [fdt]:fdt 就是设备树文件在 DRAM 中的地址。

2)bootm

bootm 用于启动 uImage 镜像文件,用法和bootz一样:
bootm [addr [initrd[:size]] [fdt]]

3)boot

boot 会读取环境变量 bootcmd 来启动 Linux 系统,具体的引导命令内容是可以修改的。

  • 示例1 用tftp命令从网络启动Linux镜像
setenv bootcmd 'tftp 60003000 uImage; tftp 608000000 vexpress-v2p-ca9.dtb; bootm 60003000 - 60800000'
saveenv
boot
  • 示例2 用从EMMC启动Linux镜像
 setenv bootcmd 'fatload mcc 1:1 60003000 zImage; fatload 1:1 60800000 vexpress-v2p-ca9.dtb; bootm 60003000 - 60800000'
 saveenv
 boot

7、通过menuconfig配置u-boot环境变量

1)安装运行make menuconfig所需的依赖库

sudo apt-get install libncurses-dev

2)进入u-boot源码目录配置运行环境

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- clean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mrproper
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- vexpress_ca9x4_defconfig O=../qemu_work/u-boot-mmc
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig O=../qemu_work/u-boot-mmc

在u-boot的menuconfig界面根据需要修改
本次主要修改 Environment->Environment in an MMC device
并根据实际MMC文件系统指定环境变量在文件系统的偏移量,如可以将器指定在内核或者文件系统分区的最后一个块
保持环境变量存储的大小不变
MMC device number 0
MMC partition number 0

3)重新编译

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 O=../qemu_work/u-boot-mmc

4)启动qemu验证u-boot配置修改

qemu启动u-boot,通过sd卡加载Linux内核、设备树和文件系统并修改保存 u-boot环境变量,再次启动qemu,验证u-boot配置修改的效果。

 qemu-system-arm -M vexpress-a9 -m 512M -smp 1 -nographic -kernel u-bootmmc -sd uboot.disk

在u-boot命令行下输入:

#设置u-boot启动参数
setenv bootargs 'root=/dev/mmcblk0p2 rw rootfstype=ext3 rootwait earlycon console=ttyAMA0,38400N8 init=/linuxrc ignore_loglevel'
#设置u-boot启动命令
setenv bootcmd 'load mmc 0:1 0x60003000 uImage; load mmc 0:1 0x60800000 vexpress-v2p-ca9.dtb; bootm 0x60003000 - 0x60800000'
#保存配置
saveenv
#运行u-boot启动命令
run bootcmd

linux正常启动
退出qemu、再次启动,linux自动启动,不用再输入u-boot环境变量。
注意:此处u-boot不支持ext4文件格式,在制作SD镜像时请使用ext3文件格式。
【返回目录】

九、通过u-boot tftp加载内核、设备树,NFS加载文件系统

这是在系统开发过程中最常用的方式,除u-boot外、内核、dtb、文件系统均通过网络形式传输,避免了对系统非易失存储器的频繁操作,提高系统开发、调试效率。
如何通过nfs加载跟文件系统已经在第七部分详细说明。本部分重点描述如何通过用u-boot通过tftp传输内核和dtb,以及使用qemu要解决的特有问题

1、安装tftp服务器

sudo app-get install tftp-hpa tftpd-hpa xinetd

2、配置tftp路径文件

sudo mkdir -p /mnt/tftp
sudo chmod 777 /mnt/tftp
sudo vim /etc/default/tftpd-hpa
 
# 在tftpd-hpa文件下添加以下内容
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/mnt/tftp" #该路径即为tftp可以访问到的路径
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"

3、重启tftp服务器

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

4、将内核文件和设备树拷贝之tftp目录

sudo cp vexpress-v2p-ca9.dtb /mnt/tftp/
sudo cp uImage /mnt/tftp/

5、配置主机虚拟网卡,详细见第七部分

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

6、启动qemu验证tftp配置

sudo qemu-system-arm -M vexpress-a9 -m 512M -kernel u-boot -net tap,ifname=tap0,script=no,downscript=no -net nic, macaddr=00:16:3e:00:00:01 -nographic

在u-boot命令行状态下输入如下命令,引导内核和文件系统

setenv bootargs 'root=/dev/nfs rw nfsroot=172.16.16.10:/mnt/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
#saveenv 会报错,原因:u-boot默认的参数保存位置为FLASH,模拟器未模拟
#在实际的开发板上是有相应设备的可以保存,
#保存出错不影响本次运行,只是在每次运行时都要有参数设置环节
#可以参考下面的提示,修改u-boot的默认启动参数、命令

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

内核成功启动、文件系统加载

7、本例u-boot启动的配置修改

在实际开发过程不需要如此操作,u-boot配置参数可以保存。 这部分操作有助于大家对u-boot的理解。

1)修改u-boot/configs/vexpress_ca9x4_defconfig

#进入u-boot源码目录
vim configs/vexpress_ca9x4_defconfig

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

2)修改u-boot/include/configs/vexpress_common.h

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

重新编译u-boot!!!
这部分的修改建议以修改配置文件的方式完成,不建议通过图形化配置u-boot方式完成。
【返回目录】

十、u-boot+kernel+rootfs启动(本部分没有修改u-boot,未成功

1、制作文件系统压缩文件

cd rootfs  //进入fsfoot目录`
find . | cpio -o --format=newc > ../rootfs.img
cd ..
gzip -c rootfs.img >rootfs.img.gz

2、验证文件系统

qemu-system-arm -M vexpress-a9 -m 512M -nographic -kernel zImage -dtb vexpress-v2p-ca9.dtb -initrd rootfs.img.gz -append "root=/dev/ram rdinit=/sbin/init console=ttyAMA0"

3、制作flash文件

现在有了u-boot、uImage、rootfs.img.gz、vexpress-v2p-ca9.dtb

# 使用一下命令制作image文件反不能正常运行
# mkimage -A arm -C none -O linux -T kernel -d uImage -a 0x60003000 -e 0x60003000 uImage.uimg
# mkimage -A arm -C none -O linux -T kernel -d vexpress-v2p-ca9.dtb -a 0x60800000 -e 0x60800000 dtb.uimg
# mkimage -A arm -C none -O linux -T ramdisk -d rootfs.img.gz -a 0x61000000 -e 0x61000000 rootfs.uimg

#制作64M的Flash镜像 64M为板载Flash容量 每个sector=128K
dd if=/dev/zero of=flash.bin bs=128K count=512 
#在flash的起始位置放dtb
dd if=vexpress-v2p-ca9.dtb  of=flash.bin conv=notrunc bs=128K 
# 在flash的1M偏移位置起放内核
dd if=uImage of=flash.bin conv=notrunc bs=128K seek=8
# 在flash的8M偏移位置起放文件系统
dd if=rootfs.img.gz of=flash.bin conv=notrunc bs=128K seek=64

4、启动qemu测试

启动qemu
`qemu-system-arm -M vexpress-a9 -m 512M -nographic -kernel u-boot -pflash flash.bin’
在u-boot命令行下设置以下变量

setenv bootcmd 'cp.b 0x0 0x60800000 0x10000; cp.b 0x100000 0x60003000 0x600000; cp.b 0x800000 0x61000000 0x1000000; bootm 0x60003000 - 0x60800000;'
setenv bootargs 'root=/dev/ram  rdinit=/sbin/init console=ttyAMA0'
run bootcmd

内核可启动,找不到文件系统

5、另换qemu启动参数

qemu-system-arm -M vexpress-a9 -m 512M -nographic -kernel u-boot -initrd rootfs.img.gz -pflash flash.bin -append "root=/dev/ram rdinit=/sbin/init console=ttyAMA0"

在u-boot命令行下设置以下变量

setenv bootcmd 'cp.b 0x0 0x60800000 0x10000; cp.b 0x100000 0x60003000 0x600000; bootm 0x60003000 - 0x60800000;'
run bootcmd

现象同上 内核可启动,找不到文件系统
失败!可能是由于没有修改u-boot配置,等有时间了再试。
【返回目录】

十一、gdb与gdbserver的编译与安装

基本步骤:源码下载->查看REAMD->配置编译->编译->安装

1、下载gdb源码(不建议下载最新版本)

下载 wget http://ftp.gnu.org/gnu/gdb/gdb-13.1.tar.xz
解压 tar vxf gdb-13.1.tar.xz

2、查看README

根据README进行相关操作

cd ~/gdb-13.1
查看编译配置帮助
./configure --help

3、配置编译gdb

#建立编译目录
mkdir build-gdb
cd build-gdb 
#建立安装目录
mkdir _install
#配置编译选项
# --host 选项因是编译在本机运行的gdb 可忽略
# --target 选项参数可以 通过运行 arm-linux-gnueabihf -v 获取
../configure --target=arm-linux-gnueabihf --prefix=/home/dev/gdb-13.1/build-gdb/_install

4、编译

#因只是编译gdb 使用make all-gdb
make all-gdb -j4

问题1、 WARNING: ‘makeinfo‘ is missing on your system

sudo apt-get install texinfo

问题2、缺少libxml-libxml-perl

建议在安装本库之前将apt 的源换到主服务器,并保证 Canonical 相关选项选中,否则会出现无法安装提示。
sudo apt-get install libxml-libxml-perl

问题3、缺少GMP

#确定GMP依赖的安装包
sudo apt-cache search GMP

sudo apt-get install libgmp-dev

5、安装arm-linux-gnueabihf-gdb

make install-gdb
会在_install/目录下安装编译完成的内容

6编译gdbserver

步骤与gdb基本一致不再详细解释

mkdir build-gdbserver
cd build-gdbserver 
mkdir _install
../configure --host=arm-linux-gnueabihf --prefix=/home/dev/gdb-13.1/build-gdbserver/_install

#错误提示1:
../../gdbserver/linux-arm-low.cc:894:29: error: ‘__NR_sigreturn’ was not declared in this scope; did you mean ‘sigreturn’

#原因:未安装g++编译器

sudo apt install g++-arm-linux-gnueabi*

错误提示2:
error: run `make distclean' and/or `rm ./config.cache' and start over
#原因:安装g++后系统环境变化,配置缓存未清除
make distclean

make all-gdbserver

make install-gdbserver
#在_install目录下会安装gdbserver

【返回目录】

十二、使用gdb与gdbserver交叉调试用户程序

基本步骤:拷贝gdbserver到目标板/bin目录->在宿主机上使用-g参数交叉编译要调试的文件->将源文件和编译后的文件拷贝至目标机的适当目录->在目标机上运行gdbserver->宿主机上运行arm-linux-gnueabihf-gdb调试用户程序。
以下详细步骤是基于nfs加载根文件系统的方式给出,其他根系统加载方式与之类似,注意要保证目标机与宿主机之间的网络联通。
由于以下命令会分别在宿主机和目标机之间交替运行,为了进行区分有以下约定

  • 以$开头的命令代表该命令是在宿主机上输入;
  • 以#开头的命令代表该命令是在目标机上输入;
  • 以(gdb)开头的命令代表是在arm-linux-gnueabihf-gdb中输入。

1、拷贝gdbserver至目标板/bin目录

gdgserver所在目录及目标板文件系统的NFS目录位置因系统而异
#cp path-to-gdbserver-install/gdbserver path-to-target-NFS-rootfs/bin/

2、在宿主机上用-g参数重新交叉编译要调试的文件

#arm-linux-gnueabihf-gcc -g -o mfloat-gdb mfloat.c
#cp mfloat-gdb mfloat.c path-to-target-NFS-rootfs/root/

3、以NFS挂载跟文件系统的方式启动qemu

$sudo tunctl -u root -t tap0
$sudo ifconfig tap0 172.16.16.10 promisc up
$sudo qemu-system-arm -M vexpress-a9 -m 512M -kernel zImage -dtb 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:/mnt/rootfs,proto=tcp,nfsvers=3,nolock init=/linuxrc console=ttyAMA0 ip=172.16.16.20"

4、开始交叉调试

# cd root
# gdbserver 172.16.16.20:1234 ./mfloat-gdb 
显示:process ./mfloat-gdb created; pid = 86 
      listening on port 1234
gdbserver已正常运行等待client端的链接

$arm-linux-gnueabihf-gdb ./mfloat-gdb

显示信息中有一行为当前gdb的配置信息

 This GDB was configured as "--host=x86_64-pc-linux-gnu --target=arm-linux-gnueabihf".

证明gdb 配置正确

 //配置 solib的搜索路径
(gdb) set solib-search-path /usr/arm-linux-gnueabihf/lib

//配置服务器端地址及端口号
(gdb) target remote 172.16.16.20:1234

//显示被调试程序源码
(gdb) list

//在main函数处设置断点
(gdb) b main

//开始执行
(gdb) c

出现错误提示如下:

argc=<error reading variable: Remote 'g' packet reply is too long (expected 168 bytes, got 332 bytes)

原因:gdb通过XML语言描述了各处理器的信息,显然gdb没能正确解释目标处理器信息。仔细观察arm-linux-gnueabihf-gdb启动后的提示信息有一行提示信息为:
warning: Can not parse XML target description; XML support was disabled at compile time
出现该提示的原因:gdb编译时缺少XML的解析库expat,且该库为可选项,不会报错

$ apt-search expat
根据提示安装以下依赖库
$ sudo apt install libexpat1 libexpat1-dev

重新编译 arm-linux-gnueabihf-gdb
以上问题解决,可以开始对程序进行交叉调试。
【返回目录】

十三、虚拟开发板连接互联网

1、修改开发板配置

在开发板文件系统目录下操作
###1)开发板指定DNS服务器

touch etc/resolv.conf
chmod 777 etc/resolv.conf
vim etc/resolv.conf

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

2)开发板初始化规则修改

vim etc/init.d/rcS

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

2、修改主机配置

包括:开启IP转发、配置静态路由、配置iptable规则等

1)主机开启IP转发

vim /etc/sysctl.conf

# 将sysctl.conf中的net.ipv4.ip_forward置为1
net.ipv4.ip_forward=1

注意:本修改后需重启操作系统方可生效!!!

2)主机配置TAP虚拟网卡

每次重启操作系统,tap0都会消失,需要重新配置

#创建虚拟网卡
sudo tunctl -u root -t tap0 
#配置虚拟网卡IP
sudo ifconfig tap0 172.16.16.10 promisc up
#添加静态路由信息
sudo route add -net 172.16.0.0 netmask 255.255.0.0 dev tap0
#配置iptable规则
sudo iptables -t nat -A POSTROUTING -s 172.16.0.0/16 -o ens33 -j MASQUERADE
sudo netfilter-persistent save

【返回目录】

QEMU 命令行选项

QEMU 命令行选项的详细解释,这些选项可用于模拟各种情境:

1、硬件架构和机型选项:

  • -M : 指定模拟的机型,如 -M virt 表示模拟 ARM Virt 平台。
  • -cpu : 指定 CPU 类型,例如 -cpu cortex-a9。
  • -smp : 指定模拟的 CPU 核心数量。
  • -m : 指定虚拟机内存大小,如 -m 512M 表示分配 512MB 内存。
  • -kernel : 指定模拟时使用的内核镜像。

2、设备选项:

  • -drive: 模拟磁盘驱动器,例如 -drive file=flash.img,format=raw。
  • -nic: 模拟网络接口卡,例如 -nic user,model=virtio-net-pci。
  • -usb: 启用 USB 支持。
  • -device: 添加其他设备到虚拟机,例如 -device virtio-gpu.

3、启动选项:

  • -append: 设置内核启动参数,例如 -append “console=ttyS0 root=/dev/sda1”.
  • -initrd : 指定用于初始化 RAMDisk 的文件。
  • -serial : 将虚拟串口连接到主机的字符设备,例如 * -serial stdio。
  • -monitor stdio: 通过标准输入输出启动 QEMU 监视器。

4、图形界面选项:

  • -display : 指定图形显示类型,例如 -display gtk。
  • -vga : 指定图形卡类型,如 -vga virtio。
  • -spice: 启用 SPICE 协议支持,用于远程图形显示。

5、调试选项:

  • -gdb : 启动 GDB 服务器,例如 -gdb tcp::1234。
  • -S: 启动时暂停虚拟机,等待 GDB 连接。

6、其他常见选项:

  • -snapshot: 使用快照模式,虚拟机关闭后不保存状态。
  • -enable-kvm: 启用 KVM 加速(需要支持虚拟化的硬件和内核模块)。
  • -drive file=cdrom.iso,media=cdrom: 将 ISO 文件挂载为光盘。

这只是 QEMU 命令行选项的一小部分,实际使用中可能会根据具体需求进行更多的配置。你可以通过运行 qemu-system- -help 来获取特定硬件架构的详细选项。
【返回目录】

其他问题的解决方法

1、Ubuntu链接不了网络

现象:右上角的网络链接标志消失、ifconfig 只能看到本地环路lo
解决方案(一) 我的问题是这样解决的!

sudo vim /etc/NetworkManager/NetworkManager.conf
#修改 managed=false 为 managed=true

sudo service network-manager restart

#如果问题依然存在
reboot

#重复以上步骤即可(重启一次后问题依然存在需要找其他原因了)

解决方案(二) 我试过没成功

sudo nmcli networking off
sudo nmcli networking on
sudo service network-manager restart

2、设置网桥后不能上网

###1)删除网桥

# 停用网桥
ifconfig <网桥名> down
# 删除网桥
brctl delbr <网桥名>
#将网卡移出网桥
brctl delif br0 eno1

2)清空网络服务状态

sudo service network-manager stop

sudo rm /var/lib/NetworkManager/NetworkManager.state

sudo service network-manager start

3)网络管理器清理多余的连接

nm-connection-editor
#界面里删除不使用的连接

4)设置网关

Sudo route add default gw 192.168.2.1

3、VMware 虚拟机卡住不反应

现象:在Windows主机端操作一段时间后,Ubuntu 20.04 的VMware虚拟机不对任何按键响应,只能重启客户机。
环境:Vmware Workstation 17.5 Win 11
解决:

1)修改VMware Workstation设置

编辑->首选项->内存->额外内存->系统如何为虚拟机分配内存
选择 “调整所有虚拟机内存使其适应预留的主机RAM(F)

2)修改虚拟设置

虚拟机->设置-选项->高级->
选择 “禁用内存页面休整(M)”
通过以上设置可以降低虚拟机不反应的概率

3)操作注意

在启动虚拟机登录后调整好虚拟机窗口尺寸和位置后,建议不要再移动或调整虚拟机窗口尺寸。
网上有建议将VMware Workstation版本降至17.0。好像也可以,以前在这个版本的时候没发现有这样的问题。

4、通过NFS服务器传输文件

在目标机上挂载NFS服务器文件系统

mount -t nfs -o nolock,rsize=1024,wsize=1024 IP:目录 /挂载点
如:mount -t nfs -o nolock,rize=1024,wsize=1024 172.16.16.10:/mnt/rootfs /mnt/tmp
  • nolock 参数 nfs mount 默认选项包括文件锁,需要在挂载是加入该参数

5、通过tftp 传输文件

从服务器段拷贝文件到本地
tftp –g –r 服务器端源文件名 –l 本地文件名 服务器地址IP地址
从本地上传文件到服务器
tfpt -p -r 服务器端源文件名 –l 本地文件名 服务器地址IP地址

  • -l 是local的缩写,后跟存在于Client的源文件名,或下载Client后重命名的文件名。
  • -r 是remote的缩写,后跟Server即PC机tftp服务器根目录中的源文件名,或上传Server后 重命名后的文件名。
  • -g 是get的缩写,下载文件时用,
  • -p 是put的缩写,上传文件时用

【返回目录】

参考资料

1.QEMU官方网站
2.QEMU Wiki
3.QEMU中文Wiki
4.从零开始用qemu搭建虚拟arm环境
5.qemu-system-arm仿真vexpress-a9踩坑记
6.u-boot调试笔记一
7.u-boot启动内核命令:bootz、bootm、boot
8.qemu的详细资料大全
9.QEMU搭建ARM虚拟开发板
10.Qemu调试Linux内核,实现NFS挂载
11.Linux程序员
12.GDB Wiki

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值