大家好,欢迎来到IT知识分享网。
一、UBOOT简介
U-boot全称 Universal Boot Loader,是遵循GPL条款的开放源码项目,uboot 是一个裸机代码,可以看作是一个裸机综合例程,执行启动内核的功能。
补充:GPL条款(GNU General Public License,GNU通用公共许可证)是一种自由软件许可证,而GNU代表“GNU’s Not Unix”,是开源的操作系统项目,大多数GNU系统使用开源的Linux内核,GPL条款保证了开源内核的自由性,使用GPL条款后,
- 源代码公开:在分发软件时必须提供源代码,或者提供方便获取源代码的方式。
- 修改后仍使用GPL:对软件进行修改后,必须使用相同的GPL许可证分发。
- 保留版权和许可证:必须在分发软件时保留原始版权声明和GPL许可证条款。
由上可知,UBOOT是通用的引导程序,对系统架构没有要求,因为适用,所以流行。
二、UBOOT源码结构
重点包括:
系统架构、CPU、board、各个开发板的配置文件XXX-defconfig、makefile
三、Uboot支持多种启动方式
项目中知道的有 SPI Flash/eMMC/Nvme/SD/Hard Disk/U-Disk/net,要用到的内核映像在哪,就是决定怎么启动。
四、UBOOT启动流程
关于具体设备比如imx6u的启动:
启动有两种方式,一种是改写 eFUSE(熔 丝),一种是修改相应的 GPIO 高低电平。第一种修改 eFUSE 的方式只能修改一次,后面就不能 再修改了,所以我们不使用。我们使用的是通过拨码开关修改 BOOT_MODE[1:0]对应的 GPIO 高低电平来选择启动方式,所有的开发板都使用的这种方式,I.MX6U 有一个 BOOT_MODE1 引脚和 BOOT_MODE0 引脚,这两个引脚对应这BOOT_MODE[1:0]。
内部 BOOT 模式(芯片内部的bootRom将引导程序拷贝到指定的内存地址)
当 BOOT_MODE1 为 1,BOOT_MODE0 为 0 的时候此模式使能,在此模式下,芯片会执行内部的 boot ROM 代码,这段 boot ROM 代码会进行硬件初始化(一部分外设),然后从 boot 设备(就是存放代码的设备、比如 SD/EMMC、NAND)中将引导代码拷贝出来复制到指定的 RAM 中, 一般是 DDR。
Boot ROM 与 U-Boot 启动流程的关系
在典型的嵌入式系统中,Boot ROM 和 U-Boot 的启动流程大致如下:
- CPU复位与Boot ROM执行
- 当系统加电或复位时,CPU从复位向量地址开始执行代码,这个地址指向Boot ROM中的代码。
- Boot ROM执行初步的硬件初始化,如基本的系统时钟主频、片上RAM的配置等。
- Boot ROM检测启动模式(例如通过引脚状态或配置寄存器),决定从哪个设备加载二级引导程序。
- 加载二级引导程序(U-Boot)
- 根据启动模式,Boot ROM从选定的存储介质(如Flash存储器)中读取二级引导程序(通常是U-Boot)到片上RAM或外部RAM。
- 加载完成后,Boot ROM将程序计数器(PC)设置为U-Boot的入口地址,将控制权移交给U-Boot。
U-Boot 启动流程概述
U-Boot的启动流程可以分为以下几个阶段:
- CPU上电复位(Initial CPU Reset)也就是bootROM的执行
- 启动汇编代码(Start-up Assembly Code)
- 板级初始化(Board Initialization)
- 初始化内存控制器(Memory Controller Initialization)
- C语言环境初始化(Initialization of C Runtime Environment)
- 加载并启动内核或其他镜像(Load and Boot the OS Kernel or Other Image)
详细启动步骤
1. CPU上电复位
- 上电复位:系统上电或复位时,CPU首先执行从一个预定义的复位向量开始的指令。这些指令通常存储在只读存储器(ROM)或闪存的固定位置。(BootROM)
- 执行初始化代码:在复位后,CPU会执行初始化代码,该代码通常用汇编语言编写。这些初始指令一般会关闭Cache和MMU,以保证系统以一种可预测的方式启动。
2. 启动汇编代码
- 堆栈指针初始化:初始化堆栈指针,通常使用内嵌的SRAM来设置堆栈位置,因为此时外部RAM可能还未初始化。
- CPU模式设置:在ARM架构的系统中,通常会将CPU切换到管理模式(Supervisor mode)或中断模式(IRQ mode)下,以便有足够的权限进行接下来的初始化操作。
- 关闭Cache和MMU:通常在初始化过程中,Cache和MMU都是关闭的。这是为了避免Cache中存在的任何旧数据影响系统初始化的正确性,并确保物理地址空间能够被正确访问。
3. 板级初始化(Board Initialization)
- 初始化引脚和外设:启动汇编代码会执行一些板级初始化操作,包括设置GPIO、初始化串口等。这些操作通常是特定于硬件平台的。
- 内存控制器初始化:在初始化外部RAM之前,必须先初始化内存控制器。这包括设置内存控制寄存器,配置内存的时序参数等。
4. 内存初始化
- 初始化外部RAM:在内存控制器初始化后,外部RAM就可以被使用。此时,可以将堆栈指针从内嵌SRAM迁移到外部RAM,以提供更多的堆栈空间。
- 拷贝U-Boot到RAM:通常,U-Boot在启动时是从Flash存储器中运行的,为了加快执行速度,通常会将U-Boot代码从Flash拷贝到RAM中执行。uboot 会将自己重定位到 DRAM 最后面的地址区域,也就是将自己拷贝到 DRAM 最后面的内存区域中。
5. C语言环境初始化
- 初始化全局数据区:此时可以进行全局变量的初始化,并设置全局数据区。
- 调用C函数:随着C环境的初始化,U-Boot从汇编代码过渡到C代码,接下来大部分初始化和功能都在C代码中实现。
6. Cache和MMU配置
- MMU(内存管理单元)配置:在某些系统中,U-Boot会在C环境初始化后配置MMU,以启用虚拟内存管理。启用MMU后,系统可以使用虚拟地址空间,这对于复杂的操作系统启动过程是必要的。
- Cache初始化:Cache的使用可以显著提升系统性能。U-Boot在这个阶段会根据需要启用Cache。
7. 加载并启动内核或其他镜像
- 加载镜像:U-Boot的主要功能之一是加载并启动操作系统内核或其他镜像(如Linux、RTOS等)。从flash中读取环境变量到内存,选择从某一介质(如Flash、SD卡、网络等)加载镜像。
- 启动操作系统:在加载内核镜像后,U-Boot会跳转到内核的入口点,并将控制权交给内核,完成系统引导。
总结:初始化 》重定位 》 加载内核 》设置内核启动参数 》 启动内核
五、UBOOT命令使用
信息查询指令
进入 uboot 的命令行模式以后输入“help”或者“?”,然后按下回车即可查看当前 uboot 所支持的命令,如图 所示:
输入“help(或?) 命令名”既可以查看命令的详细用法
环境变量操作命令
环境变量的操作涉及到两个命令:setenv 和 saveenv,命令 setenv 用于设置或者修改环境变量的值。命令 saveenv 用于保存修改后的环境变量,一般环境变量是存放在外部 flash 中的,uboot 启动的时候会将环境变量从 flash 读取到 DRAM 中。所以使用命令 setenv 修改的是 DRAM中的环境变量值,修改以后要使用 saveenv 命令将修改后的环境变量保存到 flash 中,否则的话uboot 下一次重启会继续使用以前的环境变量值。
有时候我们修改的环境变量值可能会有空格,比如 bootcmd、bootargs 等,这个时候环境变量值就得用单引号括起来,比如下面修改环境变量 bootargs 的值:
setenv bootargs 'console=ttymxc0, root=/dev/mmcblk1p2 rootwait rw' saveenv
上面命令设置 bootargs 的值为“console=ttymxc0, root=/dev/mmcblk1p2 rootwait rw”,其中“console=ttymxc0,”、“root=/dev/mmcblk1p2”、“rootwait”和“rw”相当于四组“值”,这四组“值”之间用空格隔开,所以需要使用单引号‘’将其括起来,表示这四组“值”都属于环境变量 bootargs。
网络操作命令
uboot 是支持网络的,我们在移植 uboot 的时候一般都要调通网络功能,因为在移植 linux kernel 的时候需要使用到 uboot 的网络功能做调试。
1、ping 命令
开发板的网络能否使用,是否可以和服务器(Ubuntu 主机)进行通信,通过 ping 命令就可以验证,直接 ping 服务器的 IP 地址即可。
注意!只能在 uboot 中 ping 其他的机器,其他机器不能 ping uboot,因为 uboot 没有对 ping
命令做处理,如果用其他的机器 ping uboot 的话会失败!
补充:
Ping命令是一种网络诊断工具,用于测试主机之间的连通性。它的实现原理基于ICMP(Internet Control Message Protocol,Internet控制消息协议)。
以下是Ping命令的实现原理:
- 发送ICMP Echo请求:Ping命令向目标主机发送一个ICMP Echo请求。ICMP Echo请求的作用是请求目标主机返回一个ICMP Echo Reply响应。
- 接收ICMP Echo Reply响应:目标主机收到ICMP Echo请求后,如果目标主机正常工作并且网络连接正常,它将会返回一个ICMP Echo Reply响应。ICMP Echo Reply中包含了原始请求的数据,以便发送主机可以确认响应是否与请求匹配。
- 计算往返时间(Round-Trip Time,RTT):发送主机接收到ICMP Echo Reply响应后,它会计算往返时间(RTT),即从发送请求到接收响应的时间。RTT通常用于衡量网络延迟。
- 显示结果:Ping命令将收到的ICMP Echo Reply响应和计算得到的往返时间显示给用户。这些信息可以用来判断网络连接的质量和稳定性。
需要注意的是,Ping命令通常需要在发送主机和目标主机之间存在双向的网络连接,并且目标主机需要正确地响应ICMP Echo请求。如果目标主机的网络连接出现故障或者目标主机配置了防火墙,可能会导致Ping命令无法正常工作。
2、nfs 命令
nfs(Network File System)网络文件系统,通过 nfs 可以在计算机之间通过网络来分享资源,比如我们将 linux 镜像和设备树文件放到 Ubuntu 中,然后在 uboot 中使用 nfs 命令将 Ubuntu 中 的 linux 镜像和设备树下载到开发板的 DRAM 中。
这样做的目的是为了方便调试 linux 镜像和设备树,也就是网络调试,通过网络调试是 Linux 开发中最常用的调试方法。原因是嵌入式 linux开发不像单片机开发,可以直接通过 JLINK 或 STLink 等仿真器将代码直接烧写到单片机内部的 flash 中,嵌入式 Linux 通常是烧写到 EMMC、NAND Flash、SPI Flash 等外置 flash 中,但是嵌入式 Linux 开发也没有 MDK,IAR 这样的 IDE,更没有烧写算法,因此不可能通过点击一个“download”按钮就将固件烧写到外部 flash 中。虽然半导体厂商一般都会提供一个烧写固件的软件,但是这个软件使用起来比较复杂,这个烧写软件一般用于量产的。其远没有 MDK、IAR的一键下载方便,在 Linux 内核调试阶段,如果用这个烧写软件的话将会非常浪费时间,而这个时候网络调试的优势就显现出来了,可以通过网络将编译好的 linux 镜像和设备树文件下载到 DRAM 中,然后就可以直接运行。
在使用 之前需要开启 Ubuntu 主机的 NFS 服务,并且要新建一个 NFS 使用的目录,以后所有要通过NFS 访问的文件都需要放到这个 NFS 目录中。
nfs 192.168.1.253:/home/zuozhongkai/linux/nfs/zImage
命 令 中 的 “ ”表示 zImage 保 存在DRAM中的地址 ,“192.168.1.253:/home/zuozhongkai/linux/nfs/zImage”表示 zImage 在 192.168.1.253 这个主机中, 路径为/home/zuozhongkai/linux/nfs/zImage。
3、tftp 命令
tftp 命令的作用和 nfs 命令一样,都是用于通过网络下载东西到 DRAM 中,只是 tftp 命令使用的 TFTP 协议,Ubuntu 主机作为 TFTP 服务器。因此需要在 Ubuntu 上搭建 TFTP 服务器
和nfs命令相比,都是开启服务之后,创建文件夹存放映像文件,但和nfs 命令的区别在于,tftp 命令不需要输入文件在 Ubuntu 中的完整路径,只需要输入文件名即可
tftp zImage
EMMC和SD卡操作
如果 EMMC 里面烧写了 Linux 系统的话,EMMC 是有 3 个分区的,第 0 个分区存放 uboot,第 1 个分区存放Linux 镜像文件和设备树,第 2 个分区存放根文件系统。
关于镜像烧写:
学习 STM32 的时候我们可以直接将编译生成的.bin 文件烧写到 STM32 内部 flash 里面,但是 I.MX6U 不能直接烧写编译生成的.bin 文件,我们需要在.bin 文件前面添加一些头信息构成满足 I.MX6U 需求的最终可烧写文件。
总结一下,我们编译出来的.bin 文件不能直接烧写到 SD 卡中,需 要在.bin 文件前面加上 IVT、Boot Data 和 DCD 这三个数据块。这三个数据块是有指定格式的, 我们必须按照格式填写,然后将其放到.bin 文件前面,最终合成的才是可以直接烧写到 SD 卡中的文件,可以通过nxp的软件来烧写。
关于更新,先将更新编译后Uboot下载到内存中,然后在uboot命令行模式中切换对应分区,使用mmc write命令向指定mmc内存块位置将Uboot写入,完成更新。
如果要在 uboot 中更新 EMMC 对应的 uboot,可以使用如下所示命令:
mmc dev 1 0 //切换到 EMMC 分区 0 tftp u-boot.imx //下载 u-boot.imx 到 DRAM mmc write 2 32E //烧写 u-boot.imx 到 EMMC 中 mmc partconf 1 1 0 0 //分区配置,EMMC 需要这一步!
千万不要写 SD 卡或者 EMMC 的前两个块(扇区),里面保存着分区表!
,还是使用
NXP
提供的
Mfgtool
工具来烧写, 因为根文件系统太大!很有可能超过开发板 DRAM
的大小,这样连下载都没法下载,更别说更 新了。
BOOT 操作命令
uboot 的本质工作是引导 Linux,所以 uboot 肯定有相关的 boot(引导)命令来启动 Linux。常用的跟 boot 有关的命令有:bootz、bootm 和 boot。
1、bootz命令
bootz 命令用于启动 zImage 镜像文件,
bootz [addr [initrd[:size]] [fdt]]
addr 是 Linux 镜像文件在 DRAM 中的位置,initrd 是 initrd 文件在DRAM 中的地址,如果不使用 initrd 的话使用‘-’代替即可,fdt 就是设备树文件在 DRAM 中的地址。
2、bootm 命令
bootm 和 bootz 功能类似,但是 bootm 用于启动 uImage 镜像文件。
补充:
zImage:更轻便
- zImage是Linux内核的一种压缩格式。它是一种轻量级的内核映像文件,通常用于嵌入式系统或者对启动速度有较高要求的场景。
- 在编译内核时,可以选择生成zImage格式的内核映像文件。这个文件通常命名为”zImage”,并且是一个压缩过的内核镜像。
uImage:更灵活更扩展
- uImage是一种带有头部和校验和的Linux内核映像文件格式,用于各种体系结构。
- 与zImage/bzImage/vmlinuz相比,uImage提供了更多的元数据,如内核命令行参数、内核的加载地址等。
3、boot 命令
boot 命令也是用来启动 Linux 系统的,只是 boot 会读取环境变量 bootcmd 来启动 Linux 系统,bootcmd 是一个很重要的环境变量!其名字分为“boot”和“cmd”,也就是“引导”和“命令”,说明这个环境变量保存着引导命令,其实就是启动的命令集合,具体的引导命令内容是可以修改的。比如我们要想使用 tftp 命令从网络启动 Linux 那么就可以设置 bootcmd 为“tftp zImage; tftp imx6ull-14×14-emmc-7-1024×600-c.dtb; bootz – ”,然后使用 saveenv 将 bootcmd 保存起来。然后直接输入 boot 命令即可从网络启动Linux 系统。
setenv bootcmd 'tftp zImage; tftp imx6ull-14x14-emmc-7-1024x600-c.dtb; bootz - ' saveenv boot
boot命令是在设置好环境变量bootcmd基础上执行的,boot命令会读取bootcmd参数启动Linux。
中的启动命令。只要不修改 bootcmd
中的内容,以后每次开机
uboot
倒计时结束以后都会使用
tftp
命令。
zImage
和
imx6ull-14×14-emmc-7-1024×600-c.dtb
,然后启动
Linux
。
EMMC
启动那就设置
bootcmd
为“
fatload mmc 1:1 zImage; fatload mmc 1:1 imx6ull-14×14-emmc-7-1024×600-c.dtb; bootz – ”,然后使用
boot 命令启动即可。
参考链接:全网最全面最易懂的U-Boot解读_uboot-CSDN博客
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/122945.html