为什么要有uboot带你全面分析嵌入式中uboot的作用
1.为什么要有uboot
1.1、计算机系统的主要部件
(1)计算机系统就是以CPU为核心来运行的系统。典型的计算机系统有:PC机(台式机+笔记本)、嵌入式设备(手机、平板电脑、游戏机)、单片机(家用电器像电饭锅、空调)
(2)计算机系统的组成部件非常多,不同的计算机系统组成部件也不同。但是所有的计算机系统运行时需要的主要核心部件都是3个东西:
CPU + 外部存储器(Flash/硬盘) + 内部存储器(DDR SDRAM/SDRAM/SRAM)
1.2、PC机的启动过程
(1)部署:典型的PC机的BIOS程序部署在PC机主板上(随主板出厂时已经预制了),操作系统部署在硬盘上,内存在掉电时无作用,CPU在掉电时不工作。
(2)启动过程:PC上电后先执行BIOS程序(实际上PC的BIOS就是NorFlash),BIOS程序负责初始化DDR内存,负责初始化硬盘,然后从硬盘上将OS镜像读取到DDR中,然后跳转到DDR中去执行OS直到启动(OS启动后BIOS就无用了)
1.3、典型嵌入式linux系统启动过程
(1)典型嵌入式系统的部署:uboot程序部署在Flash(能作为启动设备的Flash)上、OS部署在FLash(嵌入式系统中用Flash代替了硬盘)上、内存在掉电时无作用,CPU在掉电时不工作。
(2)启动过程:嵌入式系统上电后先执行uboot、然后uboot负责初始化DDR,初始化Flash,然后将OS从Flash中读取到DDR中,然后启动OS(OS启动后uboot就无用了)
总结:嵌入式系统和PC机的启动过程几乎没有两样,只是BIOS成了uboot,硬盘成了Flash。
1.4、android系统启动过程
(1)Android系统的启动和Linux系统(前面讲的典型的嵌入式系统启动)几乎一样。几乎一样意思就是前面完全一样,只是在内核启动后加载根文件系统后不同了。
(2)可以认为启动分为2个阶段:第一个阶段是uboot到OS启动;第二个阶段是OS启动后到rootfs加载到命令行执行;现在我们主要研究第一个阶段,android的启动和linux的差别在第二阶段。
1.5、总结:uboot到底是干嘛的
(1)uboot主要作用是用来启动操作系统内核。
(2)uboot还要负责部署整个计算机系统。
(3)uboot中还有操作Flash等板子上硬盘的驱动。
(4)uboot还得提供一个命令行界面供人来操作。
2.为什么是uboot
2.1、uboot从哪里来的?
(1)uboot是SourceForge上的开源项目
(2)uboot项目的作者:一个德国人最早发起的项目
(3)uboot就是由一个人发起,然后由整个网络上所有感兴趣的人共同维护发展而来的一个bootloader。
2.2、uboot的发展历程
(1)自己使用的小开源项目。
(2)被更多人认可使用
(3)被SoC厂商默认支持。
总结:uboot经过多年发展,已经成为事实上的业内bootloader标准。现在大部分的嵌入式设备都会默认使用uboot来做为bootloader。
2.3、uboot的版本号问题
(1)早期的uboot的版本号类似于这样:uboot1.3.4。后来版本号便成了类似于uboot-2010.06。
(2)uboot的核心部分几乎没怎么变化,越新的版本支持的开发板越多而已,对于一个老版本的芯片来说,新旧版本的uboot并没有差异。
2.4、uboot的可移植性的正确理解
(1)uboot就是universal bootloader(通用的启动代码),通用的意思就是在各种地方都可以用。所以说uboot具有可移植性。
(2)uboot具有可移植性并不是说uboot在哪个开发板都可以随便用,而是说uboot具有在源代码级别的移植能力,可以针对多个开发板进行移植,移植后就可以在这个开发板上使用了。
3.uboot必须解决哪些问题
3.1、自身可开机直接启动
(1)一般的SoC都支持多种启动方式,譬如SD卡启动、NorFlash启动、NandFlash启动等·····uboot要能够开机启动,必须根据具体的SoC的启动设计来设计uboot。
(2)uboot必须进行和硬件相对应的代码级别的更改和移植,才能够保证可以从相应的启动介质启动。uboot中第一阶段的start.S文件中具体处理了这一块。
3.2、能够引导操作系统内核启动并给内核传参
(1)uboot的终极目标就是启动内核。
(2)linux内核在设计的时候,设计为可以被传参。也就是说我们可以在uboot中事先给linux内核准备一些启动参数放在内存中特定位置然后传给内核,内核启动后会到这个特定位置去取uboot传给他的参数,然后在内核中解析这些参数,这些参数将被用来指导linux内核的启动过程。
3.3、能提供系统部署功能
(1)uboot必须能够被人借助而完成整个系统(包括uboot、kernel、rootfs等的镜像)在Flash上的烧录下载工作。
(2)裸机教程中刷机(ARM裸机第三部分)就是利用uboot中的fastboot功能将各种镜像烧录到iNand中,然后从iNand启动。
3.4能进行soc级和板级硬件管理
(1)uboot中实现了一部分硬件的控制能力(uboot中初始化了一部分硬件),因为uboot为了完成一些任务必须让这些硬件工作。譬如uboot要实现刷机必须能驱动iNand,譬如uboot要在刷机时LCD上显示进度条就必须能驱动LCD,譬如uboot能够通过串口提供操作界面就必须驱动串口。譬如uboot要实现网络功能就必须驱动网卡芯片。
(2)SoC级(譬如串口)就是SoC内部外设,板级就是SoC外面开发板上面的硬件(譬如网卡、iNand)
3.5、uboot的“生命周期”
(1)uboot的生命周期就是指:uboot什么时候开始运行,什么时候结束运行。
(2)uboot本质上是一个裸机程序(不是操作系统),一旦uboot开始SoC就会单纯运行uboot(意思就是uboot运行的时候别的程序是不可能同时运行的),一旦uboot结束运行则无法再回到uboot(所以uboot启动了内核后uboot自己本身就死了,要想再次看到uboot界面只能重启系统。重启并不是复活了刚才的uboot,重启只是uboot的另一生)
(3)uboot的入口和出口。uboot的入口就是开机自动启动,uboot的唯一出口就是启动内核。uboot还可以执行很多别的任务(譬如烧录系统),但是其他任务执行完后都可以回到uboot的命令行继续执行uboot命令,而启动内核命令一旦执行就回不来了。
总结:一切都是为了启动内核
4.uboot的工作方式
4.1、从裸机程序镜像uboot.bin说起
(1)uboot的本质就是一个裸机程序,和我们裸机全集中写的那些裸机程序xx.bin并没有本质区别。如果非说要有区别,那就是:我们写的大部分小于16KB,而uboot大于16KB(一般uboot在180k-400k之间)
(2)uboot本身是一个开源项目,由若干个.c文件和.h文件组成,配置编译之后会生成一个uboot.bin,这就是uboot这个裸机程序的镜像文件。然后这个镜像文件被合理的烧录到启动介质中拿给SoC去启动。也就是说uboot在没有运行时表现为uboot.bin,一般躺在启动介质中。
(3)uboot运行时会被加载到内存中然后一条指令一条指令的拿给CPU去运行。
4.2、uboot的命令式shell界面
(1)普通的裸机程序运行起来就直接执行了,执行时效果和代码有关。
(2)有些程序需要和人进行交互,于是乎程序中就实现了一个shell(shell就是提供人机交互的一个界面,回想ARM裸机全集第十六部分),uboot就实现了一个shell。
注意:shell并不是操作系统,和操作系统一点关系都没有。linux中打开一个终端后就得到了一个shell,可以输入命令回车执行。uboot中的shell工作方式和linux中的终端shell非常像(其实几乎是一样的,只是命令集不一样。譬如linux中可以ls,uboot中ls就不识别)
4.3、掌握uboot使用的2个关键点:命令和环境变量
(1)uboot启动后大部分时间和工作都是在shell下完成的(譬如uboot要部署系统要在shell下输命令、要设置环境变量也得在命令行地下,要启动内核也要在命令行底下敲命令)
(2)命令就是uboot的shell中可以识别的各种命令。uboot中有几十个命令,其中有一些常用另一些不常用(我们还可以自己给uboot添加命令),后面会用几节课时间来依次学习uboot中常用命令。
(3)uboot的环境变量和操作系统的环境变量工作原理和方式几乎完全相同。uboot在设计时借助了操作系统的设计理念(命令行工作方式借鉴了linux终端命令行,环境变量借鉴了操作系统的环境变量,uboot的驱动管理几乎完全照抄了linux的驱动框架)。
(4)环境变量可以被认为是系统的全局变量,环境变量名都是系统内置的(认识就认识,不认识就不认识,这部分是系统自带的默认的环境变量,譬如PATH;但是也有一部分环境变量是自己添加的,自己添加的系统就不认识但是我们自己认识)。系统或者我们自己的程序在运行时可以通过读取环境变量来指导程序的运行。这样设计的好处就是灵活,譬如我们要让一个程序更改运行方法,不用去重新修改程序代码再重新编译运行,而只要修改相应的环境变量就可以了。
(5)环境变量就是运行时的配置属性。
5.uboot的常用命令1
5.1、类似linux终端的行缓冲命令行
(1)行缓冲的意思就是:当我们向终端命令行输入命令的时候,这些命令没有立即被系统识别,而是被缓冲到一个缓存区(也就是系统认为我们还没有输入完),当我们按下回车键(换行)后系统就认为我们输入完了,然后将缓冲区中所有刚才输入的作为命令拿去分析处理。
(2)linux终端设计有3种缓冲机制:无缓冲、行缓冲、全缓冲
(3)有些命令有简化的别名,譬如printenv命令可以简化为print,譬如setenv可以简化为set
(4)有些命令会带参数(注意格式是固定的),uboot的每个命令都有事先规定好的各种格式。有些命令就是不带参数的,譬如printenv/print命令;有些命令带可选的参数(可以带也可以不带,当然带不带参数的执行结果是不同的);有些命令带必须的参数(譬如setenv/set命令)
(5)采用“help+命令名”来查询命令的详细信息,只输入help时,则打印出命令列表。
5.2、命令中的特殊符号(譬如单引号)
(1)uboot的有些命令带的参数非常长,为了告诉uboot这个非常长而且中间有好多个空格的东西是给他的一整个参数,所以用单引号将这个很长且中间有空格隔开的参数引起来。
(2)别的符号也许也有,而且有特定的意义。当碰到uboot的命令行有特殊符号时要注意不是弄错了,而是可能有特别的含义。
5.3、有些命令是一个命令族(譬如movi)
(1)命令族意思就是好多个命令开头都是用同一个命令关键字的,但是后面的参数不一样,这些命令的功能和作用也不同。这就叫一个命令族。
(2)同一个命令族中所有的命令都有极大的关联,譬如movi开头的命令族都和moviNand(EMMC、iNand)操作有关。
5.4、第一个命令:printenv/print
(1)print命令不用带参数,作用是打印出系统中所有的环境变量。
(2)环境变量就好像程序的全局变量一样。程序中任何地方都可以根据需要去调用或者更改环境变量(一般都是调用),环境变量和全局变量不同之处在于:全局变量的生命周期是在程序的一次运行当中,开始运行时诞生程序结束时死亡,下次运行程序时从头开始;但是环境变量被存储在Flash的另一块专门区域(Flash上有一个环境变量分区),一旦我们在程序中保存了该环境变量,那么下次开机时该环境变量的值将维持上一次更改保存后的值。
6.uboot的常用命令2
1、设置(添加/更改)环境变量:setenv/set
用法:set name value
2、保存环境变量的更改:saveenv/save
saveenv/save命令不带参数,直接执行,作用是将内存中的环境变量的值同步保存到Flash中环境变量的分区。注意:环境变量的保存是整体的覆盖保存,也就是说内存中所有的环境变量都会整体的将Flash中环境变量分区中原来的内容整体覆盖。
总结:彻底更改一个环境变量的值,需要2步:
第一步:set命令来更改内存中的环境变量
第二步:用save命令将其同步到Flash中环境变量的分区。
有时候我们只是想测试下这个环境变量,不希望影响到下一次开机,那就只set不save,这样set后当前本次运行的uboot已经起效果了,只不过没save下一次开机还是会恢复到原来的状况。
3、网络测试指令:ping
(1)命令用法: ping ip地址
注意:ping是测试开发板和主机之间的网络链接,注意以下步骤:
1)首先要插上网线。
2)先试图ping通主机windows。注意Windows中有线网卡的地址设置(设置本地连接)。设置主机windows的本地连接IPv4地址为192.168.1.10
3)第三步确认开发板中uboot里几个网络相关的环境变量的值对不对。最重要的是ipaddr(这个环境变量表示当前开发板的IP地址),这个地址必须和主机windows的IP地址在同一个网段。
网段的概念:一个IP地址分为2部分,一部分是网段地址,另一部分是网段内的主机地址(由子网掩码来区分哪一部分是网段地址,哪一部分是IP地址)。在子网掩码是255.255.255.0的情况下,192.168.1.10这个IP地址的前三部分(192.168.1.)属于网段地址,第4部分(10)属于主机地址。
7.开发板和主机的ping通
上节课最后的结果是:uboot中的ipaddr和主机windows本地连接地址已经设置到一个网段,但是实际还ping不通。
还发现了这样的现象:1、我把2个的网段都从192.168.1.x改到192.168.0.x时会ping通一次,第二次开始就ping不通了;2、有同学说ping不通可能是因为uboot中gatewayip没设置,我就实际测试设置网管为同网段.1,再次测试结论是第一次ping通了,第二次开始又不通了。
7.1、开发板运行linux下和主机Windows的ping通
(1)先将开发板刷机成linux+QT镜像(刷机见裸机教程第三部分),然后启动进入linux命令行终端下。
(2)在linux下使用ifconfig命令将开发板中linux系统的IP地址设置为和主机windows同一网段(为了上课方便,以后就固定:主机windows地址192.168.1.10,开发板uboot或linux的地址为192.168.1.20,虚拟机ubuntu地址为192.168.1.141)
(3)此时开发板端ping windows通的。
(4)windows中ping开发板也是通的。
说明:首先开发板和主机的网络部分硬件都是好的,网络连接也是好的,主机windows中的网络软件设置是好的。
7.2、开发板运行linux下和虚拟机ubuntu的ping通
(1)在linux基础课中讲过:虚拟机的网卡设置可以选择好几种方式,常用的就是NAT和桥接(bridged)。
(2)虚拟机要和开发板进行网络通信,只能通过桥接方式连接。
(3)虚拟机要想被开发板ping通,设置步骤如下:
第一步:虚拟机设置成桥接方式。
第二步:虚拟机的菜单中有个“虚拟网络编辑器”,这里面要设置为桥接到有线网卡。(默认是自动的,自动的一般会影响ping通。因为电脑现在一般都有2个网卡:一个有线的一个无线的。如果选了自动,那么虚拟机会自动桥接到无线网卡上,但是我们却是通过有线网卡来连接开发板的,自然ping不通)
第三步:在虚拟机ubuntu中设置IP地址为192.168.1.141(可以通过/etc/network/interfaces文件来设置静态的然后重启;也可以直接命令行ifconfig去设置)
(4)此时开发板ping虚拟机ubuntu应该就通了。
(5)此时虚拟机ubuntu中ping开发板也是通的。
7.3、开发板运行uboot下和主机Windows的ping通
(1)刚才开发板运行linux时和主机windows、虚拟机ubuntu都ping通了,说明硬件和连接和主机设置没错。
(2)此时开发板重启进入uboot,设置好ipaddr、gatewayip,然后去ping windows发现还是不通。 怀疑uboot本身网络驱动有问题。
(3)然后同样情况下尝试去ping通虚拟机ubuntu,理论分析应该也不通,但是实际发现是通的。
7.4、开发板运行uboot下和虚拟机ubuntu的ping通
uboot和虚拟机ubuntu互相ping通(前提是虚拟机ubuntu设置为桥接,且桥接到有线网卡,且ip地址设置正确的情况下)
结论:开发板中运行的uboot有点小bug,ping windows就不通,ping虚拟机ubuntu就通。
8.uboot常用命令3
8.1、tftp下载指令:tftp
(1)uboot本身主要目标是启动内核,为了完成启动内核必须要能够部署内核,uboot为了部署内核就需要将内核镜像从主机中下载过来然后烧录到本地flash中。uboot如何从主机(windows或者虚拟机ubuntu)下载镜像到开发板上?有很多种方式,主流方式是:fastboot和tftp。
fastboot的方式是通过USB线进行数据传输。
tftp的方式是通过有线网络的。典型的方式就是通过网络,fastboot是近些年才新发展的。
(2)tftp方式下载时实际上uboot扮演的是tftp客户端程序角色,主机windows或虚拟机ubuntu中必须有一个tftp服务器,然后将要下载的镜像文件放在服务器的下载目录中,然后开发板中使用uboot的tftp命令去下载即可。
(3)有些人习惯在windows中搭建tftp服务器,一般是用一些软件来搭建(譬如tftpd32,使用起来比较简单);有些人习惯在linux下搭建tftp服务器,可以参考网盘中的虚拟机下载目录下的一个教程《嵌入式开发环境搭建-基于14.04.pdf》,这里面有ubuntu中搭建tftp服务器的教程,也可以自己上网搜索教程尝试。(如果你直接就用我的虚拟机,那就已经搭建好了,不用再搭建了;如果是自己新装的那就参考文档搭建;如果你的版本和我的不一样那搭建过程可能不一样)
(4)我的虚拟机搭建的时候设置的tftp下载目录是/tftpboot,将要被下载的镜像复制到这个目录下。
(5)检查开发板uboot的环境变量,注意serverip必须设置为虚拟机ubuntu的ip地址。(serverip这个环境变量的意义就是主机tftp服务器的ip地址)
(6)然后在开发板的uboot下先ping通虚拟机ubuntu,然后再尝试下载:tftp 0x30000000 zImage-qt(意思是将服务器上名为zImage-qt的文件下载到开发板内存的0x30000000地址处。)
(7)镜像下载到开发板的DDR中后,uboot就可以用movi指令进行镜像的烧写了。
注意:
如果你是用的windows下的tftp服务器,那uboot的serverip就要设置为和windwos下tftp服务器的ip地址一样(windows下的tftp服务器软件设置的时候就有个步骤是让你设置服务器的ip地址,这个ip地址和主机windows必须在一个网段)。
9.uboot的常用命令4
9.1、SD卡/iNand操作指令movi
(1)开发板如果用SD卡/EMMC/iNand等作为Flash,则在uboot中操作flash的指令为movi(或mmc)
(2)movi指令是一个命令集,有很多子命令,具体用法可以help movi查看。
(3)movi的指令都是movi read和movi write一组的,movi read用来读取iNand到DDR上,movi write用来将DDR中的内容写入iNand中。理解这些指令时一定要注意涉及到的2个硬件:iNand和DDR内存。
(4)movi read {u-boot | kernel} {addr} 这个命令使用了一种通用型的描述方法来描述:movi 和read外面没有任何标记说明每一次使用这个指令都是必选的;一对大括号{}括起来的部分必选1个;大括号中的竖线表是多选一;中括号[]表示可选参数
(5)指令有多种用法,譬如 movi read u-boot 0x30000000,意思就是把iNand中的u-boot分区读出到DDR的0x30000000起始的位置处。(uboot代码中将iNand分成了很多个分区,每个分区有地址范围和分区名,uboot程序操作中可以使用直接地址来操作iNand分区,也可以使用分区名来操作分区。);注意这里的0x30000000也可以直接写作30000000,意思是一样的(uboot的命令行中所有数字都被默认当作十六进制处理,不管你加不加0x都一样)。
9.2、NandFlash操作指令nand
理解方法和操作方法完全类似于movi指令
9.3、内存操作指令:mm、mw、md
(1)DDR中是没有分区的(只听说过对硬盘、Flash进行分区,没听说过对内存进行分区····),但是内存使用时要注意,千万不能越界踩到别人了。因为uboot是一个裸机程序,不像操作系统会由系统整体管理所有内存,系统负责分配和管理,系统会保证内存不会随便越界。然后裸机程序中uboot并不管理所有内存,内存是散的随便用的,所以如果程序员(使用uboot的人)自己不注意就可能出现自己把自己的数据给覆盖了。(所以你思考下我们为什么把uboot放在23E00000地址处)
(2)md就是memory display,用来显示内存中的内容。
(3)mw就是memory write,将内容写到内存中
(4)mm就是memory modify,修改内存中的某一块,说白了还是写内存(如果需要批量的逐个单元的修改内存,用mm最合适)
9.4、启动内核指令:bootm、go
(1)uboot的终极目标就是启动内核,启动内核在uboot中表现为一个指令,uboot命令行中调用这个指令就会启动内核(不管成功与否,所以这个指令是一条死路)。
(2)差别:bootm启动内核同时给内核传参,而Go命令启动内核不传参。bootm其实才是正宗的启动内核的命令,一般情况下都用这个;go命令本来不是专为启动内核设计的,go命令内部其实就是一个函数指针指向一个内存地址然后直接调用那个函数,go命令的实质就是PC直接跳转到一个内存地址去运行而已。go命令可以用来在uboot中执行任何的裸机程序(有一种调试裸机程序的方法就是事先启动uboot,然后在uboot中去下载裸机程序,用go命令去执行裸机程序)
10.uboot的常用环境变量1
10.1、环境变量如何参与程序运行
(1)环境变量有2份,一份在Flash中,另一份在DDR中。uboot开机时一次性从Flash中读取全部环境变量到DDR中作为环境变量的初始化值,然后使用过程中都是用DDR中这一份,用户可以用saveenv指令将DDR中的环境变量重新写入Flash中去更新Flash中环境变量。下次开机时又会从Flash中再读一次。
(2)环境变量在uboot中是用字符串表示的,也就是说uboot是按照字符匹配的方式来区分各个环境变量的。因此用的时候一定要注意不要打错字了。
1、自动运行倒数时间:bootdelay
2、网络设置:ipaddr serverip
(1)ipaddr是开发板的本地IP地址
(2)serverip是开发板通过tftp指令去tftp服务器下载东西时,tftp服务器的IP地址。
(3)gatewayip是开发板的本地网关地址
(4)netmask是子网掩码
(5)ethaddr是开发板的本地网卡的MAC地址。
11.uboot的常用环境变量2
11.1、自动运行命令设置:bootcmd
(1)uboot启动后会开机自动倒数bootdelay秒,如果没有人按下回车打断启动,则uboot会自动执行启动命令来启动内核。
(2)uboot开机自动启动时实际就是在内部执行了bootcmd这个环境变量的值所对应的命令集:bootcmd=movi read kernel 30008000; bootm 30008000
意思是:将iNand的kernel分区读取到DDR内存的0x30008000地址处,然后使用bootm启动命令从内存0x30008000处去启动内核。
(3)set bootcmd printenv,然后saveenv;然后重启则会看到启动倒数后自动执行printenv命令打印出环境变量。这个小实验说明开机自动执行了bootcmd。
(4)设置bootcmd环境变量:set bootcmd 'movi read kernel 30008000; bootm 30008000'
11.2、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 rw 根文件系统在SD卡端口0设备(iNand)第2分区,根文件系统是可读可写的
init=/linuxrc linux的进程1(init进程)的路径
rootfstype=ext3 根文件系统的类型是ext3
(4)内核传参非常重要。在内核移植的时候,新手经常因为忘记给内核传参,或者给内核传递的参数不对,造成内核启动不起来。
11.3、新建、更改、删除一个环境变量的方法
(1)新建一个环境变量,使用set var value
(2)更改一个环境变量,使用set var value
(3)删除一个环境变量,使用set var
注意:修改完成环境变量后一定要保存,否则下次开机更改就又没了。
12.uboot中对Flash和DDR的管理
12.1、uboot阶段Flash的分区
(1)所谓分区,就是说对Flash进行分块管理。
(2)PC机等产品中,因为大家都是在操作系统下使用硬盘的,整个硬盘由操作系统统一管理,操作系统会使用文件系统帮我们管理硬盘空间。(管理保证了文件之间不会互相堆叠),于是乎使用者不用自己太过在意分区问题。
(3)在uboot中是没有操作系统的,因此我们对Flash(相当于硬盘)的管理必须事先使用分区界定(实际上在uboot中和kernel中都有个分区表,分区表就是我们在做系统移植时对Flash的整体管理分配方法)。有了这个界定后,我们在部署系统时按照分区界定方法来部署,uboot和kernel的软件中也是按照这个分区界定来工作,就不会错。
(4)分区方法不是一定的,不是固定的,是可以变动的。但是在一个移植中必须事先设计好定死,一般在设计系统移植时就会定好,定的标准是:
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中使用同一个分区表。将来在系统部署时和系统代码中的分区方法也必须一样。
12.2、uboot阶段DDR的分区
(1)DDR的分区和Flash的分区不同,主要是因为Flash是掉电存在的,而DDR是掉电消失,因此可以说DDR是每次系统运行时才开始部署使用的。
(2)内存的分区主要是在linux内核启动起来之前,linux内核启动后内核的内存管理模块会接管整个内存空间,那时候就不用我们来管了。
(3)注意内存分区关键就在于内存中哪一块用来干什么必须分配好,以避免各个不同功能使用了同一块内存造成的互相踩踏。譬如说我们tftp 0x23E00000 zImage去下载zImage到内存的0x23E00000处就会出错,因为这个内存处实际是uboot的镜像所在。这样下载会导致下载的zImage把内存中的uboot给冲掉。
广告商务合作,请联系0755-33248146
汽车整车OTA升级篇之 uboot介绍
前面提到FOTA,需要升级的时候如果涉及到uboot部分,这部分会要求非常高,毕竟我是硬件出身,就在这里班门弄斧简单通过有趣的内容给大家介绍一下uboot,为什么需要uboot。
先进行一下科普吧,大家都在家炒过菜吧,其实你发现做一顿晚餐的过程就特别像安卓系统的工作原理。
1、首先要有基本的炒菜的环境,厨房要有电、天然气要通气,有锅和铲子等工具,这些类似底层硬件的电源管理,需要有这些基本的电气条件满足。
2、其次要有炒菜的基本佐料,包括盐、酱油、白醋、陈醋,糖、味精、鸡精,生抽、老抽、香油,芝麻油,葱,姜,蒜,孑然,耗油、白胡椒、黑胡椒,番茄酱,花椒,辣椒,辣椒油。
无论你炒什么菜,都首先把这些佐料准备好,可能炒爆炒肥肠和番茄炒蛋所需要的佐料有很多不同的,但是盐和油肯定是都需要的,只是其他佐料有区别,这个不影响提前把这些炒菜的佐料进行准备好,尽可能的把这些佐料都准备齐全。
这里就相当于Linux内核层,进行USB接口、蓝牙、wifi、摄像头、音视频、显示屏等基本服务,可能不同的APP应用所需要调用的这些服务不同,比如一款聊天软件可能需要使用到WIFI、摄像头、显示等等,不需要使用USB接口,但是不影响另外APP会可能调用到USB、存储等等。
3、不知道你们炒菜是否需要菜谱,至少机哥我炒菜需要使用到菜谱的,需要百度一下某个菜需要什么佐料,什么样的配比材料,没错机哥这期内容修改为美食栏目去了,下面是网上水煮肉片的菜谱。
其实这里使用到的菜谱就可以理解为安卓系统里面的硬件抽象层,这里简单理解为,就是你如果知道这个菜谱中佐料的比例,在你自己家里炒菜和在朋友家里炒菜,这个炒出来的味道基本上也就味道相同,就可以理解为为什么这个在安卓系统中硬件抽象层可以在不同的平台进行移植,也就是掌握了菜谱的精髓,功夫我有,天下我走。
4、最后就是炒菜的动作了,其实熟练的厨师是可以至少掌握好几个菜同时操作,这个不仅考验厨师的速度,也考验厨师的精准度,对于火候的掌控要精准,对于佐料使用要合理分配。
其实这里炒不同的菜就类似于使用不同的APP的应用,这里如果有一个菜炒胡了,不能影响到另外一个菜的正常发挥,类似于多线程中的某个APP挂掉了,但是不能影响到其他APP的正常使用。
这里也会出现占用资源的情况,比如同时用两个锅炒菜,左边那个锅在炒爆炒肥肠,直接把所有的盐都一不小心全部倒完了,此时右边锅里面的菜也就报废掉了,没有盐的菜不能称之为一道菜。这个是不是类似于某个APP调用内存泄露,把全部的内存占用没有释放,导致机器只能重启。
安卓系统启动简单介绍
1、安卓系统平台架构
可以看出整个架构由5部分构成,从下到上分别为:
1. Linux内核层
Android 的核心系统服务基于Linux 内核,在此基础上添加了部分Android专用的驱动。系统的安全性、内存管理、进程管理、网络协议栈和驱动模型等都依赖于该内核。
2. 硬件抽象层(HAL)
硬件抽象层是位于操作系统内核与硬件电路之间的接口层,其目的在于将硬件抽象化,为了保护硬件厂商的知识产权,它隐藏了特定平台的硬件接口细节,为操作系统提供虚拟硬件平台,使其具有硬件无关性,可在多种平台上进行移植。HAL 由多个库模块组成,每个模块都为特定类型的硬件组件实现了一个接口,例如相机或蓝牙模块。当框架 API 调用设备硬件时,Android 系统为该硬件组件加载库模块。
3. 系统运行库层(Native)
系统运行库层分为两部分,分别是C/C++程序库和Android运行时库。C/C++程序库被Android中不同的部分使用 runtime库主要是Java核心库(提供了Java语言核心功能因此开发者可以使用Java编写应用)和ART(Android 5.0 之前是Dalvik)该虚拟机不同于JVM是专门用于移动设备的虚拟机 允许在有限的内存内运行多个虚拟机实例 并且每个应用都是独立的linux进程这样可以防止虚拟机崩溃时不会导致所有的进程被关闭。
4. 应用框架层(Java Framework)
应用框架层为开发人员提供了可以开发应用程序所需要的API,我们平常开发应用程序都是调用的这一层所提供的API,当然也包括系统的应用。这一层的是由Java代码编写的,可以称为Java Framework
5、应用层
系统内置的应用程序以及非系统级的应用程序都是属于应用层。负责与用户进行直接交互,通常都是用Java进行开发的
2、安卓系统启动介绍
上图是车载中控导航的系统启动的简单介绍
1. POWER 部分
目前的导航系统基本上都是CPU+MCU的架构,MCU进行电源部分的管理,CAN通讯的处理、收音部分的处理,所以这里的开电源的时候,一定是MCU完成整个中控导航系统的电源初始化。
MCU内部的电源管理器(regulator)将系统置于POR复位状态,直到VDD电压上升到超过POR复位门限电平,然后低电压检测模块会接管系统复位,直到VDD电压上升超过其LVR复位门限电平。在完成POR和LVR复位后,MCU系统的电源系统已经能够为内部时钟(FIRC、SIRC和LPO等)和存储器(NVM)模块以及CPU内核提供稳定的工作电压了。
这里的加载时间一般是500ms,这里考验的时间其实更多的是MCU的启动时间,一些整车的网络管理也要求ECU在低功耗模式唤醒后,能够尽快响应CAN/LIN总线报文,也要求MCU的启动时间要足够快。
一些功能安全要求较高的汽车ECU应用,比如电子助力转向(EPS)、电子档位控制(gear control)等,对于ECU的启动时间(startup/boot time)有严格的要求, 希望ECU使用的MCU能够尽快完成系统启动初始化,执行功能程序。
2. uboot 部分
这里的uboot主要进行CPU状态检查、DDR/emmc/usb等初始化,同时也有电源管理、USB升级检测等等,这里耗时基本上1S左右。
3.kernel部分
linux内核的启动,包括硬件初始化,驱动模块加载,包括USB、video、camera、touch等初始化,init进程,这里耗时1.5S左右。
4. Android初始化
init进程启动程序,zygote加载进程,系统启动服务。这里其实就是我们常见的开机动画就在这个初始化的时候完成的,这包含窗口管理服务,蓝牙服务、GPS服务,这里的GPS默认设置为打开状态,即服务初始化完成后就可以马上启动GSP定位开始,所以GPS的冷启动定位时间不是进入主界面开始算的时间,而且在动画界面初始化完成后就可以算时间了,这样可以让用户感觉体验更快就能GPS定位了。
5.主界面
系统启动,以下应用启动工作:收音、音视频播放、导航、语音、倒车、DVR、360全景、蓝牙等其他应用,这里的时间为2S左右。
一般的安卓系统启动时间为18S左右,应用启动2S,总计20S就可以正常操作APP应用了,这就是为什么安卓车机开机时间都会很久的,不太适合用于仪表,因为仪表要求开机5S左右就能正常显示工作。
从这个耗时来看,Android初始化的时间15S最长,所以要优化整个系统的启动时间的话,可以优先考虑这部分的优化时间。
吃瓜群众:机哥,你说的这些我都不懂,我们还是说回炒菜吧。
机哥:好的,那我们再来看看uboot在整个炒菜中,它是起到什么作用,初始化uboot,如果是炒菜,就是准备了哪些东西。
其实这里的uboot主要进行CPU状态检查、DDR/emmc/usb等初始化,同时也有电源管理、USB升级检测等等,想想炒菜之前是不是要检查锅是否干净,是否需要重新洗一遍,然后佐料这些是否足够,炒菜的燃气是否够大,有一个初步的火量大小的控制,等后面放好佐料后根据实际运气的情况再调节燃气大小的控制,就类似于前面初始化DDR和FLASH的运行速率,后面实际还可以调整这部分的运行速率。
Uboot 的简单介绍
1、为什么需要uboot
计算机系统的组成部件非常多,不同的计算机系统组成部件也不同。但是所有的计算机系统运行时需要的主要核心部件都是3个东西:CPU+外部存储器(Flash/硬盘+内部存储器(DDR SDRAM/SDRAM/SRAM)。
而一般的PC机启动过程为:PC上电后先执行BIOS程序(实际上PC的BIOS就是NorFlash),BIOS程序负责初始化DDR内存,负责初始化硬盘,然后从硬盘上将OS镜像读取到DDR中,然后跳转到DDR中去执行OS直到启动(OS启动后BIOS就无用了)。
总结:嵌入式系统和PC机的启动过程几乎没有两样,只是BIOS成了uboot,硬盘成了Flash。
从第一章节中我们简单介绍了Android系统的启动流程,Android系统的启动流程大致分为三个阶段:
1、电源键按下后加载引导程序Bootloader到RAM 然后Bootloader把OS拉起
2、Linux 内核层面的启动
3、Android系统层面的启动
这里的uboot就是刚开始被放到flash中,板子上电后,会自动把其中的一部分代码拷到内存中执行,这部分代码负责把剩余的uboot代码拷到内存中,然后uboot代码再把kernel部分代码也拷到内存中,并且启动,内核启动后,挂着根文件系统,执行应用程序。
2、uboot有什么特点
uboot 属于bootloader的一种,是用来引导启动内核的,它的最终目的就是,从flash中读出内核,放到内存中,启动内核。
1.自身可开机直接启动
1)一般的SoC都支持多种启动方式,譬如SD卡启动、NorFlash启动、NandFlash启动等•••••uboot要能够开机启动,必须根据具体的SoC的启动设计来设计uboot。
上图是安霸A12的boot支持的启动方式,有NOR FLASH,NAND FLASH,USB、EMMC等多种存储设备,但是要注意,这里启动的地址默认都是从第一个零地址开始,比如NAND FLASH就是BLOCK 0启动,如果这个block损坏那么就无法启动,如果要跳转到block 1,那么就需要CPU芯片内部支持存储代码进行判断,否则只能从默认block 0启动。
2)uboot必须进行和硬件相对应的代码级别的更改和移植,才能够保证可以从相应的启动介质启动。uboot中第一阶段的start.S文件中具体处理了这一块。
2.能够引导操作系统内核启动并给内核传参
1)uboot的终极目标就是启动内核。
2)linux内核在设计的时候,设计为可以被传参。也就是说我们可以在uboot中事先给linux内核准备一些启动参数放在内存中特定位置然后传给内核,内核启动后会到这个特定位置去取uboot传给他的参数,然后在内核中解析这些参数,这些参数将被用来指导linux内核的启动过程。
3.能提供系统部署功能
1)uboot必须能够被人借助而完成整个系统(包括uboot、kernel、rootfs等的镜像)在Flash上的烧录下载工作。
2)裸机教程中刷机(ARM裸机第三部分)就是利用uboot中的fastboot功能将各种镜像烧录到iNand中,然后从iNand启动。
4. 能进行soc级和板级硬件管理
1)uboot中实现了一部分硬件的控制能力(uboot中初始化了一部分硬件),因为uboot为了完成一些任务必须让这些硬件工作。譬如uboot要实现刷机必须能驱动iNand,譬如uboot要在刷机时LCD上显示进度条就必须能驱动LCD,譬如uboot能够通过串口提供操作界面就必须驱动串口。譬如uboot要实现网络功能就必须驱动网卡芯片。
2)SoC级(譬如串口)就是SoC内部外设,板级就是SoC外面开发板上面的硬件(譬如网卡、iNand)
5. uboot的"生命周期"
1)uboot的生命周期就是指:uboot什么时候开始运行,什么时候结束运行。
2)uboot本质上是一个裸机程序(不是操作系统),一旦uboot开始SoC就会单纯运行uboot(意思就是uboot运行的时候别的程序是不可能同时运行的),一旦uboot结束运行则无法再回到uboot(所以uboot启动了内核后uboot自己本身就死了,要想再次看到uboot界面只能重启系统。重启并不是复活了刚才的uboot,重启只是uboot的另一生)
3)uboot的入口和出口。uboot的入口就是开机自动启动,uboot的唯一出口就是启动内核。uboot还可以执行很多别的任务(譬如烧录系统),但是其他任务执行完后都可以回到uboot的命令行继续执行uboot命令,而启动内核命令一旦执行就回不来了。
总结:uboot的一切都是为了启动内核。
1)uboot主要作用是用来启动操作系统内核。体现在uboot最后一句代码就是启动内核。
2)uboot还要负责部署整个计算机系统。体现在uboot最后的传参。
3)uboot中还有操作Flash等板子上硬件的驱动。例如串口要打印,ping网络成功,擦除、烧写flash是否成功等。
4)uboot还得提供一个命令行界面供人来操作。很简单,至少你能看到。
3、Uboot完成后进入的模式有哪些。
安卓开机后,硬件系统上电,首先是完成一系列的初始化过程,如 CPU、串口、中断、timer、DDR 等硬件设备,然后接着加载 bootloader,为后面内核的加载作好准备。在一些系统启动必要的初始完成之后,系统会通过检测三个条件来判断要进入何种工作模式,流程如图。
这里重点说说Recovery模式,我们可以简单的理解为工程模式,手机进入Recovery模式可以进行重启手机、清空SD卡数据、恢复出厂设置、刷机、备份与恢复数据等诸多功能。
以前买到小米手机,手机无法正常开机进入不了系统了,此时就从百度上搜索怎么强制恢复出厂设置,方法是先关闭小米手机,然后同时按住“小米3音量+键”和“电源键”,大约3s左右,即可进入小米3Recovery模式了。
怎么加快uboot的启动时间
1、使用通讯速率快的存储,接口需要不占用
一些功能安全要求较高的汽车ECU应用,比如电子助力转向(EPS)、电子档位控制(gear control)等,对于ECU的启动时间(startup/boot time)有严格的要求, 希望ECU使用的MCU能够尽快完成系统启动初始化,执行功能程序。此外,一些整车的网络管理也要求ECU在低功耗模式唤醒后,能够尽快响应CAN/LIN总线报文,也要求MCU的启动时间要足够快。
在有双核的CPU的时候,可以在不同的内核执行不同的程序,这样可以缩短启动时间。
液晶仪表的开机速度要求比较快,一般要求在6S之内要进行开机进行工作,这样就可以更快的让用户处理相关的车身检测和报警功能。
其实这里比较简单粗暴的方便就是使用通信速度更快的存储,下图就是东芝产品介绍boot time的在使用普通NOR flash,EMMC、UFS的存储设备,可以看到UFS接口的EMMC在64MB的数据下,也就115ms可以运行完成,而SPI NOR FLASH需要1185ms,基本上差了10倍时间的差距。
这里唯一的不同就是存储设备的通讯速率不同,UFS的通讯速率可以达到850MB/S,而NOR FLASH最快也就是54MB/S。
在仪表赛普拉斯推荐的平台上,使用hyperflash,可以让开机时间在2S之内。
赛普拉斯主推的hyperflash,独占带宽无抢占的情况下,目标带宽为200MB/s,1280x480的标清屏的开机速度可以达到0.7S。目前创维汽车智能在使用这个平台供货仪表,做的非常棒。
2、优化一些时钟、ECC校验等方法加快启动速度(参考 浅谈嵌入式MCU软件开发之S32K1xx系列MCU的启动过程和启动时间优化方法详细 )
下图是S32KXX系列的MCU的启动流程图,首先是关闭CPU到的全局中断,把CPU的内核寄存器清零,初始化SRAM的ECC,然后进行系统的初始化等等。
比如在MCU的硬件加密模块CSEc的安全启动(Secure boot)功能,建议使用串行(Sequential) Secure boot而不是并行(Parallel) Secure boot, 因为后者工作时CSEc和CPU内核都会访问P-Flash,从而导致CPU内核从P-Flash取指令的速度变慢,从而拉长Startup运行时间,而且Secure boot运行完之前不允许修改系统时钟配置(尤其是Flash的工作时钟FLASH_CLK):
Freescale S12G系列汽车MCU的外部晶振时钟起振时间如下,作为参考,也是频率越高,启动越快(start-up时间越短)
BOOT升级的模式
正常情况下,下载了升级固件,肯定是要把新固件替换到老固件,这个时候就涉及到两种模式。
其实这个最容易理解了,机哥给你说一个生活中的例子就好理解了,你手里拿着一个冰淇淋,现在老板告诉你有新款的冰淇淋来了,可以免费领取一个,你会怎么做呢?
有的人是把手里的冰淇淋扔掉,直接去领取新的冰淇淋,这样的做法是不占用手的资料,反正都只占用一个手,缺点就是可能去排队的时候,老板新的冰淇淋都领取完了,这个时候你就一个冰淇淋都没有了。
有的人的做法是先排队,确认领用到新的冰淇淋后再把老的冰淇淋扔掉,此时在领用的过程中会耗费掉两个手的资源,不过这样最保险,哪怕没有领用到最新的冰淇淋,老的冰淇淋还可以继续吃。
同样的道理,新固件替换老固件覆盖的两种方式:双区模式和单区模式。
双区模式:
双区模式中老固件和新固件在flash中各占一块bank(存储区)。假设老固件放在bank0(运行区)中,新固件放在bank1(下载区)中,升级的时候,应用程序先把新固件下载到bank1中,只有当新固件下载完成并校验成功后,系统才会跳入BootLoader程序,然后擦除老固件所在的bank0区,并把bank1的新固件拷贝到bank0中。后台式下载必须采用双区模式进行升级。
优点:升级过程中出现问题或者新固件有问题,它还可以选择之前的老固件老系统继续执行而不受其影响。
缺点:多占用flash空间的一个存储区,在系统资源比较紧张的时候较为困难。
单区模式:
单区模式的非后台式下载只有一个bank0(运行区),老固件和新固件共享这一个bank0。升级的时候,进入bootloader程序后先擦除老固件,然后直接把新固件下载到同一个bank中,下载完成后校验新固件的有效性,新固件有效升级完成,否则要求重来。
优点:跟双区模式相比,单区模式节省了Flash空间的一个bank,在系统资源比较紧张的时候,单区模式是一个不错的选择。
缺点:如果升级过程中出现问题或者新固件有问题,单区模式碰到这种情况就只能一直待在bootloader中,然后等待再次升级尝试,此时设备的正常功能已无法使用,从用户使用这个角度来说,可以说此时设备已经“变砖”了。
相比较,双区模式虽然牺牲了很多存储空间,但是换来了更好的升级体验。
相关问答
flash烧录和ic烧录?,IC烧录设备该怎么选,都来说说?[回答]聪明人与朋友同行,步调总是齐一的,这个是我和弘月科技合作以来一直的习惯我咋没听说有这么玩过的,我们都是一个个来,要简单点也行,可以把命令写在...
Linux U-boot环境变量设置错了,怎么删除修改?在应用程序中按需要对文件进行修改后,再用dd烧回去。开机,结果出现CRC错误,好吧,原来u-boot为了保证环境变量的正确性,在环境变量的前四个字节储存了CRC效...