Uboot介绍
本人是刚毕业大学生,对linux系统移植了解尚浅,如果有疑问或者错误,欢迎在评论区指出
[1uboot基础了解 - 知乎.pdf](PDF\uboot\1uboot基础了解 - 知乎.pdf)
bootloader
- boot,为了运行程序,做一些初始化
- loader,执行应用逻辑,加载Linux内核
什么是bootloader
- 嵌入式系统在加电之后执行的第一段代码
- 用于将软硬件环境初始化到一个合适的状态,为操作系统的加载和运行做准备(本身不是操作系统)
- 将操作系统映像或固化的嵌入式应用程序装载到内存中然后跳转到操作系统所在的空间,启动操作系统运行
- 当操作系统内核加载完成后,Bootloader 生命周期就结束了
为什么使用bootloader
bootloader 是启动引导程序的统称
-
介绍
相当于windows下的BIOS,是操作系统内核的一段程序
bootloader 赋值检测硬件、配置设备和加载操作系统内核,是操作系统中非常重要的组成部分,确保操作系统能够顺序启动并加载
-
功能:
- 初始化软硬件环境
- 引导加载Linux内核
- 给linux内核传参
- 执行用户命令
bootloder启动分析
第一阶段
- 硬件设备初始化,设置时钟,设置分配系数,关闭看泵,关中断,启动ICACHE,关闭DCACHE和TLB,关闭MMU,设置分配系数,FCLK:HCLK:PCLK=1:4:8
- FCLK:内核时钟,提供给内核的时钟
- HCLK:总线时钟,供给用于存储器控制器,中断控制器,LCD 控制器,DMA 和 USB 主机模块的 AHB总线的时钟
- PCLK:I/O接口时钟,提供给用于外设APB总线的时钟
- 初始化内存空间
- 将bootloader的第二阶段代码复制到RAM中
- 设置堆栈
- 跳转到第二阶段的C入口点
第二阶段
- 初始化本阶段要使用到的硬件设备
- 检测系统内存映射
- 将内核映像和根文件系统映像从Flash读到SDRAM中
- 为内核设置启动参数
- 调用内核
- 跳转到内核
开发板启动过程
材料准备
windows | linux |
---|---|
windows镜像 和 U盘(启动盘) | 顺序linux内核镜像、SD卡启动盘 |
进入BIOS选择启动方式 | 通过拨码开关选择启动方式 |
通过U盘中的引导程序安装系统 | 通过SD卡中的引导程序安装系统 |
安装Windows驱动系统 | 安装linux驱动系统 |
安装Windows应用系统 | 安装linux应用程序 |
启动流程图
- 将BL0固化到芯片内部,只做UBoot(BL1)的加载
- UBoot(BL1)将linux内核加载到RAM上运行
- linux内核完成跟文件系统挂载,系统启动完成
bootloader有哪些
U-Boot:
遵循GPL条款
的开放源码目录
优点:功能最多,灵活最强,开源
功能:支持多个文件系统、附带调试、脚本、引导等工具
结构:与linux类似
BootLoader | 描述 | x86 | ARM | PowerPC |
---|---|---|---|---|
LILO | Linux磁盘引导程序 | 是 | 否 | 否 |
GRUB | GNU的LILO替代程序 | 是 | 否 | 否 |
Loadlin | 从DOS引导Linux | 是 | 否 | 否 |
ROLO | 从ROM引导Linux而不需要BIOS | 是 | 否 | 否 |
Etherboot | 通过以太网卡启动Linux系统的固件 | 是 | 否 | 否 |
LinuxBIOS | 完全替代BUIS的Linux引导程序 | 是 | 否 | 否 |
BLOB | LART等硬件平台的引导程序 | 否 | 是 | 否 |
U-boot | 通用 引导程序 | 是 | 是 | 是 |
RedBoot | 基于eCos的引导程序 | 是 | 是 | 是 |
uboot工作方式
[2uboot启动流程分析 - 知乎.pdf](PDF\uboot\2uboot启动流程分析 - 知乎.pdf)
- 启动加载模式:Bootloader正常工作模式,正常上电和Bootloader将嵌入式操作系统从flash中加载到SDRAM中
- 下载模式,Bootloader通过通讯,将内核镜像、跟文件系统镜像从PC机直接下载到目标包的FLASH中
uboot执行流程
-
uboot入口函数
:- uboot工程连接脚本文件,决定了Uboot的组装
- uboot文件中ENTRY(_start)指定了uboot的入口地址
建立一个基本指向环境,初始化硬件寄存器和堆栈等
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) @程序的入口函数 SECTIONS @定义了段 { . = 0x00000000; @起始地址 . = ALIGN(4); @四字节对齐 .text : { *(.__image_copy_start) @映像文件复制起始地址 *(.vectors) @异常向量表 arch/arm/cpu/armv7/start.o (.text*) @启动函数 } ...... }
-
board_init_f板级前置初始化
- 调用init_sequence_f,对串口、定时器设备树等进行一系列初始化工作
- 初始化末尾执行了reloc_xxx函数,实现的UBoot的重定向功能
对特定的硬件板进行设置和配置
void board_init_f(ulong boot_flags) { gd->flags = boot_flags; gd->have_console = 0; if (initcall_run_list(init_sequence_f)) hang(); } static const init_fnc_t init_sequence_f[] = { setup_mon_len, ... log_init, arch_cpu_init, /* 基本的 arch cpu 相关设置 */ env_init, /* 初始化环境 */ ... reloc_fdt, /* 重定向 */ reloc_bootstage, reloc_bloblist, setup_reloc, ... }
-
relocate_code重定向
,将uboot自身镜像拷贝到ddr上的另一个位置的动作- uboot在ROM上,需要将代码拷贝到内存上才能完整运行
- 为kernel腾空间,kernel一般放在内存上,需要把uboot重定向到顶端,避免内存践踏
-
board_init_r
:板级后置初始化- 同board_init_f,拥有一个init_sequence_r初始化列表,DM模型初始化,MMC驱动初始化
对设备进行调试和故障排除
-
main_loop:Uboot主循环
Uboot最终指向函数
- 加载kernel
- uboot命令体系
uboot的存放位置
- flash上存放着U-boot、环境变量、内核映像、文件系统等
- U-boot存放于Flash的指定位置,这个位置由厂商决定
uboot移植
编译uboot
- https://www.nxp.com.cn/lgfiles/NMG/MAD/YOCTO/firmware-sentinel-0.9.bin ——哨兵映像
make distclean //清理工程
make imx93_11x11_evk_defconfig //配置uboot 配置文件
make V=1 -j4 //编译
V=1:打印更多的详细信息
-j4:使用4核心进行编译
uboot写SD卡
-
MMC/SD
sudo dd if=<U-Boot image> of=/dev/sdx bs=1k seek=<offset> conv=fsync
-
偏移量
1 - 用于imx6 和 imx7
33 - 用于i.MX 8QuadMax A0, i.MX 8QuadXPlus A0, 和 i.MX 8M Quad, 和 i.MX 8M Mini
13 - 用于i.MX 8QuadXPlus B0, i.MX 8QuadMax B0, i.MX 8DualX, i.MX 8DXL, i.MX 8M Nano, i.MX 8M Plus,
i.MX 8ULP, 和 i.MX 9
-
UUU下载uboot
-
sudo uuu -b <emmc|emmc_all|sd|sd_all|spl> imx-boot.......flash_singleboot
- emmc / emm_all:向emmc写uboot
- sd / sd_all:向sd卡写uboot
- spl:向ram写uboot
-
uuu uboot.imx uuu flash.bin //uboot.imx ≈ flash.bin
- 先将uboot启动在ram中,然后在写入闪存中
uboot命令
-
内核引导
-
boot——完成内核重定位,将内核从外存加载到内存,然后启动内核
-
boot读取环境变量
bootcmd
启动系统 -
格式:
boot
-
-
bootm/booti——调用时一般要传入内核在内存中的地址,然后取该地址处启动内核
-
bootm/booti用于启动
uImage
镜像文件,m调用32位,i调用64位 -
格式:
1. bootm addr //不使用设备树 2. bootm [addr [initrd [:size]] [fdt]] //要使用设备树 * addr:镜像在DRAM中的首地址 * initrd是initrd的地址,为空时用"-"代替 * fdt是设备树在DRAM中的首地址
-
-
bootz——镜像文件已经存储在DRAM中,bootz来启动
-
用于自动zImage镜像文件
-
格式:
bootz [addr [initrd[:size]] [fdt]] * addr:镜像在DRAM中的首地址 * initrd是initrd的地址,为空时用"-"代替 * fdt是设备树在DRAM中的首地址
-
-
-
内存操作
-
md——显示内存值
- 格式
md [.b .w .l] address [#of objects] [.b .w .l]:byte、word、long //以1字节、2字节、4字节显示内存值 address:内存起始地址 [#of objects]:查看数据的长度
-
nm——修改指定地址的内存值,修改时指向地址不会自增
- 格式
nm [.b .w .l] address [.b .w .l]:byte、word、long //以1字节、2字节、4字节指定操作格式 address:内存起始地址
-
mm——修改指定地址的内存值,修改时指向地址会自增
- 格式
nm [.b .w .l] address [.b .w .l]:byte、word、long //以1字节、2字节、4字节指定操作格式 address:内存起始地址
-
mw——使用一个指定的数据填充一段内存
- 格式
mw [.b, .w, .l] address value [count] [.b .w .l]:byte、word、long //以1字节、2字节、4字节指定操作格式 address:内存起始地址 value:要填充的数据 [count]:要填充的长度
-
cp——数据拷贝,将DRAM中的数据从一段内存拷贝到另一端内存中
- 格式
cp [.b, .w, .l] source target count [.b .w .l]:byte、word、long //以1字节、2字节、4字节指定操作格式 source:源地址 target:目的地址 count:拷贝长度
-
cmp——用于比较两端内存数据是否相等
- 格式
cmp [.b, .w, .l] addr1 addr2 count [.b .w .l]:byte、word、long //以1字节、2字节、4字节指定操作格式 addr1:第一段内存首地址 addr2:第二段内存首地址 count:比较长度
-
-
flash操作
-
uboot支持EMMC和SD卡,一般认为emmc和sd卡是同种大小,没有特殊说明,mmc是一系列命令
加上SD卡一共两个设备,FSL_SDHC:0是SD卡,FSL_SDHC:1是emmc,默认将emmc设为当前设备
命令 描述 格式 mmc info 输出mmc设备信息 mmc info mmc read 读取mmc中的数据 mcc read [存储地址] [起始块号] [读取块数] mmc write 向mmc写数据 mmc write [读取地址] [写入块号] [写入块数] mmc rescan 扫描mmc设备 mmc rescan mmc part 列出mmc设备分区 mmc part mmc dev 切换mmc设备 mmc dev [设备号] [分区号] mmc list 列出当前有些的所有mmc设备 mmc list mmc hwpartition 设置mmc设备的分区 mmc hwpartition [设备号] [分区ID] [访问权限] [分区起始块号] [分区大小] mmc bootbus 设置指定mmc设备的BOOT_BUS_WIDTH区域 mmc bootbus [设备号] [数据总线宽度] [启动总线模式] [复位阶段] mmc bootpart 设置指定mmc设备的boot和RPMB分区的大小 mmc bootpart [设备编号] [启动分区的分区号] [启动时是否显示启动分区信息] mmc partconf 设置指定的mmc设备的PARTITON_CONFIG域的值 mmc partconf [设备号] [配置编号] [配置值] mmc rst 复位mmc设备 mmc rst [设备号] mmc setdsr 设置dsr寄存器的值 mmc setdsr [设备号] [要设置的值] -
FAT格式文件操作命令
-
fatinfo命令
- 功能:查询指定MMC设置指定分区文件系统信息
- 格式:
fatinfo <interface> [<dev[:part]>] interface:表示接口 dev:设备号 part:分区
-
fatls命令
- 功能:查询FAT格式设备的目录和文件信息
- 格式:
fatls <interface> [<dev[:part]>] [directory] interface:表示接口 dev:设备号 part:分区 directory:要查询的目录
-
fstype命令
- 功能:查看mmc设备某个文件的文件系统格式
- 格式:
fstype <interface> <dev>:<part> interface:表示接口 dev:设备号 part:分区
-
fatload命令
- 功能:将指定的文件读取到DRAM中
- 格式:
fatload <interface> [<dev[:part]> [<addr> [<filename> [bytes [pos]]]]] interface:接口 dev:设备号 part:分区 addr:报错在DRAM中的起始地址 filename:要去读的文件名 bytes:读多少字节数据 pos要读的文件相对于文件搜地址的偏移
-
-
EXT格式文件操作命令
ext2load、 ext2ls、 ext4load、 ext4ls 和 ext4write
。这些命令的含义和使用与 fatload、 fatls 和 fatwrit一样,只是 ext2 和 ext4 都是针对 ext 文件系统的
-
-
网络操作
- 环境变量
环境变量 描述 ipaddr 开发板ip地址,可以不设置,使用dhcp命令来从路由器获取ip地址 ethaddr 开发板的MAC地址 gatewayip 网关地址 netmask 子网掩码 serverip 服务器IP地址,Ubuntu主机IP地址,用于调试代码 -
ping命令
- 验证开发板网络是否可用,是否可用和主机进行通信
- 使用:
ping 主机ip
-
dhcp命令
- 从路由器获取IP地址,需要将开发板接入路由器
- 使用
dhcp
-
nfs命令
- 网络文件系统,通过nfs在计算机直接通过网络来分享资源
nfs zImage_addr ip 路径 zImage_addr:zImage报错地址 ip:主机ip 路径:镜像在主机中的路径
-
ftp命令
-
同nfs,tftp使用的协议基于
TCP/IP
-
使用
-
创建文件夹存储文件
mkdir /home/< name >/linux/tftpboot chmod 777 /home/< name >/linux/tftpboot
-
配置tftp
server tftp { socket_type = dgram protocol = udp wait = yes user = root server = /usr/sbin/in.tftpd server_args = -s /home/wanli/linux/tftpboot/ disable = no per_source = 11 cps = 100 2 flags = IPv4 }
-
启动tftp服务
sudo service tftpd-hpa start
-
重启tftp服务器
sudo service tftpd-hpa restart
-
uboot启动tftp服务器
tftpboot [loadAddress] [[hostIPaddr:]bootfilename] loadAddress:文件在DRAM中存放地址 [[hostIPaddr:]bootfilename]:文件名即可 //与nfs区别
-
-
从网络更新uboot镜像
-
设备连接到tftp服务器网络
- 确保ubuntu安装了tftp
重启tftp:sudo service tftpd-hpa restart
-
uboot命令行界面下配置网络参数
setenv gatewayip <网关ip> setenv ipaddr <板子ip> setenv serverip <服务器ip> setenv netmask <子网掩码ip> saveenv //如果报错,可能uboot在ram中没有写入闪存 printenv //查看板子环境变量信息
-
使用tftpboot从tftp下载uboot镜像
tftpboot <存储位置> <文件名> //使用TFTP从服务器下载指定文件,到指定内存 mmc write <存储位置> <指定闪存> //从内存拷贝uboot到指定emmc中
-
使用bootm命令启动U-boot镜像
bootm <内存地址>
通过命令方式读取拨码开关状态
-
使用gpio info查看引脚状态
gpio stat -a //列出端口详细电平 gpio input GPIOx_y //将GPIOx口下y引脚设置为输入模式,并读取电平
-
使用md查看寄存器数据
md <地址> //列出寄存器地址的数据
boot_mode | gpio | Reuse |
---|---|---|
BOOT_MODE[0] | gpio1.IO[5] | UART1_TXD |
BOOT_MODE[1] | gpio1.IO[7] | UART2_TXD |
BOOT_MODE[2] | gpio1.IO[11] | SAI1_TXFS |
BOOT_MODE[3] | gpio1.IO[13] | SAI1_TXD |
uboot环境变量
变量 | 含义 |
---|---|
sdt_addr | SDT的存储地址,SDT是用于描述系统硬件配置的数据结构 |
bootm_size | 启动映像的大小,以字节为单位,通常指的是内核映像大小 |
cntr_addr | 控制台的存储地址,控制台是用户与计算机进行交互的输入/输出设置 |
fd_addr_r | 文件系统设备的存储地址,用于启动过程中虚拟文件系统的根目录地址 |
fdt_high | FDT的加载地址,用于描述硬件设备和配置信息的数据结构 |
fileaddr | 文件的加载地址,引导过程中需要加载的某个文件的存储地址 |
filesize | 文件大小 |
initrd_addr | initrd的加载地址,initrd是一个临时的文件系统,用于启动过程中提供额外的驱动程序和工具 |
kernel_addr_r | 内核的加载地址,这是引导式加载内核的存储地址 |
scriptaddr | 启动加班的存储地址,启动脚本是包含引导过程中指向命令的脚本文件 |