发布占位示例:

开发板环境搭建

1
readelf -h exec_file  查看可执行文件的信息,可以查看它使用什么工具链编译的

如果在 QEMU 模拟器中,通常可以通过以下方式退出:
在 QEMU 窗口中,按下 Ctrl + A,然后松开并按 X,这将关闭 QEMU。
或者,您可以直接关闭模拟器窗口。

  • 使用Qemu虚拟机的几种选择
  • 利用Qemu来运行ARM虚拟机,你有2个选择:
    • 简单方式:直接下载别人编译好的映像文件(包含了内核,根文件系统),直接执行即可。
    • 缺点是:别人编译好的也许不适合你的需求,没法定制。
    • 复杂方式:自己下载内核代码、根文件系统代码(例如:busybox),然后进行编译。
    • 优点是:可以按照自己的实际需求,对内核、根文件系统机型裁剪。
  • 在第2种复杂模式中,又可以有2个选择:
    • ==2-1==. 内核代码、根文件系统代码全部自己手动编译,最后把这些编译结果手动组织在一个文件夹中,形成自己的根目录;
    • ==2-2==. 利用 buildroot 整个框架,只需要手动进行配置(比如:交叉编译器在本机上的位置、输出路径、系统的裁剪),然后就可以一键编译出一个完整的系统,可以直接烧写到机器!

buildroot

  • 直接使用buildroot编译就会全部配置好了.哦买噶!!!
1
2
3
4
5
make configs/qemu_arm_vexpress_defconfig
# 这个大小可能有点小,要改为128?
BR2_TARGET_ROOTFS_EXT2_SIZE="64M"
# 最好在docker中运行,如果有错误搜索解决吧
make

qt配置

  • 启用C++
  • 启用qt5
  • 使用make编译如果报错clean并重新编译
  • 可能会没有buildroot/output/host/bin/arm-buildroot-linux-gnueabihf-gcc这个工具包,应该是在arn官网下载的,到时候在查一下吧

buildroot/output/host/bin/arm-buildroot-linux-gnueabihf-gcc tmp.c -o tmp -I buildroot/output/host/arm-buildroot-linux-gnueabihf/sysroot/usr/include -L buildroot/output/host/arm-buildroot-linux-gnueabihf/sysroot/usr/lib -lgpiod

manual build

编译内核

  • 下载内核
    1
    2
    git https://github.com/torvalds/linux.git
    指定版本的 https://www.kernel.org/ (相对内存占用小一点)
  • 编译内核镜像文件
    • 编译zImage
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    * 安装依赖模块
    * sudo apt-get install flex
    * sudo apt-get install bison
    * sudo apt install gcc-arm-linux-gnueabi
    * sudo apt install g++-arm-linux-gnueabi
    * sudo apt install libncurses5-dev libncursesw5-dev

    make source 下载资源离线编译


    export ARCH=arm
    export CROSS_COMPILE=arm-linux-gnueabi- (以32位来编译)
    make vexpress_defconfig(vexpress_defconfig为开发板配置,每个支持的开发板都会有个默认配置文件)
    编译成功的配置会存放在.config文件中

    # make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- vexpress_defconfig(这样设置是错误的并没有设置到指定参数)

    * make zImage -j6(系统镜像)
    * make modules
    * make dtbs
    • 编译uImage
    1
    2
    3
    4
    5
    6
    7
    export ARCH=arm // 说明是arm体系
    export CROSS_COMPILE=arm-linux-gnueabi- // 使用的交叉编译器
    export LOADADDR=0x60003000 // 设置uImage启动的地址 这个地址在linux内核 arch/arm/configs 中相应的开发板来查看<CONFIG_BOOTCOMMAND>
    make vexpress_defconfig // 使用内核中的默认vexpress架构的配置
    make modules // 编译内核外模块
    make dtbs // 编译设备树
    make uImage // 编译uImage

编译U-BOOT

1
2
3
4
export ARCH=arm // 说明是arm体系
export CROSS_COMPILE=arm-linux-gnueabi- // 使用的交叉编译器
make vexpress_ca9x4_defconfig // 使用u-boot中默认的vexpress_ca9x4的配置
make //编译

编译busybox

  • busybox是Linux平台上的一个工具集。busybox最大的特点是把不同的工具代码以及公用代码都集成在一起,从而大大减少了可执行文件的体积。非常适合资源有限的嵌入式设备。
1
2
3
4
5
6
7
8
#安装依赖
sudo apt-get install build-essential

export ARCH=arm // 说明是arm体系
export CROSS_COMPILE=arm-linux-gnueabi- // 使用的交叉编译器
make defconfig
make -j4
make install

使用zImage运行qemu (镜像启动)

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
#!/bin/bash

export BUSY_BOX=./busybox-1.29.3 // 设置busybox的环境变量进行命令的转移
export ETC=./busybox-1.29.3/examples/bootfloppy/etc // 使用busybox中默认的配置 自己创建也可以

#1. 创建Linux中的必要文件夹
sudo mkdir rootfs
sudo mkdir -p roots/bin # /bin包含普通用户和超级用户都能使用的命令
sudo mkdir -p rootfs/sbin # /sbin包含系统运行的关键可执行文件以及一些管理程序
sudo mkdir -p rootfs/home # /home普通用户的工作目录,没有普通用户都会在这里建立一个文件夹
sudo mkdir -p rootfs/etc # /etc存放系统配置文件以及应用程序的配置文件
sudo mkdir -p rootfs/lib # /lib存放所有应用程序的共享文件以及内核模块
sudo mkdir -p rootfs/proc/ # /proc目录是内核在内存中映射的实时文件系统,存放内核向用户应用程序提供的信息文件
sudo mkdir -p rootfs/sys/ # /sys是文件系统挂载的地方
sudo mkdir -p rootfs/tmp/ # /tmp存放系统或应用程序产生的临时文件
sudo mkdir -p rootfs/root/ # /root是超级用户的用户目录
sudo mkdir -p rootfs/var/ # /var存放假脱机数据以及系统日志
sudo mkdir -p rootfs/mnt/ # /mnt用于加载磁盘分区和硬件设备挂载点
sudo mkdir -p roots/usr # /usr包含所有用户的二进制文件和库文件等
sudo mkdir -p rootfs/dev/ # /dev用于存放设备文件

#2. 将busybox中的编译的可执行文件放到rootfs下
sudo cp -arf ${BUSY_BOX}/_install/* rootfs/
sudo cp -arf ${ETC} rootfs/

#3. 添加交叉编译环境
sudo cp -arf /usr/arm-linux-gnueabi/lib rootfs/
sudo rm rootfs/lib/*.a
sudo arm-linux-gnueabi-strip rootfs/lib/*

#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 rootfs/dev/console c 5 1
sudo mknod rootfs/dev/null c 1 3

#5. 生成一个空的文件作为文件系统 (可以看做是一个SD卡)
sudo dd if=/dev/zero of=rootfs.ext3 bs=1M count=32
sudo mkfs -t ext3 rootfs.ext3

#6. 将文件系统挂载到/mnt目录下
sudo mount -t ext3 rootfs.ext3 /mnt -o loop

#7. 将之前创建的文件系统相关的文件放到通过tmpfs放到rootfs.ext3文件系统中去
sudo cp -r rootfs/* tmpfs/
sudo umount /mnt
  • 现在对上面的文件系统构建步骤进行一下梳理:
    • 创建arm-linux的必要文件夹
    • 将busybox生成的命令以及etc配置文件放到arm-linux文件系统中去。这里有两个环境变量是需要在执行之前设置的。
    • 将交叉编译环境放到arm-linux文件系统中去,这样最后运行Hello程序才能运行
    • 创建必要的设备文件
    • 通过dd、mkfs -t etx4命令制作文件系统。其中dd命令是一个很有用的命令。它可以用来进行设置分区、设置内存交换空间等操作
    • 然后将dd出来的roofs.ext3挂载到/mnt文件夹下,并且把刚才rootfs中配置好的文件放到/mnt中去。也就是放在了roofs.ext3中。
    • 最后取消roofs.ext3的挂载
    • /etc/init.d/srC 这个文件夹是启动后会指定运行的文件,要创建.(没有会有提示但不会形成致命错误)
1
2
3
4
5
6
7
8
# run
qemu-system-arm -M vexpress-a9 \
-m 512M \
-kernel <LOCAL_PATH> \
-dtb <LOCAL_PATH> \
-nographic \
-append "root=/dev/mmcblk0 rw console=ttyAMA0" \
-sd <LOCAL_PATH>

使用uImage运行qemu (手动uboot启动)

配置tftp

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
#安装
sudo apt-get install xinetd tftp-hpa tftpd-hpa

#配置 打开/etc/xinetd.d/tftp配置文件,修改为如下: 文件不存在自行创建

service tftp
{
protocol = udp
port = 69
socket_type = dgram
wait = yes user = anriku // 这个是你linux下boot的用户名,当然后面会把boot目录下的访问权限都设置为777这个配置就没有太大的用处了
server = /usr/sbin/in.tftpd
# server_args = ~/vexpress-a9/linux-4.10.8/arch/arm/boot // 这里配置的是ftp传送目录
server_args = <LOCAL_PATH> // 这里配置的是ftp服务器目录,客户端就是访问的这个目录
disable = no
}

#然后打开/etc/default/tftpd-hpa进行ftp服务器配置:

# /etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY= "<LOCAL_PATH>" // 这里配置的是ftp服务器目录
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"

/ 下面把tftp需要传送文件的目录的权限给到最大
sudo chmod -R 777 <LOCAL_PATH>
// 重启tftpd-hpa
sudo service tftpd-hpa restart
// 重启xinetd服务
sudo /etc/init.d/xinetd reload
sudo /etc/init.d/xinetd restart

#测试
tftp <ubuntu的ip地址> //启动客户端
get uImage //从服务器获取文件到本地 即当前目录

#如果本地目录存在uImage并且大小一致就说明设置成功了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Loopback interface
auto lo
iface lo inet loopback

# Physical interface (ens33) set to manual
auto ens33
iface ens33 inet manual # 设置为手动,不直接获取 IP 地址
bridge_ports tap0 tap1 # 将 tap0 和 tap1 添加到桥接

# Bridge interface (br0)
auto br0
iface br0 inet dhcp # 使用 DHCP 获取 IP 地址
bridge_ports ens33 # 将 ens33 添加到桥接

# TAP interface (tap0)
iface tap0 inet dhcp # 使用 DHCP 获取 IP 地址
pre-up ip tuntap add tap0 mode tap # 创建 TAP 设备
up ip link set tap0 up # 启动 tap0

# TAP interface (tap1)
iface tap1 inet dhcp # 使用 DHCP 获取 IP 地址
pre-up ip tuntap add tap1 mode tap # 创建 TAP 设备
up ip link set tap1 up # 启动 tap1

检查日志:

1
sudo journalctl -xe

重启网络服务:

1
sudo systemctl restart networking

u-boot/include/configs/vexpress_a9.h 在这个文件中可以修改内核的启动地址,设置自动ttp加载内核等命令

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
#define CONFIG_EXTRA_ENV_SETTINGS \
CONFIG_PLATFORM_ENV_SETTINGS \
BOOTENV \
"console=ttyAMA0,38400n8\0" \
"dram=1024M\0" \
"root=/dev/sda1 rw\0" \
"mtd=armflash:1M@0x800000(uboot),7M@0x1000000(kernel)," \
"24M@0x2000000(initrd)\0" \
"flashargs=setenv bootargs root=${root} console=${console} " \
"mem=${dram} mtdparts=${mtd} mmci.fmax=190000 " \
"devtmpfs.mount=0 vmalloc=256M\0" \
"bootflash=run flashargs; " \
// "bootm ${kernel_addr} ${ramdisk_addr_r}\0"
// 设置 ARM 虚拟机的 IP 地址
"ipaddr=<HOST_IP>\0" \
// 设置服务器的 IP 地址
"serverip=<HOST_IP>\0" \
// 启动时获取 uImage
"get_uimage=tftp 0x60003000 uImage\0" \
// 加载设备树
"get_dtb=tftp 0x70003000 dts/vexpress-v2p-ca9.dtb\0" \
// 设置启动参数
"set_bootargs=setenv bootargs 'root=/dev/mmcblk0 console=ttyAMA0 init=/linuxrc'\0" \
// 启动 uImage
"cp ${ramdisk_addr} ${ramdisk_addr_r} ${maxramdisk}; " \
"boot_uimage=bootm 0x60003000 - 0x70003000\0"