PC机的启动流程:上电——>BIOS——>引导操作系统——>识别盘符(C、D盘)——>运行应用程序。同样在嵌入式系统中,启动流程也是类似的:上电——>bootloader——>运行内核——>挂载根文件系统——>运行运用程序。PC机上引导的操作系统是Windows,而嵌入式中基本上是Linux内核、VxWorks、ucOS、wince等。

BootLoader最终的目的:引导内核。嵌入式中内核基本上是存放在flash中的,所以要运行内核就需要从flash中读取内核,然后放到SDRAM中运行。这样BootLoader最基本的能力需要能读取flash、写SDRAM以及执行内核。BootLoader流程:

  • 硬件相关的初始化:

  1. 设置模式(进入SVC)
  2. 初始化时钟(芯片刚上电的时候时钟都很低)
  3. 关闭中断(记住终极目的是引导内核、引导内核、引导内核。用不上的东西都需要关闭,别影响内核的引导)。
  4. 关闭看门狗(有些芯片看门狗默认是开启的,不喂狗隔一段时间芯片就会重启。而此时的任务是引导内核,重启要不得。)
  5. 初始化SDRAM,初始化flash(让flash可以读取数据)。
  6. 初始化串口(方便观察打印信息)、初始化网卡、USB等方便调试(可以通过USB来烧写内核、文件系统之类的)
  7. 设置栈(C运行必备的)
  • 加载内核到SDRAM
  • 运行内核

多阶段BootLoader的原因?

BootLoader终极目的是引导内核,加载内核到内存中然后再执行。具备更复杂的功能以及更好的可移植性的多阶段BootLoader。存在两个阶段:第一个阶段使用汇编来实现,它完成一些依赖于CPU体系结构的初始化,并调用第二阶段的代码(硬件设备串口、时钟、看门狗、中断、RAM等的初始化、进入管理模式、复制BootLoader的第二段代码到RAM空间中、设置栈、清除BSS段{主要初始化值为0的全局变量和静态变量,不放入程序中占用额外的内存}、运行第二阶段的代码start_armboot);第二阶段则是使用C语言来实现,目的是可以实现更为复杂的功能以及提高可读性、移植性(本阶段使用到的硬件设备如网卡、nand、USB等硬件设备的初始化、检测系统内存映射以确定内存大小以及地址空间、将内核映像和根文件系统映像从flash中读到RAM中间中、为内核设置启动参数、执行内核)。

对于第二阶段中的读取flash上的镜像放到内存空间上,从什么地址读取,放到内核的什么地方,以及如何调用内核、内核执行需要满足什么条件?

由于内核镜像是烧写在flash中的固定位置,所以读取的时候也是从烧写进去的位置开始读取。通常的做法是给flash划分分区,存在在分区中,然后再从分区中读取出来。而要放入的地址,如果镜像是uImage原则上是除了不破坏u-boot的内存分布是可以随意放置的。因为uImage包含64字节的头部和Image,头部信息中会存有内核的加载地址以及入口地址(加载地址是:把Image放到内存中的地址,而入口地址是内核的执行起始地址。这两个地址都是在编译内核的时候确定的),如果u-boot发现了内核放在内存中的地址和uImage头部中的加载地址不一致的话,就会把Image移动到加载地址的地方。最后再调用Image的执行地址执行内核。要是镜像是Image,也可以加载到不破坏u-boot内存分布的内存中,然后在执行加载地址处的程序。

内核执行要满足的条件:由于BootLoader加载内核后,就进入了内核程序,BootLoader里面的程序再也看不到了所有需要把内核需要的参数(比如根文件系统存放在什么地方,是什么格式的以及内核起来后执行的第一个程序)传递给内核。通常的方法是在内存中指定一块空间,然后按照一定的格式把参数保存在里面,最后把参数的地址告诉内核。内核运行时需要访问些硬件资源,需要进入特权模式(SVC)。内核支持众多的CPU以及ARCH,所以还需要把机器ID告诉内核。最后还需要把第一个传给内核的参数设置为0。

这里分析下第二个阶段的流程。第二阶段是从start_armboot()开始,里面主要是初始化flash,和各种初始化(CPU、board、中断、环境变量等)———>然后调用main_loop(此函数里面主要执行getenv()获取环境变量,在调用run_command()执行相应的函数。在获取bootcmd环境变量后,里面有内核程序的执行地址)。———>最后执行getenv(bootcmd),然后调用run_conmand()执行获取到的bootcmd环境变量值,执行do_bootm()函数里面的在这个函数里面有把从uImage头部中解析出来的内核入口地址转化为函数指针,调用一些列的宏把bootargs里面的参数保存在内存中,最后调用函数指针执行内核(由于BootLoader是单机,执行这个之后再也不会回来了,所以需要把内核启动时的一些参数传递给内核。参数R0:0,R1:设置为机器码,R2:设置为BootLoader给内核传递参数的内存地址)。

u-boot中执行指令时,是根据name来匹配找到相应的函数,所有的指令都是通过下面的封装来实现的。

这个 U_BOOT_CMD的宏定义了一个cmd_tbl_t带有属性的变量,里面存放有指令的名字,指令的最大参数个数以及是否可以重复执行、还有处理函数以及帮助信息等。

在开发时,通常需要使用各种命令操作BootLoader,一般是通过串口连接PC和开发板。可以在串口上输入各种命令以及观察运行结果等。这个对开发人员有帮助。而平常客户使用时压根不需要操作BootLoader。所以从这个观点来看,bootloader分为以下两种模式:启动加载模式(客户使用)和下载模式(开发人员使用)。下载模式中主要有串口协议xmodem/ymodem/zmodem、网络协议TFTP以及nsf。

BootLoader中常用的有u-boot、vivi、redboot等。u-boot源码获取:http://sourceforge.net/projects/U-Boot。

u-boot(universal boot loader)中代码的结构主要有:

平台相关:cpu/  lib_arm/ 里面存放这各种架构的CPU代码以及lib库。

开发板相关:board/ 里面存放着各种板级相关的代码。

通用函数:include、lib_generic、common。include中存放头文件以及开发板的配置文件。开发板的配置文件都存放在include/configs中。需要手动修改配置文件中的宏定义。

其它通用部分:disk(硬盘接口程序)、drivers(各类具体设备的驱动程序)、dtt(数字温度测量器驱动)、fs(文件系统)、net(各种网络协议)、post(上电自检程序)、RTC(实时时钟驱动)、nand_spl(nand启动)

工具、示例、文档:tools(mkimage制作镜像的工具)、doc(文档)、example(示例程序)。

u-boot操作流程:

在u-boot1.1.6版本中,需要先配置u-boot,使用make xxx_config进行配置,配置好了再make进行编译。配置的时候执行Makefile文件中的:,$0 -$6 分别是配置目标名、arm arm920t smdk2400 null s3c24x0。这个文件的主要目的是根据传进来的参数在include文件夹中建立asm、asm-$2/arch、asm-$2/proc连接,以及生成config.mk(里面存在着ARCH(arm) CPU(arm920t) BOARD(smdk2400) VENDOR(null) SOC(s3c24x0)等)和config.h文件。

编译时会使用配置生成的文件来选择CROSS_COMPILE,然后把相关的库文件都加入到LIBS中,链接标志为,链接脚本为(顶级config.mk中的指定)u-boot.lds。链接地址为:是在相关的板子里面的config.mk中定义的。

u-boot1.1.6中没有类似内核的图形化界面配置,所以配置u-boot的时候是通过make <board_name>_config命令来配置的,<board_name>是在目录board/中定义的,里面存放有编译链接脚本以及链接时正文段的地址(保存在config.mk中)。然后在执行make 或者是make all来编译生成u-boot.bin、u-boot等文件,在编译成功后会在tools目录中生成一些工具如(mkimage,编译内核是可以使用上,用mkimage来生成u-boot格式的内核镜像文件uImage)。

配置u-boot的时候首先调会用顶层目录下的mkconfig文件,mkconfig的作用是:①:确定开发板名称BOARD_NAME②:创建到平台/开发板相关的头文件的链接。③:创建include/config.mk文件,这个文件里面主要包含开发板所使用的ARCH CPU BOARD SOCmake编译的时候会根据这个来确定编译链以及库文件等。④创建开发板的头文件include/config.h,里面的内容是#include<configs/$1.h>,这里选择编译开发板的配置文件。里面存放开发板的一些配置如CONFG_前缀是选择项,即是否使用,还有CFG_的前缀是参数的设置,编译的时候几乎所有的文件都会被编译和链接,但是文件是否包含有效的代码则有这些宏开关来设置。

配置完成后,执行make all进行编译。此过程如下:首先把配置生成的include/config.mk文件包含进来(即使用的ARCH CPU BOARD SOC)——>再包含顶层目录中的config.mk文件,此文件会根据配置生成的config.mk文件的值确定编译器、编译选项以及BOARDDIR等。

BootLoader基础详解相关推荐

  1. 主线剧情03-NXP-i.MX系列的u-boot移植基础详解

    u-boot 移植基础详解 本文系广泛撷取.借鉴和整理(相关的内容在网络上有很多,但很多相互抄,或者是版本太老,或者就是不通用的非常有平台针对性的步骤,碎片化泛滥,甚至就是有待分拣的垃圾厂,当然也有一 ...

  2. c 语言中 %是什么运算符,C 语言基础----详解C中的运算符

    C语言中又有哪些运算符呢? 如下所示: ※ 算术运算符 ※ 赋值运算符 ※ 关系运算符 ※ 逻辑运算符 ※ 三目运算符 C语言基本算术运算符如下表: 除法运算中注意: 如果相除的两个数都是整数的话,则 ...

  3. Python学习二:词典基础详解

    作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/7862377.html 邮箱:moyi@moyib ...

  4. 【云原生之k8s】k8s基础详解

    [云原生之k8s]k8s基础详解 前言 一.kubernetes介绍 (1)kubernetes简介 (2)应用部署方式的演变 二.kubernetes组件 (1)kubernetes架构 (2)ma ...

  5. 微信小程序详解 php,微信小程序canvas基础详解

    canvas 元素用于在网页上绘制图形.HTML5 的 canvas 元素使用 JavaScript 在网页上绘制2D图像.本文主要和大家分享微信小程序canvas基础详解,希望能帮助到大家. 一.了 ...

  6. 线程状态,优先级,守护线程基础详解

    线程状态,优先级,守护线程基础详解 线程状态 停止线程 线程休眠 线程礼让 线程强制执行 线程状态检测 线程的优先级 守护线程 线程同步 线程状态 创建状态(new 之后就是创建状态 就绪状态(调用s ...

  7. 03 html基础详解

    02html基础详解 文章目录 02html基础详解 1.HTML编辑器 2.标签 html常用标签 3.元素 4.属性 常用属性 5.标题 水平线 注释 6.段落 折行 7.格式化标签 属性dir ...

  8. 视频教程-FPS游戏逆向与安全+UE4引擎基础详解-其他

    FPS游戏逆向与安全+UE4引擎基础详解 想把自己的知识传播出去,让更多人学习到 苏瑞兵 ¥188.00 立即订阅 扫码下载「CSDN程序员学院APP」,1000+技术好课免费看 APP订阅课程,领取 ...

  9. linux网络服务详解,Linux网络服务器配置基础详解 (3)

    Linux网络服务器配置基础详解 (3) Linux网络服务器配置基础详解 (3) 第三步:编辑"inetd.conf"文件(vi /etc/inetd.conf),禁止所有不需要 ...

最新文章

  1. 微信小程序把繁琐的判断用Js简单的解决
  2. Silverlight 2 Beta 1, IE 8 Beta 1, ASP.NET MVC 预览版2 可以下载了 - 思归呓语 - 博客堂
  3. COM中的IDL语言的难点之接口指针
  4. 问题和任务包003.使用报告.数据可视化.PowerBI.微软的新武器
  5. jvm性能调优实战 - 39一次大促导致的内存泄漏和Full GC优化
  6. sql like 多条件
  7. Linux ln指令
  8. 使用批处理查看.class文件内容--javap指令
  9. pythonplc曲线_PLC的编程策略:面向对象编程和梯形图逻辑之比较
  10. mysql group set,Mysql--group_concat()、group by、find_in_set()使用笔记
  11. html 空行_一篇文章学习html「经典案例」
  12. C# 在PowerPoint中给图片添加超链接和获取图片的超链接
  13. 同程容器云平台网络方案演进
  14. IT大学生成长周报 | 第 8 期
  15. 酸性溶液中HER动力学分析
  16. Micheal Nielsen's神经网络学习之二
  17. 淘管家一键铺货怎么弄?和分销下单有什么区别?
  18. 如何理解工程测量中的各种误差
  19. linux C -- ftok函数
  20. JavaScript高级编程设计(第三版)——第四章:变量作用域和内存问题

热门文章

  1. 用NI的数据采集卡实现简单电子测试之6——数字I/O及测试平台
  2. 数据库系列之SequoiaDB高可用集群部署(二)
  3. html字体兼容ie8,IE8 CSS 样式兼容性清单
  4. Meshgrid函数的基本用法
  5. layui表单验证不生效
  6. android动态主题下载,安卓动态壁纸(com.androidesk.livewallpaper) - 4.2.3 - 应用 - 酷安
  7. 我与机器斗争过但失败了:与深蓝“人机大战”20年,卡斯帕罗夫TED演讲
  8. 斥资16亿,湖北襄阳华侨城奇幻度假区“奇妙镇”正式迎客
  9. python 数据可视化- 地图
  10. 【Kevin Learn 小程序】--> dialog