亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫(kù)
最近訪問板塊 發(fā)新帖
查看: 1645 | 回復(fù): 0
打印 上一主題 下一主題

UBOOT學(xué)習(xí)筆記 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2011-02-06 18:48 |只看該作者 |倒序?yàn)g覽
作者:old five zhang
地址:swust
UBoot版本:記不太清楚了

http://blog.chinaunix.net/space.php?uid=14782631

本文檔是自己學(xué)習(xí)UBoot的總結(jié),只涉及到自己以前迷惑的地方


初探

執(zhí)行一下make,看下make的過程中發(fā)生了什么。

UNDEF_SYM=`arm_v5t_le-objdump -x lib_generic/libgeneric.a board/dahua_davinci/libdahua_davinci.a cpu/arm926ejs/libarm926ejs.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/sk98lin/libsk98lin.a post/libpost.a post/cpu/libcpu.a common/libcommon.a |sed  -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;

查找各源文件中的u_boot_cmd段。

arm_v5t_le-ld -Bstatic -T uboot/Trunk/board/dahua_davinci/u-boot.lds -Ttext 0x81080000  $UNDEF_SYM cpu/arm926ejs/start.o --start-group lib_generic/libgeneric.a board/dahua_davinci/libdahua_davinci.a cpu/arm926ejs/libarm926ejs.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/sk98lin/libsk98lin.a post/libpost.a post/cpu/libcpu.a common/libcommon.a --end-group -L /opt/toolchains/davinci/pro/devkit/arm/v5t_le/bin/../lib/gcc/armv5tl-montavista-linuxeabi/3.4.3 -lgcc  -Map u-boot.map -o u-boot

鏈接各源程序?yàn)?font face="Times New Roman">u-boot可執(zhí)行文件,并生成u-boot.map文件。U-boot中包含了一些調(diào)試信息,比如說debug_frame ,debug_info等。u-boot.map中記錄了各函數(shù)/變量的地址。

arm_v5t_le-objcopy --gap-fill=0xff -O srec u-boot u-boot.srec

u-boot生成S記錄文件,這個(gè)文件一般在MOTOROLA的機(jī)子上有用。

objcopy的作用是拷貝一個(gè)目標(biāo)文件的內(nèi)容到另一個(gè)目標(biāo)文件中。Objcopy使用GNU BFD庫(kù)去讀或?qū)懩繕?biāo)文件。Objcopy可以使用不同于源目標(biāo)文件的格式來(lái)寫目的目標(biāo)文件(也即是說可以將一種格式的目標(biāo)文件轉(zhuǎn)換成另一種格式的目標(biāo)文件)。通過以上命令行選項(xiàng)可以控制Objcopy的具體操作。

通過使用srec作為輸出目標(biāo)(使用命令行選項(xiàng)-o srec),Objcopy可以產(chǎn)生S記錄格式文件。
通過使用binary作為輸出目標(biāo)(使用命令行選項(xiàng)-o binary),Objcopy可以產(chǎn)生原始的二進(jìn)制文件。使用Objcopy產(chǎn)生一個(gè)原始的二進(jìn)制文件,實(shí)質(zhì)上是進(jìn)行了一回輸入目標(biāo)文件內(nèi)容的內(nèi)存轉(zhuǎn)儲(chǔ)。所有的符號(hào)和重定位信息都將被丟棄。內(nèi)存轉(zhuǎn)儲(chǔ)起始于輸入目標(biāo)文件中那些將要拷貝到輸出目標(biāo)文件去的部分的最小虛地址處。
使用Objcopy生成S記錄格式文件或者原始的二進(jìn)制文件的過程中,-S選項(xiàng)和-R選項(xiàng)可能會(huì)比較有用。-S選項(xiàng)是用來(lái)刪掉包含調(diào)試信息的部分,-R選項(xiàng)是用來(lái)刪掉包含了二進(jìn)制文件不需要的內(nèi)容的那些部分。

arm_v5t_le-objcopy --gap-fill=0xff -O binary u-boot dhboot.bin

uboot可執(zhí)行文件生成RAW二進(jìn)制文件。對(duì)于在PC上運(yùn)行的程序或者在設(shè)備上運(yùn)行的應(yīng)用程序,沒有這一步,因?yàn)椴僮飨到y(tǒng)會(huì)解析并根據(jù)可執(zhí)行文件中的信息加載程序執(zhí)行。但對(duì)于系統(tǒng)運(yùn)行的第一個(gè)程序u-boot,沒有誰(shuí)會(huì)去解析加載這個(gè)程序,所以,需要將其做成RAW的二進(jìn)制文件,使其能一開始就能在設(shè)備上運(yùn)行。

連接腳本

對(duì)于.lds文件,它定義了整個(gè)程序編譯之后的連接過程,決定了一個(gè)可執(zhí)行程序的各個(gè)段的存儲(chǔ)位置。雖然現(xiàn)在我還沒怎么用它,但感覺還是挺重要的,有必要了解一下。

先看一下GNU官方網(wǎng)站上對(duì).lds文件形式的完整描述:

SECTIONS {
...
secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
  { contents } >region :phdr =fill
...
}

secnamecontents是必須的,其他的都是可選的。下面挑幾個(gè)常用的看看:

1、secname:段名

2、contents:決定哪些內(nèi)容放在本段,可以是整個(gè)目標(biāo)文件,也可以是目標(biāo)文件中的某段(代碼段、數(shù)據(jù)段等)

3、start:本段連接(運(yùn)行)的地址,如果沒有使用ATldadr),本段存儲(chǔ)的地址也是startGNU網(wǎng)站上說start可以用任意一種描述地址的符號(hào)來(lái)描述。

4ATldadr):定義本段存儲(chǔ)(加載)的地址。

看一個(gè)簡(jiǎn)單的例子:(摘自《2410完全開發(fā)》)

/* nand.lds */
SECTIONS { 
firtst 0x00000000 : { head.o init.o } 
second 0x30000000 : AT(4096) { main.o } 
}

以上,head.o放在0x00000000地址開始處,init.o放在head.o后面,他們的運(yùn)行地址也是0x00000000,即連接和存儲(chǔ)地址相同(沒有AT指定);main.o放在40960x1000,是AT指定的,存儲(chǔ)地址)開始處,但是它的運(yùn)行地址在0x30000000,運(yùn)行之前需要從0x1000(加載處)復(fù)制到0x30000000(運(yùn)行處),此過程也就用到了讀取Nand flash。這就是存儲(chǔ)地址和連接(運(yùn)行)地址的不同,稱為加載時(shí)域和運(yùn)行時(shí)域,可以在.lds連接腳本文件中分別指定。 

arm_v5t_le-ld -Bstatic -T uboot/Trunk/board/dahua_davinci/u-boot.lds -Ttext 0x81080000  $UNDEF_SYM cpu/arm926ejs/start.o --start-group lib_generic/libgeneric.a board/dahua_davinci/libdahua_davinci.a cpu/arm926ejs/libarm926ejs.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/sk98lin/libsk98lin.a post/libpost.a post/cpu/libcpu.a common/libcommon.a --end-group -L /opt/toolchains/davinci/pro/devkit/arm/v5t_le/bin/../lib/gcc/armv5tl-montavista-linuxeabi/3.4.3 -lgcc  -Map u-boot.map -o u-boot

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

OUTPUT_ARCH(arm)

ENTRY(_start)

SECTIONS

{

. = 0x00000000;

. = ALIGN(4);

.text :

{

  cpu/arm926ejs/start.o (.text)  /*.text段表示代碼段,起始位置由-Ttext選項(xiàng)指定 */

  *(.text)

}

. = ALIGN(4);

.rodata : { *(.rodata) }  /*只讀數(shù)據(jù)段保存已經(jīng)初始化的全局只讀數(shù)據(jù),比如只讀字符串*/

. = ALIGN(4);

.data : { *(.data) }  /*數(shù)據(jù)段保存已經(jīng)初始化的全局?jǐn)?shù)據(jù) */

. = ALIGN(4);

.got : { *(.got) }

. = .;

__u_boot_cmd_start = .;/* 指定u_boot_cmd, uboot把所有的uboot命令放在該段. */

.u_boot_cmd : { *(.u_boot_cmd) }

__u_boot_cmd_end = .;

. = ALIGN(4);

__bss_start = .;

.bss : { *(.bss) }  /*堆棧段,未初始化的全局變量也保存在此*/

_end = .;

}

__u_boot_cmd_end ,__bss_start_end相當(dāng)是在這里定義的變量,變量的值是‘.’的地址,變量的地址也是‘.’的地址。這個(gè)在程序里可以引用,但__u_boot_cmd_end ,__bss_start,_end它們不占用存儲(chǔ)空間。以__bss_start為例,在反匯編的代碼中,有

                0x8109928c                __u_boot_cmd_version

                0x8109925c                __u_boot_cmd_help

                0x810992a4                __u_boot_cmd_end = .

                0x810992a4                . = ALIGN (0x4)

                0x810992a4                __bss_start = .

.bss            0x810992a4    0x197f8

 *(.bss)

 .bss           0x810992a4        0x8 cpu/arm926ejs/libarm926ejs.a(interrupts.o)

 .bss           0x810992ac       0x30 lib_arm/libarm.a(board.o)

                0x810992ac                monitor_flash_len

                0x810992b0                hwid

從這里來(lái)看,__u_boot_cmd_end__bss_start不占用存儲(chǔ)空間,因?yàn)樗麄兊闹狄粯忧遗ccpu/arm926ejs/libarm926ejs.a(interrupts.o)的起始位置的地址一樣。通常,我們只是去讀__u_boot_cmd_end,__bss_start的值去確定一個(gè)邊界,例如,在start.S中,

_bss_start:

.word __bss_start

這句話的意思是,在_bss_start這個(gè)地址的位置放一個(gè)值,該值為_bss_start的地址。

查看其匯編代碼:

81080048 <_bss_start>:

81080048:       810992a4        smlatbhi        r9, r4, r2, r9

可見,81080048這個(gè)地址中的值就是810992a4。而810992a4正好是__bss_start的值。

再來(lái)看另外一個(gè)例子,在do_help()中,C代碼為:

int do_help (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])

{

int i;

int rcode = 0;

if (argc == 1) { /*show list of commands */

int cmd_items = &__u_boot_cmd_end -

&__u_boot_cmd_start; /* pointer arith! */

其匯編代碼為:

8108aca4 <do_help>:

8108aca4:       e1a0c00d        mov     ip, sp

8108aca8:       e92ddef0        stmdb   sp!, {r4, r5, r6, r7, r9, sl, fp, ip, lr, pc}

8108acac:       e3520001        cmp     r2, #1  ; 0x1

8108acb0:       e24cb004        sub     fp, ip, #4      ; 0x4

8108acb4:       e1a04002        mov     r4, r2

8108acb8:       e1a0a003        mov     sl, r3

8108acbc:       e3a07000        mov     r7, #0  ; 0x0

8108acc0:       13a06001        movne   r6, #1  ; 0x1

8108acc4:       e24dd008        sub     sp, sp, #8      ; 0x8

8108acc8:       1a000044        bne     8108ade0 <do_help+0x13c>

8108accc:       e59f3184        ldr     r3, [pc, #388]  ; 8108ae58 <.text+0xae58>

8108acd0:       e59f2184        ldr     r2, [pc, #388]  ; 8108ae5c <.text+0xae5c>

8108ae58:       81098e0c        tsthi   r9, ip, lsl #28

8108ae5c:       810992a4        smlatbhi        r9, r4, r2, r9

可見,對(duì)&__u_boot_cmd_end的引用被解析成了對(duì)810992a4這個(gè)地址,810992a4正好是__u_boot_cmd_end的地址。

(可以在內(nèi)核中測(cè)試一下,修改這個(gè)變量,如能修改,說明。打印出這個(gè)變量的值和地址。。。。)

Start.S

Start.S的作用是實(shí)現(xiàn)UBOOT對(duì)中斷的處理以及一些必須要做的低級(jí)的工作,比如代碼拷貝等。有三種情況需要拷貝:

1. 因?yàn)橛行?font face="Times New Roman">CPU的代碼可以在NOR FLASH中執(zhí)行,有些可以在片內(nèi)的ROM中執(zhí)行,這樣的話,速度有了限制。所以,在START.S中會(huì)有代碼的COPY,將代碼拷貝到RAM

2.程序雖然一開始在RAM中運(yùn)行,但期待的運(yùn)行地址與程序一開始運(yùn)行的地址不一樣。比如說程序一開始運(yùn)行在0x81000000,但這個(gè)位置我們需要存放LINUX內(nèi)核或者我想將其作為棧的起始位置,那我們就需要把代碼轉(zhuǎn)移到另外一個(gè)位置。

3.還有種情況是代碼開始在片內(nèi)ROM中執(zhí)行,因?yàn)槠瑑?nèi)ROM容量太小,不包含所有的代碼,也需要拷貝,但這里對(duì)于我們所用的CPU不考慮這情況。

程序一開始,程序做一些初始化,比如禁止MMUCACHE,然后就跳到函數(shù)lowlevel_init 中去了。對(duì)于我們的程序,lowlever_initboard/dahua_davinci/lowlevel_init.S中定義。這個(gè)函數(shù)主要做一些PLL,DDR的初始化。

初始化完成后,程序看是否需要拷貝代碼。

adr r0, _start /* r0 <- current position of code   */

ldr r1, _TEXT_BASE /* test if we run from flash or RAM */

cmp     r0, r1                  /* don't reloc during debug         */

beq     stack_setup

adr r0, _start_start的相對(duì)位置加載到r0 到,ADR指令的效果與當(dāng)前PC指針的位置有關(guān),其匯編代碼為:

81080064:       e24f006c        sub     r0, pc, #108    ; 0x6c

如果代碼一開始在0X0運(yùn)行,那這里的r0就為0,如果在0x8000運(yùn)行,那么r0就為0x8000。

ldr r1, _TEXT_BASE_TEXT_BASE的值加載到r1中,效果與PC的位置無(wú)關(guān),即是說無(wú)論開始在0X0運(yùn)行,還是在81080000運(yùn)行,這里r1的值都為0x81080000(_TEXT_BASE=0x81080000)。

81080000 <_start>:

81080000:       ea000012        b       81080050 <reset>

cmp     r0, r1比較兩者的值,如果相等,說明是在RAM中運(yùn)行,如果不等,則是在其它地方運(yùn)行,需要COPY。

拷貝首先計(jì)算拷貝的大小和結(jié)束的位置,大小size可以用_bss_start -_armboot_start,結(jié)束的地址可以用_start+size?截惖倪^程使用ldmstm的循環(huán)完成。

ldr r2, _armboot_start

ldr r3, _bss_start

sub r2, r3, r2 /* r2 <- size of armboot            */

add r2, r0, r2 /* r2 <- source end address         */

拷貝完成后就是棧的設(shè)置,將_TEXT_BASE-CFG_MALLOC_LEN-CFG_GBL_DATA_SIZE_TEXT_BASE 這段空間設(shè)為棧,使SP指針的值為_TEXT_BASE-CFG_MALLOC_LEN-CFG_GBL_DATA_SIZE 。

然后就是bss的初始化,將__bss_start__bss_end這段空間的內(nèi)容初始化為0

接著,程序跳到RAM中執(zhí)行,也就是810800c4這個(gè)地址:

ldr pc, _start_armboot

_start_armboot:

.word start_armboot

其匯編代碼為:

810800c0:       e51ff004        ldr     pc, [pc, #-4]   ; 810800c4 <_start_armboot>

810800c4 <_start_armboot>:

810800c4:       810810c0        smlabthi        r8, r0, r0, r1





start_armboot

#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")

/*這個(gè)聲明告訴編譯器使用寄存器r8來(lái)存儲(chǔ)gd_t類型的指針gd,即這個(gè)定義聲明了一個(gè)指針,并且指明了它的存儲(chǔ)位置。*/

__asm__ __volatile__("": : :"memory");

/*

1__asm__用于指示編譯器在此插入?yún)R編語(yǔ)句 

2__volatile__用于告訴編譯器,嚴(yán)禁將此處的匯編語(yǔ)句與其它的語(yǔ)句重組合優(yōu)化。即:原原本本按原來(lái)的樣子處理這這里的匯編。 

3) memory強(qiáng)制gcc編譯器假設(shè)RAM所有內(nèi)存單元均被匯編指令修改,這樣cpu中的registerscache中已緩存的內(nèi)存單元中的數(shù)據(jù)將作廢。cpu將不得不在需要的時(shí)候重新讀取內(nèi)存中的數(shù)據(jù)。這就阻止了cpu又將registerscache中的數(shù)據(jù)用于去優(yōu)化指令,而避免去訪問內(nèi)存。 

4"":::表示這是個(gè)空指令。

*/

 C語(yǔ)言中嵌入?yún)R編

   格式: _asm_("asm statements":outputs:inputs:registers-modified)

   其中,"asm statements"是匯編語(yǔ)句表達(dá)式,outputs,inputs,register-modified都是可選參數(shù),以冒號(hào)隔開,且一次以09編號(hào),如outputs的寄存器是0號(hào),inputs寄存器是1號(hào),往后依次類推。outputs是匯編語(yǔ)句執(zhí)行完后輸出到的寄存器,inputs是輸入到某個(gè)寄存器。

   1_asm_("pushl %%eax\n\t" "movl $0,%%eax\n\t" "popl %%eax");

   在嵌入?yún)R編中,寄存器前面要加兩個(gè)%,因?yàn)?/font>gcc在編譯是,會(huì)先去掉一個(gè)%再輸出成匯編格式。

   2{ register char _res;\

         asm("push %%fs\n\t"

         "movw %%ax,%%fs\n\t"

         "movb %%fs:%2,%%al\n\t"

         "pop %%fs"

         :"=a"(_res):"0"(seg),"m"(*(addr)));\

         _res;}

    movb %%fs:%2,%%al\n\t一句中是把以fs為段地址,以后面的第二號(hào)寄存器即后面的seg中的值為偏移地址所對(duì)應(yīng)的值裝入al。"=a"(_res):"0"(seg),"m"(*(addr)))一句中,"=a"(_res)表示把a寄存器中的內(nèi)容給_res"0"(seg)表示把seg中的內(nèi)容給0所對(duì)應(yīng)的寄存器,而0即表示使用和前一個(gè)寄存器相同的寄存器,這里即使用a寄存器,也就是說把seg中的內(nèi)容個(gè)a寄存器。

   需要解釋以下的是,a,b,c,d分別表示寄存器eax,ebx,ecx,edx

                  SD分別表示寄存器esi,edi

                  r表示任意寄存器

                  0(數(shù)字0,不是o!)表示使用上一個(gè)寄存器


您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP