嵌入式学习——2.1 uboot基础

uboot基础

1.为什么要有uboot?

  • 预备知识
    • 计算机系统运行时的主要核心部件包含3个东西:CPU+外部存储器+内部存储器
    • PC机启动过程为:PC上电后先执行BIOS程序(实际上PC 的BIOS就是NorFlash),BIOS负责初始化DDR内存和硬盘,然后从硬盘上将OS镜像读取到DDR中,然后跳转到DDR中去执行OS直到启动(OS启动后BIOS就无用了)
  • uboot主要作用是用来启动操作系统内核,部署整个计算机系统,有操作Flash等板子上硬件的驱动,提供一个命令行界面供人操作
  • uboot程序部署在能作为启动设备的Flash做上,OS部署在Flash上,内存在掉电时无作用,CPU在掉电时不工作
  • 嵌入式系统上电后先执行uboot、然后uboot负责初始化DDR,初始化Flash,然后将OS从Flash中读取到DDR中,然后启动OS(OS启动后uboot就无用了)

2. uboot必须解决的问题

  • 自身可开机直接启动

    • 必须根据具体的SoC的启动方式来设计uboot

    • uboot必须进行和硬件相对应的代码级别的更改和移植,才能保证响应启动介质的启动,uboot中第一阶段的start.S文件中处理了这一块

  • 能够引导操作系统内核启动并给内核传参

    • 我们可以在uboot中事先给Linux内核准备一些启动参数放在内存中特定位置然后传给内核,内核启动后会到这个特定位置去取uboot传给他的参数,然后内核解析这些参数
  • 能提供系统部署功能

    • uboot必须能够被人借助而完成整个系统在Flash上的烧录下载工作(裸机在刷机时就是利用uboot中的fastboot功能将各种镜像烧录到iNand中,然后从iNand启动)
  • 能进行SoC级和板级硬件管理

    • uboot中实现了一部分硬件的控制能力,因为uboot为了完成一些任务必须让一些硬件工作。譬如uboot要在刷机时LCD上显示进度条就必须驱动LCD。
    • SoC级就是SoC内部外设,板级就是SoC外面开发板上面的硬件
  • uboot存在生命周期

    • uboot本质上是一个裸机程序,一旦uboot开始SoC就会单纯运行uboot,一旦uboot结束运行就无法再回到uboot
    • uboot入口为开机自动启动;出口为启动内核

3. uboot的工作方式

  • 从裸机程序镜像uboot.bin说起
    • uboot的本质就是一个裸机程序,和裸机教程中的裸机程序xx.bin没有本质区别,区别主要在于文件大小,uboot在180k-400k之间
    • uboot本身为一个开源项目,由若干个.c文件和.h文件组成,配置编译之后会生成一个uboot.bin,这就是uboot这个裸机的镜像文件。然后镜像文件被合理的烧录到启动介质中拿去给SoC启动,即uboot在没有运行时表现为uboot.bin
    • uboot运行时会被加载到内存中,然后逐次拿给CPU去运行
  • uboot的命令式shell界面
    • 有些程序需要人机交互,于是程序中就实现了一个shell
    • shell并不是操作系统,和操作系统一点关系都没有,裸机也可以有shell
  • uboot使用的关键点:命令和环境变量
    • uboot启动后大部分时间和工作都是在shell下完成的。uboot部署系统要在shell下输入命令、要设置环境变量也需要在命令行下,要启动内核也要在命令行下输入命令
    • uboot中有几十个命令,其中一些常用,还可以自己给uboot添加命令
    • uboot的环境变量和操作系统的环境变量工作原理和方式几乎完全相同,uboot的驱动管理完全照抄了linux的驱动框架。系统或者程序在运行时可以通过读取环境变量来指导程序的运行。环境变量就是运行时的配置属性。

4. uboot常用命令

  • 命令特点

    • 有些命令有简化的别名
      • printenv -> print
      • setenv -> set
    • 有些命令会带参数
      • 每个命令都有事先规定好的格式,可以通过help命令查看
    • 命令中的特殊符号(譬如单引号)
      • uboot有些命令带的参数非常长,为了告诉uboot这个非常长且中间有好多空格的语句为一整个参数,使用单引号将这个语句引起来
    • 有些命令是一个命令族(譬如movi)
      • 命令族的意思就是好多个命令开头都是用同一个命令关键字的,但是后面的参数不一样,这些命令的功能和作用也不同
      • 同一个命令族中所有的命令都有极大的关联,譬如movi开头的命令族都和moviNand(EMMC、iNand)操作有关。
  • 常见命令

    • 打印环境变量:printenv/print

      • 命令不用带参数,打印出系统中所有的环境变量。环境变量被存储在Flash的一块专门区域,一旦程序中保存了该环境变量,下次开机时该环境变量的值将维持上一次更改保存后的值
    • 设置(添加/更改)环境变量:setenv/set

      • set name value
    • 保存环境变量的更改:saveenv/save

      • 不带参数,直接执行。是对整体环境变量的保存
    • 网络测试指令:ping

      • 步骤
        • 用网线将电脑和开发板连接
        • 设置电脑本地连接IPV4地址为192.168.1.10
        • 确认开发板中uboot里几个与网络相关的环境变量的值对不对。最重要的是ipaddr的地址必须与主机的IP地址在同一个网段内。(set ipaddr 192.168.1.xx)
    • tftp下载命令:tftp

      • uboot主要目标是启动内核,为了完成启动内核必须要能够部署内核,而内核镜像需要从主机中下载烧录到开发板的Flash中,下载镜像的主流方式为fastboot和tftp。fastboot的方式是通过usb线进行数据传输;tftp是通过网络传输的

      • tftp方式下载时uboot扮演的是tftp客户端程序角色,主机中必须有一个tftp服务器,然后将要下载的镜像文件放在服务器的下载目录中,然后在开发板中使用uboot的tftp命令去下载

      • 虚拟机和开发板ping通的步骤

        • 虚拟机处选择桥接方式

        • 在虚拟网络编辑器中设置为桥接到有线网卡

        • 在虚拟机中设置IP静态地址为192.168.1.102(修改/etc/network/interfaces文件中的内容)

        • 重启网络

          • sudo ifconfig eth0 down
            
          • sudo ifconfig eth0 up
            
        • 在虚拟机上搭建tftp的下载目录/tftpboot,将要被下载的镜像复制到这个目录下

        • 检查开发板uboot的环境变量,注意serverip必须设置与虚拟机Ubuntu的ip静态地址相同

      • 在开发板uboot中使用tftp命令下载虚拟机中的镜像

        • tftp 0x30000000 zImage-qt
          
        • 意思为将服务器上名为zImage-qt的文件下载到开发板内存的0x30000000地址处

      • 镜像下载到开发板DDR中后,uboot就可以用movi指令进行镜像的烧写了

    • SD卡/iNand操作指令:movi

      • 开发板如果用SD卡/EMMC/iNand等作为Flash,则在uboot中操作Flash用指令movi

      • movi指令是一个命令集,在uboot中可通过help movi查看

      • movi 的指令都是movi read和movi write一组的,movi read用来读取iNand到DDR上,movi write用来将DDR中的内容写入iNand中

      • movi read {u-boot|kernel} {addr}
        

        上述命令为通用型描述方法:movi和read外面没有任何标记说明每一次使用这个指令都是必选的;一对大括号{ }括起来的部分必选1个,大括号中的|表示多选一,中括号[]表示可选参数(可以有,也可以没有)

        movi read u-boot 0x30000000
        

        上面的语句为:把iNand中的u-boot分区读出到DDR的0x30000000起始的位置处

    • NandFlash操作指令:nand

      • 操作方法完全类似于movi指令
    • 内存操作指令:mm、mw、md

      • DDR中是没有分区的,但是内存使用时千万不能越界,因为uboot是一个裸机程序,不像操作系统会由系统整体管理所有内存,则可能会出现程序的覆盖
      • md:memory display,显示内存中的内容
      • mw:memory write,将内容写到内存中
      • mm:memory modify,修改内存中的一块,会批量逐个修改
    • 启动内核指令:bootm、go

      • bootm启动内核同时给内核传参,而go命令启动内核不传参。
      • bootm是正宗的启动内核的命令,go命令本来不是专为启动内核设计的,go命令的实质是PC直接跳转到一个内存地址去运行而已。go命令可以用来在uboot中执行任何的裸机程序

5. uboot环境变量

  • 如何理解环境变量

    • 环境变量有2份,一份在Flash中,一份在DDR中。uboot开机时一次性从Flash中读取全部环境变量到DDR中作为环境变量的初始化值,然后使用过程中都是用DDR中这一份,用户可以通过saveenv指令将DDR中的环境变量重新写入Flash中去更新Flash中环境变量。下次开机时又会从Flash中再读一次
    • 环境变量在uboot中是用字符串表示的,注意不要错别字,出现保存错误环境变量后set xxx消除并保存
  • 自动运行命令设置:bootcmd

    • uboot在启动后会开机自动倒数bootdelay秒,如果没有打断则会自动启动内核
    • uboot中打印环境变量可以看到
      • bootcmd=movi read kernel 30008000
      • 上述语句意思为将iNand的kernel分区读取到DDR内存的0x30008000地址处,然后使用bootm启动命令从内存0x30008000处去启东内核
  • uboot给kernel传参:bootargs

    • Linux内核启动时可以接收uboot给他传递的启动参数,这些参数使uboot和内核约定好的形式、内容,为了内核在不重新编译的情况下可以用不同的方式启动
    • 在uboot的环境变量中设置bootargs,然后bootm命令启动内核时会自动将bootargs传给内核
    • bootargs=console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3
      • 意义解释:控制台使用串口2,波特率为115200
      • root=… 根文件系统在SD卡端口0设备(iNand)第2分区,根文件系统是可读可写的
      • init=… Linux的进程1(init进程)的路径
      • rootfstype=… 根文件系统的类型是ext3
    • 内核传参非常重要。在内核移植的时候,新手经常忘记给内核传参,或者给内核传递的参数不对,造成内核无法启动
  • 新建、更改、删除一个环境变量的方法

    • 新建和更改
      • set var value
    • 删除
      • set var
  • 修改完环境变量后一定要保存

6. uboot对Flash和DDR的管理

  • uboot阶段的Flash分区
    • 所谓分区,就是对Flash进行分块管理
    • PC机等产品,都是在操作系统下使用硬盘的,整个硬盘由操作系统统一管理,使用者不用自己太在意分区问题
    • 在uboot中没有操作系统,对Flash的管理必须事先使用分区界定,在部署系统时按照分区界定方法来部署,uboot和kernel的软件中也是按照这个分区界定来工作就不会出错
    • 分区不是固定的,在一个移植中必须事先设计好定死。一般在设计系统移植时就会定好,定的标准是:uboot必须从Flash起始地址开始存放,uboot分区大小必须保证uboot肯定能放下,一般设计为512kb或者1MB;环境变量分区一般紧贴着uboot来存放,大小为32KB或多一点;kernel可以紧贴环境变量存放,大小一般为3MB或5MB或其他;rootfs紧贴着kernel;剩下的就是自动分区,一般kernel启动后将自由分区挂载到rootfs下使用
    • 总结
      • 各分区彼此相连
      • 整个Flash充分利用,从开头到结尾
      • uboot必须在Flash开头,其他分区相对位置可变
      • 各分区的大小由系统移植工程师来定
      • 分区在系统移植前确定好,在uboot中和kernel中使用同一个分区表
  • uboot阶段DDR的分区
    • 因为Flash是掉电存在的,而DDR是掉电消失,因此可以说DDR是每次系统运行时才开始部署使用的
    • 内存的分区主要是在Linux内核启动之前,Linux内核启动后内核的内存管理模块会接管整个内存空间
    • 内存分区关键就在于内存中哪一块用来干什么必须分配好,以避免各个不同功能使用了同一块内存造成覆盖。

你可能感兴趣的:(uboot)