001.1 - uboot启动 [ 第一阶段 ]

来源:互联网 发布:三明职业技术学院网络 编辑:程序博客网 时间:2024/06/03 15:29
cpu/arm920t/start.S
1. 设置中断向量表、跳转到 reset、设置处理SVC工作模式 
    
     >>  当一个异常产生时、CPU根据异常号、在异常向量表中找到对应的异常向量、
            然后执行异常向量处的跳转指令、CPU跳转到对应的异常处理程序执行
  

2. 设置寄存器地址
     >>  [ pWTCON、INTMOD\INTMSK、INTSUBMSK、CLKDIVN ]

          >>> CONFIG_S3C2410 -- BOARD/100ask24x0/100ask24x0.h

3. 关闭看门狗
   

4. 屏蔽中断
     >> [ INTMSK、INTSUBMSK ] 主中断屏蔽器、子中断屏蔽器
    
      >>  通过设置 [ INTMSK、INTSUBMSK ]、从而屏蔽所有中断
            1. INTMSK中的每一位对应 SRCPND(源中断未决寄存器) 中的一位
                表明 SRCPND 相应位代表的中断请求是否会被CPU处理
            2. INTSUBMSK中的每一位对应 SUBSRCPND中的一位
                表明 SUBSRCPND 相应位代表的中断请求是否会被CPU处理

5. 判断当前代码地址是否是在链接地址
    
     >>  __start - 当前代码首地址 SRAM = 0
            __TEXT_BASE  -  链接地址0x33F8 0000

     >>  如果一开始上电运行的话、程序是从Nand Copy To SRAM、起始地址_start = 0;
       如果程序是通过仿真器拷贝到SDRAM中的话、_TEXT_BASE - 链接地址

>>>  这两个不等的话、证明SDRAM还没有被初始化  <<<
          cpu_init_crit
          --> lowlevel_init
          --> 初始化存储控制器、初始化之后、内存才可以使用

6. 关闭mmu和cache
    
6. 初始化存储控制器
     >>  lowlevel_init设置了13个寄存器来对存储控制器进行初始化
     >>  lowlevel_init的作用是将 SMRDATA 开始的13个值复制给开始地址 [ BWSCON ] 的13个寄存器、从而完成存储控制器的设置

     >>  代码分析
     [ A ]. ldr r0, =SMRDATA
          获取SMRDATA的地址 - 链接后确定的地址
     [ B ]. ldr r1, =__TEXT_BASE
          获取_TEXT_BASE的值  - 链接重定位时的基地址0x33f80000
     [ C ]. sub r0, r0, r1
          获取启动时 SMRDATA在nand/nor中的绝对地址/偏移地址
          >>  r0-r1得到0xB10 ,这就是SMRDATA这个数据结构在uboot可执行文件中相对于零点的偏移量

          而这里初始化SDRAM时代码还在SRAM(对应nand启动)或nor(对应norflash启动)中
          标号都是重定位之后的地址,所以要通过上面的-TEXT_BASE的值来得到SMRDATA重定位之前在SRAM或是nor中的地址
 

     >>  ==============================================================
     >>  通过反汇编观察地址情况
          arm-linux-objdump –d lowlevel_init.o
          arm-linux-objdump –d uboot | grep lowlevel_init
          vi System.map

     >>>>  SMRDATA   : 0x33F8 0B10
                __TEXT_BASE:0X33F8 0000
     >>>>  SMRDATA = PC + 32
           就是lowlevel_init的入口地址(.text + 4)加8+32
>>>>   PC = PC + 8
     >>>>  ( lowlevel_init.o )_< .text > = 0x33f80ae4

     >> SMRDATA = ( low level_init.o )_< .text > + 4 + PC +32
     >> SMRDATA = lowlevel_init.o入口地址 + lowlevel的段内偏移地址
     + (执行 ldr r0, =SMRDATA)当前PC值 + 32
         

    

     >>  ==============================================================
     >> 链接
          因为代码链接时的重定位,所以SMRDATA的地址直接引用的话
          指向的将是他将来被加载到SDRAM后对应的地址  -  0x33F8 0B10

     >> 启动方式
          从NandFlash 启动的话,会将NandFlash开头的4K内容拷贝到SRAM中,其首地址是0x0
          从NorFLash 启动的话,0x0地址指向NorFLash
          不管从nand还是nor启动,总之uboot可执行档起初都是在零地址开始的空间内的
         

     >> 分析
          不管从nand还是nor启动,总之uboot可执行档起初都是在零地址开始的空间内的
          假设执行到了lowlevel_init里面,还是按照原来的地址去寻找SMRDATA的话,那肯定就找不到
          因为这个时候的代码是运行在SRAM(对应nand启动)或nor(对应norflash启动)中
          所以这里 [r0-r1] 得到的即是启动时 SMRDATA在nand/nor中的绝对地址
          从这个内存地址(这里的内存不是SDRAM,而是SRAM或者norflash)去寻址即可读出 SRMDATA数值
          应该去找0xB10这个地址才是正确的

          上面的[r0-r1]= 0xB10 = 2832 < 4K,可见这个安排nand/nor启动都是支持的
          如果启动部分比较大,SMRDATA的绝对地址(即相当于_start的地址)大于了4K,则这个代码就不能使用nand启动了
          因为nand启动时只能映射前4k代码到SRAM
          而nor启动则没有这个限制,因为nor启动在SDRAM运行代码前可支配的地址空间是0到norflash大小

7. 设置栈 -  为第二阶段的 C 语言做准备
    

8. 设置时钟
     /cpu/arm920t/start.S  -->  /board/100ask24x0/Boot_init.c
    
     
9. 把代码重定位到SDRAM中的链接地址

     >>  CopyCode2Ram()
          通过判断零地址是否可写、来确定启动方式、从而选择如果拷贝U-boot到SDRAM中
          /cpu/arm920t/start.S  -->  /board/100ask24x0/Boot_init.c


     >>  CopyCode2Ram() -- nandFlash拷贝


10. 清BSS段  -  为第二阶段的 C 语言做准备
  
     >>  BSS 段( bss segment)通常是用来存放程序中未初始化的全局变量和静态变量的一块内存区域
            BSS段属于静态内存分配
     >>  在编译时,编译器已经为他们分配好了空间,只不过值为 0,为了节省空间,在 bin 或 ELF 文件中不占空
            编译器会计算出_bss_start_bss_end的值,不是定义的(根据未初始化的全局变量的占用空间
            为了合理的使用内存,那么在最后编译出来的(可执行文件).bin文件中BSS段是不存在的
            uboot里的清除BSS段的代码,其实也是在为bss段分配空间
            BSS段默认值本来就是0了啊,正是这次清零操作的结果
     >>  变量  -  变量和局部变量
            局部变量是保留在栈中的,根据C语言规定,如果对局部变量不进行初始化,初始值是不确定的,在栈中位置也不固定
            全局变量有专门的数据段存储,且初始化值为0,且位置是固定的
     >>>>  综上,数据分为俩种
                 位置固定(全局,数据段)
                 位置不固定(局部-栈里)
     >>>> 其实,数据段里的这么多全局变量都初始化为0存在目标文件中是没有必要的,增大了存储空间使用
               所以就把数据段里边数据,也即未初始化全局变量存放到了BSS段里边
               当有目标文件被载入的时候,清除bss段,将全局变量和静态变量清0


     >> 参考网页  < http://www.xuebuyuan.com/754807.html >
     >>>  1、既然BSS段在最终编译出来的文件中是不存在的,那么,BSS还有什么作用呢?
                    因为在程序编译链接后,在指令代码中会指令访问未初始化全局、静态变量的地址
                    而在编译链接的时候,所以对应BSS段的地址还是会分配给这些变量
                    而BSS的作用就在于给出start_bss和end_bss这个地址
     >>>  2、BSS既然被砍掉了,那么怎么从程序中获取start_bss和end_bss这两个地址?
                    还是一样,程序在编译的时候,会指定两个地址的
                    所以即使没有了BSS,这两个地址在编译的时候就已经形成到机器代码中
                    换句话说,是先编译程序,然后砍BSS
     >>>  3、为什么要用程序对BSS进行清零?
                    承上所述,BSS在编译出bin文件的后是被砍掉了的
                    那么,程序烧到存储器中后,对应的BSS那段内存中的内容就是未知的
                    所以我们必须的人为的把它清零
 
11. 跳入第二阶段的 C 语言代码入口  -  _start_armboot(已经被重定向到内存)
     /cpu/arm920t/start.S  -->  /lib_arm/Board.c - start_armboot()
     
0 0