微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > ARM技术讨论 > ARM启动代码深入分析

ARM启动代码深入分析

时间:10-02 整理:3721RD 点击:

这几天在看《ARM处理器裸机开发实践---机制而非策略》,这本书对于ARM的初学者来说是非常适合的,基础篇详尽介绍了ARM 汇编程序结构,C语言基础以及混合编程。提高篇一上来就是干货---分析启动代码,看的我简直如获珍宝,看了一遍又一遍,之后就是ARM各个模块逐一各个讲解击破。其他先不多说,这里主要分享几个在分析启动代码时所碰到的几个问题,希望大神不吝赐教。
书中讲到,上电后(Nand Flash启动)首先会在4K的Stepping Stone 中运行,直到运行到nand_boot_beg处,先是执行bl RdNF2SDRAM 完成将Nand Flash所有代码搬移到SDRAM(也就是内存中),然后再执行ldr        pc, =copy_proc_beg 通过绝对地址跳转到 SDRAM(内存中)的标号 copy_proc_beg 去执行,copy_proc_beg 标号处代码的功能是将加载域代码搬移到运行域代码,而运行域就是0x30000000起始的一段内存,加载域就是存储代码的地方这里应当是Nand Flash。
所以基于此段描述有如下几个问题:
1. Stepping Stone 中的4KB代码是否会一直存在,跳转到内存执行之后发生异常时会跳到Stepping Stone的异常向量表 还是内存中的异常向量表,为什么?
2. 我理解从加载域到运行域的搬移就是:将代码从存储它的地方(Nand 或 Nor,起始地址都是0x0)搬移到可以较快执行它的地方(内存也就是SRAM,起始地址为0x30000000),不知道这样理解对不对?个人觉得这样理解还是很肤浅,没有领略到它的本质,希望大神解答。
3. Nand 启动跳转到内存之后会去执行 copy_proc_beg 处代码,其功能是将加载域搬移到运行域执行,但是之前已经通过bl RdNF2SDRAM 将Nand 中所有代码复制到内存了,已经可以往下正常运行了为什么还要再将加载域搬到运行域?运行域不就是位于内存中0X30000000处开始的地方么(ADS1.2 中设置RO Base 为0x30000000)?这两个搬移的本质区别是什么?如果两个搬移都必不可少,目前Nand的所有代码已经被搬移到内存(包括实现从加载域到运行域的代码段),接下来从加载域到运行域的搬移不会覆盖现有的内存中的代码段吗?
4. 参考书中Nor Flash的启动过程,因为代码可以直接在Nor Flash中运行,所以它会直接在Nor Flash中的copy_proc_beg 标号处直接运行 ,实现代码从加载域到运行域的搬移工作,之后会通过 b Main 跳转到Main函数中运行,执行到此处应该是已经到内存里执行了吧,但是b Main 是怎么实现从Nor Flash跳到内存中执行的?
5. 说这么多,我的困惑其实很简单,可执行代码一般存放于Flash中(掉电非易失,但不能直接运行代码或运行代码很慢),代码一般是在内存中执行的(内存运行速度快,读写速度快,但掉电易失)。这两者的结合使用才能构建一个可以正常启动的计算机系统,在ARM中,存储代码的就是Nand 或 Nor,运行代码的就是SDRAM,怎样从前者过度到后者实现系统正常启动的过程就是我所关注的焦点,希望得到详尽分析。

你这个问题有点多
1,4k代码存在,但是不执行,跳到内存之后就执行内存里面的异常向量表。其实这个是具体看芯片内核和bootloader的
2,先拷贝到芯片内部的sram里面执行,初始化好外部ram后拷贝到外部ram执行,有的bootloader还分两个部分,或者三个部分的呢

1. 异常向量表 是存储在 0地址 的8*4字节空间, 当发生某一种异常时,PC是被硬件置为 这8个的某一个地址,这个地址显然不是内存地址,为什么会到内存中去。
2. 对内部SRAM就是 那4KB的 Stepping Stone,上电后Nand中前4K 会被硬件电路自动复制到SRAM中,我的问题不在这,而是 原问题中提到的两个搬移。

异常向量表一样会在外部ram中有,但地址不是0了

不同的芯片会有不同的方案

这里讨论的是S3C2440

没人回答,我来谈谈自己的理解吧。
回答1:
源程序经过编译及汇编会生成可重定位目标文件,各个目标文件经过链接器会生成可执行目标文件,在可执行目标文件中,代码段和数据段的所有符号(函数和全局变量)都被分配一个唯一的内存地址。加载就是(根据可执行目标文件中的头信息)将只读存储段(包括代码段,只读数据段),读写数据段(包括已初始化的全局变量,未初始化的全局变量)拷贝到指定内存地址运行的过程。
在这里,加载过程是由启动代码中的copy_proc_beg 函数完成的,之后会跳到主函数去执行。这时异常向量表在起步石和内存中各有一份,起步石的异常向量表地址从0x0 开始,内存中的异常向量表由编译链接生成的地址确定。当发生中断时,比如IRQ中断,根据参考资料,CPU会自动将PC强制置为0x00000018,这个地址是起步石中异常向量表的地址而不是内存中的地址,由于在0x00000018处存放的是跳转指令,PC值会通过查表被置为相应中断服务函数的入口地址,注意这个中断服务函数的入口地址在内存中,所以又会跳到内存中去执行。
简单来说,就是当发生中断时,由于PC会被强制置为0x00000018,程序必须先跳到此处执行,即跳到起步石中(如果是Nor Flash启动则跳到Nor Flash中,Nor Flash的地址从0开始),再经过程序的处理会跳到内存中的中断服务函数执行。
个人理解,欢迎指正。

回答2:
加载域到运行域的搬移起始就是回答1所说的加载过程。在Linux系统中,参见《深入理解计算机系统》第7章或《链接器和加载器》第8章,加载是专门由加载器完成的,它将可执行文件中的代码和数据从磁盘拷贝到内存,然后跳转到程序的第一条指令或入口点来运行程序。
这里的过程其实就是加载过程,只不过不是由加载器完成而是由启动代码完成。
个人理解,欢迎指正。

回答3:
参考Nor Flash的启动过程,Nand 启动之所以需要起步石就是因为 Nand不能运行程序,所以Nand启动时,起步石的作用其实跟Nor Flash的作用一样,但由于起步石只有4KB大小,不能存储全部的程序代码,所以将所有代码搬到内存中存储,这就是第一个搬移,这个搬移的作用就是为加载作准备,(想想加载的过程,将代码从存储的地方搬移到内存中运行,起步石根本就没有存储全部的程序代码怎么实现加载),其实这时候这块内存起只是存储的作用;接下来就是加载了,就是第二次搬移,相信已经很清楚了;但是有个问题就是,两次搬移不会互相影响吗?这点我也不能确定,但我想编译器肯定会避免这种情况吧。
个人理解,欢迎指正。

回答4:
我想说这个问题问的很脑残。
在启动代码中不是都说了,会有个加载过程,加载就是从磁盘(这里可以用Nor Flash理解)将代码搬到内存去运行,先搬移,再跳转到内存,而B Main 这条指令就在加载代码之后。这个时候已经是在内存中执行了。
个人理解,欢迎指正。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top