Uboot启动流程分析(转载)
最近一段时间一直在做uboot移植相关的工作,需要将uboot-2016-7移植到单位设计的ARMv7的处理器上。正好元旦放假三天闲来无事,有段完整的时间来整理下最近的工作成果。之前在学习uboot时,在网上看了很多文章,很多都是基于老版本的的uboot,并且很多都是直接从代码开始分析,并没有将uboot与ARM处理器体系结构结合起来。毕竟很多时候做一件事情,你知道怎么去做这件事和你知道这件事为什么要这么去做两个不同的概念。即英文中常说的:how do?和 why do?
将2016年7月发布的新版本uboot移植到单位的板子上并进行了调试,在此也将我的学习成果分享给大家。文中有很多地方加入了我自己的理解,可能不太准确,希望大家提出修改意见。
开始深入了解处理器启动流程前,请准备好两个工具:
1.uboot-2016-7源码包
(开源的随便下载 官方下载地址:ftp://ftp.denx.de/pub/u-boot/ 下载u-boot-2016.07.tar.bz2)
2.代码阅读软件source insight
(推荐! 可以想象uboot源码包有10000多个文件,每个文件都有几百行甚至上千行代码。没有专业的代码阅读器如何查找函数原型。 当然不是全都需要看的! 根据自己的需要去查看)
同时下载好这几个技术文档
(笔者在学习uboot时阅读的几个文档 可以根据需求去查找阅读 完全没必要重头读到尾)
1.arm公司官方提供的ARMv7-A体系结构文档
《ARM® Architecture Reference Manual ARM®v7-A and ARM®v7-R 》
( 官方 品质保证! 如果觉得英文看着费劲 可以去看 杜春雷 《ARM体系结构与编程》 )
2.《Uboot中start.S源码的指令级的详尽解析_v1.6.pdf》(好吧 中文滴)
(对理解gnu arm汇编极其有帮助)
3.《ARM指令集快速查询手册.pdf》(中文滴)
(工具手册,快速查找各种arm指令用法)
4.《ARM指令详解[ARM标准].pdf》(还是中文滴)
(arm汇编的一些规范和常用形式,很多例子非常有用:子程序调用、散转、数据块复制等。对写裸机程序很有帮助,同样对理解uboot和内核启动代码有很大帮助)
5.《程序员的自我修养—链接、装载与库.pdf》(全是中文滴)
(里面会介绍ELF文件 程序链接的过程 最重要的部分就是帮助理解uboot的核心重定位!这个真的很重要!!)
好了,现在进入正题。
什么是uboot?
在嵌入式操作系统中,Boot Loader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。在嵌入式系统中,通常并没有像BIOS那样的固件程序(注,有的嵌入式CPU也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由Boot Loader来完成。 uboot就是bootloader的一种,全称Universal Boot Loader。
目标:用uboot来启动单位设计的ARMv7的处理器。
问题:如何启动? 启动流程是什么?
首先,我先来描述一下需要移植uboot的这块板子上使用到的存储器(处理器架构可以暂时先不考虑,后面我会根据arm公司官方提供的ARMv7-A体系结构文档去分析uboot初始化处理器的汇编代码。无论是arm9 arm11 armv7 armv8都是相同的套路,首先需要根据存储器资源,去定制自己的启动流程)。在我手上的这块板子上使用存储器资源:Norflash(16MB) SRAM(512KB) SDRAM(512MB)。
看到这里应该想到两个问题:
1. Norflash SRAM SDRAM 作为存储器它们之间有何异同?
2. 如何通过它们去启动arm处理器?(重要的事情说三遍:先一定要理解启动流程 然后再去看uboot源码 要不然看了也无法理解 嵌入式的代码都是与硬件息息相关 了解硬件结构再去读代码 事半功倍)
下面我将对以上问题依次做出解析:
一. Norflash SRAM SDRAM 异同
norflash:norfalsh是非易失存储器(失去电源供电后norflash里存储的数据依然存在),NOR flash带有SRAM接口,有足够的地址引脚来寻址,可以很容易地读取其内部的每一个字节(注意是读取!对于flash不是随意可以写入,一般写入NOR flash流程是:解保护->擦除->写入数据。由于flash特性只能从1翻转到0,无法从0翻转到1。擦除过程就是将flash中的某一个扇区全写0xFFFFFFF,再写入数据),代码指令可以直接在norflash上运行。(重要! 上电后可以读取norfalsh中的数据 写操作无法直接进行 前面我已经说得很清楚了)
SRAM:静态随机访问存储器(Static Random Access Memory)它是一种类型的半导体存储器。“静态”是指只要不掉电,存储在SRAM中的数据就不会丢失。这一点与动态RAM(DRAM)不同,DRAM需要进行周期性的刷新操作。然后,我们不应将SRAM与只读存储器(ROM)和Flash Memory相混淆,因为SRAM是一种易失性存储器,它只有在电源保持连续供应的情况下才能够保持数据。“随机访问”是指存储器的内容可以以任何顺序访问,而不管前一次访问的是哪一个位置。 (重要!上电后就可以读写SRAM中的数据,无需初始化操作)
SDRAM:同步动态随机存取存储器(Synchronous Dynamic Random Access Memory)需要不断的刷新,才能保存数据。而且是行列地址复用的,许多都有页模式。(重要! 需要对ddr控制器进行初始化<配置寄存器>,才能去读写SDRAM中的数据)
最后用表格来归纳总结下:
存储器 | 上电后存储器访问状态 | 掉电后存储器中数据状态 |
NORFLASH | 可以读取数据,无法直接写人 | 数据存在 |
SRAM | 可以直接读取写入数据 | 数据不存在 |
SDRAM | 上电后没有初始化DDR控制器 无法进行数据读写 |
数据不存在 |
前面介绍了Norflash SRAM SDRAM存储特性,下面就来聊聊他们各自的功能和完成的任务(重要!!Norflash SRAM SDRAM在arm处理器启动阶段完成的任务,都是根据他们各自的存储特性来的。如果对于我前面介绍的Norflash SRAM SDRAM存储特性还不太理解的同学可以自行百度再深入理解。)
Norflash特性:掉电非易失(失去电源供电后norflash里存储的数据依然存在),可以直接<读取>数据,无法直接<写入>数据。
Norflash作为arm处理器程序存储器。可以试想一下,如果程序存储器掉电以后里面的数据没有了。那么你的电脑如何自启动,难道每次开机前都要重新烧写一次代码。在此处可以思考一个问题,在上电后norflash可以看作一个可以随机读取的只读存储器。但是我们运行的程序,一般情况下.text段(代码段)是只读(ok),.rodata(只读数据段)是只读(也ok)。那么问题来了,对于.data段(数据段)和.bss段(未初始化的全局变量和静态变量)在程序运行的过程中变量的值是需要改变的(改变一个变量的值在底层硬件完成操作<在相应的地址(变量在物理地址上存储地址)上写入数据>),很可惜Norflash只能直接读取无法直接进行写操作。(重要! 怎么解决这个问题? 这时就需要SRAM 因为SRAM上电后就可以直接去读写,下面我就解释下SRAM的功能和作用)
SRAM特性:掉电易失(失去电源供电后SRAM里存储的数据不存在了),可以随意<读写>数据。(重要!容量小:512KB 程序运行速度快 价格贵!)。
在实际运行时,SRAM可以作为c语言运行时的堆栈空间。把arm处理器的sp(堆栈指针寄存器)设置在sram中,为c语言运行提供环境。关于全局变量的问题,我单独提一下,uboot在重定位前(将uboot镜像从flash搬运到ddr中继续运行前),无论是汇编还是c程序中没有定义全局变量。只是定义了一个结构体指针gd_t *gd_ptr用于存储uboot镜像的长度,重定位地址等信息,将gd_ptr的地址存储在r9中,r9中存储的地址值为sram顶端减去一个sizeof(gd_t )。(存储在sram里就可以随意读写了嘛 后面分析uboot代码时我会详细讲解)
SDRAM特性:掉电易失(失去电源供电后SDRAM里存储的数据不存在了),上电后没有初始化DDR控制器,无法进行数据读写。(重要!容量大:512MB 程序运行速度快 价格自己猜一下<必须价格便宜>)
既然需要使用大容量的SDRAM,必须配置ddr时钟和ddr控制器的寄存器。这一步在哪完成呢?(思考一下)
没错就是在norflash和SRAM搭建的程序运行环境中完成。完成什么呢?
1.完成对处理器时钟的初始化
2. DDR的初始化
3.给gd_t *gd_ptr赋值 (用于存储uboot镜像的长度,重定位地址,重定位偏移量等信息)
在uboot搬运到DDR中运行前进行最小系统的初始化,之后就将uboot搬运到ddr中进行运行。
(重要!此时Norfalsh和SRAM的任务就完成了(这俩就没用了),现在uboot就在ddr中运行了)
二. arm处理器启动流程分析
前面讲解了各个存储器在处理器启动阶段的作用,下面就归纳总结一下启动过程。
有时候描述说不清楚,直接上图。下图为手上这块ARM处理器的存储器地址空间(包括各存储器在arm处理器上的地址空间 以及容量大小)
那么启动流程可以总结为:
step1.uboot镜像(也就是bin文件 重要!不是elf文件 bin文件 和 elf文件异同 自行百度)存储在norflash中,上电后ARM默认从地址0x00000000处取出第一条指令。当运行C程时,形参和局部变量需要入栈,栈顶设置SRAM的顶端,为C程序提供运行环境。完成对gd_t *gd_ptr赋值(存储uboot镜像的长度,重定位地址等信息)。
step2.在第一阶段会完成arm处理器的时钟和DDR的配置以及对gd_t *gd_ptr赋值(用于存储uboot镜像的长度,重定位地址等信息)。此时SDRAM就可以正常进行数据读写。将uboot镜像复制到SDRAM中(重定位地址由gd_t *gd_ptr提供),根据重定位偏移量得到新的PC指针值,在DDR中继续运行uboot。
这里我想多提一下,uboot在ddr中运行后的地址跟其链接地址不一致(原来norflash中text_base = 0x0 在ddr中运行后text_base = 0x70453670 ),编译器会在链接时确定了其中变量以及函数的绝对地址,链接地址 加载地址 运行地址应该一致的(只是写裸机程序时大多数情况下)。
(1)如何对函数进行寻址调用(执行函数的过程就是跳转到某个地址上去执行一段代码)
(2)如何对全局变量进行寻址操作(全局变量的地址变了如何找到进行读写)
(3)对于全局指针变量中存储的其他变量或函数地址在重定位到DDR中之后如何操作?
问题先放在这 后面我会专门写一篇博客 将一个可执行程序静态链接过程 动态链接过程 与uboot重定位过程放在一起比较 感兴趣的可以直接去阅读这篇博客。
step3.在DDR中继续运行的uboot完成对ARM处理器各外围硬件的初始化,如SPI、I2C、网卡等。最终uboot进入main_loop,阻塞等待串口终端输入命令或者去启动内核。始终要清楚一点uboot的主要作用是通过 Flash和Sram初始化时钟和DDR(arm最小系统),最终uboot是需要在ddr中运行进行裸机调试或者去引导操作系统内核启动。
(如何编写uboot命令进行裸机调试 以及uboot如何引导操作系统 后面我会依次介绍)
最后上还是上图<启动流程图>:
上电后arm默认从地址0x00000000处取出第一条指令。SP指向SRAM的顶端,当运行C程序时,形参和局部变量需要入栈,SP依次减4入栈。在这部分运行的程序完成对时钟和ddr的配置(arm最小系统)以及对gd_t *gd_ptr赋值(用于存储uboot镜像的长度,重定位地址,重定位偏移量等信息)。此时ddr已经可以成功进行数据读写,将uboot镜像从flash复制到DDR,根据重定位偏移量获得新的PC位置 继续运行uboot。
step3
uboot已经在ddr中运行了,也就不存在任何硬件上限制了。step3完成对ARM处理器各外围硬件的初始化,如SPI、I2C、网卡等。最终uboot进入main_loop,阻塞等待串口终端输入命令或者去启动内核。
以上就是arm处理器的启动流程,是否弄明白了呢?
下一篇我就以三星出品的S3C2410以及S5PV210为例子,讲解一下他们从nandflash启动。至于现在手机和平板电脑上广泛运用的eMCC(内部就是nandflash 只不过是改变一下读写接口)也是一样的套路(请记住万事不离其宗 以不变应万变)。
参考自:https://blog.csdn.net/kernel_yx/article/details/53045424
Uboot启动流程分析(转载)的更多相关文章
- u-boot启动流程分析(2)_板级(board)部分
转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global dat ...
- imx6 uboot启动流程分析
参考http://blog.csdn.net/skyflying2012/article/details/25804209 这里以imx6平台为例,分析uboot启动流程对于任何程序,入口函数是在链接 ...
- Uboot启动流程分析(三)
1.前言 在前面的文章Uboot启动流程分析(二)中,链接如下: https://www.cnblogs.com/Cqlismy/p/12002764.html 已经对_main函数的整个大体调用流程 ...
- Uboot启动流程分析(二)
1.前言 在前面的文章Uboot启动流程分析(一)中,链接如下: https://www.cnblogs.com/Cqlismy/p/12000889.html 已经简单地分析了low_level_i ...
- Uboot启动流程分析(一)
1.前言 Linux系统的启动需要一个bootloader程序,该bootloader程序会先初始化DDR等外设,然后将Linux内核从flash中拷贝到DDR中,最后启动Linux内核,uboot的 ...
- 嵌入式Linux驱动学习之路(五)u-boot启动流程分析
这里说的u-boot启动流程,值得是从上电开机执行u-boot,到u-boot,到u-boot加载操作系统的过程.这一过程可以分为两个过程,各个阶段的功能如下. 第一阶段的功能: 硬件设备初始化. 加 ...
- u-boot启动流程分析(1)_平台相关部分
转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的“board—>machine—>arch—> ...
- am335x uboot启动流程分析
基本指令含义 .globl _start .globl指示告诉汇编器,_start这个符号要被链接器用到,所以要在目标文件的符号表中标记它是一个全局符号 b,bl b是不带返回的跳转 bl带返回的跳 ...
- U-BOOT启动流程分析--start.s(二)
一.概述 u-boot的启动流程: 从文件层面上看主要流程是在两个文件中:cpu/arm920t/start.s,lib_arm/board.c, 先来分析start.s 在flash中执行的引 ...
随机推荐
- DAY1 计算机组成和操作系统
一.编程与编程目的 1.编程语言的定义 编程语言是人与计算机之间沟通的介质 2.什么是编程 编程就是程序员通过编程语言让计算机实现所想做的事 3.编程的目的 解放人力,让计算机按照人的逻辑思维进行工作 ...
- Python全栈开发-Day8-Socket网络编程
本节内容 断言 Socket构建框架 ftp构建框架 Socket粘包 Socket介绍 Socket参数介绍 基本Socket实例 通过Socket实现简单SSH SocketServer 支持多用 ...
- 记录python接口自动化测试--简单总结一下学习过程(第十目)
至此,从excel文件中循环读取接口到把测试结果写进excel,一个简易的接口自动化测试框架就完成了.大概花了1周的时间,利用下班和周末的时间来理顺思路.编写调试代码,当然现在也还有很多不足,例如没有 ...
- 昂达 v891 v1 终于 删除 windows 分区 并且恢复了容量。
参考了很多文章(最后列出重要的),却始终失败. 途中因为乱改分区表,竟然fastboot 都进不去了,当时真是欲哭无泪. 总结关键点: 1) partition.tbl不能把硬盘剩余空间全给data分 ...
- MySQL official tutorial
1.installation 2.setup environment variables add %/MySQL Server/bin to path. then restart cmd/powers ...
- 雷林鹏分享:C# 循环
C# 循环 有的时候,可能需要多次执行同一块代码.一般情况下,语句是顺序执行的:函数中的第一个语句先执行,接着是第二个语句,依此类推. 编程语言提供了允许更为复杂的执行路径的多种控制结构. 循环语句允 ...
- 20165303 2017-2017-2《Java程序设计》课程总结
1.我期待的师生关系 20165303我期望的师生关系 2.学习基础和C语言基础调查 20165303学习基础和C语言基础调查 3.linux安装及学习 20165303 预备作业3 Linux安装及 ...
- English trip V1 - B 23. Nosy People 爱管闲事的人 Teacher:Parice Key: Be + Ving
In this lesson you will learn to talk about what happened. 谈论发生什么? 课上内容(Lesson) Nosy 好管闲事Noise 噪声 ...
- android -------- Data Binding的使用 RecyclerView
今天来说说DataBinding在列表RecyclerView中的使用 列表绑定 App中经常用到列表展示,Data Binding在列表中一样可以扮演重要的作用,直接绑定数据和事件到每一个列表的it ...
- Confluence 6 创建一个项目空间
火星移民小组的程序需要一个地方能够调出他们任务的相关关键信息和资源,你的任务就是帮助他们实现和管理这个需求.这部分是比较容易实现的,因为这些信息需要让空间项目组中完全可见. 这样的话,你就可以设置项目 ...