uboot的本质就是一个复杂点的裸机程序。
操作系统内核本身就是一个裸机程序,和uboot、和其他裸机程序并没有本质区别。
区别就是操作系统运行起来后在软件上分为内核层和应用层,分层后两层的权限不同,
内存访问和设备操作的管理上更加精细(内核可以随便访问各种硬件,而应用程序只能被限制的访问硬件和内存地址)。
uboot的镜像是u-boot.bin,linux系统的镜像是zImage,这两个东西其实都是两个裸机程序镜像。
从系统的启动角度来讲,内核其实就是一个大的复杂点裸机程序。
嵌入式系统部署在Flash设备上时,对于不同SoC和Flash设备,bootloader、kernel、rootfs的分区是不同的。
嵌入式系统在启动时,uboot、kernel、rootfs不能随意存放,必须存放在规划好的相应分区,在启动过程中uboot、kernel会到相应分区加载相应内容,确保正常启动,
因此嵌入式系统中,uboot和kernel规划的分区和启动设备中uoot、kernel、rootfs的实际存储分区是一致的。
【启动过程】
典型嵌入式系统的部署:uboot程序部署在Flash(能作为启动设备的Flash)上、
OS部署在FLash(嵌入式系统中用Flash代替了硬盘)上、
内存在掉电时无作用,CPU在掉电时不工作。
【uboot的作用】
(1)uboot主要作用是用来启动操作系统内核。
(2)uboot还要负责部署整个计算机系统。
(3)uboot中还有操作Flash等板子上硬盘的驱动。
(4)uboot还得提供一个命令行界面供人来操作。
【uboot本质】
(1)uboot的本质就是一个裸机程序,和我们裸机全集中写的那些裸机程序xx.bin并没有本质区别。
如果非说要有区别,那就是:我们写的大部分小于16KB,而uboot大于16KB(一般uboot在180k-400k之间)
(2)uboot本身是一个开源项目,由若干个.c文件和.h文件组成,
配置编译之后会生成一个uboot.bin,这就是uboot这个裸机程序的镜像文件。
然后这个镜像文件被合理的烧录到启动介质中拿给SoC去启动。也就是说uboot在没有运行时表现为uboot.bin,
一般躺在启动介质中。
(3)uboot运行时会被加载到内存中然后一条指令一条指令的拿给CPU去运行。
【uboot的生命期】
uboot的生命周期就是指:uboot什么时候开始运行,什么时候结束运行;
uboot本质上是一个裸机程序(不是操作系统),
一旦uboot开始SoC就会单纯运行uboot(意思就是uboot运行的时候别的程序是不可能同时运行的),
一旦uboot结束运行则无法再回到uboot(所以uboot启动了内核后uboot自己本身就死了,
要想再次看到uboot界面只能重启系统。重启并不是复活了刚才的uboot,重启只是uboot的另一生)
uboot的入口和出口。
uboot的入口就是开机自动启动,
uboot的唯一出口就是启动内核。
uboot还可以执行很多别的任务(譬如烧录系统),
但是其他任务执行完后都可以回到uboot的命令行继续执行uboot命令,而启动内核命令一旦执行就回不来了。
【内核参数】
linux内核在设计的时候,设计为可以被传参。
也就是说我们可以在uboot中事先给linux内核准备一些启动参数放在内存中特定位置然后传给内核,
内核启动后会到这个特定位置去取uboot传给他的参数,然后在内核中解析这些参数,
这些参数将被用来指导linux内核的启动过程。
【uboot的移植】
uboot具有可移植性并不是说uboot在哪个开发板都可以随便用;
uboot必须进行和硬件相对应的代码级别的更改和移植,才能够保证可以从相应的启动介质启动。
uboot中第一阶段的start.S文件中具体处理了这一块。
uboot具有在源代码级别的移植能力,可以针对多个开发板进行移植,移植后就可以在这个开发板上使用了。
【uboot必须解决哪些问题】
1、开机启动:
必须根据具体的SoC的启动设计来设计uboot。//跟硬件相关
2、能够引导操作系统内核启动并给内核传参
3、能提供系统部署功能
3.1、uboot必须能够被人借助而完成整个系统(包括uboot、kernel、rootfs等的镜像)在Flash上的烧录下载工作。
4、能进行soc级和板级硬件管理
4.1、uboot中实现了一部分硬件的控制能力(uboot中初始化了一部分硬件),
因为uboot为了完成一些任务必须让这些硬件工作。
譬如uboot要实现刷机必须能驱动iNand,
譬如uboot要在刷机时LCD上显示进度条就必须能驱动LCD,
譬如uboot能够通过串口提供操作界面就必须驱动串口。
譬如uboot要实现网络功能就必须驱动网卡芯片。
4.2、SoC级(譬如串口)就是SoC内部外设,板级就是SoC外面开发板上面的硬件(譬如网卡、iNand)
【uboot的工作方式】
1、uboot的命令式shell界面
有些程序需要和人进行交互,于是乎程序中就实现了一个shell
(shell就是提供人机交互的一个界面)uboot就实现了一个shell。
uboot中的shell工作方式和linux中的终端shell非常像
(其实几乎是一样的,只是命令集不一样。譬如linux中可以ls,uboot中ls就不识别)
2、环境变量:
uboot的环境变量和操作系统的环境变量工作原理和方式几乎完全相同。
环境变量可以被认为是系统的全局变量,环境变量名都是系统内置的;
这样设计的好处就是灵活,譬如我们要让一个程序更改运行方法,
不用去重新修改程序代码再重新编译运行,而只要修改相应的环境变量就可以了。
环境变量就是运行时的配置属性。
3、uboot常见命令:
3.1、printenv/print;
3.2、setenv/set //设置(添加/更改)环境变量 set name value
3.3、saveenv/save //保存环境变量的更改,永久生效;
3.4、ping //网络测试命令 ping ip地址
3.5、tftp //下载使用的命令
uboot为了部署内核就需要将内核镜像从主机中下载过来然后烧录到本地flash中。
uboot如何从主机(windows或者虚拟机ubuntu)下载镜像到开发板上?
有很多种方式,主流方式是:fastboot和tftp。
fastboot的方式是通过USB线进行数据传输。
tftp的方式是通过有线网络的。典型的方式就是通过网络。
fastboot是近些年才新发展的。
3.6、bootm、go //启动内核指令
uboot的终极目标就是启动内核,启动内核在uboot中表现为一个指令,
uboot命令行中调用这个指令就会启动内核(不管成功与否,所以这个指令是一条死路)。
bootm启动内核同时给内核传参,而Go命令启动内核不传参。
bootm其实才是正宗的启动内核的命令,一般情况下都用这个;
go命令本来不是专为启动内核设计的,
go命令内部其实就是一个函数指针指向一个内存地址然后直接调用那个函数,
go命令的实质就是PC直接跳转到一个内存地址去运行而已。
go命令可以用来在uboot中执行任何的裸机程序(有一种调试裸机程序的方法就是事先启动uboot,
然后在uboot中去下载裸机程序,用go命令去执行裸机程序)。
3.7、bootcmd
uboot启动后会开机自动倒数bootdelay秒,
如果没有人按下回车打断启动,则uboot会自动执行启动命令来启动内核。