Bootstrap

嵌入式系统那些事-一张图秒懂系统启动流程

0 背景

        引导篇中,笔者介绍了嵌入式系统的架构,本文将端到端的梳理一下嵌入式系统的启动流程,通过对该流程的梳理,可以全面了解嵌入式系统各层的初始化过程。另外在笔者的嵌入式通信设备开发经验中,新开发一块板子或者产品,有两个重要的软件里程碑:一个是板子能够正常启动,另外一个就是能够通流(即业务是正常);只要完成了上面两个基础功能,基本上工作任务也就完成了80%,剩下的就是不断优化的过程了。最后在笔者工作中也有30%以上的问题是跟启动过程有关的,如启动性能、单板起不来、断链、异常复位等等,快速定位问题首要的是清楚启动流程。基于以上三点原因,笔者通过一张图的方式描述嵌入式通信系统的启动流程,尽可能具有普适性,但是读者仍需结合自己的产品去梳理一张类似的图,然后将实践问题不断丰富到这样图上,顺着这张图建立一棵完整的知识树。

1 一张图秒懂启动流程

        如下图所示是笔者梳理的启动流程图,图中红色的数字圆点表示启动的先后顺序。主要分为4个阶段,分别是第一阶段bootloader阶段,第二阶段uboot阶段,第三阶段内核启动阶段,第四阶段app启动阶段。

 各个阶段的功能、图中对应关系、存储位置和运行位置等信息描述如下:

  • bootloader阶段:主要完成第一阶段系统的引导和初始化工作,包括序号1~3。系统上电后,首先是cpu开始工作,此时引导程序(通常是汇编代码)从ROM被加载到RAM 中,对cpu的寄存器初始化,启动核0,如果是核1或者其他核则处于休眠状态,等待核0在内核启动正常后通过中断或者事件将其唤醒(图中10的位置)。接下来就是完成flash和ddr初始化,为后面从flash加载bin文件,在DDR中运行程序提供基本环境,一般情况下都是从flash为0的位置,将flash中的bootloader镜像文件加载到RAM或DDR中,该引导程序最终将uboot从flash复制到DDR中,然后交接给uboot进行下一步处理。
  • uboot阶段:首先对dram,flash,串口进行检查,保障uboot的运行环境是ok的,同时为linux分配内存空间;接下来初始化网络配置,包括mac地址的设置、通信端口的工作模式设置,可以让用户通过网络加载程序;最后将linux从flash中复制到内存中,linux镜像文件中包含内核、文件系统和设备管理树(FDT)三个基本组件,uboot会根据设备管理树定义的信息进行检查,然后依次加载到内存中 。包括序号4~5,这个阶段最后将linux加载后,就可以交接给内核进行操作。
  • 内核启动阶段:主要负责创建进程、绑定进程、划分内存、唤醒核1、加载文件系统等基本工作,包括序号6~13。首先会生成一个初始init0进程,后续创建的所有进程都是从该进程中产生,该进程还负责对内存和虚拟内存进行划分,然后vfork出一个主核进程,绑定到核0上,接下来由cpu主核(核0)唤醒其他的核,从init进程vfork出副核进程,并将该进程绑定到核1上,最后是基于设备管理树完成对系统中其他设备的初始化。
  • app启动阶段:这一阶段主要对各类app应用进行初始化,如文中以通信设备为例,此处主要完成对转发芯片的初始化,会涉及一些基础转发表项的初始配置,端口和各种通信总线的初始化。接下来会初始化中间件,中间件是作为应用程序和操作系统之间的桥梁,向下屏蔽操作系统的差异,向上为应用程序提供平台化的技术支持;最后就是各种应用程序的初始化了,包括各种特性的初始化,心跳信息,单板信息,版本信息等等。日常工作中,最容易出问题的地方其实都是在app的启动阶段,这部分才是最应该做一个详尽的图出来,后续笔者有了具体的项目案例后将会补充该图例。

2 小结

        本文通过一张图的方式将系统启动的整个流程串了一下,其实每个阶段都有非常复杂的启动流程,不过笔者化繁就简,只针对关键的节点做了简述,目的是启发读者自己去根据手头的产品做一个类似的图出来,在日常的问题定位中可以按图索骥,看启动到哪个阶段了,再根据具体的阶段做详细的分析。

;