免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版
打開APP
未登錄
開通VIP,暢享免費電子書等14項超值服
開通VIP
首頁
好書
留言交流
下載APP
聯系客服
BOOT閱讀筆記【轉貼】
定慧圖書館
>《嵌入式》
2011.12.26
關注
做了近兩年ARM下的驅動開發(fā),常用的各個設備驅動基本都碰過,不過Boot由于任務安排的緣故(公司一直有專人在做),一直沒有機會接觸,從剛開始接觸嵌入式的時候,就一直想弄清楚板子上電后,程序是怎么執(zhí)行的,不過看了下公司boot源碼,就很快放棄了,當時對匯編充滿了畏懼,做了1年多的驅動后,再看匯編感覺就沒那邊痛苦了,最近把boot的資料整理下,把我覺得boot比較核心的部分,完整的看了一遍,現在做個記號.我把我覺得我之前比較困惑的難點整理出來,也許大家一起討論下,也許和我一樣的新手就可以少走些彎路.
BOOT的核心就是relocate,目前見到的典型嵌入式系統,除了處理器,至少都有ROM(norflash,nandflash)RAM(SDRAM),一般把Bootloader代碼放在norflash里面,而nandflash因為本身硬件原因不能隨機訪問,一般只是用來放應用程序.在系統加電或復位后,CPU通常由CPU制造商預先安排上地址取指令,arm體系下一般都是0x0地址取它的第一條指令,即PC = 0開始.
和boot緊密相關的個人覺得就是一下幾點.
1.remap.
remap比較簡單,和MMU的功能可以看做是等價的,只是一般remap地址估定為0x0 ,網上有個帖子叫<<ARM remap與重定位摘抄>>專門講了它對remap的理解,對remap的作用是這樣講的: 當ARM處理器上電或者Reset之后,處理器從0x0取指。因此,必須保證系統上電時,0x0處有指令可以執(zhí)行。所以,上電的時候,0x0地址處必定是ROM或者Flash(NOR)。但是,為了加快啟動的速度,也方便可以更改異常向量表,加快中斷響應速度,往往把異常向量表映射到更快、更寬(32bit/16bit)的RAM中。但是異常向量表的開始地址是由ARM架構決定的,必須位于0x0處,因此,必須把RAM映射到0x0。
文中提到了ARM處理器remap的三種情況,如下
1)如果處理器有專門的寄存器可以完成Remap。那么Remap是通過Remap寄存器的相應bit置1完成的。
如Atmel AT91xx
2)如果處理器沒有專門的寄存器,但是memory的bank控制寄存器可以用來配置bank的起始地址,那么只要把RAM的起始地址編程為0x0,也可以完成remap。如samsung s3c4510 .
3)如果上面兩種機制都沒有,那么Remap就不要做了。因為處理器實現決定了SDRAM對應的bank地址是不能改變的。如Samsung S3c2410.
不過我的看法有點稍微不一樣,如果上面兩種機制都沒有,那么Remap就不要做了,它給的典型例子是Samsung S3c2410 ,2410雖然sdram對應的bank地址不能改變,但它有MMU功能, MMU可以起到remap的作用,常用的最典型的應該是例子Samsung S3c44b0,它既沒有mmu,又SDRAM對應地址有沒辦法改變.順便補充下除了4510可以改變每個bank的地址,還有華邦的w90P740(arm7),呵呵,我現在用的U就是這款U,可以把bank的地址隨意的設置.
2.relocate .
relocate (地址重定位),個人覺得這個是boot里面最麻煩也是最核心的部分,剛開始看boot代碼的時候,它簡直是我的惡夢,不知道大家分析boot的源碼流程是否這樣,也可能我大學不是計算機的,沒學過編譯原理(現在也沒看過)對鏈接和加載一無所知,有兩個星期非常痛苦,就是不懂人家boot里面的鏈接腳本為什么要那樣寫.網上關于uboot的帖子很多,但對鏈接加載這塊,始終寫的不詳細,不知道是不是太過于基礎了,高手都不愿意講,最后自己找資料,發(fā)現其實一切痛苦的根源都是對鏈接和加載不太清楚造成的,但個人感覺boot除了初始化以外就是搬運程序,如何搬運?為什么要那樣搬運都需要對硬件板的地址分布很清楚?而這些都是鏈接決定的,所以非弄清楚不可!
1.我們?yōu)槭裁葱枰猺elocate ? 經濟方面,(nandflash和norflash 每兆價格相差懸殊),把boot代碼放在norflash里面(為什么不放在nandflash里面,因為nandflash讀需要驅動支持,norflash可以直接訪問),boot通常很小,只需要占用幾十k的空間,所以只需要很小的norflash芯片,這樣很便宜,而把應用程序通常很大,所以用價格低廉nandflash來儲存,實際應用,通過執(zhí)行boot程序,把nandflash里面代碼和數據搬運到內存中來執(zhí)行,這樣比程序直接放在norflash里執(zhí)行,可以.另外還有運行速度方面的差別,程序在norflash里執(zhí)行的速度遠遠小于在sdram中執(zhí)行的速度,為了追求更高的速度,也需要relocate,讓程序在sdram里面執(zhí)行 .
2.關于加載域(VMA)和運行域(LMA),杜春雷在它那本經典的<<arm體系結構與編程>>一書專門有一章來講加載域和運行域不一致的情況,但我當初接觸了它的這些加載域和運行域后,看uboot的lds ,uboot的lds沒有設置LMA,只是設置了VMA,為此我疑惑很久.直到耐心的看了那本鏈接器和加載器的書才豁然明白(
http://bbs.chinaunix.net/viewthread.php?tid=817770
),任何一個鏈接器和加載器的基本工作都非常簡單: 將更抽象的名字與更底層的名字綁定起來,好讓程序員使用更抽象的名字編寫代碼,鏈接器的就是把源文件進行符號解析,把解析出來的符號和地址的進行綁定,把全局變量,函數,標號等等這些符合和地址綁定起來.
3.boot上電后開始能夠正確執(zhí)行還有個很重要的原因,是要保證boot在系統加電或復位后最初執(zhí)行的代碼是跟地址無關的,(即在代碼搬運前所執(zhí)行的代碼是與地址無關),地址無關即地址無關代碼生成的這個映象文件可以被放在內存中的任何一個地址上運行。對于地址無關的代碼, 尋址是基于pc值的, 在pc值上+/-一個偏移值, 得到運行地址,如跳轉指令B.當我們執(zhí)行完代碼搬運,就需要跳到和地址相關的地方去執(zhí)行,即我們的RAM中,一般是跳轉到一個標號, 這時地址相關代碼就開始運行了ldr pc,_start_armboot.因為在bin映象生成的時候,就已經把_start_armboot這個符號,和實際地址綁定在一起,當我們執(zhí)行l(wèi)dr pc,_start_armboot 程序就從在ROM中執(zhí)行跳入到RAM中了,但前提是我們進行了代碼搬移,如果沒有代碼搬運ldr pc,_start_armboot,RAM中沒有代碼程序就馬上飛掉了,所有我們在在搬運之前不能尋址絕對地址有關代碼,必須執(zhí)行代碼地址無關.
拿u-boot-1.1.4下的smdk2410來做例子,和smdk2410 board密切相關的就兩個文件夾\board\smdk2410和\cpu\arm920t,里面核心文件就u-boot.lds , config.mk ,start.S .
ENTRY(_start)
SECTIONS
{
. = 0x00000000;//從0地址起始
. = ALIGN(4);
.text :
{
cpu/arm920t/start.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
. = ALIGN(4);
__bss_start = .;//為搬運代碼提供的符號,來標明bss段地址,方便relocate
.bss : { *(.bss) }
_end = .; //定義整個image的結束地址
}
u-boot.lds 是鏈接腳本文件, 我剛開始看這個鏈接腳本文件時,我疑惑很久,不明白lds中VMA= LMA(資料上很多鏈接腳本包括我們公司項目里面自己寫的lds腳本是通過AT命令設置過LMA,這樣看起來地址空間分配更清晰),而且整個image 的VMA按照lds為基址為0x0,而2410芯片不能remap,0x0地址是ROM的區(qū)域,不是運行時RAM的地址,我的理解是代碼段地址應該是指向該硬件板內存區(qū)域,設置 .text=TEXT_BASE 而不是lds中的.text=0x0 ,這個疑點弄的我當時很郁悶,想了很久也沒想沒有搞清楚u-boot這樣鏈接腳本都能讓boot跑起來,當我把編譯出來的bin燒到norflash中,uboot居然跑起來了,同時發(fā)現了一個問題, u-boot.map 中發(fā)現 .text 是從config.mk 定義TEXT_BASE =0x33f80000 ,而不是lds設置的0x0,這又讓我吃驚,沒清楚是怎么會事,手上有介紹移植uboot的資料,但都對uboot鏈接這部分,寫的不夠詳細,知道事config.mk文件搞的鬼,但把makefile文件看了幾遍都沒找不到是怎么回事(還是對makefile不熟啊!),最后把編譯uboot的過程看了隱藏了個機關是
arm-linux-ld –Tu-boot-1.1.4\board\smdk2410\u-boot.lds –Ttext 0x33f80000
arm-linux-objcopy --gap-fill =0xff –O binary uboot ubtoot.bin
不知道uboot設計者為什么要在這里加一個–Ttext 而不是在lds就設置?而很多移植uboot的資料對lds文件都有所描述,但這個重要的細節(jié)似乎都漏掉了,不知道是不是因為太基礎了,所以沒有講.
不過最后生成的bin 從上看arm-linux-objcopy --gap-fill =0xff –O binary uboot ubtoot.bin沒有對鏈接生成的elf文件進行重定位,因此它的運行地址是config.mk 定義TEXT_BASE為基地址,順序按照lds的順序依次增加的,所以整個uboot最初運行的流程是
_start  reset  cpu_init_crit  relocate
這個部分就是完成初始化,設SVC32,關看門狗,關中斷,設置時鐘,初始化SDRAM(為代碼搬運到SDRAM做準備),這些都很簡單
relocate:
adr r0, _start
ldr r1, _TEXT_BASE
cmp r0, r1
beq stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2
add r2, r0, r2
copy_loop:
ldmia r0!, {r3-r10}
stmia r1!, {r3-r10}
cmp r0, r2
ble copy_loop
看了下網上的帖子,adr指令,網上很多人被這這個指令弄郁悶,我看杜春雷的<<arm體系結構與編程>>P143講,這個指令是基于PC或者寄存器的,讀到是地址無關的,一般被編譯器替換為SUB r0, pc,#offset ,不要理解為讀取符合表中_start符號的地址(0x33f80000).在我們上電開始執(zhí)行時,pc從0開始,所以現在r0值為0 +offset,不等于_TEXT_BASE(0x33f80000).接下來要用到鏈接時確定的符號地址了,_armboot_start(0x33f80000)., _bss_start(0x33f97954)這些可以在u-boot.map里面的看到, size of armboot =0x33f97954-0x33f80000 ,把_start:0x0 (norflsh)把.text ,.data的代碼往SDRAM里_TEXT_BASE確定的地址: 0x33f80000搬運.s3c2410的SDRAM基地址是0x3000_0000,由于uboot支持的這個board SDRAM是64M,(0x3000_0000---0x3400_0000),所以把u-boot.bin搬運到內存的高端地址.然后跳到內存中執(zhí)行,提高速度.
之后就relocate  stack_setup  clear_bss  ldr pc, _start_armboot ( ROMRAM)
_start_armboot: .word start_armboot ( u-boot-1.1.4\lib_arm\board.c)
stack_setup , clear_bss設置堆棧清bss段,都是為進入C語言做初始化準備,通過對start_armboot鏈接后以及把這個函數地址已經綁定在RAM中,當執(zhí)行完ldr pc, label 指令,程序將從標號綁定地址開始執(zhí)行,從而實現了從地址無關程序到地址相關的轉變,我們做代碼搬移也是為了跳轉做準備,如果沒有搬移,直接訪問地址相關,由于RAM中都是隨機值,一跳轉就馬上飛了.當進入start_armboot C函數,剩下的都沒什么難度了.可以慢分析源碼搞定.2410沒有remap寄存器, relocate時候要容易些,有remap寄存器的芯片在relocate時候進行remap會讓情況更復雜些.不過原理都差不多.
在進入board.c后,uboot還做了一次代碼搬運如下,大概如下圖,不過分兩種,一種是把pc機傳的image通過串口或者網絡傳到內存開始執(zhí)行,或者從nandflash里把應用搬到內存開始執(zhí)行,不過原理都差不多.
正好公司內部給我們做了板級初始化培訓,把硬件板初始流程注意要點整理出來,.和boot這部分初始化對比,可以發(fā)現硬件板初始化流程都差不多.比較頭痛還是鏈接這部分,這方面的資料感覺太少了,沒人可以指點,自己看這部分資料看的很痛苦.
【CPU核相關初始化】 【Watchdog初始化】 【GPIO初始化】 【系統時鐘初始化】 【內存初始化】 【模式初始化】 【中斷向量初始化】 【MMU初始化】 【Cache初始化】 【總線初始化】 【語言相關初始化】 【設備相關初始化】
4.elf 格式和bin格式
executable and linking format (ELF)重定位,可以參與程序的鏈接(創(chuàng)建一個程序)和程序的執(zhí)行(運行一個程序) ,主要鏈接,和執(zhí)行,但介紹elf文件的資料很多,沒時間仔細看和實際密切的就是調試程序時候都用elf格式調試,因為它包含了調試所需的各種符號, 固化的時候都是用的bin格式,是可執(zhí)行映象,用objcopy 把elf 轉換成bin ,不過網上介紹bin格式的資料很少,只是知道bin程序,只要把pc設置為bin映象的入口地址,就可以正確執(zhí)行, objcopy 可以對elf 轉換成bin再進行地址重定位,不過目前還沒看見過這么干過,對于elf,和bin這些理解的都不系統,資料也很少,工作中,集成開發(fā)工具IDE又把這些設置都給屏蔽起來,有沒有那個強人能寫一個文檔,把這些都系統的講清楚就好了!
順便問下,論壇上上海的多不多,大家找工作都是在網上找的?有個MM拉我去上海,雖然對現在工作很滿意,不過MM比工作更重要,要我做選擇,只有去上海了,不過在51job上投了點簡歷,都石沉大海,按理說2年也不短了,至少也會冒一個泡的,有沒有上海的能夠指點下,你們在上海石怎么找相關工作的?
補充一個當時找資料看見對網上一個帖子,感覺寫的很精辟的,關于地址無關的解釋,網頁地址被改成相當路徑了,就沒辦法地址粘貼出來,現在把原文粘貼出來.
關鍵詞: 地址無關
術語
地址無關: 編譯地址不等于運行地址.
地址相關: 編譯地址等于運行地址.
常見的一些Boot(如, U-Boot, VIVI)和Linux Kernel代碼開始的一段是位置無關的, 意思就是說運行地址與編譯地址無關. 如, Kernel編譯地址是0xc0008000, 而運行地址是0x30008000.
為什么?
為什么代碼的編譯地址和運行地址會不相等呢? 原因主要有以下幾種: 1) 對于Boot, 用于存放Boot代碼的存儲器容量小于代碼量. 如, Boot片有4K, 而代碼通常有50-60K. 這樣, 通常會在前4K代碼里, 讓Boot把自己復制到RAM, 再接著運行.這里我們需要作出一個選擇, 是讓前面的代碼與地址相關, 還是讓后面的代碼與地址相關呢? 顯然我們會選擇前面一段代碼量小的與地址無關. 2) 對于Linux Kernel, 它是運行在虛擬地址空間的, 如0xc0008000, 但在MMU打開之前, 通常這個地址是
不存在的, 也就是說在MMU打開之前, Kernel的代碼必須是地址無關的.
怎么辦?
對于位置無關的代碼, 尋址是基于pc值的, 在pc值上+/-一個偏移值, 得到運行地址.以ARM為例, 用adr來尋址, adr的實際上是一個宏指令, 在代碼編譯時, 會被編譯器替換成對pc的+/-運算
這里要注意, 對pc的+/-運行顯然是有一個地址范圍的, 所以我們在上面選擇代碼量小的地址無關, 是很明智的.
而訪問地址相關的代碼, 只需要使用其它的尋址指令就行了. 但在這之前, 必須保證代碼被放在正確的地址上, 所以通常都會有一個復制代碼的過程, 然后就是跳轉到一個標號, 地址相關代碼就開始運行了.
本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現有害或侵權內容,請
點擊舉報
。
打開APP,閱讀全文并永久保存
查看更多類似文章
猜你喜歡
類似文章
Uboot 運行時內存的分配 -- 轉
UBoot中關于TEXT_BASE,代碼重定位,鏈接地址相關說明
u-boot2012.04.01編譯過程分析
uboot 2013.07 lds 分析
u-boot啟動代碼start.S詳解
U-boot啟動分析 - 嵌入式 - IT博客
更多類似文章 >>
生活服務
首頁
萬象
文化
人生
生活
健康
教育
職場
理財
娛樂
藝術
上網
留言交流
回頂部
聯系我們
分享
收藏
點擊這里,查看已保存的文章
導長圖
關注
一鍵復制
下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯系客服!
聯系客服
微信登錄中...
請勿關閉此頁面
先別劃走!
送你5元優(yōu)惠券,購買VIP限時立減!
5
元
優(yōu)惠券
優(yōu)惠券還有
10:00
過期
馬上使用
×