S3C6410之uboot回炉再造(2)地址无关性

发布时间:2024-09-19  

这一篇写得有点慢,期间为了弄清楚一些细节的问题耽搁了,不过写得也会更详细。


1 /*

2  *************************************************************************

3  *

4  * CPU_init_critical registers

5  *

6  * setup important registers

7  * setup memory timing

8  *

9  *************************************************************************

10  */

11     /*

12      * we do sys-critical inits only at reboot,

13      * not when booting from ram!

14      */

15 cpu_init_crit:

16     /*

17      * When booting from NAND - it has definitely been a reset, so, no need

18      * to flush caches and disable the MMU

19      */

20 #ifndef CONFIG_NAND_SPL

21     /*

22      * flush v4 I/D caches

23      */

24     mov    r0, #0    //清零 r0 寄存器,以下的3个协处理器操作稍后详解

25     mcr    p15, 0, r0, c7, c7, 0    /* flush v3/v4 cache */

26     mcr    p15, 0, r0, c8, c7, 0    /* flush v4 TLB */

27 

28     /*

29      * disable MMU stuff and caches

30      */

31     mrc    p15, 0, r0, c1, c0, 0

32     bic    r0, r0, #0x00002300    @ clear bits 13, 9:8 (--V- --RS)

33     bic    r0, r0, #0x00000087    @ clear bits 7, 2:0 (B--- -CAM)

34     orr    r0, r0, #0x00000002    @ set bit 2 (A) Align

35     orr    r0, r0, #0x00001000    @ set bit 12 (I) I-Cache

/* ------------------------------------------------------------------------ */

36     /* Prepare to disable the MMU */

37     adr    r1, mmu_disable_phys  //取 mmu_... 的地址放入,即55行的地址

38     /* We presume we're within the first 1024 bytes */

39     and    r1, r1, #0x3fc      //仅保留 [9:2] 位

40     ldr    r2, _TEXT_PHY_BASE   //_TEXT_PHY_BASE --> CONFIG_SYS_UBOOT_BASE

                      //上一篇已经分析过它可能的两种取址了

    //这里出现了一个问题:SDRAM是在lowlevel_init中初始化的,那此时的程序运行在哪呢?

    //稍后解答~、~

41     ldr    r3, =0xfff00000                          

42     and    r2, r2, r3        //仅保留 [32:20] 位,即保存下不同取取址的首地址

43     orr    r2, r2, r1        //取或之后,寄存器已经包含两部分内容了:

44     b    mmu_disable         //r2中为 首地址 + 偏移地址(mmu_diable_phys)

                      //从最终实现上看,这段代码是无意义的操作

/* ------------------------------------------------------------------------- */

45 

46     .align 5  //这里的 .align 是按 2^5 = 32 对齐,此处即 4个字节   

           //有别于.lds文件中的ALIGN(4), lds文件中的 4 即为 4个字节的意思       

47     /* Run in a single cache-line */

48 mmu_disable:             

49     mcr    p15, 0, r0, c1, c0, 0  //协处理器,稍后一起讲

50     nop

51     nop

52     mov    pc, r2          

53 #endif

54 

55 mmu_disable_phys:          

56     /* Peri port setup */

57     ldr    r0, =0x70000000

58     orr    r0, r0, #0x13      //下面还是协处理器,下面依次讲完他们的功能

59     mcr    p15,0,r0,c15,c2,4       @ 256M (0x70000000 - 0x7fffffff)

60 

61     /*

62      * Go setup Memory and board specific bits prior to relocation.

63      */

64     bl    lowlevel_init        /* go setup pll,mux,memory */


  1、首先,协处理器的简介内容,可以参阅如下网站


http://blog.csdn.net/genglei1022/article/details/5712843

  接着回到我们的代码段,要了解协处理器,先了解两个指令


MCR{cond}    coproc, opcode1, Rd, CRn, CRm{, opcode2}

MRC{cond}    coproc, opcode1, Rd, CRn, CRm{, opcode2}

//其中

//coproc(essor) 为协处理器,标准名为 pn, n = 1 ~ 15 对应 CPn

//opcode1 为协处理器行为操作码,永远为 0, 否则协处理器状态不确定

//Rd ARM的寄存器, CRn 目标寄存器, CRm 附加寄存器,不使用则设为 c0

//提供附加信息比如寄存器的版本号或者访问类型,用于区分同一个编号的不同物理寄存器

//可以省略 或者将其 设置为 0,否则结果未知


  接着是协处理器。


   CP15 是系统控制协处理器寄存器,用于连接在内存中的页表描述符,此外还用于决定对MMU的操作。


  此处最先遇到的是两个MCR:


24     mov    r0, #0    //清零 r0 寄存器

//Move to Coprocessor frem Register , MCR的含义,下面一句相仿

25     mcr    p15, 0, r0, c7, c7, 0    /* flush v3/v4 cache */

26     mcr    p15, 0, r0, c8, c7, 0    /* flush v4 TLB */

  此处出现了两个寄存器 c7, c8


寄存器编号      基本作用            MMU中的作用

  c7    控制cache和写缓存          同左

  c8     存储保护和控制          TLB 控制

  这里贡献一个强大的网站,详细地介绍了芯片的各个部分


http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0301h/ch03s02s01.html

  然后说一下怎么查阅到相关寄存的信息:


  1、找到芯片,这里我用的是 ARM1176-JZF-S


  2、现在要找的是协处理器单元 System Control Coprocessor


  3、当前要找的是协处理器的寄存器 System control processor registers


  4、最后可以在 Register allocation 中查阅寄存器总表


  5、若想了解某一个寄存器的实际功用,比如此处我们的寄存器操作位


25     mcr    p15, 0, r0, c7, c7, 0    /* flush v3/v4 cache */

  那么我们找的就应该是


CRn    Op1    CRm    Op2    Register or operation

c7     0      c7     0     Invalidate Both Caches

  在此行中其实就有我们想了解的协处理器操作的信息,若想进一步了解,点击行末链接。


  在此摘录一段 c7 的功能


The purpose of c7 is to:

  control these operations:

    clean and invalidate instruction and data caches, including range operations

    prefetch instruction cache line

    Flush Prefetch Buffer

    flush branch target address cache

  virtual to physical address translation.

  implement the Data Synchronization Barrier (DSB) operation

  implement the Data Memory Barrier (DMB) operation

  implement the Wait For Interrupt clock control function.


  看得懂英文的童鞋应该明白了


  25行的意思是清空和禁用 指令和数据高速缓存,和后面的注释意思相同。


  26行的意思是禁用TLB。


31     mrc    p15, 0, r0, c1, c0, 0

//Read Control Register configuration data


49     mcr    p15, 0, r0, c1, c0, 0

//Write Control Register configuration data


59     mcr    p15,0,r0,c15,c2,4

//Peripheral Port Memory Remap


  此后,在代码段中,不详细解释每个汇编指令的实现了,而是按模块进行讲解。


  但是一些难点的地方还是会仔细分析的。


  2、SDRAM初始化前的代码运行


  要了解代码的运行情况,首先得了解ARM的片上存储系统。


  在此以XIP(eXecute In Place, 内执行)的标准来区分:


  支持XIP:NOR flash, mDDR(mobile DDR);


  不支持XIP:NAND flash。


  而速度快慢来说 NOR flash > mDDR > NAND flash。


  了解了这些,再联系开发板来细分有:


  NOR flash作为内执行运存,负责系统最开始的初始化代码执行(例如 start.o);


  mDDR作为常规运存,即SDRAM,是代码的主要运行环境;


  NAND flash作为存储设备,可以视为我们PC上的硬盘。


 


  在此就很容易理解了,SDRAM是在lowlevel_init中初始化的,在SDRAM初始化之前,代码执行在NOR flash中。


 


  接着来解决刚才留下的初始化顺序的问题:


40     ldr    r2, _TEXT_PHY_BASE

  在这一句中,_TEXT_PHY_BASE究竟存的是什么。


  我们先来反汇编看一下


arm-linux-objdump -D -S -t start.o

//加入 -t 可以看到代码段的段标的位置


00000044 <_TEXT_PHY_BASE>:

  44:    57e00000     .word    0x57e00000

...

    ldr    r2, _TEXT_PHY_BASE

  8c:    e51f2050     ldr    r2, [pc, #-80]    ; 44 <_TEXT_PHY_BASE>


  很显然,这里的_TEXT_PHY_BASE就是0x57e00000了!


  但是咱们细想一下,lowlevel_init还在后面,SDRAM还没有初始化!


  所以我们是无法调用这个地址的,可是这里明明看到了。


  眼睛看到的、不一定是真实的。


  这里引入一个新概念来解释这个问题:运行地址无关性。


  首先是参详地:


http://blog.sina.com.cn/s/blog_4a9fb5cf01008d8u.html~type=v5_one&label=rela_nextarticle

  只需要看最后面的内容就行了。


 


  作为运行代码,无论是 bootloader 还是 kernel 的初始化代码,总会有一段乏力期:代码太长、空间太短。


  在 uboot 中表现为 SDRAM 初始化之前,在 kernel 中表现为 MMU 使能前。


  在这个乏力期,代码的寻址空间是很有限的,而在编译过程中预定的位置就可能导致寻址出错。


  所以地址无关性的需求就出现了,集中表现为需要这段代码寻址范围限于我们的 NOR flash,且不破坏代码执行。


  此时,我们从本质上理解一下这里的 0x57e00000


00000044 <_TEXT_PHY_BASE>:

  44:    57e00000     .word    0x57e00000

...

    ldr    r2, _TEXT_PHY_BASE

  8c:    e51f2050     ldr    r2, [pc, #-80]    ; 44 <_TEXT_PHY_BASE>

  倘若,我们的SDRAM已经使能,那么这个地址实际上是 uboot.bin 安放的起始地址。  


  但是,此时的 uboot.bin 安放在了 NOR flash 中, 那么此时的起始地应该为 0x00000000。


  按此逻辑往下推导,结果是正确地,那一段代码的执行是 “可有可无” 的,这也是为什么很多人在修改这段代码的时候选择删去。


  当然,这个 0x00000000 只是我的理解,欢迎讨论。


  lowlevel_init还是留在下一篇讨论了。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>