Uboot的一些基础知识 .(有用)

1. 下面代码是系统启动后U-boot上电后运行的第一段代码,他是 什么意思?
.globl _start
_start:      b           reset
      ldr      pc, _undefined_instruction
      ldr      pc, _software_interrupt
      ldr      pc, _prefetch_abort
      ldr      pc, _data_abort
      ldr      pc, _not_used
      ldr      pc, _irq
      ldr      pc, _fiq

_undefined_instruction     .word undefined_instruction
_software_interrupt:      .word software_interrupt
_prefetch_abort:      .word prefetch_abort
_data_abort:              .word data_abort
_not_used:              .word not_u sed
_irq:                    .word irq
_fiq:                    .word fiq
      .balignl 16,0xdeadbeef
他们是系统定义的异常,一 上电程序跳转到re set异常处执行相应 汇编指令 下面定义出的都是不同的异 常, 比如软件发生软中断时 ,CPU就会去执行软中断的指令 ,这些异常中断在CUP中地址是从0开始 ,每 个异常占4个字节。
reset:
    
      mrs      r0,cpsr
      bic      r0,r0,#0x1f
      orr      r0,r0,#0xd3
      msr      cpsr,r0
操作系统先注册一个总的中断,然后去查是由哪个中断源产生的中断 ,再去查用户注册的中断表,查出来后就去执行用户定义的用户中断处理函数。

ldr      pc, _undefined_instruction表示把_undefined_instruction存放的数值存放到pc指针上,_undefined_instruction:      .word undefined_instruction表示未定义的这个异常是由.word来定义的,它表示定义一个字,一个32位的数,.word后面的数表示把该标识的编译地址写入当前地址,标识是不占用任何指令的。把标识存放的数值copy到指针pc上面,那么标识上存放的值是什么?是由.word undefined_instruction来指定的,pc就代表你运行代码的地址,她就实现了CPU要做一次跳转时的工作。

什么是编译地址?什么是运行地址?
32位的处理器,它的每一条指令是4个字 ,以4个字节存 储顺序,进行顺序执行,CPU是顺序执行的 ,只要没发生什么跳转,它会顺序进行执行,编译器会对 每一条指令分配一个编译地址 ,这是编译器分配的,在编译过程中分配的地址,我们称之为编译地址。
运行地址是指,程序指令真正运 行的地址, 是由用户指定的 ,用户将运行地址烧录到哪里 ,哪里就是运行的地址。比如有一个指令的编译地址是0 x5,实 际运行的地址是0x200 ,如果用户将指令烧到0x200上 ,那么这条指令的运行地址就是0x200,当编译地址和 运行地址不同的时候会出现什么结果 ?结果是不能跳转,编译后会产生跳转地址,如果实际地址和编译后产生的地址不相等, 那么就不能跳转。C语言编译地址都希望把编译地址和 实际运行地址放在一起的,但是汇编代码因为不需要 做C语言到汇编的转换, 可以认为的去 写地址, 所以直接写的就是他的运行地址,这就是为什么任何bootload er刚开始会 有一段汇编代码,因为起始代码 编译地址和 实际地址不相等,这段代码和汇编无关,跳 转用的运行地址。 编译地址和运行地址如何来算呢? 假如有两个编译地址a=0x10,b=0x7,b的运行 地址是0x300,那么 a的运行地址就是b的运行 地址加上两者编译地址 的差值,a-b=0x10-0x7=0x3,a的运行地址就是0x300+0x3= 0x303。
假设uboot上两条指令的编译地址为a=0x3 3000007和b=0x330 00001,这两 条指令都落在bank6上,现在要计算出他们对应的运行地址,要找出运行地址的始地址,这个是由用户 烧录进去的,假设运行地址的首地址 是0x0,则a的运行地址
为0x7,b为0x1,就是这样算出来的。

为什么要分配编译地址?这样做有什么好处,有什么作用?
比如在函数a中定义了函数b ,当执 行到函数b时要进行指令跳转 ,要跳转到b函数所对应的起始地址上去 ,编译时,编译器给每条指令都分配了编译地址 ,如果编译器已经给分配 了地址 就可以直接进行跳转,查 找b函数跳转指令所对应的表,进行直接跳转,因为有个编译地址和指令对应的一个表,如果没有分配,编译器就 查找不到这个跳转地址,要进行计算,非常麻烦。

什么是相对地址?
以NOR Flash为例,NOR Falsh是映射到bank0上面,SDRAM是映射到bank6上面,uboot和内核最终 是在SDRAM上面运行,最开始我们是从Nor Flash的零地址 开始 后烧录,ubo ot中至少有一段代码 译地址和 运行地址是不一样的,编译uboot或内核时,都会将编译地址放 入到SDRAM中, 他们 最终都 会在SDRAM中执行,刚开始uboot Nor Flash中运行,运行地址是一个低端地址, 是bank0中的一个地址, 但编译地址是bank6中的地址,这样就会导致 绝对跳转指令执行的失败,所以就引出了相对地址的概念。那么什么是相对地址 呢?至少在 bank0中uboot这段代码要知道不能用b+编译地址这样的方法去跳转指令,因为 这段代码的编译地址和运行地址不一样,那如何去做呢?要去计算这个指令运行的真实地址,计算出来后再做跳转,应 该是b+运行 地址, 不能 出现b+编译地址,而是b+运行地址,而运行地址是算出来的。

_TEXT_BASE:
     .word      TEXT_BASE    //0x33F80000,在board/config.mk中
这段话表示,用户告诉编译器编译地址的起始地址

Uboot启动流程
1.      设置CPU的启动模式
reset:
//设置CPU进入管理模式 即设置 相应的CPSR程序状态字
    
      mrs      r0,cpsr
      bic      r0,r0,#0x1f
      orr      r0,r0,#0xd3
      msr      cpsr,r0
2.      关闭看门狗,关闭中断,所谓 的喂狗是每隔一段时 间给某个寄存器置位而已 ,在实际中会专门启动一个线程或进程会专门喂狗,当上层软件出现故障时就会停止喂狗,停止喂狗之后,cpu会自动复位,一般都在外部专门有一个看门狗,做一个外部的电路,不在cpu内部使用看门狗,cpu内部的看门狗是复位的cpu,当开发板很复杂时,有好几个cpu时,就不能完全让板子复位,但我们通常都让整个板子复位。 看门狗每隔短时间就会喂狗,问题是在两次喂狗之间的时间间隔内,运行 的代 码的时间是否够用,两次 喂狗之间的代码是否在 两次喂狗的时间延迟之内,如果在延迟之外的话,代码还没改完就又进行喂狗,代码永远也改不 完。
//关闭看门狗的实际代码
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
      ldr         r0, =pWTCON //将pwtcon寄存器地址赋给R0
      mov         r1, #0x0 //r1的内容为0
      str         r1, [r0]    //将R1的内容送到Ro寄存器中去

3. 屏蔽所有中断,为什么要关中断?中 断处理 中ldr p c是将代码的 编译地址放在了指针上 ,而这段时间还没有搬移代码,所以编译地址上面没有这个代码,如果进行跳转就会跳转到空指针上面
    
      mov      r1, #0xffffffff    //寄存器中的值全为111111111111111111111111 11111111
      ldr      r0, =INTMSK     //将管理中断的寄存器地址赋给ro
      str      r1, [r0]          //将 全1的值赋给ro地址中的内容
#if defined(CONFIG_S3C2410)
      ldr      r1, =0x3ff
      ldr      r0, =INTSUBMSK
      str      r1, [r0]
#endif

3.      设置时钟分频,为什么要设置时钟?起始可以不设,系统能不能跑起来和频率没有任何关系,频率的设置是要让外围的设备能承受所设置的频率,如果频率过高则会导致cpu操作外围设备失败
//设置CPU的频率
    
    
      ldr      r0, =CLKDIVN
      mov      r1, #3
      str      r1, [r0]

4. 做bank的设置
cpu_init_crit:

    
      mov      r0, #0
      mcr      p15, 0, r0, c7, c7, 0    
      mcr      p15, 0, r0, c8, c7, 0      //协处理器

//禁止MMU
    
      mrc      p15, 0, r0, c1, c0, 0
      bic      r0, r0, #0x00002300      @ clear bits 13, 9:8 (--V- --RS)
      bic      r0, r0, #0x00000087      @ clear bits 7, 2:0 (B--- -CAM)
      orr      r0, r0, #0x00000002      @ set bit 2 (A) Align
      orr      r0, r0, #0x00001000      @ set bit 12 (I) I-Cache
      mcr      p15, 0, r0, c1, c0, 0    //关闭
为什么要关闭catch和MMU呢?catch和MMU是做什么用的?
Catch是cpu内部的一个2级缓存,她的作用是将常用的数据和指令放在cpu内部,MMU是用来做虚实地址转换用的,我们的目的是设置控制的寄存器,寄存器都是实地址,如果既要开启MMU又要做虚实地址转换的话,中间还多一步,
先要把实地址转换成虚地址,然后再做设置,但对uboot而言就是起到一个简单的初始化的作用和引导操作系统,如果开启MMU的话,很麻烦,也没必要,所以关闭MMU.
      说道catch就必须提到一个关键字Volatile,以后在设置寄存器时会经常遇到,他的本质是告诉编译器不要对我的代码进行优化,优化的过程是将常用的代码取出来放到catch中,它 没有从实际的物理地址去取,它直接从cpu的缓存中去取,但常用的代码就是为了感知一些常用变量的变化,如果正在取数据的时候发生跳变,那么就感觉不到变量的变化了,所以在这种情况下要用Volatile关键字告 诉编译器不要做优化,每次从实际的物理地址中去取指令,这就是为什么关闭catch关闭MMU。但在C 语言中是不会关闭catch和MMU的,会打开,如果编写者要感知外界变化,或变化太快,从catch中取数据会有误差,就加一个关键字Volatile。

5. bl      lowlevel_init下来初始化各个bank,把各个bank设置必须搞清楚,对以后移植复杂的uboot有很大帮助
6.设置完毕后拷贝uboot代码到4k空间 ,拷贝完毕后执行内存中的uboot代码
以上流程基本上适用于所有的bootloader,这就 是step1阶段
7. 问题:如果换一块开发板有可能改哪些东西?
     首先,cpu的运行模式,如 果需要对cpu进行设置那就 设置 ,管看门狗,关中断不用改,时钟有可能要改,如果能正常使用则不用改,关闭catch和MMU不用改,设置bank有可能要改。最后一步拷贝 时看地址会不会变,如果变化也要改,执行内存中代码,地址有可能要改。
8. Nor Flash和Nand Flash 区别 就在 于是否 代码拷贝,也 是下面代码所表 无论是Nor Flash还是Nand Flash,核心思想就是将uboot代码搬 到内 中去运 没有拷贝bss后面这段代码 只拷贝bss前面的代码,bss代码是放置全局变量的 。Bss段代码 是为了清零,拷 贝过去再清零 重复 操作
//uboot代码搬运到RAM中
#ifndef CONFIG_SKIP_RELOCATE_UB OOT
relocate:                        
      adr      r0, _start             
      ldr      r1, _TEXT_BASE             
      cmp         r0, r1                             
      beq         stack_setup

      ldr      r2, _armboot_start    //flash中armboot_start的起始地址
      ldr      r3, _bss_start    //uboot_bss的起始地址
      sub      r2, r3, r2             
      add      r2, r0, r2             

copy_loop:
      ldmia      r0!, {r3-r10}             
      stmia      r1!, {r3-r10}             
      cmp      r0, r2                   
      ble      copy_loop
#endif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值