1. 程式人生 > >U-boot 開始檔案Start.s的異常向量表CONFIG_SPL_BUILD巨集及VBAR地址對映

U-boot 開始檔案Start.s的異常向量表CONFIG_SPL_BUILD巨集及VBAR地址對映

#include <asm-offsets.h>          /* 標頭檔案在根目錄下的include及根
#include <config.h>             目錄下的arch/arm/include目錄 */ 
#include <version.h>
#include <asm/system.h>
#include <linux/linkage.h>

.globl _start
_start: b   reset //跳轉到reset 進行地址判斷,設定SVC模式
    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                    //快中斷
#ifdef CONFIG_SPL_BUILD
_undefined_instruction: .word _undefined_instruction
_software_interrupt:    .word _software_interrupt
_prefetch_abort:    .word _prefetch_abort
_data_abort:        .word _data_abort
_not_used:      .word _not_used
_irq:           .word _irq
_fiq:           .word _fiq
_pad:           .word 0x12345678 /* now 16*4=64 */
#else
_undefined_instruction: .word undefined_instruction
_software_interrupt:    .word software_interrupt
_prefetch_abort:    .word prefetch_abort
_data_abort:        .word data_abort
_not_used:      .word not_used
_irq:           .word irq
_fiq:           .word fiq
_pad:           .word 0x12345678 /* now 16*4=64 */
#endif  /* CONFIG_SPL_BUILD */

.global _end_vect
_end_vect:

    .balignl 16,0xdeadbeef
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
CONFIG_SPL_BUILD巨集

我們可以看到異常向量表有兩個定義,多了巨集:#ifdef CONFIG_SPL_BUILD 
什麼是SPL呢,我們需要從啟動機制說起: 
以S3C6410為例: 
1、將uboot.bin前4K拷貝到片內記憶體SRAM中,進行初始化記憶體SDRAM 
2、將uboot.bin的內容約為200k全部拷貝到SDRAM中,PC指標跳轉到SDRAM開始執行(前4K內容會判斷自身在哪個記憶體當中,判斷在SDRAM中則直接跳過前4K到後續部分進行執行。) 
3、將核心載入到SDRAM中執行。

有了這種情況,隨著廠家處理器改進:增加了片內記憶體的大小約為96K左右,希望整個Uboot.bin全部在片內記憶體進行執行,然後把核心載入到片外記憶體SDRAM中執行。 
但是呢,uboot整體編譯出來至少100K-200K,這樣就造成了沒法執行上述方案,於是Uboot作者就把uboot設定成2個部分: 
ubootspl.bin (16K)和 uboot.bin (210K) 
ubootspl.bin放到片內SRAM執行,進行初始化記憶體,將uboot.bin拷貝到外存SDRAM中執行,然後PC指標直接跳轉到SDRAM中進行執行。 
這就是#ifdef CONFIG_SPL_BUILD 巨集的由來。

異常向量的地址對映問題

根據ARM的手冊我們知道,異常向量地址的入口為0x00000000或者0xffff0000然而片內記憶體中開始地址0x00000000為ROM區,開始地址不可寫,處理器廠家知道這樣設計有些問題,所以在片內記憶體開闢了一塊新的區域專門用於放置異常向量表。這樣做話我們就需要將異常向量表的地址重新定位到廠家的那塊記憶體。 
上述是uboot在片內記憶體中,如果是在SD卡執行,且啟用了MMU,這時候就很麻煩,RAM公司也考慮到了這種情況,所以在CP15協處理器中設計了一個叫VBAR的暫存器,我們將異常向量表的地址放到VBAR暫存器,那麼發生異常以後ARM處理器會自動的從VBAR暫存器尋到異常向量表的地址,跳轉到該處進行執行。

uboot編譯以後的檔案

 
綠顏色的uboot 檔案:是所有.o檔案連結後的檔案,很大約有900K,裡面包含了很多的除錯資訊和註釋資訊,是不能放到板子裡執行的,是用來除錯的檔案。(elf格式的image) 
uboot.bin是uboot檔案剝離掉除錯資訊和註釋資訊的檔案,可以放置到板子中執行。(原始二進位制檔案(raw image)) 
uboot.map (符號表) 
uboot.srec ( S-Record格式的image) 
uboot.lds (uboot的連結指令碼檔案) 
uboot.16K(ubootspl-16K 檔案)

檢視uboot反彙編指令:
  arm-linux-objdump -S u-boot | less
1
2
_pad:           .word 0x12345678 /* now 16*4=64 */
#endif  /* CONFIG_SPL_BUILD */

.global _end_vect
_end_vect:

    .balignl 16,0xdeadbeef
1
2
3
4
5
6
7
這段_pad標識佔位 
.global _end_vect 標識異常向量表結束 
.balignl 16,0xdeadbeef 標識如果沒有16位元組對齊就填充0xdeadbeef 直到填充到下個標號16位元組對齊為止。

利用cp15協處理器設定異常向量表地址

#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
    /* Set V=0 in CP15 SCTRL register - for VBAR to point to vector */
    mrc p15, 0, r0, c1, c0, 0   @ Read CP15 SCTRL Register
    bic r0, #CR_V       @ V = 0
    mcr p15, 0, r0, c1, c0, 0   @ Write CP15 SCTRL Register

    /* Set vector address in CP15 VBAR register */
    ldr r0, =_start
    mcr p15, 0, r0, c12, c0, 0  @Set VBAR
#endif
1
2
3
4
5
6
7
8
9
10
1、將cp15 SCTRL暫存器讀出來 
2、清零第13位(#CR_V在arch/arm/include/asm/system.h中定義 是1<<13bit) 
3、寫會SCTRL暫存器 
該位意思是中斷異常地址設定0x00000000,選擇1是對映到0xffff0000 
4、將異常向量表實際執行的地址放入r0 
5、將r0的內容寫入VBAR暫存器

VBAR暫存器:如果中斷向量表的地址沒有被對映到0xffff0000的話,有一種更好的方法,可以使用該暫存器將中斷向量表的地址對映到任何地址。
--------------------- 
作者:曦饒 
來源:CSDN 
原文:https://blog.csdn.net/q980655156/article/details/80157707 
版權宣告:本文為博主原創文章,轉載請附上博文連結!