1. 程式人生 > >自己學驅動8——uboot程式碼閱讀三(start.S)

自己學驅動8——uboot程式碼閱讀三(start.S)

    /* Set up the stack                            */
stack_setup:
    ldr    r0, _TEXT_BASE        /* upper 128 KiB: relocated uboot   */
    sub    r0, r0, #CFG_MALLOC_LEN    /* malloc area                      */
    sub    r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
#ifdef CONFIG_USE_IRQ
    sub    r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
    sub    sp, r0, #12        /* leave 3 words for abort-stack    */

clear_bss:
    ldr    r0, _bss_start        /* find start of bss segment        */
    ldr    r1, _bss_end        /* stop here                        */
    mov     r2, #0x00000000        /* clear                            */

clbss_l:str    r2, [r0]        /* clear loop...                    */
    add    r0, r0, #4
    cmp    r0, r1
    ble    clbss_l
    這一段程式碼的功能是設定棧和清零.bss段。從程式碼中也可以看出,程式碼段是在高地址處,程式碼段前面是堆(也就是給動態記憶體分配預留的空間)。CFG_GBL_DATA_SIZE在config檔案中定義,start.S中會根據這個值分配棧空間用於儲存board的有關資訊。bdinfo之前的就是IRQ和FIQ的棧空間,當然這個是否分配是取決於是否定義了CONFIG_USE_IRQ這個巨集。後面緊跟著的一條語句
sub    sp, r0, #1
    這裡沒有直接將r0的值賦值給棧指標sp,而是將r0-12的值賦值給了sp,當然必須清楚的一點是這裡的棧是向下增長的,也就是相當於sp會從當前的地址往地址更小的地方生長。這裡留出來的這多餘的12個位元組是為了給FIQ或者IRQ中斷棧預留的空間(防止其棧溢位而破壞sp棧中的資料)。
    後面的程式碼是用了一段迴圈來將.bss段全部清零,因為邏輯比較清晰,也就不再贅述了。

    ldr    pc, _start_armboot

_start_armboot:    .word start_armboot
    這是比較關鍵的一個地方,因為程式執行到這裡,將會跳轉到到C語言部分去執行。這個start_armboot函式的路徑為lib_arm\Board.c。

cpu_init_crit:
    /*
     * flush v4 I/D caches
     */
    mov    r0, #0
    mcr    p15, 0, r0, c7, c7, 0    /* flush v3/v4 cache */
    mcr    p15, 0, r0, c8, c7, 0    /* flush v4 TLB */

    /*
     * disable MMU stuff and caches
     */
    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

    /*
     * before relocating, we have to setup RAM timing
     * because memory timing is board-dependend, you will
     * find a lowlevel_init.S in your board directory.
     */
    mov    ip, lr
    bl    lowlevel_init
    mov    lr, ip
    mov    pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
    程式mov    r0, #0開始的這三行重新整理cache和TLB。cache是一種快取記憶體儲存器,用於儲存CPU頻繁使用的資料。在使用Cache技術的處理器上,當一條指令要訪問記憶體的資料時,首先查詢cache快取中是否有資料以及資料是否過期,如果資料未過期則從cache讀出資料。處理器會定期回寫cache中的資料到記憶體。根據程式的區域性性原理,使用cache後可以大大加快處理器訪問記憶體資料的速度。
    TLB的作用是在處理器訪問記憶體資料的時候做地址轉換。TLB的全稱是Translation Lookaside Buffer,可以翻譯做旁路緩衝。TLB中存放了一些頁表文件,檔案中記錄了虛擬地址和實體地址的對映關係。當應用程式訪問一個虛擬地址的時候,會從TLB中查詢出對應的實體地址,然後訪問實體地址。TLB通常是一個分層結構,使用與Cache類似的原理。處理器使用一定的演算法把最常用的頁表放在最先訪問的層次。提示:ARM處理器Cache和TLB的配置暫存器可以參考ARM體系結構手冊。
    程式以mrc    p15, 0, r0, c1, c0, 0開始的這6行關閉MMU。MMU是記憶體管理單元(Memory Management Unit)的縮寫。在現代計算機體系結構上,MMU被廣泛應用。使用MMU技術可以嚮應用程式提供一個巨大的虛擬地址空間。在U-Boot初始化的時候,程式看到的地址都是實體地址,無須使用MMU。
    程式bl    lowlevel_init跳轉到lowlevel_init標號,執行與開發板相關的初始化配置。需要注意的是bl是一個會返回的跳轉,程式執行完與開發板相關的操作之後會跳轉回來繼續往下執行。
mov    ip, lr
bl    lowlevel_init
mov    lr, ip
mov    pc, lr
    ip是r12暫存器的別名,它在過程連結膠合程式碼(例如,互動操作膠合程式碼)中用於此角色。在過程呼叫之間,可以將它用於任何用途。被呼叫函式在返回之前不必恢復r12。
    r14是連結暫存器lr。如果您儲存了返回地址,則可以在呼叫之間將 r14 用於其它用途,程式返回時要恢復。
    這一段程式碼需要說明的是,相當於在子程式內部還要呼叫一個子程式,但是這裡是彙編程式碼,第一次被呼叫的子程式(也就是cpu_init_crit這個標號)時返回地址被硬體自動的儲存在了lr暫存器中,但是當在cpu_init_crit還要呼叫一個子程式的時候這是lr會被重新賦值,那麼以前的lr的值就丟了!所以程式在這裡用了ip來儲存lr最開始的值,子程式內部的子程式呼叫結束後再將其復原回來,這樣通過mov pc, lr就可以返回最初的呼叫點後面繼續執行了。

#define S_FRAME_SIZE    72

#define S_OLD_R0    68
#define S_PSR        64
#define S_PC        60
#define S_LR        56
#define S_SP        52

#define S_IP        48
#define S_FP        44
#define S_R10        40
#define S_R9        36
#define S_R8        32
#define S_R7        28
#define S_R6        24
#define S_R5        20
#define S_R4        16
#define S_R3        12
#define S_R2        8
#define S_R1        4
#define S_R0        0
    這一部分巨集看起來很讓人迷惑,感覺像是定義的地址。其實這就是pt_regs結構體的偏移值,該結構體定義在include\asm-arm\proc-armv\ptrace.h中。

/*
 * use bad_save_user_regs for abort/prefetch/undef/swi ...
 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
 */

    .macro    bad_save_user_regs
    sub    sp, sp, #S_FRAME_SIZE
    stmia    sp, {r0 - r12}            @ Calling r0-r12
    ldr    r2, _armboot_start
    sub    r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
    sub    r2, r2, #(CFG_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack
    ldmia    r2, {r2 - r3}            @ get pc, cpsr
    add    r0, sp, #S_FRAME_SIZE        @ restore sp_SVC

    add    r5, sp, #S_SP
    mov    r1, lr
    stmia    r5, {r0 - r3}            @ save sp_SVC, lr_SVC, pc, cpsr
    mov    r0, sp
    .endm

    .macro    irq_save_user_regs
    sub    sp, sp, #S_FRAME_SIZE
    stmia    sp, {r0 - r12}            @ Calling r0-r12
    add     r8, sp, #S_PC
    stmdb   r8, {sp, lr}^                   @ Calling SP, LR
    str     lr, [r8, #0]                    @ Save calling PC
    mrs     r6, spsr
    str     r6, [r8, #4]                    @ Save CPSR
    str     r0, [r8, #8]                    @ Save OLD_R0
    mov    r0, sp
    .endm

    .macro    irq_restore_user_regs
    ldmia    sp, {r0 - lr}^            @ Calling r0 - lr
    mov    r0, r0
    ldr    lr, [sp, #S_PC]            @ Get PC
    add    sp, sp, #S_FRAME_SIZE
    subs    pc, lr, #4            @ return & move spsr_svc into cpsr
    .endm

    .macro get_bad_stack
    ldr    r13, _armboot_start        @ setup our mode stack
    sub    r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
    sub    r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack

    str    lr, [r13]            @ save caller lr / spsr
    mrs    lr, spsr
    str     lr, [r13, #4]

    mov    r13, #MODE_SVC            @ prepare SVC-Mode
    @ msr    spsr_c, r13
    msr    spsr, r13
    mov    lr, pc
    movs    pc, lr
    .endm

    .macro get_irq_stack            @ setup IRQ stack
    ldr    sp, IRQ_STACK_START
    .endm

    .macro get_fiq_stack            @ setup FIQ stack
    ldr    sp, FIQ_STACK_START
    .endm

/*
 * exception handlers
 */
    .align  5
undefined_instruction:
    get_bad_stack
    bad_save_user_regs
    bl     do_undefined_instruction

    .align    5
software_interrupt:
    get_bad_stack
    bad_save_user_regs
    bl     do_software_interrupt

    .align    5
prefetch_abort:
    get_bad_stack
    bad_save_user_regs
    bl     do_prefetch_abort

    .align    5
data_abort:
    get_bad_stack
    bad_save_user_regs
    bl     do_data_abort

    .align    5
not_used:
    get_bad_stack
    bad_save_user_regs
    bl     do_not_used

#ifdef CONFIG_USE_IRQ

    .align    5
irq:
    get_irq_stack
    irq_save_user_regs
    bl     do_irq
    irq_restore_user_regs

    .align    5
fiq:
    get_fiq_stack
    /* someone ought to write a more effiction fiq_save_user_regs */
    irq_save_user_regs
    bl     do_fiq
    irq_restore_user_regs

#else

    .align    5
irq:
    get_bad_stack
    bad_save_user_regs
    bl     do_irq

    .align    5
fiq:
    get_bad_stack
    bad_save_user_regs
    bl     do_fiq
    這一部分是中斷處理的中間部分,這裡會完成儲存中斷現場並跳轉到中斷處理函式的功能,使用了巨集程式碼段來使這部分的邏輯更為清晰。

相關推薦

自己驅動8——uboot程式碼閱讀(start.S)

    /* Set up the stack                            */ stack_setup:     ldr    r0, _TEXT_BASE        /* upper 128 KiB: relocated uboot   *

自己驅動6——uboot程式碼閱讀一(start.S)

uboot中的start.S檔案開頭的這段程式碼:.globl _start _start: b reset ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefe

自己驅動11——簡單GPIO操作

1.對於GPIO的操作     對於GPIO的操作,通常是通過讀寫其相應的暫存器來實現的,S3C2440也是如此。比如,S3C2440的GPBCON和GPBDAT暫存器的地址分別是0x56000010和0x56000014,可以通過如下的指令讓GPB5輸出低電平。    

自己驅動12——儲存控制器

1.2440的BANK     2440一共提供給外部8個BANK(BANK0~BANK7),每個BANK均為128MB的地址空間,一共1GB地址空間。2440對外引出了27根地址線ADDR0~ADDR26,這27根地址線的訪問地址大小為128MB,2440對外還引出了8根

自己驅動15——Cache

1.Cache簡介     同樣是基於程式訪問的區域性性,在主存和CPU通用暫存器之間設定一個高速的、容量相對較小的儲存器,把正在執行的指令地址附近的一部分指令或資料從主存調入這個儲存器,供CPU在一段時間內使用,這對提高系統的效能很有幫助。這個位於主存和CPU之間的高速小

自己驅動17——ARM工作模式和ARM9暫存器

1.ARM體系CPU的7種工作模式     (1)使用者模式(usr):ARM處理器正常的程式執行狀態。     (2)快速中斷模式(fiq):用於高速資料傳輸或通道處理。     (3)中斷模式(irq):用於通用的中斷處理。     (4)管理模式(svc):作業系統使

自己驅動10——arm-linux-選項

1、arm-linux-gcc選項 總體選項 (1)-E:預處理之後立即停止,不進行編譯。 (2)-S:編譯後停止,不進行彙編。 (3)-c:預處理、編譯和彙編原始檔,但是不作連結,編譯器根據原始檔生成obj檔案。 (4)-o:指定輸出檔名。這個選項可以使用在預處理、編譯、

自己驅動16——NAND Flash

1.NOR Flash和NAND Flash     對於Flash儲存器件的可靠性需要考慮3點:位反轉、壞塊和可擦除次數。所有的Flash器件(包括NOR Flash和NAND Flash)都遭遇位反轉的問題:由於Flash固有的電器特性,在讀寫資料過程中,偶然會產生一位

自己驅動18——中斷

1.中斷原理     當某個事件發生時,硬體會設定某個暫存器;CPU在執行完一個指令時,通過硬體檢視這個暫存器,如果發現所關注的事件發生了,則中斷當前程式流程,跳轉到一個固定的地址去處理這個事件,最後返回繼續執行被中斷的程式。2.中斷處理過程     (1)中斷控制器彙集各

自己驅動13——記憶體管理單元MMU(虛擬地址和實體地址)

1.MMU簡介     MMU負責完成虛擬地址到實體地址的對映,並提供硬體機制的記憶體訪問許可權檢查。現代的多使用者多程序作業系統通過MMU使得各個使用者程序都擁有自己獨立的地址空間:地址對映功能使得各個程序擁有"看起來"一樣的地址空間,而記憶體訪問許可權的檢查可以保護每個

uboot啟動第一階段——start.S

一:引入start.S     u-boot整個程式的入口取決於連結指令碼u-boot.lds中ENTRY宣告的地方。ENTRY(_start)因此 _start符號是整個程式的入口。 二:分析start.S      從SD卡和nand啟動是需要16位元組校驗頭(m

VPP程式碼閱讀中文註解()

static void vpe_main_init (vlib_main_t * vm) { void vat_plugin_hash_create (void); if (CLIB_DEBUG > 0) vlib_unix_cli_set_prompt ("DBGvpp#

linux藍芽驅動程式碼閱讀筆記

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

[uboot] (第章)uboot流程——uboot-spl程式碼流程

以下例子都以project X專案tiny210(s5pv210平臺,armv7架構)為例。 建議先看《[project X] tiny210(s5pv210)上電啟動流程(BL0-BL2)》,根據例子瞭解一下上電之後的BL0\BL1\BL2階段,以及各個階段的

跟我 Java 8 新特性之 Stream 流()縮減操作

和前面兩篇文章一起服用,效果會更佳。通過對流API的基礎體驗Demo和關鍵知識點的講解,相信大家對流API都有一定的認識了,但是流API強大的功能,可不僅僅像前面兩篇文章中說的那樣簡單,大家應該注意到,在第二篇中,我對Stream介面進行介紹的時候,並沒有把他的全部方法都

java1.8實戰學習()——通過行為引數化傳遞程式碼

 上一篇:java1.8實戰學習(二)——總結:流處理、行為引數化、並行與共享  下一篇:java1.8實戰學習(四)——通過行為引數化傳遞程式碼 通過行為引數化傳遞程式碼 在軟體工程中,一個眾所周知的問題就是,不管你做什麼,使用者的需求肯定會變。比

自己Python()練手小遊戲:不要猜中

不要猜中的小遊戲 背景 和朋友閒待著兩個人無聊,都想吃蘋果又都不想洗,想起玩過的一個酒桌上猜數字的遊戲,然後在手機上寫了出來,三局兩勝輸了去洗蘋果…… 遊戲介紹 零到99(包括邊界),隨機一個數兩人(N人也可以)輪流猜測,如果沒猜中,新的數將做為邊界

leveldb程式碼閱讀8)——查詢資料

        1、DBImpl::Put 函式用於資料查詢         2、流程如下:         3、首先在可讀可寫的記憶體table中查詢,查詢到就返回         4、在只讀記憶體table中查詢,查詢到就返回         5、如果都沒有找到,那麼只

自己Python(五)程式碼骨架

程式碼骨架 從前面的內容中,我們已經看到Python的一行程式碼寫完之後,不需要額外加一個的;進行說明。在Guido設計語言時,為了避免輸入太多的括號或者關鍵字,Python中使用縮排來區分程式碼塊,建議使用四個空格進行縮排(不要使用Tab和空格混排)。就像我

自己js程式碼常用(一)

圖片輪播 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <