Linux-基础入门-学习笔记(3):uboot常用命令与环境变量

Linux-基础入门-学习笔记(3):uboot常用命令与环境变量

一、uboot基础知识

1. 类比PC机与嵌入式系统的启动过程

(1)PC机
典型的PC机的部署: BIOS程序部署在PC机主板上(随主板出厂时已经预制了),操作系统部署在硬盘上,内存在掉电时无作用,CPU在掉电时不工作。
PC机启动过程: PC上电后先执行BIOS程序(实际上PC的BIOS就是NorFlash),BIOS程序负责初始化DDR内存,负责初始化硬盘,然后从硬盘上将OS镜像读取到DDR中,然后跳转到DDR中去执行OS直到启动(OS启动后BIOS就无用了)。

(2)嵌入式系统
典型嵌入式系统的部署: uboot程序部署在Flash(能作为启动设备的Flash)上、OS部署在FLash(嵌入式系统中用Flash代替了硬盘)上、内存在掉电时无作用,CPU在掉电时不工作。
嵌入式系统启动过程: 嵌入式系统上电后先执行uboot、然后uboot负责初始化DDR,初始化Flash,然后将OS从Flash中读取到DDR中,然后启动OS(OS启动后uboot就无用了)

总结:我们可以看出,嵌入式系统与PC机的部署和启动方式基本相同。嵌入式系统中的uboot相当于PC机的BIOS。

(3)android
android系统启动过程: android系统的启动和linux系统几乎一样(只是在内核启动后加载根文件系统后不同了)。
可以认为启动分为2个阶段:第一个阶段是uboot到OS启动;第二个阶段是OS启动后到rootfs加载到命令行执行。

2. uboot的作用

uboot就是universal bootloader(通用的启动代码),通用的意思就是在各种地方都可以用。所以说uboot具有可移植性
uboot具有可移植性并不是说uboot在哪个开发板都可以随便用,而是说uboot具有在源代码级别的移植能力,可以针对多个开发板进行移植,移植后就可以在这个开发板上使用了。

uboot的主要作用是:
(1)uboot主要作用是用来启动操作系统内核。
(2)uboot还要负责部署整个计算机系统。
(3)uboot中还有操作Flash等板子上硬盘的驱动。
(4)uboot还得提供一个命令行界面供人来操作。

3. uboot需要解决的问题

(1)自身可开机直接启动
一般的SoC都支持多种启动方式,譬如SD卡启动、NorFlash启动、NandFlash启动等·····uboot要能够开机启动,必须根据具体的SoC的启动设计来设计uboot。
uboot必须进行和硬件相对应的代码级别的更改和移植,才能够保证可以从相应的启动介质启动。uboot中第一阶段的start.S文件中具体处理了这一块。

(2)能够引导操作系统内核启动并给内核传参
uboot的终极目标就是启动内核。 linux内核在设计的时候,设计为可以被传参。也就是说我们可以在uboot中事先给linux内核准备一些启动参数放在内存中特定位置然后传给内核,内核启动后会到这个特定位置去取uboot传给他的参数,然后在内核中解析这些参数这些参数将被用来指导linux内核的启动过程

(3)能提供系统部署功能
uboot必须能够被人借助而完成整个系统(包括uboot、kernel、rootfs等的镜像)在Flash上的烧录下载工作
例如利用uboot中的fastboot功能将各种镜像烧录到iNand中,然后从iNand启动。

(4)能进行soc级和板级硬件管理
uboot中实现了一部分硬件的控制能力(uboot中初始化了一部分硬件),因为uboot为了完成一些任务必须让这些硬件工作。譬如uboot要实现刷机必须能驱动iNand,譬如uboot要在刷机时LCD上显示进度条就必须能驱动LCD,譬如uboot能够通过串口提供操作界面就必须驱动串口。譬如uboot要实现网络功能就必须驱动网卡芯片。

(5)uboot的“生命周期”
uboot本质上是一个裸机程序(不是操作系统),一旦uboot开始SoC就会单纯运行uboot(意思就是uboot运行的时候别的程序是不可能同时运行的,一旦uboot结束运行则无法再回到uboot,所以uboot启动了内核后uboot自己本身就死了)。
uboot的入口和出口:uboot的入口就是开机自动启动,uboot的唯一出口就是启动内核。uboot还可以执行很多别的任务(譬如烧录系统),但是其他任务执行完后都可以回到uboot的命令行继续执行uboot命令,而启动内核命令一旦执行就回不来了

二、uboot常用命令

uboot启动后大部分时间和工作都是在shell下完成的,譬如uboot要部署(就是烧录)系统要在shell下输命令、要设置环境变量也得在命令行地下,要启动内核也要在命令行底下敲命令。命令就是uboot的shell中可以识别的各种命令。

uboot的有些命令带的参数非常长,为了告诉uboot这个非常长而且中间有好多个空格的东西是给他的一整个参数,所以用单引号将这个很长且中间有空格隔开的参数引起来。

序号 命令行 备注
1 printenv/print 打印出系统所有的环境变量
2 setenv/set name value 设置更改环境变量 ,name为环境变量名,value为对该环境变量设置的内容
3 saveenv/save 保存环境变量的更改,下次重启仍存在
4 ping pingAddress 测试对应地址下的网络链接是否通
5 tftp [loadaddress] [bootfilename] 将bootfile文件下载到指定的loadaddress地址中
nfs [loadaddress] [bootfilename] 原理同tftp
6 movi init 查看内存信息
movi read {u-boot / kernel} {addr} 从内存中读取数据
movi write {fwbl1 / u-boot / kernel} {addr} 写数据到内存中
movi read rootfs {addr} [bytes(hex)] 按某个字节大小读取根文件系统中的数据
movi write rootfs {addr} [bytes(hex)] 按某个字节大小读取根文件系统中的数据
7 mm [.b, .w, .l] address 逐个单元的修改内存中的某一块数据
md [.b, .w, .l] address 显示内存中的内容
mw [.b, .w, .l] address 将内容写到内存中
8 bootm/go 启动内核(bootm启动内核同时给内核传参,而go命令启动内核不传参)

命令演示:
1、printenv/print
在这里插入图片描述
在这里插入图片描述
print命令不用带参数,作用是打印出系统中所有的环境变量
环境变量就好像程序的全局变量一样。程序中任何地方都可以根据需要去调用或者更改环境变量(一般都是调用),环境变量和全局变量不同之处在于:全局变量的生命周期是在程序的一次运行当中,开始运行时诞生程序结束时死亡,下次运行程序时从头开始;但是环境变量被存储在Flash的另一块专门区域(Flash上有一个环境变量分区),一旦我们在程序中保存了该环境变量,那么下次开机时该环境变量的值将维持上一次更改保存后的值
2、setenv/set
在这里插入图片描述
(1)新建一个环境变量,使用set var value
(2)更改一个环境变量,使用set var value
(3)删除一个环境变量,使用set var

3、saveenv/save
在这里插入图片描述
在这里插入图片描述
这里说明一下,当启动后,uboot会将Flash中的环境变量拷贝一份到内存中去,set命令只能更改内存中的环境变量,下次重启后仍为Flash中的环境变量;save命令则能同步内存中的环境变量到Flash中环境变量的分区,下次重启仍保持设置值。

4、ping

首先声明:主机windows地址192.168.1.10,开发板uboot或linux的地址为192.168.1.20,虚拟机ubuntu地址为192.168.1.141

(1)ping开发板和主机之间的网络链接
1)首先将开发板和主机之间的网线插好。
2)设置主机的IP地址和子网掩码。控制面板->网络和Internet->网络和共享中心->更改适配器设置->设置主机IP地址为192.168.1.10
在这里插入图片描述
3)设置开发板IP地址为192.168.1.20
在这里插入图片描述
这里要想ping通,一定要在一个网段下,并且子网掩码相同。
网段的概念:一个IP地址分为2部分,一部分是网段地址,另一部分是网段内的主机地址(由子网掩码来区分哪一部分是网段地址,哪一部分是IP地址)。在子网掩码是255.255.255.0的情况下,192.168.1.10这个IP地址的前三部分(192.168.1.)属于网段地址,第4部分(10)属于主机地址。

4)通过开发板ping主机。
在这里插入图片描述
(2)ping开发板和虚拟机ubuntu之间的网络链接
1)设置虚拟机上网为桥接方式。虚拟机->设置->网络适配器
在这里插入图片描述
2)虚拟机的菜单中有个“虚拟网络编辑器”,这里面要设置为桥接到有线网卡。(默认是自动的,如果选了自动,那么虚拟机会自动桥接到无线网卡上,但是我们却是通过有线网卡来连接开发板的,自然ping不通)。
在这里插入图片描述
3)设置虚拟机的IP地址为192.168.1.141
也可以通过 /etc/network/interfaces文件来设置静态的然后重启。
在这里插入图片描述
在这里插入图片描述
4)通过开发板ping虚拟机。
在这里插入图片描述
5)虚拟机Ping开发板。
在这里插入图片描述
(3)ping uboot和主机/ubuntu之间的网络链接
设置uboot中的环境变量,再ping主机/ubuntu。
在这里插入图片描述
5、tftp
uboot本身主要目标是启动内核,为了完成启动内核必须要能够部署内核,uboot为了部署内核就需要将内核镜像从主机中下载过来然后烧录到本地flash中。uboot如何从主机(windows或者虚拟机ubuntu)下载镜像到开发板上?有很多种方式,主流方式是:fastboot和tftp
fastboot的方式是通过USB线进行数据传输。而tftp的方式是通过有线网络的。

tftp方式下载时实际上uboot扮演的是tftp客户端程序角色,主机windows或虚拟机ubuntu中必须有一个tftp服务器,然后将要下载的镜像文件放在服务器的下载目录中,然后开发板中使用uboot的tftp命令去下载即可。
搭建ubuntu的tftp服务器方法

1)我的虚拟机搭建的时候设置的tftp下载目录是 /tftpboot,将要被下载的镜像复制到这个目录下。
在这里插入图片描述
2)检查开发板uboot的环境变量,注意serverip必须设置为虚拟机ubuntu的ip地址。(serverip这个环境变量的意义就是主机tftp服务器的ip地址)
3)然后在开发板的uboot下先ping通虚拟机ubuntu,然后再尝试下载:tftp 0x30000000 zImage-qt(意思是将服务器上名为zImage-qt的文件下载到开发板内存的0x30000000地址处。)
在这里插入图片描述
6、movi
开发板如果用SD卡/EMMC/iNand等作为Flash,则在uboot中操作flash的指令为movi(或mmc)。
在这里插入图片描述
movi的指令都是movi read和movi write一组的,movi read用来读取iNand到DDR上,movi write用来将DDR中的内容写入iNand中。
在这里插入图片描述
7、内存操作指令:mm、mw、md
md就是memory display,用来显示内存中的内容。(.b字节为单位 .w2个字节 .l4个字节
在这里插入图片描述

mw就是memory write,将内容写到内存中。在这里插入图片描述

mm就是memory modify,修改内存中的某一块,说白了还是写内存(如果需要批量的逐个单元的修改内存,用mm最合适)。在这里插入图片描述
8、bootm,go
待补充……

三、uboot的环境变量

uboot的环境变量和操作系统的环境变量工作原理和方式几乎完全相同。环境变量可以被认为是系统的全局变量,环境变量名都是系统内置的。系统或者我们自己的程序在运行时可以通过读取环境变量来指导程序的运行。环境变量就是运行时的配置属性

环境变量有2份,一份在Flash中,另一份在DDR中。 uboot开机时一次性从Flash中读取全部环境变量到DDR中作为环境变量的初始化值,然后使用过程中都是用DDR中这一份,用户可以用save指令将DDR中的环境变量重新写入Flash中去更新Flash中环境变量。下次开机时又会从Flash中再读一次。
在这里插入图片描述

环境变量 表示的意义
mtdpart=80000 400000 3000000 mtd分区
baudrate=115200 串口波特率
ethaddr=00:40:5c:26:0a:5b 开发板的本地网卡的MAC地址
bootargs…… 在uboot的环境变量中设置bootargs,然后bootm命令启动内核时会自动将bootargs传给内核
bootcmd…… uboot开机自动启动时实际就是在内部执行了bootcmd这个环境变量的值所对应的命令集
bootdelay=5 开机自动倒数bootdelay秒
netmask=netmask 255.255.255.0 子网掩码
ipaddr=192.168.1.20 开发板的本地IP地址
gatewayip=192.168.1.1 开发板的本地网关地址
serverip=192.168.1.141 开发板通过tftp指令去tftp服务器下载东西时,tftp服务器的IP地址

四、uboot对flash和DDR的管理

1. uboot阶段Flash的分区

所谓分区,就是说对Flash进行分块管理。
PC机等产品中,因为大家都是在操作系统下使用硬盘的,整个硬盘由操作系统统一管理,操作系统会使用文件系统帮我们管理硬盘空间。(管理保证了文件之间不会互相堆叠),于是乎使用者不用自己太过在意分区问题。
在uboot中是没有操作系统的,因此我们对Flash(相当于硬盘)的管理必须事先使用分区界定(实际上在uboot中和kernel中都有个分区表,分区表就是我们在做系统移植时对Flash的整体管理分配方法)。有了这个界定后,我们在部署系统时按照分区界定方法来部署,uboot和kernel的软件中也是按照这个分区界定来工作,就不会错。
分区方法不是一定的,不是固定的,是可以变动的。但是在一个移植中必须事先设计好定死,一般在设计系统移植时就会定好,定的标准是:

  • uboot: uboot必须从Flash起始地址开始存放(也许是扇区0,也许是扇区1,也许是其他,取决于SoC的启动设计),uboot分区的大小必须保证uboot肯定能放下,一般设计为512KB或者1MB(因为一般uboot肯定不足512KB,给再大其实也可以工作,但是浪费);
  • 环境变量: 环境变量分区一般紧贴着uboot来存放,大小为32KB或者更多一点。
  • kernel: kernel可以紧贴环境变量存放,大小一般为3MB或5MB或其他。
  • rootfs: 一般也是紧贴着,看用到了多大。
  • 剩下的就是自由分区,一般kernel启动后将自由分区挂载到rootfs下使用。

总结:
(1)各分区彼此相连,前面一个分区的结尾就是后一个分区的开头。
(2)整个flash充分利用,从开头到结尾。
(3)uboot必须在Flash开头,其他分区相对位置是可变的。
(4)各分区的大小由系统移植工程师自己来定,一般定为合适大小(不能太小,太小了容易溢出;不能太大,太大了浪费空间)
(5)分区在系统移植前确定好,在uboot中和kernel中使用同一个分区表。将来在系统部署时和系统代码中的分区方法也必须一样。(烧录时要按照分区表进行烧录)

2. uboot阶段DDR的分区

DDR的分区和Flash的分区不同,主要是因为Flash是掉电存在的,而DDR是掉电消失,因此可以说DDR是每次系统运行时才开始部署使用的。
内存的分区主要是在linux内核启动起来之前,linux内核启动后内核的内存管理模块会接管整个内存空间,那时候就不用我们来管了。
注意内存分区关键就在于内存中哪一块用来干什么必须分配好,以避免各个不同功能使用了同一块内存造成的互相踩踏。譬如说我们tftp 0x23E00000 zImage去下载zImage到内存的0x23E00000处就会出错,因为这个内存处实际是uboot的镜像所在。这样下载会导致下载的zImage把内存中的uboot给冲掉。

发布了72 篇原创文章 · 获赞 98 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/qq_42826337/article/details/104931732