S3C6410之uboot回爐再造(2)地址無關性


   這一篇寫得有點慢,期間為了弄清楚一些細節的問題耽擱了,不過寫得也會更詳細。

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
//提供附加信息比如寄存器的版本號或者訪問類型,用於區分同一個編號的不同物理寄存器
//可以省略
 <opcode_2> 或者將其 設置為 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還是留在下一篇討論了。

 

 
          

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM