加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

试图搞懂MDK程序下载到Flash(一)--Nand Flash启动流程,加载域和

发布时间:2020-12-15 18:08:38 所属栏目:百科 来源:网络整理
导读:NAND FLASH启动流程??? 在这里我先以TQ2440的启动代码分析,因为手上有本书,反正Nand Flash启动流程都是一样的对于mini2440和TQ2440来说。TQ2440的启动代码部分如下: ??? ;*****************************************************************************

NAND FLASH启动流程???

在这里我先以TQ2440的启动代码分析,因为手上有本书,反正Nand Flash启动流程都是一样的对于mini2440和TQ2440来说。TQ2440的启动代码部分如下:

??? ;**********************************************************************************

??? .....???????????????????????????????????????????????;38行之前的代码都是一些准备工作

??? .....?????????????????????????????????????????????? ;如宏定义、符号导入之类的

??? 35?????????????? AREA???? Init,CODE,READONLY

????36?????????????? ENTRY

??? 37????? ResetEntry

??? 38??????????????? b???????????????ResetHandled????????? ;程序执行代码的第一句?

??? ....????????????????????????????????????????????????????????????????? ;跳转到标号ResetHandler处执行

??? ....

??? 63?????? ResetHandler

??? 64??????????????? ldr???????????? r0,=WTCON

??? 65?????????????? ldr????????????? r0,=0x0

??? .....

??? .....

??? 106??????????? ? ldr??????????? ?r0,=BWSCON

??? 107?????????? ?? ldr???????????? r0,[r0]

????108??????????? ? ands???????? r0,r0,#6????????????????????? ;OM[1:0]!=0,NOR Flash 启动

????109?????????? ?? bne????????? copy_proc_beg?????????? ;do not read nand flash

??? 110?????????? ? adr???????????r0,ResetEntry????????????? ;OM[1:0]==0,NAND Flash启动

??? 111???????? ??? cmp????????? r0,#0?????????????????????????? ;if use Multi-ice

??? 112??????????? ?bne?????????? copy_proc_beg??????????? ;do not read nand flash for boot

??? 113??? nand_boot_beg

??? 114?????????????bl??????????? RdNF2SDRAM

????115???????????? ldr?????????? pc,=copy_proc_beg

??? 116????copy_proc_beg

????117???????????? adr???????? r0,ResetEntry

??? 118???????????? ldr????????? r2,BaSEOfROM

??? 119???????????? cmp?????? r0,r2

????120???????????? ldreq????? r0,TopOfRom

??? 121???????????? beq??????? InitRam

????122???????????? ldr????????? r3,TopOfRom

??? 123??? 0?

??? 124???????????? ldmia????? r0!,{r4-r7}

??? 125???????????? stmia????? r2!,{r4-r7}

????126???????????? cmp???????r2,r3

??? 127?????????? ? bcc???????? %B0

?

??? 128???????????? sub??????? r2,r2,r3

??? 129???????????? sub??????? r0,r2?

??? 130??? InitRam

????131??????????? ldr???????????r2,BaSEOfBSS

??? 132??????????? ldr?????????? r3,BaSEOfZero

????133??? 0

????134???????????cmp??????? r2,r3

????135?????????? ldrcc??????? r1,[r0],#4

????136?????????? strcc?????? r1,[r2],#4

????137???????? ? bcc???????? %B0

??? 138????????? ?mov??????? r0,#0

???? 139??????? ? ldr????????? r3,EndOfBSS

???? 140??? 1

???? 141????????? cmp?????? r2,r3

???? 142????????? strcc?????? r0,#4

????? 143???????? bcc????????%B1

????? ;安装中断向量表

????? 144???????? ldr???????? r0,=HandleIRQ

????? 145???????? ldr???????? r1,=IsrIRQ

??????146??????? ?str????????? r1,[r0]

?

??????147?????? ? b?????????? Main

??????148?? InitStacks

??????149??????????????????????? ;堆栈初始化代码部分的开始行

?????? ....

????? 168??????????????????????? ;堆栈初始化代码部分的结束行?

???????....

???????....

????? 231?????????END?????? ;启动代码结束

???? 现在开始分析代码:

??? 106????????????? ldr???????????? r0,=BWSCON?????????????????????????????????????????????????????? ??? ?

??? 107????????????? ldr???????????? r0,[r0]????????????????????????????????????????????????????????????? ???????? ??

??? 108????????????? ands???????? r0,#6????????????????????? ;OM[1:0]!=0,NOR Flash 启动

??? 109????????????? bne????????? copy_proc_beg?????????? ;do not read nand flash???????????

??? 110???????????? adr?????????? r0,ResetEntry????????????? ;OM[1:0]==0,NAND Flash启动

??? 111???????????? cmp????????? r0,#0?????????????????????????? ;if use Multi-ice???????????????????????????

??? 112???????????? bne?????????? copy_proc_beg??????????? ;do not read nand flash for boot

?????第106~112行才是选择从NAND FLASH或者NOR FLASH启动的关键。

???? 第106~107行将BWSCON寄存器里的数据读入寄存器r0。从S3C2440的数据手册上可以查到BWSCON寄存器第1、2位,反映了系统总线宽度的信息。

???? 第108行,and指令主要用于测试数据的某几位是0还是1,后面的s表示该指令的运算结果影响标志位。因此,该条指令主要是测试r0第1、2两位。当运算结果是0时,说明r0的第1、2位是0,即BWSCON寄存器的第1、2位是0,即系统是从Nand Flash启动的,则执行第110行程序;当运算结果不为0时,说明是从Nor Flash启动,在执行第109行程序。

??? 第109行,执行该条指令的前提是系统从Nor Flash启动,然后跳转到copy_proc_beg标号处执行,其功能是:实现代码从加载域到运行域的搬移工作,这也是启动代码的核心。关于加载域和运行域在后面会讲到。

???第110~112行,其中adr指令比较难理解,adr伪指令是将标号基于PC的相对地址加载到寄存器中,因为是将程序下载到了NADN FLASH的0地址处,所以ResetEntry的地址为0,所以最终结果就是r0=0。关于ldr与adr指令、相对地址与绝对地址请看博客:点此打开链接

?? 第112行,由上面的分析可以知道,该行指令不执行,执行第113行指令。

??? 113??? nand_boot_beg????????????????????????????????????????????

??? 114???????????? bl??????????? RdNF2SDRAM?????????????????????

??? 115???????????? ldr?????????? pc,=copy_proc_beg??????????????

???? 第113行,只是一个程序标号,没有实际的用处。

???? 第114行,调用C语言函数RdNF2SDRAM,将代码从NAND FLASH读入到内存中,这个函数是在C文件中定义的。

???? 第115行,用ldr指令将copy_proc_beg的绝对地址加载到程序计数器PC中,即跳转到了内存中去执行。

???? 到此为止,从NAND FLASH启动的流程已经完全讲清楚了,尽管我还是不”很清楚“,下面就结合图1详细分析从NAND FLASH启动总流程,做到真清楚!


?

????① 系统上电后,S3C2440处理器通过硬件电路自动将NAND FLASH中的前4KB代码复制到内部的Stepping Stonezhong ,该Stepping Stone就是一块RAM,可以执行程序。

???? ② 程序从Stepping Stone的0地址处开始执行第1条指令。

???? ③ 程序执行到bl???? RdNF2SDRAM(第114行)时,调用NAND FLASH函数,将NAND FLASH中的代码全部复制到SDRAM中。

???? ④ 执行? ldr??? pc,=copy_proc_beg,将copy_proc_beg的绝对地址加载到程序计数器PC中。

???? ⑤ 程序跳转到SDRAM中copy_proc_beg标号处执行。

???? 注意:第(4)步中提到了copy_proc_beg的绝对地址,那么什么是绝对地址呢?绝对地址是程序编译链接后确定的,如图2所示

在链接时,指定的entry 地址是0x3000 0000,这个entry地址即第36行的ENTRY,也就是说,在最终编译链接后生成的可执行程序中,copy_proc_beg的绝对地址=0x3000 0000+偏移量。这个偏移量是多少呢?就是copy_proc_beg距离ENTRY的偏移量。因此,在第(4)步执行完后,虽然stepping stone中也有copy_proc_beg,SDRAM中也有copy_proc_beg,但是程序并没有跳到stepping stone中的copy_proc_beg处执行,而是跳到了SDRAM中的copy_proc_beg处去执行。

加载域和运行域、RW、RO、ZI

?? 一个简单的可执行程序的映像文件如图3所示。它由RO、RW、和ZI三个段组成,其中RO为代码段和只读数据段;RW为可读/写的数据段;ZI为未初始化的数据段。

?? 此外,映像文件还可以分为加载域(Load View)和运行域(Execution View)。加载域反映了ARM可执行映像文件各个段存放在存储器中时的位置关系,运行域反映了ARM可执行映像文件各个段真正执行时在存储器中的位置关系。

?? 前文讲到,从NOR FLASH启动后,当启动代码执行到第109行时,会跳转到copy_proc_beg处执行。此时,程序加载域和运行域的分布情况如图4所示

????? 加载域的起始地址是0x0000 0000,为什么呢?因为加载域反映了ARM可执行文件存放在存储器中时的位置关系,程序下载到NOR FLASH中,又知道NOR FLASH的起始地址是0x0000 0000,因此加载域的起始地址是0x0000 0000,在加载域中,首先存放RO,后面紧跟着存放的是RW,并没有ZI。RO为代码段,属性为只读;RW为已经初始化的全局变量段,属性可读、可写;ZI为未初始化的全局变量段。为什么在加载域中没有ZI呢,这主要是为了减小ARM可执行映像文件的容量,因为ZI中存放的是未初始化的全局变量,那么只需要记录该段的容量即可,在运行域中需要根据这个容量分配内存,然后用0填充。

????? 运行域的起始地址是0x3000 0000,这又是为什么呢?

???? 如图4所示,为ADS中在配置选项”ARM Linker“中有一项是”RO Base“,这个地方就表明了运行域中RO的起始地址。"RW Base"为空,这表明在运行域总共RW紧跟着RO的后面。

?????????????????????????????????????????????????????????????

??? 启动代码做的工作就是如图3中虚线部分所指示的,将各个段搬移到指定的位置,然后将ZI初始化为0.下面这段程序就是围绕这个工作来展开。

??? 116??? copy_proc_beg??????????????????????????????

??? 117???????????? adr???????? r0,ResetEntry??????????

??? 118???????????? ldr????????? r2,BaSEOfROM????????

??? 119???????????? cmp?????? r0,r2?????????????????????????

??? 120???????????? ldreq????? r0,TopOfRom??????????

??? 121???????????? beq??????? InitRam????????????????????

??? 122???????????? ldr????????? r3,TopOfRom???????????

??? 123??? 0??????????????????????????????????????????????????????

??? 124???????????? ldmia????? r0!,{r4-r7}??????????????????

??? 125???????????? stmia????? r2!,192)">??? 126???????????? cmp?????? r2,r3??????????????????????????

??? 127???????????? bcc???????? %B0?????????????????????????

??? 128???????????? sub??????? r2,r3??????????????????????

??? 129???????????? sub??????? r0,r2??????????????????????

?????有了上面的讲解,再看第116~129行程序就很容易理解。在上述程序中,BaSEOfROM和TopOfROM是用DCD分配的内存单元,里面存放的是RO的起始地址和结束地址(准确点说是结束地址+1)。该起始地址和结束地址是由编译器自动生成的,在程序中使用即可,见第183~184行

???? 183????????? BaSEOfROM????? DCD??????? |Image$$RO$$Base|?????

???? 184????????? TopOfROM????? ? DCD??????? |Image$$RO$$Limit|??????

?? 其|Image$$RO$$Base|???和|Image$$RO$$Base|? 是ADS编译器自动生成的符号,在该启动代码的开头使用IMPORT引入了,如下

?????28??????????? IMPORT??? |Image$$RO$$Base|???????????????? ;Base of ROM?code

?

?????? 29?????????? IMPORT??? |Image$$RO$$Limit|????????????????? ;End? of?? ROM? code??dd?????????????????????????

?????

表1? 编译器生成的符号
编译生成的符号 含义
|Image$$RO$$Base| RO段起始地址
|Image$$RO$$Limit| RO段结束地址+1
|Image$$RW$$Base| RW段起始地址
|Image$$RW$$Limit| RW段结束地址+1
|Image$$ZI$$Base| ZI段起始地址
|Image$$ZI$$Limit| ZI段结束地址+1

??? 下面接着分析第116~129行。

??? 第117行,使用adr指令将ResetEntry的相对地址加载到寄存器r0中,这个地址就是0。

??? 第118行,使用ldr指令将RO的起始地址加载到寄存器r2中。

??? 第119行,比较r0和r2是否相同,如图5所示,可以看出r0和r2并不相等,因此第120~121行并不执行。

??? 第122行,使用ldr指令将RO的结束地址+1加载到寄存器r3中。

??? 执行完上述指令后,图5详细展示程序执行的最后结果,下面的工作就是将代码从r0指示的加载域中的RO搬移到r2、r3所限定的运行域中的RO。

??? 第123行,定义了一个局部标号0。

? ? 第124行,使用批量加载指令ldmia,将r0地址出的数据加载到寄存器r4~r7中,注意后面的感叹号“!”说明取完数据后,r0的地址自动更新,即指向下一个地址处。此外,可以得出这样的结论每次搬移16个字节(每个寄存器是4个字节的长度,共4个寄存器) 。

??? 第125行,将r4~r7中的数据存储到r2开始的地址处,同时r2地址自动更新。

??? 第126~127行,比较r2和r3的值,如果r2的值小于r3的值,就跳转到第123行定义的局部标号0处知心。更形象的理解是,如图5所示,当r2小于r3时,说明RO还没有搬移完,因此就接着搬移,直到r2的值大于r3的值。

??? 第128~129行,这两行的作用就是调整r0的值,使其指向加载域中RW的起始地址。有的人会说,怎么r0就指向RW起始地址呢?已知咱们的RW段紧跟着RO段,当搬移完RO内容后,很可能r2不一定等于r3,如果r2大于r3,说明r2指向的地址超过了运行域中的RW段起始地址,此时r0指向的地址也超过了加载域中RW段的起始地址。为了更形象的展示这一调整的过程,请看图6:

????? 由第124行的讨论可知,每次搬移16个字节,因此最后肯那个出现的情况如图6所示,当r2的值大于r3的值时,停止搬移,那么现在的情况是已经完成了RO从加载域到运行域的搬移,下面需要完成RW从加载域到运行域的搬移。面临的首要问题是如何在加载域中找到RW的起始地址,现在知道的信息是在加载域中RW紧邻着RO存放。由图6可以看到r0已经移到了RW,只要计算出这个偏移,即可计算出RW的首地址。这个偏移地址怎么计算呢,其实就是r2-r3。

???? 第128行,计算出偏移地址r2-r3,将其存放在寄存器r2中。

???? 第129行,将r0的值减去这个偏移地址,即得到了RW的起始地址。

??? 其实,在这种加载域和运行域布局情况下,即加载域和运行域中RO和RW紧挨着存放,完全可以将RO和RW整体搬移,但是该启动代码照顾到更为一般的情况,并没有采取这种搬移方法,而是采取各个段分别搬移的方法。下面的程序就是搬移RW段。

??? 130??? InitRam??????????????????????????????????????

??? 131??????????? ldr?????????? r2,BaSEOfBSS????

??? 132 ?????????? ldr?????????? r3,BaSEOfZero????

??? 133??? 0????????????????????????????????????????????????

??? 134?????????? cmp??????? r2,r3?????????????????????

??? 135?????????? ldrcc??????? r1,#4?????????????

??? 136?????????? strcc?????? r1,#4??????????????

??? 137?????????? bcc???????? %B0?????????????????????

??? 138?????????? mov??????? r0,#0????????????????????

???? 139????????? ldr????????? r3,EndOfBSS????????

???? 140??? 1???????????????????????????????????????????????

???? 141????????? cmp?????? r2,r3??????????????????????

???? 142????????? strcc?????? r0,192)">????? 143???????? bcc??????? %B1??????????????????????

??? 上述的BaSEOfBss和BaSEOfZero仍然是用DCD分配的内存单元。如下:

???????185??????? BaSEOfBss??? DCD??? |Image$$RW$$Base|???? ;RW段起始地址

?????? 186??????? BaSEOfZero?? DCD??? |Image$$ZI$$Base|??????? ;ZI段起始地址

?????? 187??????? EndOfBss????? DCD??? |Image$$ZI$$Limit|??????? ;ZI段结束地址

????? 有了前面RO搬移的讲解,下面RW的搬移工作变得较为简单。在RO搬移完以后,r0已经指向了加载域中RW的起始地址处。

??? 第131行,将r2指向运行域中RW的起始地址处,其中BaSEOfBSS是在185行定义的。

??? 第132行,将r3指向RW的结束地址+1处,又因为ZI在RW后面紧挨着存放,所以可以得出这样的结论:RW的结束地址+1就是ZI的起始地址。

??? RW的搬移如图7所示:

???? 第133行定义了一个局部标号 0。

???? 第134行比较r2和r3的值。

???? 第135行,ldr指令后面的cc表示条件执行,如果r2的值小于r3的值,就从r0地址处取出一个字数据,加载到r1中,然后r0自动加4,即r0=r0+4

???? 第136行,将r1中的数据存储到r2指向的地址处,然后,r2的值自动加4,即r2=r2+4。

???? 第137行,如果r2的值小于r3,则跳转到133行定义的局部标号0处执行。

???? 经过前面的讲解,已经实现了RO和RW的搬移工作,下面需要做的就是将ZI初始化为0即可。注意,这里并不是ZI的搬移,因为在加载域中没有ZI,所以不存在搬移这一说法。

???? 138????????? mov??????? r0,#0????????????????????????

???? 140??? 1???????????????????????????????????????????????????

?????143???? ???? bcc??????? %B1??????????????????????????

???? RW搬移结束后,r2指向了RW的结束地址+1处,即ZI的起始地址处。

???? 第138行,将0赋值给寄存器r0.

?????第139行,将ZI的结束地址+1加载到寄存器r3,即r3指向了ZI的结束地址+1处。程序执行到了现在,加载域中的分布情况如图8所示,可以看出,r2指向了ZI的起始地址,r3指向了ZI的结束地址+1处。

????? 第140~143行就是将ZI用0填充,即实现了初始化为0。

???? 到此为止,启动代码做的工作已经接近尾声,下面回顾一下启动代码将程序从加载域到运行域的搬移过程。

??? ① 找到加载域中各个段的起始地址和结束地址。

??? 方法:用adr指令找到了RO的起始地址。

??? ② 找到运行域中各个段的起始地址和结束地址。

?? 方法: 使用编译器自动生成的各个段的起始地址和结束地址。

??? ③ 使用循环执行搬移即可。

?

????? 144???????? ldr???????? r0,=IsrIRQ

????? 146???????? str????????? r1,[r0]

???? 对于第144~146行,就是安装中断向量表。

?????? 147??????? b???????? Main?? ;

????? 第147行使用b跳转指令跳转到C语言函数Main函数处执行。

?

?

??? 到这里,我有了一个大概的想法,可不可以在MDK中自带的S3C2440.s中加入这段由加载域搬移到运行域,然后用MDK生成bin文件,利用J-Flash ARM将bin文件下载到nor flash中去,这样子代码就可以搬移到SDRAM中去运行了。不能用axf好像,我看网上说是什么axf携带地址信息,现在还不是很懂。

?? 我想上述方法可行,关键就是要RO? RW怎么安放,这又好像和分散加载文件scatter有关,再接着看。

RealView MDK中如何获得RO,RW,ZI的地址和长度?

? ? 问题分析:

??? 在RealView MDK里有专门的字符用来表示RO,RW,ZI的起始地址和长度。

??? 解决办法:

?? 1.在不使用Scatter文件时,默认的为Image$$RW$$Base、Image$$RW$$Limit、Image$$RO$$Base、Image$$RO$$Limit、Image$$ZI$$Base和Image$$ZI$$Limit等6个地址,它的长度这样计算:Length = (Image$$RW$$Limit-Image$$RW$$Base)。

??? 2. 在使用Scatter文件后,上述的6个默认地址没有了,取而代之的是Image$$段名$$Base 和Image$$段名$$Limit表示的地址,长度计算的方法和上述一样,即Length = (Image$$段名$$Limit-Image$$段名

??? 3. 关于Scatter文件的使用方法请参考下面的网址:http://www.realview.com.cn/wen-list3.asp?id=330

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读