1.bootload概念
bootload-->内核-->文件系统
建议大家在学习之前,先去看一下百度百科的bootload启动流程解释部分
bootload的作用
软件是依赖于硬件运行的,比如内存、 MCU 等,刚上电的那一刻,即使是最简单的程序也无法运行,更不用说启动操作系统内核,因为这个时候软件代码所需要的执行环境还没有准备好,所以必须对硬件进行初始化操作。这里要明白最终的目标是进入操作系统内核,在进入操作系统内核之前所运行的一小段程序代码就被称为是 BootLoader。这段代码的主要作用就是初始化硬件设备、建立内存空间映射,从而将系统的软硬件配置为合适的状态,为最终的操作系统内核提供良好的运行环境。
Bootloader 是一种很常见的软件技术,日常使用的手机、路由器、游戏机、电视机及其他嵌入式产品大多都采用这个技术。
单片机--主要应用低端市场,相对来说不是需要特别复杂的设置(软件层次),不代表硬件很简单,底层数据采集,电机控制,环境监测
RK3399--主要应用消费类电子产品,可视化电子产品,摄像头,手机,电视机,偏向于应用方向。
Bootloader 的功能(加载阶段)
Stage 1:
这个阶段一般是用汇编来实现的, 高级语言运行所需的环境还没准备好,比如函数参数传递使用的寄存器、内存、外设总线、栈空间等, 它主要是完成一些 CPU体系结构的初始化,并调用第二阶段的入口函数,执行对应的代码。
Stage 2:
这个阶段一般使用 C 语言来编写,主要的作用就是加载或者安装设备驱动,让一部分必须的外设运行起来, 比如串口、显示屏、 I/O 口的按键、指示灯、网口等,主要是为了后续的内核加载提供基础, 这个阶段被称为是平台初始化(PlatForm Initialize)。
Stage 3:
这个阶段的主要作用就是加载操作系统的内核,并向内核传递一些启动参数, 并将执行流程跳转入操作系统的内核。 这个传参过程不是必须的!但目前基于 Linux 操作系统的都有这个功能 。
这样的分层设计、 分阶段启动, 从软件架构上看, 使得代码结构清晰、流程简洁, 能更利于对多个硬件平台的兼容和扩展;从软件功能上看,特定平台的硬件资源在逐步加载,最终完成启动流程。
为什么使用bootload
常见的Bootloader
Bootloader 并不是某个特定的软件,而是在完成对硬件初始化、操作系统加载、引导功能的软件的统称。在不同的发展阶段,针对不同的 MCU 平台,出现了多个完成Bootloader 功能的软件。 其中, U-Boot 因为开源、良好的软件架构和硬件兼容性,得到广泛应用。 下表简单列出了目前集中主流 Bootloader 的对比。
uboot介绍
U-Boot(Universal Boot Loader),是一个遵循 GPL 协议的开源软件, 也是一个广泛使用的 Bootloader。
U-Boot 配置及编译过程
交叉编译基本概念
交叉编译, 就是在一个平台编译出可以在另外一个平台运行的可执行文件。 比如说,我们可以在 x86 平台上编译出能够在 arm 平台上运行的可执行文件。本质上,就是在 x86平台上,按照 arm 平台规则翻译了可执行文件。 完成这个编译过程的, 通常叫交叉编译工具, 因为这个工具往往是很多个程序组成, 也叫交叉编译工具链。 执行编译的平台,叫宿主机; 编译出来的程序运行的平台, 叫目标平台或目标板。
通用的 U-Boot 源码,都配套提供了针对常见平台的交叉编译工具链。同时,部分厂家针对自己的 MCU 和板卡产品,也会提供自己的工具链。实际使用过程中,优先选择厂家提供的工具链。
获取源码:
我们当前源码包中的boot是经过裁剪(瑞芯微--》九鼎)之后,适合于RK3399使用的boot
官方路径:
The U-Boot Documentation — Das U-Boot unknown version documentation
一般我们在做开发的时候,不会直接选择uboot官方提供的引导程序,而是根据瑞芯微或者其他的开发商提供的代码进行修改,这样可以缩短项目的开发周期。
uboot结构:
重要目录介绍:
arch: 存放和硬件平台及 CPU 体系架构相关的文件,下面 根据不同的硬件 CPU 架构分子目录。
board: 存放不同厂家的板卡产品相关的文件,下面以厂 家为名称分子目录。
drivers: 存放所有外围芯片的驱动, 如网卡、 USB、串口、 LCD、 Nand Flash 等。 这些驱动是保证 U-Boot 作为一个早 期调试平台,提供基本的硬件功能。
fs: 存放文件系统相关的代码。 net: 存 放 网 络 协 议 相 关 的 代 码 , 主 要 是 支 持 在 Bootloader 阶段使用 TCP/IP 协议栈及一些网络命令。
common: 存放与处理器体系结构无关的通用代码, 如命令 解析代码/common/command.c、所有命令的上层代码 cmd_*.c、环境变量处理代码 env_*.c、 CRC 校验等都位于 本目录下。 configs: 存放 U-Boot 的配置文件,不同厂家会根据自己 产品情况提供基本的配置文件。 Include, lib: 头文件和库文件路径。当需要在 U-Boot 上进行开发时使用。 比如,增加自己的驱动或调试命令。
查看boot中包含的内容:
uboot的命令:
作为 Bootloader 的基本功能,为用户提供调试手段,便于用户解决启动和操作系统加载过程中的问题,是非常重要的。 U-Boot 通过简单的命令行界面,为用户提供丰富的调试命令;同时,我们也可以在其中增加自己的命令,极大方便了内核的开发和调试过程。
进入调试模式
安装一个软件
调试接口连接方式:
将USB转串口连接到电脑上:
通过设备管理器查看使用的端口:
选择端口进行设置:
开启电源,启动bootload加载内核,在bootload运行的过程中,看到如下命令行,点击键盘上的ctrl+c即可进入bootload中,查看bootload内容:
在进入bootload之前,设备加载打印的信息如下:
u-boot中全部命令:
? - alias for 'help'
android_print_hdr- print android image header
base - print or set address offset
bdinfo - print Board Info structure
boot - boot default, i.e., run 'bootcmd'
boot_android- Execute the Android Bootloader flow.
bootavb - Execute the Android avb a/b boot flow.
bootd - boot default, i.e., run 'bootcmd'
booti - boot arm64 Linux Image image from memory
bootm - boot application image from memory
bootp - boot image via network using BOOTP/TFTP protocol
bootrkp - Boot Linux Image from rockchip image type
bootz - boot Linux zImage image from memory
charge - Charge display
cmp - memory compare
coninfo - print console devices and information
cp - memory copy
crc32 - checksum calculation
dhcp - boot image via network using DHCP/TFTP protocol
dm - Driver model low level access
download- enter rockusb/bootrom download mode
dtimg - manipulate dtb/dtbo Android image
dump_atags- Dump the content of the atags
dump_bidram- Dump bidram layout
dump_irqs- Dump IRQs
dump_sysmem- Dump sysmem layout
echo - echo args to console
editenv - edit environment variable
env - environment handling commands
exit - exit script
ext2load- load binary file from a Ext2 filesystem
ext2ls - list files in a directory (default /)
ext4load- load binary file from a Ext4 filesystem
ext4ls - list files in a directory (default /)
ext4size- determine a file's size
false - do nothing, unsuccessfully
fastboot- use USB or UDP Fastboot protocol
fatinfo - print information about filesystem
fatload - load binary file from a dos filesystem
fatls - list files in a directory (default /)
fatsize - determine a file's size
fatwrite- write file into a dos filesystem
fdt - flattened device tree utility commands
fstype - Look up a filesystem type
go - start application at address 'addr'
gpt - GUID Partition Table
help - print command description/usage
iomem - Show iomem data by device compatible(high priority) or node name
lcdputs - print string on video framebuffer
load - load binary file from a filesystem
loop - infinite loop on address range
ls - list files in a directory (default /)
md - memory display
mdio - MDIO utility commands
mii - MII utility commands
mm - memory modify (auto-incrementing address)
mmc - MMC sub system
mmcinfo - display MMC info
mw - memory write (fill)
nfs - boot image via network using NFS protocol
nm - memory modify (constant address)
part - disk partition related commands
ping - send ICMP ECHO_REQUEST to network host
printenv- print environment variables
pxe - commands to get and boot from pxe files
rbrom - Perform RESET of the CPU
reset - Perform RESET of the CPU
rkimgtest- Test if storage media have rockchip image
rktest - Rockchip board modules test
rockchip_show_bmp- load and display bmp from resource partition
rockchip_show_logo- load and display log from resource partition
rockusb - Use the rockusb Protocol
run - run commands in an environment variable
save - save file to a filesystem
setcurs - set cursor position within screen
setenv - set environment variables
showvar - print local hushshell variables
size - determine a file's size
source - run script from memory
sysboot - command to get and boot from syslinux files
test - minimal test like /bin/sh
tftpboot- boot image via network using TFTP protocol
true - do nothing, successfully
usb - USB sub-system
usbboot - boot from USB device
version - print monitor, compiler and linker version
当前使用的u-boot中环境变量内容:
=> printenv
arch=arm
baudrate=115200
board=evb_rk3399
board_name=evb_rk3399
boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}
boot_extlinux=sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}extlinux/extlinux.conf
boot_net_usb_start=usb start
boot_prefixes=/ /boot/
boot_script_dhcp=boot.scr.uimg
boot_scripts=boot.scr.uimg boot.scr
boot_targets=mmc1 mmc0 usb0 pxe dhcp
bootargs=storagemedia=emmc androidboot.storagemedia=emmc androidboot.mode=normal
bootcmd=boot_android ${devtype} ${devnum};bootrkp;run distro_bootcmd;
bootcmd_dhcp=run boot_net_usb_start; if dhcp ${scriptaddr} ${boot_script_dhcp}; then source ${scriptaddr}; fi;
bootcmd_mmc0=setenv devnum 0; run mmc_boot
bootcmd_mmc1=setenv devnum 1; run mmc_boot
bootcmd_pxe=run boot_net_usb_start; dhcp; if pxe get; then pxe boot; fi
bootcmd_usb0=setenv devnum 0; run usb_boot
bootdelay=1
cpu=armv8
cpuid#=5447395639342e30300000000016030a
devnum=0
devtype=mmc
distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done
ethaddr=1a:31:9c:ed:46:4c
fdt_addr_r=0x08300000
kernel_addr_r=0x00280000
mmc_boot=if mmc dev ${devnum}; then setenv devtype mmc; run scan_dev_for_boot_part; fi
partitions=uuid_disk=${uuid_gpt_disk};name=loader1,start=32K,size=4000K,uuid=${uuid_gpt_loader1};name=loader2,start=8MB,size=4MB,uuid=${uuid_gpt_loader2};name=trust,size=4M,uuid=${uuid_gpt_atf};name=boot,size=112M,bootable,uuid=${uuid_gpt_boot};name=rootfs,size=-,uuid=B921B045-1DF0-41C3-AF44-4C6F280D3FAE;
pxefile_addr_r=0x00600000
ramdisk_addr_r=0x0a200000
rkimg_bootdev=if mmc dev 1 && rkimgtest mmc 1; then setenv devtype mmc; setenv devnum 1; echo Boot from SDcard;elif mmc dev 0; then setenv devtype mmc; setenv devnum 0;elif mtd_blk dev 0; then setenv devtype mtd; setenv devnum 0;elif mtd_blk dev 1; then setenv devtype mtd; setenv devnum 1;elif mtd_blk dev 2; then setenv devtype mtd; setenv devnum 2;elif rknand dev 0; then setenv devtype rknand; setenv devnum 0;elif rksfc dev 0; then setenv devtype spinand; setenv devnum 0;elif rksfc dev 1; then setenv devtype spinor; setenv devnum 1;fi;
scan_dev_for_boot=echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; for prefix in ${boot_prefixes}; do run scan_dev_for_extlinux; run scan_dev_for_scripts; done;
scan_dev_for_boot_part=part list ${devtype} ${devnum} -bootable devplist; env exists devplist || setenv devplist 1; for distro_bootpart in ${devplist}; do if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then run scan_dev_for_boot; fi; done
scan_dev_for_extlinux=if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}extlinux/extlinux.conf; then echo Found ${prefix}extlinux/extlinux.conf; run boot_extlinux; echo SCRIPT FAILED: continuing...; fi
scan_dev_for_scripts=for script in ${boot_scripts}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then echo Found U-Boot script ${prefix}${script}; run boot_a_script; echo SCRIPT FAILED: continuing...; fi; done
scriptaddr=0x00500000
serial#=ad481058a1dab68d
soc=rockchip
stderr=serial,vidconsole
stdout=serial,vidconsole
usb_boot=usb start; if usb dev ${devnum}; then setenv devtype usb; run scan_dev_for_boot_part; fi
vendor=rockchip
Environment size: 3320/32764 bytes
文件传输软件FZ
依赖于SSH服务
sudo apt-get install openssh-server
如果连接不上,安装FTP服务:
sudo apt-get install vsftpd
sudo vi /etc/vsftpd.conf
sudo /etc/init.d/vsftpd restart
savenv无法使用的问题解决
注意路径:
u-boot的配置界面:
箭头键在菜单中导航<输入>选择子菜单--->(或空子菜单----)。突出显示的字母│
│ 是热键。按<Y>包括、<N>排除、<M>模块化特征。按<Esc><Esc>退出,<?>│
│ 有关帮助,</>有关搜索。图例:[*]内置[]排除<M>模块<>模块功能
选择环境参数配置选项:
Select the location of the environment (Environment in a block device) --->
以上选项的help内容如下:
Kconfig--主要就是我们当前看到的菜单中的显示的内容
.config--是用户配置完boot之后,执行./mk.sh -u之后,根据大家的配置,生成的一个配置文件
配置完成之后,按键盘的esc键退出
重新编译我们的u-boot,将镜像文件下载到驱动板中:
./mk.sh -u
./mk.sh -U
将镜像文件重新下载到开发板中即可
每一天都需要去看内核中的源码,一定记住不同文件的路径
U-BOOT中的命令框架:
U_BOOT_CMD 宏
U-Boot 的每一个命令都是通过 U_BOOT_CMD 宏定义来实现的,这个宏在include/command.h 头文件中定义。每一个命令定义了一个 cmd_tbl_t 结构体,结构体包含的成员变量有:命令名称、最大参数个数、是否重复、命令执行函数、用法、帮助。
路径位置:
u-boot\include\command.h
ll_entry_decalre()链表
为了便于管理命令数据结构,命令结构体被统一链接到一个数据段中:
find_cmd()函数
路径位置:
u-boot\common\command.c
从控制台输入的命令都被送到 common/command.c 中的 find_cmd()函数解释执行,根据匹配输入的命令,从列表中找出对应的命令结构体,并调用其回调处理函数完成命令处理。 命令响应的过程,就是命令的查找与回调函数处理的过程, 如下图:
U-Boot 控制命令实现
cmd/Kconfig 菜单配置
在 cmd/Kconfig 文件中,增加 CMD_BUZ_TEST 菜单配置; 该菜单配置使得相应命令能在 make menuconfig 中被选中。
u-boot/cmd/Kconfig
当前路径下的Makefile文件修改:
编译的过程大家参考“boot的移植”
进入菜单查看配置:
按Y选中即可:
如果有相同的菜单操作同一个外设,一定要记得取消一个
Enable 'buztest' command 记得取消
单独编译u-boot同时也可以使用以下指令编译我们的u-boot
需要首先设置交叉编译器
make -j4 CROSS_COMPILE=aarch64-linux-gnu-
make--makefile执行命令
-j4--可以使用多线程编译
CROSS_COMPILE=aarch64-linux-gnu- 设置交叉编译器
-j4 -j后面跟的数值大小和虚拟机配置有关系:
设置环境变量:
设置好以上环境变量之后,再次执行:
make -j4 CROSS_COMPILE=aarch64-linux-gnu-
编译完成之后,返回u-boot的上一级目录,执行
./mk.sh -u