参考资料
本篇内容主要参考 韦东山的《嵌入式Linux应用开发完全手册V5.2_IMX6ULL_Pro开发板.pdf》
具体课程见 百问网嵌入式专家-韦东山嵌入式专注于嵌入式课程及硬件研发
实践环境为百问网官方开发板 100ASK_IMX6ULL-Pro
目标系统组成
Linux系统启动流程
一个有效的根文件系统集成了第三方和内部的所有软件组件。涉及组件的下载、提取、配置、编译和安装,并可能修复问题和调整配置文件。
-
一个基本的根文件系统至少需要
- 传统的目录层次结构,包括/bin、/etc、/lib、/root、/usr/bin、/usr/lib、/usr/share、/usr/sbin、/var、/sbin。
- 一套基本实用程序,至少提供 init 程序、shell 和其他传统的 UNIX 命令行工具。这通常由 BusyBox 提供。
- 安装在/lib 中的 C 库和相关库(线程库、数学库等)。一些配置文件,如/etc/inittab,以及初始化脚本/etc/init.d。
-
在大多数嵌入式 Linux 系统通用的基础之上,可以添加第三方或内部组件。
几种解决方案:
- 手动操作
- 系统构建工具
- 发行版或现成的文件系统
组件构建工具
- Makefile
- autotools
- CMake
系统构建工具
可以使用不同的工具来自动化构建目标系统的过程,包括内核,有时还包括工具链。
- 以正确的顺序自动下载、配置、编译和安装所有组件,有时在应用补丁修复交叉编译问题之后。
- 已经支持大量的包,应该符合您的主要要求,并且易于扩展。
- 构建变得可重现,这允许轻松更改某些组件的配置、升级它们、修复错误等。
常见的系统构建工具
-
Buildroot,由社区开发,https://buildroot.org。
-
项目主要特点
- 制作启动映像
- 从源代码构建所有组件
- 注重简单
-
支持:根文件系统映像、内核、引导加载程序、工具链的自由组合
-
-
OpenWRT,最初是无线路由器 Buildroot 的一个分支,现在是一个更通用的项目,https://openwrt.org。
-
OpenEmbedded,更灵活但也更复杂,http://www.openembedded.org 及其工业化版本 Yocto 项目。
发行版Linux系统
Linux系统
-
一种自由和开放源码的类UNIX操作系统,内核创建于1991-10-5,加上用户空间和应用程序之后成为Linux系统。
-
遵循 GNU通用公共许可证(GPL),任何个人和机构都可以自由使用,修改和再发布。
- GNU 是一个自由的操作系统,其内容软件完全以GPL方式发布(编译套件 GCC,C库 glibc,核心工具组 coreutils,调试器 GDB等)
发行版Linux:Linux distribution(GNU/Linux 发行版,为一般用户预先集成好Linux操作系统和各种应用软件,以软件包管理系统进行应用管理)
- 商业发行版本:Ubuntu(支持x86,arm等不同的处理器架构),Red Hat(主要支持x86),SUSE
- 社区发行版本:Debain,Fedora, Arch
- 国内衍生Linux发行版本:Deepin,优麒麟
嵌入式Linux系统
嵌入式Linux系统框架
嵌入式Linux系统构建
开发环境搭建
基础软件安装
百问网提供了 Ubuntu 配置命令脚本,支持一键下载安装
Bash
git clone https://e.coding.net/weidongshan/DevelopmentEnvConf.git
cd DevelopmentEnvConf
sudo ./Configuring_ubuntu.sh
配置交叉编译工具链
工具链:一组编程工具,用于开发软件,创建软件产品。包括编译器和链接器,C库,调试器,头文件,二进制实用程序等等
交叉编译工具链:一组工具,用来将源代码构建为可以运行在其他平台的二进制代码,将构建环境和目标环境分隔开(不同的CPU架构,ABI,OS,Clib)
SDK(software development kit):一个更广泛的集合,除了工具链外,还包括为 Target 目标架构构建的库、头文件,以及示例代码、文档、开发指南等资源。
交叉编译构建过程:
- Build(构建机器),使用 GCC 的源码,制作交叉编译工具链。
- Host(主机),使用交叉编译工具链,编译出程序。
- Target(目标机器),程序执行的地方。
本地工具链:build == host == target。
交叉编译工具链:build == host!= target
系统定义描述了一个系统:CPU 架构、芯片厂商、操作系统、ABI、C 库。
- <arch>-<vendor>-<os>-<libc/abi>(完整名称);
- <arch>-<os>-<libc/abi>。
arm-foo-none-eabi
,针对 ARM 架构的裸机工具链,来自供应商 foo。
arm-unknown-linux-gnueabihf
,针对 ARM 架构的 Linux 工具链,使用来自未知供应商的 EABlhf ABI 和 glibc C 库。
armeb-linux-uclibcgnueabi
,针对 ARM big-endian 的 Linux 工具链架构,使用 EABl ABI 和 uClibc C 库。
下载100ask_imx6ull 开发板的 BSP:
Bash
git clone https://e.coding.net/codebug8/repo.git
mkdir -p 100ask_imx6ull-sdk && cd 100ask_imx6ull-sdk
../repo/repo init -u https://gitee.com/weidongshan/manifests.git -b linux-sdk -m imx6ull/100ask_imx6ull_linux4.9.88_release.xml --no-repo-verify
../repo/repo sync -j4
交叉编译工具链配置
交叉工具链的主要内容
配置过程主要是设置 PATH, ARCH 和 CROSS_COMPILE 三个环境变量:
Bash
export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
- 永久生效:修改用户配置文件
vim ~/.bashrc
- 临时生效:直接执行命令,只对当前终端有效
系统构建
Bootloader: Uboot
Bootloader 是在操作系统运行之前运行的一段代码,用于引导操作系统,并支持下载和调试。
U-Boot 是一个开源的主引导加载程序,并含有多种命令以便调试系统。它适用于多种计算机体系结构,包括 ARM,RISC-V 和 x86。
不同的开发板对应不同的配置文件,配置文件位于 u-boot 源码的"configs/"目录。
对于 IMX6ULL Pro 版,u-boot 的编译过程如下(编译 uboot前必须先配置好工具链等开发环境):
Bash
cd /home/book/100ask_imx6ull-sdk/Uboot-2017.03
make distclean
make mx6ull_14x14_evk_defconfig
make
编译完成之后生成 u-boot-dtb.imx,可以烧在 TF 卡、EMMC 上
Bash
# 将u-boot-dtb.imx 文件烧写到 EMMC 上:
echo 0 > /sys/block/mmcblk1boot0/force_ro
dd if=u-boot-dtb.imx of=/dev/mmcblk1boot0 bs=512 seek=2
echo 1 > /sys/block/mmcblk1boot0/force_ro
Linux Kernel 和模块
编译驱动程序之前要先编译内核:
- 驱动程序要用到内核文件
- 编译驱动时用的内核、开发板上运行到内核,要保持一致
- 同理,更换板子上的内核后,板子上的其他驱动也要更换
流程说明
-
获取配套的交叉编译工具链
- SOC原厂提供:NXP ST Rockchip Amlogic Allwinnertech等。
- 社区下载:Linrao Debian ARM Bootlin
-
下载kernel源码
-
获取Linux Kernel主线LTS源码
-
获取芯片原厂Kernel源码
-
-
Host下配置开发环境
- 安装必要依赖包
- 解压配置合适的工具链
-
指定编译板子配置文件
make BOARDNAME_defconfig
-
编译
- 编译内核镜像
make -jN
- 编译设备树
make dtbs
- 编译安装模块驱动
make modules
- 编译内核镜像
编译内核
源码镜像
-
vmlinux,未压缩的原始内核映像,ELF 格式,用于调试目的,但无法启动。
-
arch/ /boot/*image,是最终可以启动的压缩后的内核镜像文件:
- bzImage for x86,
- zImage for ARM,
- Image.gz for RISC-V,
- vmlinux.bin.gz for ARC等。
-
arch/ /boot/Image,也可以引导的未压缩内核映像。
-
arch/ /boot/dts/*.dtb,编译的设备树文件(某些架构)。
-
所有内核模块,分布在内核源代码树中,作为 .ko(内核目标)文件。
配置编译环境:指定架构和编译器,以及单板的配置文件
不同的开发板对应不同的配置文件,配置文件位于内核源码 arch/arm/configs/ 目录。
IMX6ULL_Pro开发板 kernel 的编译过程如下:
Bash
cd /home/book/100ask_imx6ull-sdk/Linux-4.9.88
make mrproper
make 100ask_imx6ull_defconfig
make zImage -j8
make dtbs
编译完成后,在 arch/arm/boot 目录下生成 zImage 内核文件, 在 arch/arm/boot/dts 目录下生成设备树的二进制文件 100ask_imx6ull14x14.dtb
编译安装内核模块
- 使用内核模块可以支持更多不同的设备外设。
- 模块使无需重启即可轻松开发驱动程序:加载、测试、卸载、重建、加载...
- 有助于将内核映像大小保持在最小(在 PC 的 GNU/Linux 发行版中必不可少)。
- 对于减少启动时间也很有用:您无需花时间初始化稍后才需要的设备和内核功能。
注意:一旦加载,在系统中拥有完全控制权和权限。没有特别的保护。这就是为什么只有 root 用户才能加载和卸载模块。
编译:
Bash
cd ~/100ask_imx6ull-sdk/Linux-4.9.88/
make modles
安装内核模块到Ubuntu内的某一个目录备用:
Bash
cd ~/100ask_imx6ull-sdk/Linux-4.9.88/
make ARCH=arm INSTALL_MOD_PATH=/home/book/nfs_rootfs modules_install
编译设备树
- 目标单板所需的硬件设备信息。
- 一般用于嵌入式设备。
设备树文件要与目标单板配套使用。一般和内核镜像存放同一位置。
内核源码目录下执行 make dtbs
安装内核和模块到开发板
Bash
mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt
cp /mnt/zImage /boot
cp /mnt/100ask_imx6ull-14x14.dtb /boot
cp /mnt/lib/modules /lib -rfd
替换对应的目录中文件,重启开发板即可完成更新 zImage、dtb、模块
完整的系统
根文件系统与 busybox
Linux 系统需要一组基本的程序才能工作,包括一个 init 程序、一个 shell 以及用于文件操作和系统配置的各种基本实用程序。在普通的 GNU/Linux 系统中,这些程序由不同的项目提供。
Busybox 本身包含了很多 Linux 命令,但是要编译其他程序或者某些依赖库,需要手工下载、编译。 如果想做一个极简的文件系统,可以使用 Busybox 手工制作。
文件系统是一套实现了数据的存储、分级组织、访问和获取等操作的抽象数据类型(Abstract data type)
-
数据存取
- 使用硬盘和光盘这样的存储设备,并维护文件在设备中的物理位置
- 通过网络协议(如 NFS、SMB 等)提供的或者暂存于内存上
- 虚拟文件(如 proc 文件系统)
-
用户访问管理
- 不必关心数据实际保存在硬盘(或者光盘)的地址为多少的数据块上,只需要记住这个文件的所属目录和文件名
- 不必关心硬盘上的那个块地址没有被使用,硬盘上的存储空间管理(分配和释放)功能由文件系统自动完成
根文件系统:被挂载在特定层次结构的 root 位置,由"/"标识
- mount 和 umount 是程序,是文件系统中的文件。所以在安装至少一个文件系统之前无法使用
- 不能用普通的挂载命令挂载,由内核直接挂载,根据"root="内核选项进行设置。当没有可用的根文件系统时,内核会崩溃
- 支持从不同位置挂载,包括存储设备(硬盘,SD卡等),NFS和内存。
busybox 在根文件系统:
Buildroot
Buildroot 是一组 Makefile 和补丁,可自动化地为嵌入式系统构建完整的、可启动的 Linux 环境(包括 bootloader、Linux 内核、包含各种 APP的文件系统)。
- 可以自动构建所需的交叉编译工具链,创建根文件系统,编译 Linux 内核映像,并生成引导加载程序用于目标嵌入式系统。并支持所有步骤的任何独立组合。
- 使用简单:类似内核的menuconfig
- 支持大量的实用软件包,比如 QT等
构建说明
- 所有的构建都会输出到顶层目录下的 output/目录内。
O = output
。另外也支持 out-of-tree 构建。 - 配置文件作为.config 存储在顶级 Buildroot 源目录中。
CONFIG_DIR = $(TOPDIR),TOPDIR = $(shell pwd)
IMX6ULL_Pro 编译过程
Bash
cd ~/100ask_imx6ull-sdk/Buildroot_2020.02.x
#选择配置界面
make menuconfig
# 单独编译内核
make linux-rebuild
# 进入内核配置选项
make linux-menuconfig
# 单独编译 u-boot
make uboot-rebuild
# 单独编译某个软件包
make <pkg>-rebuild
# 进入 busybox 配置选项
make busy-box-menuconfig
# 生成系统 sdk
make sdk
配置文件说明
编译系统
Bash
cd /home/book/100ask_imx6ull-sdk/Buildroot_2020.02.x
make clean
make 100ask_imx6ull_pro_ddr512m_systemV_qt5_defconfig
make all -j4
镜像文件说明
buildroot2020.02.x/output/images/
100ask_imx6ull-14x14.dtb
【设备树文件】rootfs.ext2
rootfs.ext4
rootfs.tar
rootfs.tar.bz2
【打包并压缩的根文件系统,用于NFSROOT启动】100ask-imx6ull-pro-512d-systemv-v1.img
【完整的系统镜像,用于烧写EMMC和SD卡】uboot-dtb.imx
【Uboot镜像】zImage
【内核镜像】
系统烧录
USB 模式烧录
使用 USB 烧写工具:
使用命令行
-
执行脚本命令
sudo ./bin/uuu scripts/basic/emmc/write_all.clst #烧写整个系统
-
对于裸机程序,名字各有不同,没有提供固定的脚本
sudo ./bin/uuu -b emmc(or sd) firmware/u-boot-dtb_fastboot_100ask.imx files/led.imx #把 led.imx 烧到 EMMC
在开发板上直接烧写
烧写 u-boot
-
将uboot镜像u-boot-dtb.imx拷贝到开发板根目录
-
烧写 EMMC
bashecho 0 > /sys/block/mmcblk1boot0/force_ro //取消此分区的只读保护 dd if=u-boot-dtb.imx of=/dev/mmcblk1boot0 bs=512 seek=2 //实际烧写命令 echo 1 > /sys/block/mmcblk1boot0/force_ro //打开此分区的只读保护
-
烧写 SD/TF
dd if=u-boot-dtb.imx of=/dev/mmcblk0 bs=512 seek=2
-
更新内核或设备树
开发板使用的内核名为 zImage,设备树名为 100ask_imx6ull-14x14.dtb。 保存在开发板的/boot 目录中,只要替换/boot 目录下的文件后重启即可完成更新
烧写 SD/TF 卡
Windows SD/TF 卡烧录工具
格式化:
烧写镜像:
Ubuntu下使用命令行烧录 SD/TF 卡
在 Ubuntu 下可以更精细地操作 SD/TF 卡:把 sdcoard.img 整个烧写到卡上,单独烧写 u-boot 到卡上,甚至挂接卡上的文件系统后单独更新里面的文件。
-
识别 SD/TF 卡:使用 dmesg 命令获取设备挂载的设备节点
-
更新整个系统镜像:使用 dd 命令烧写 sdcard.img 镜像文件到 /dev/sdb 设备
sudo dd if=sdcard.img of=/dev/sdb
-
只更新卡上的 u-boot:使用 dd 命令烧写 uboot的imx 镜像文件到 /dev/sdb 设备
sudo dd if=u-boot-dtb.imx of=/dev/sdb bs=1k seek=1 conv=fsync
-
更新 SD/TF 卡中的内核和设备树
-
对于曾经烧写过的 SD/TF 卡,上面已经有分区。使用 vmware 连接 TF 卡设 备后,Ubuntu 系统系统会自动挂载 tf 卡内的分区文件系统
- 执行
df -h
命令找到对应目录,将其中的内核镜像拷贝到开发板 /boot 目录后重启
- 执行
-