Boadload和Image$$??$$Limit含义
Bootloader 即引导加载程序,是系统加电后运行的第一段软件代码。简单的说它们都是bootloader,所完成的任务也大同小异。
熟悉x86体系结构的朋友肯定知道,x86平台上bootloader 是由 BIOS和位于硬盘MBR中的OS Bootloader(比如Lilo 和 Grub)组成的。BIOS完成硬件的检测和资源的分配后,将硬盘MBR中的bootloader读到系统RAM中,之后此bootloader 就会开始进行主导,将内核搬到内存中以及进行一些必要的初始化工作,之后跳到内核的入口地址来执行,这样内核就开始启动,也就是系统就启动起来了。
      这里不得不插入一个话题,通过上面的介绍,细心的朋友就会产生一个疑问:为什么要有bootloader?既然bootloader只是作硬件的初始化并将内核引导起来,那为什么不直接将这段代码加到内核中,直接启动内核就完成所有的工作?实际上要将bootloader与内核整合在一起是完全可以做到的,但是如果这样作的話,内核就会失去他的通用性和灵活性,并且将bootloader与内核分开会更有利于开发和管理,将启动过程中与平台硬件相关的代码集合成bootloader,内核就可以集中处理那些平台通用的部分了(当然实际上并没有这么严格的划分,内核中还是会有一些平台相关的代码,不过已经算是比较通用的了)。
而嵌入式平台上就跟x86不一样了,但是很类似,而且因为不同的平台架构本身的特点,每种平台对应的bootloader做得事情会有所不同,相对x86平台,一般不会有bios(但是这些都不是绝对的,有一些平台也会有内嵌类似bios的启动程序),整个系统的引导加载都由存放在flash,rom等存储设备特定位置的bootloader来完成。如arm平台中的2410,2440,bootloader存在在flash中的0x0的地方,板子加电后,系统会将bootloader的最前面的4k代码通过硬件逻辑自动的装载到SRAM中,之后从SRAM中的0开始执行,在这4k的程序中会完成基本的硬件的初始化,将完整的bootloader搬到内存中,并跳转到ram中的bootloader来进行继续执行。
回到之前所说的,bootloader启动起来之后,通常会有两种操作模式:
启动加载模式就是一上电,bootloader进行相关的初始化之后就马上把内核启动起来,注意关键的地方在整个过程中没有用户的参与,这种其实也就是bootloader的默认处理,一般的产品设计ok进行最后的发布时,就会处于此种状态。
下载模这种模式,大家肯定非常熟悉,就是大家在进行开发的时候所处的环境,我们经常使用的tftp, erase, cp.b 等命令将相关的bin,img文件烧到板子上,这种情况下其实就是处于bootloader的执行环境下,所以一定意义来说,大多的bootloader其实就是一个嵌入式操作系统,只是它的功能不强,不像linux的结构那么复杂,而且也不会支持多进程多线程处理。
bootloader 种类和分类
vivi是mizi开发的用于s3c241x/s3c244x 的linux bootloader,友善之臂移植了USB 下载功能后就成了现在看到的supervivi;u-boot是一个广泛用于ARM平台的bootloader, 目前也支持s3c241x/s3c244x,可以用来启动Linux;Eboot是WinCE平台下的bootloader。uboot就是通过usb来下载os image文件的bootloader; eboot就是通过ethernet下载os image的bootloader。
这里的分类实际上是依据上面的bootloader的操作模式来进行划分的,根据一个系统是否支持上面的下载模式我们这里将bootloader划分为bootloader和monitor(这不是我划分的,恩,是从别人的文章中引述过来的,不过我觉得他说的很有道理), 这里”bootloader”是指只是引导设备与执行主程序的固件,而”monitor”是指不仅拥有bootloader功能的,还能够进入下载模式的固件。
===============================================================================================
(1)、ARM程序的组成
此处所说的“ARM程序”是指在ARM系统中正在执行的程序,而非保存在ROM中的bin映像(image)文件,这一点清注意区别。
一个ARM程序包含3部分:RO,RW和ZI           
        RO是程序中的指令和常量;RO就是readonly,
        RW是程序中的已初始化变量; RW就是read/write,
ZI是程序中的未初始化的变量;ZI就是zero;                 
(2) ARM映像文件的组成
    所谓ARM映像文件就是指烧录到ROM中的bin文件,也成为image文件。以下用Image文件来称呼它。Image文件包含了RO和RW数据。之所以Image文件不包含ZI数据,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域一律清零即可。包含进去反而浪费存储空间。
    Q:为什么Image中必须包含RO和RW?         
    A:因为RO中的指令和常量以及RW中初始化过的变量是不能像ZI那样“无中生有”的。
(3)ARM程序的执行过程
从以上两点可以知道,烧录到ROM中的image文件与实际运行时的ARM程序之间并不是完全一样的。因此就有必要了解ARM程序是如何从ROM中的image到达实际运行状态的。 
  实际上,ROM中的指令至少应该有这样的功能:
            1. 将RW从ROM中搬到RAM中,因为RW是变量,变量不能存在ROM中。
            2. 将ZI所在的RAM区域全部清零,因为ZI区域并不在Image中,所以需要程序根据编译器给出的ZI地址及大小来将相应得RAM区域清零。ZI中也是变量,同理:变量不能存在ROM中.在程序运行的最初阶段,RO中的指令完成了这两项工作后C程序才能正常访问变量。否则只能运行不含变量的代码。
    下面我将给出几个例子,最直观的来说明RO,RW,ZI在C中是什么意思。
        1; RO
        看下面两段程序,他们之间差了一条语句,这条语句就是声明一个字符常量。因此按照我们之前说的,他们之间应该只会在RO数据中相差一个字节(字符常量为1字节)。        
Prog1:
            #include <stdio.h>
            void main(void)
            {
                ;
            }         
Prog2:
            #include <stdio.h>
            const char a = 5;
            void main(void)
            {           
                ;
            }
 Prog1编译出来后的信息如下:          
================================================================================          
Code RO Data RW Data ZI Data Debug
            948 60 0 96 0 Grand Totals         
================================================================================        
Total RO Size(Code + RO Data) 1008 ( 0.98kB)
Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)
Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)          
================================================================================           
Prog2编译出来后的信息如下:          
================================================================================         
Code RO Data RW Data ZI Data Debug
            948 61 0 96 0 Grand Totals           
================================================================================          
Total RO Size(Code + RO Data) 1009 ( 0.99kB)
Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)
Total ROM Size(Code + RO Data + RW Data) 1009 ( 0.99kB)           
================================================================================         
以上两个程序编译出来后的信息可以看出:
   Prog1和Prog2的RO包含了Code和RO Data两类数据。他们的唯一区别就是Prog2的RO Data比Prog1多了1个字节。这正和之前的推测一致。如果增加的是一条指令而不是一个常量,则结果应该是Code数据大小有差别。
     2; RW
     同样再看两个程序,他们之间只相差一个“已初始化的变量”,按照之前所讲的,已初始化的变量应该是算在RW中的,所以两个程序之间应该是RW大小有区别。     
    Prog3:
            #include <stdio.h>
            void main(void)
            {
                ;
            }           
    Prog4:
            #include <stdio.h>
            char a = 5;
            void main(void)
            {         
                ;
            }
            Prog3编译出来后的信息如下:           
================================================================================          
Code RO Data RW Data ZI Data Debug
            948 60 0 96 0 Grand Totals         
================================================================================           
Total RO Size(Code + RO Data) 1008 ( 0.98kB) 
Total RW Size(RW Data + ZI Data) 96 ( 0.09kB) 
Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)           
================================================================================       
Prog4编译出来后的信息如下:         
================================================================================      
Code RO Data RW Data ZI Data Debug
            948 60 1 96 0 Grand Totals          
================================================================================          
Total RO Size(Code + RO Data) 1008 ( 0.98kB) 
Total RW Size(RW Data + ZI Data) 97 ( 0.09kB)
Total ROM Size(Code + RO Data + RW Data) 1009 ( 0.99kB)            
================================================================================       
可以看出Prog3和Prog4之间确实只有RW Data之间相差了1个字节,这个字节正是被初始化过的一个字符型变量“a”所引起的。
3; ZI
再看两个程序,他们之间的差别是一个未初始化的变量“a”,从之前的了解中,应该可以推测,这两个程序之间应该只有ZI大小有差别。          
Prog3:
            #include <stdio.h>
            void main(void)
            {
            ;
            }        
Prog4:
            #include <stdio.h>
            char a;
            void main(void)
            {      
                ;
            }
Prog3编译出来后的信息如下:        
================================================================================          
Code RO Data RW Data ZI Data Debug
948 60 0 96 0 Grand Totals           
================================================================================           
Total RO Size(Code + RO Data) 1008 ( 0.98kB)
Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)
Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)          
================================================================================        
Prog4编译出来后的信息如下:         
================================================================================         
Code RO Data RW Data ZI Data Debug
            948 60 0 97 0 Grand Totals         
================================================================================          
Total RO Size(Code + RO Data) 1008 ( 0.98kB)
Total RW Size(RW Data + ZI Data) 97 ( 0.09kB)
Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)           
================================================================================           
编译的结果完全符合推测,只有ZI数据相差了1个字节。这个字节正是未初始化的一个字符型变量“a”所引起的。
注意:如果一个变量被初始化为0,则该变量的处理方法与未初始化华变量一样放在ZI区域。          
即:ARM C程序中,所有的未初始化变量都会被自动初始化为0。
    总结:  1; C中的指令以及常量被编译后是RO类型数据。
               2; C中的未被初始化或初始化为0的变量编译后是ZI类型数据。
               3; C中的已被初始化成非0值的变量编译后市RW类型数据。
(3)、下面是在ADS下,一种常用存储器模型的直接实现:
         LDRr0,=|Image$$RO$$Limit|;RO结束后的地址(在rom中):即得到RW数据源的起始地址
         LDRr1,=|Image$$RW$$Base|;RW区在RAM里的执行区起始地址
         LDRr3,=|Image$$ZI$$Base|;ZI区在RAM里面的起始地址
|Image$$RO$$Limit|:表示RO区末地址后面的地址,即RW数据源的起始地址
 |Image$$RW$$Base|:RW区在RAM里的执行区起始地址,也就是编译器选项RW_Base指定的地址
 |Image$$ZI$$Base|:ZI区在RAM里面的起始地址
 |Image$$ZI$$Limit|:ZI区在RAM里面的结束地址后面的一个地址
  程序先把ROM里|Image$$RO$$Limt|开始的RW初始数据拷贝到RAM里面|Image$$RW$$Base|开始的地址,当RAM这边的目标地址到达|Image$$ZI$$Base|后就表示RW区的结束和ZI区的开始,接下去就对这片ZI区进行清零操作,直到遇到结束地址|Imag开机运行程序设置e$$ZI$$Limit|
(4) ROM主要指:NAND Flash,Nor Flash
RAM主要指:PSRAM,SDRAM,SRAM,DDRAM
(5) Image$$??$$Limit 的含义
=0x0c100000+Tatal RO size+1
                   = 0x0c200000+0x37(4的倍数,0到55,共56个单元)
对于刚学习ARM的人来说,如果分析它的启动代码,往往不明白下面几个变量的含义:|Image$$RO$$Limit|、|Image$$RW$$Base|、|Image$$ZI$$Base|。
当把程序编写好以后,就要进行编译和链接了,在ADS1.2中选择MAKE按钮,会出现一个Errors and Warnings的对话框,在该栏中显示编译和链接的结果,如果没有错误,在文件的最后应该能看到Image component sizes,后面紧跟的依次是Code,RO Data ,RW Data ,ZI Data ,Debug 各个项目的字节数,最后会有他们的一个统计数据:
Code 163632 ,RO Data 20939 ,RW Data 53 ,ZI Data 17028
Tatal RO size (Code+ RO Data) 184571 (180.25kB)
Tatal RW size(RW Data+ ZI Data) 17081(16.68 kB)
Tatal ROM size(Code+ RO Data+ RW Data) 184624(180.30 kB)
后面的字节数是根据用户不同的程序而来的,下面就以上面的数据为例来介绍那几个变量的计算。
在ADS的Debug Settings中有一栏是Linker/ARM Linker,在output选项中有一个RO base选项,
假如 RO base设置为0x0c100000,后面的RW base 设置为0x0c200000,然后在Options选项中有Image entry point ,是一个初始程序的入口地址,设置为0x0c100000 。
有了上面这些信息我们就可以完全知道这几个变量是怎么来的了:
|Image$$RO$$Base| = Image entry point =RO base =0x0c100000 ;表示程序代码存放的起始地址
|Image$$RO$$Limit|=程序代码起始地址+代码长度+1
= 0x0c100000 + 184571 + 1 = 0x0c100000 +0x2D0FB + 1
= 0x0c12d0fc
|Image$$RW$$Base| = 0x0c200000=RW base 地址指定
|Image$$RW$$Limit| =|Image$$RW$$Base|+ RW Data 53
=0x0c200037
|Image$$ZI$$Base| = |Image$$RW$$Limit| + 1 =0x0c200038
|Image$$ZI$$Limit| = |Image$$ZI$$Base| + ZI Data 17028
=0x0c200038 + 0x4284
=0x0c2042bc
也可以由此计算:
|Image$$ZI$$Limit| = |Image$$RW$$Base| +TatalRWsize(RWData+ZIData) 17081
=0x0c200000+0x42b9+3(要满足4的倍数)
=0x0c2042bc
随机推荐
- Repaint轨迹保留?(待处理,待编辑)
			
import java.awt.Color; import java.awt.Graphics; import javax.swing.JFrame; import javax.swing.JPane ...
 - Android中layout_gravity和gravity的区别
			
安卓中的 layout_gravity 属性和 gravity属性 有啥区别? LinearLayout有两个非常相似的属性: android:gravity与android:layout_gravi ...
 - javascript控制开始日期,和结束日期在同一个月
			
/* * 控制开始日期,和结束日期 * 开始日期为当前月份,结束日期为当天 * 开始日期为之前月份,结束日期为最后一天 * @return string * @poseidon 2015-9-17 * ...
 - Ansible (一)
			
epel rpm -ivh http://mirrors.ustc.edu.cn/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm yum -y ins ...
 - 通过Queue的构造函数的可选参数maxsize来设定队列长度
			
创建一个"队列"对象 import Queuemyqueue = Queue.Queue(maxsize = 10) Queue.Queue类即是一个队列的同步实现.队列长度可为无 ...
 - Bootstrap (导航、标签、面包屑导航)
			
导航 Bootstrap中可用的导航有相似的标记,用基类.nav开头,这是相似的部分.改变修饰类可以改变样式. <!DOCTYPE html> <html> <head& ...
 - mysql5.5手册读书日记(4)
			
<?php /* InnoDB事务模型和锁定 15.2.10.1. InnoDB锁定模式 15.2.10.2. InnoDB和AUTOCOMMIT 15.2.10.3. InnoDB和TRANS ...
 - hover事件优化(延时操作)
			
JQ的hover事件拓展 编写原因:当鼠标滑过某个带有hover事件的元素,但是仅仅是路过,并不是希望查看此部分内容的时候,效果不理想 $.fn.extend({ delayed : function ...
 - php使用strlen()判断中文汉字字符串长度
			
php使用strlen()判断中文汉字字符串长度 对于含有中文情况,此时可以采用: iconv_strlen($str,"UTF-8"); iconv_strlen 是无论是何种编 ...
 - ModSecurity 白名单设置
			
方法一.SecRuleRemoveById 指令:通过Rule ID禁用指定规则 #waf whitelist <LocationMatch .*> SecRuleRemoveById 9 ...