这些关于uboot的分析全是基于朱有鹏老师物联网课程
一、什么是uboot
要了解uboot的作用就要了解嵌入式设备(有系统的不是裸机)的启动过程,这里我们以S5pv210为
例来说说启动过程我之前写了一篇博客是关于S5pv210启动的https://mp.csdn.net/postedit/80296568,
在这里我简单的说一说大概的启动过程:
(1)、首先执行三星内部已经设置好的程序(BL0)(CPU时钟,关看门狗,初始化设备拷贝参数......
SoC内部的一些东西)。
(2)、运行BL1,BL1负责初始化NandFlash,然后将BL2(剩余的80kb)读取到iRAM中,然后运行。
(3)、从iRAM中运行BL2,然后BL2负责初始化DRAM,然后将OS读取到DRAM中,然后启动OS,
至此启动结束。
uboot就是BL1和BL2。它的作用就是帮助启动系统。PC机上的BIOS也是和uboot做的同样的东西。它是
用来启动操作系统内核的。部署整个计算机系统,操作Flash等板子上的硬盘驱动。提供一个简单的命令行
界面。
二、uboot从哪里来? 为什么引导OS的是uboot?
一个德国人发起的项目,然后网络上感兴趣的人都去来维护它。经过多年的发展它已经成为业内的bootloader
的标准。大部分嵌入式设备用的bootloader为uboot。
早期的版本号类似于uboot 1.3.4。而后来的版本类似于uboot-2010.06。
uboot具有可移植性并不是说它在所有开发板上都可以拿来用。而是uboot具有源码级别的移植能力。
三、uboot必须解决的问题
1、自身可以开机启动,比如SD卡启动,NorFlash启动。。。等
2、uboot必须适应这些硬件的改动,才能保证从相应的启动介质中启动。uboot中第一阶段的start.S文件处理了
这个问题。
3、能够引导操作系统内核启动并传参。linux内核在设计的时候被设定为可以传参。uboot必须传进去参数来引导
linux内核的启动。
4、能提供系统部署功能。uboot必须能够被人使用来完成整个系统的布置(包括uboot、kernel、rootfs等的镜像)
5、能够实现SoC级和板级硬件的控制。SoC级比如串口,串口刷机时要用。板级比如iNand,刷机时镜像被刷入
iNand。
6、uboot的生命周期。uboot本质上是个裸机程序,如果它的任务完成了(即启动了OS)那么它就死掉了。
7、除此之外uboot还提供了一个简单的shell命令。
四、uboot的命令集和环境变量
1、uboot有几十条命令(我们也可以自己给uboot添加命令),环境变量是系统中的全局变量,环境变量名都是
系统内置的。环境变量被更改后下一次运行时会使用被更改的值。
2、行缓冲:我们输入进去命令后不会立即进行识别而是把它放进一个缓冲区,当按下回车时才会被识别进而判断
执行。
3、简化的别名:譬如printenv命令可以简化为print,譬如setenv可以简化为set。
4、带参数命令:每个命令都被规定好了格式。有些是必须带参数的(譬如setenv/set命令),而有些是不带的
(譬如printenv/print命令),有些既可以带也可以不带(带不带参数的区别很大)。
5、命令族:好多个命令开头都是用同一个命令关键字,如(movi开头的)moviNand(EMMC、iNand)。
6、常用的一些命令:printenv/print 不用带参数,作用是打印出系统所有的环境变量。
设置(添加/更改)环境变量:setenv/set 用法 :set 环境变量名 新的值
保存环境变量的更改:saveenv/save 用法: save 不带参数
删除环境变量:setenv/set 用法:set 环境变量名
新建一个环境变量: setenv/set 用法 :set 环境变量名 值
彻底的更改环境变量的值需要将环境变量设置完之后再保存。
五、关于网络测试指令:ping的使用
1、命令用法:ping ip地址。使用前要注意:将开发板和主机之间用网线连接;开发板和主机必须在同一网段上。
2、在以上条件都满足的情况下在uboot命令行使用这个命令会在cmd中看到ping通的现象。
3、开发板和虚拟机ping通的方式:
(1)、虚拟机设置为桥接方式。
(2)、虚拟菜单中有个“虚拟网络编辑器”,这里没要设置为桥接到有线网卡。(我的vmware14没有这个选项)
(3)、把虚拟机的ip设为和开发板同一网段的,然后去ping。(开发板去ping虚拟机,虚拟机去ping开发板)
4、movi指令
(1)、开发板如果用SD卡/EMMC/iNand等作为Flash,则在uboot中操作Flash的指令为movi
(2)、movi指令是一个命令集,有很多子命令,具体用法可以看help movi查看。
(3)、movi的指令都是movi read和movi write一组的,movi read用来读取iNand到DDR上,movi write
用来将DDR中的内容写入iNand中。
(4)、指令有很多用法,譬如movi read u-boot 0x30000000。
5、uboot中内核指令:bootm、go
(1)、uboot的终极目标就是启动内核,启动内核在uboot中表现为一个指令,uboot命令行中调用这个指令来
启动内核。(不管成功与否这个命令都是一条死路)
(2)、两个命令的区别在于:bootm命令可以给内核传参,而go命令不能给内核传参。还可以通过预先在开发板
上下载uboot然后在uboot中用go命令来运行裸机程序。
6、环境变量如何参与程序运行
(1)、环境变量有两份,一份在Flash中,另一份在DDR中。uboot启动时将环境变量从Flash中读取到DDR中
然后 一直用的这份DDR中的环境变量。而当我们改变环境变量并保存时,Flash中保存的环境变量会被改变成
我们修改的值。
(2)、例如环境变量bootdelay:所表示的是自动运行倒数的时间。
六、uboot常用的环境变量和网络设置
1、自动运行命令设置:bootcmd
(1)、uboot启动后会自动倒数bootdelay秒,如果没人按下回车打断启动,则uboot会自动执行启动内核命令
来启动内核。
(2)、uboot开机自动启动时实际就是在内部执行了bootcmd这个环境变量的值所对应的命令集
2、网络设置:ipaddr serverip
(1)、ipaddr是开发板的本地IP地址
(2)、serverip是开发板通过tftp指令去tftp服务器下载东西时,tftp服务器的IP地址
(3)、gatewayip是开发板的本地网关地址
(4)、netmask是子网掩码
(5)、ethaddr是开发板的本地网卡的MAC地址
3、uboot给kernel传参:bootargs
(1)、linux内核启动时可以接收uboot给他传递的启动参数,这些启动参数时uboot和内核约定好的形式、
linux内核在这些启动参数的指导下完成启动。这样的设计是为了灵活,内核在不重新编译的情况下可以用
不同的方式启动。
(2)、我们要做的事情就是:在uboot的环境中设置bootargs,然后bootm命令启动内核时会自动将
bootargs传给内核。
(3)、bootargs=console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3
意义解释:
console=ttySAC2,115200 控制台使用串口2,波特率115200.
root=/dev/mmcblk0p2 根文件系统在SD卡端口0设备(iNand)第2分区,根文件系统是可读可写的
rw init=/linuxrc linux的进程1(init进程)的路径
rootfstype=ext3 根文件系统的类型是ext3
(4)、内核传参非常重要。在内核移植的时候,新手经常因为忘记给内核传参,或者传参错误导致内核无法
启动。
(5)、在uboot中没有操作系统的,因此我们对Flash的管理必须使用分区界定(实际上在uboot和kernel中
都有个分区表)有了这个界定之后,我们在部署系统时按照分区界定的方法来部署,uboot和kernel
中的软件也是按照这个分区界定来工作,就不会错。
(6)、uboot必须从Flash起始地址开始存放(也许是扇区0,也许是扇区1,也许是其他,取决于SoC的
启动设计),uboot分区的大小必须保证uboot肯定能放的下,一般设计为512KB或者1MB。
kernel:kernel可以紧贴环境变量存放,大小一般为3MB或5MB或其他。
(7)、总结:各个分区彼此相连,前面一个分区的结尾就是后一个分区的开头。
整个Flash充分利用,从开头到结尾。
uboot必须在Flash开头,其他分区相对位置是可变的。
各个分区的大小由系统移植工程师自己来定,一般为合适大小。
各个分区在系统移植前确定好,在uboot中和kernel中使用同一个分区表。将来在系统部署时
和系统代码中的分区方法也是一样的。
(8)、uboot阶段DDR的分区
DDR的分区和Flash的分区不同,主要是因为Flash是掉电存在的,而DDR是掉电消失,因此可以说
DDR是每次系统运行时才开始部署使用的。
内存的分区主要是在Linux内核启动起来之前, linux内核启动后内核的内存管理模块会接管整个内存
空间,那时候就不用我们来管了。
内存的分区关键就在于内存中哪一块是用来干嘛的,以避免各个不同功能使用了同一块内存造成互相
踩踏。
欢迎各位指出不足之处