u-boot的強大就在於它具有代碼relocate功能,運行時代碼在ram中跑,最明顯的一個好處就是u-boot可以自己替換自己固化在flash中的代碼。
先看一下這套代碼中和relocate有關的幾個大名鼎鼎的參數:
board/ar7100/ap83/config.mk
# ROM version
TEXT_BASE = 0xbf000000
# SDRAM version
#TEXT_BASE = 0x8020000
include/configs/ap83.h
#define CFG_MONITOR_BASE TEXT_BASE
board/ar7100/ap83/u-boot.lds
OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips", "elf32-tradbigmips")
OUTPUT_ARCH(mips)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.sdata : { *(.sdata) }
_gp = ALIGN(16);
__got_start = .;
.got : { *(.got) }
__got_end = .;
.sdata : { *(.sdata) }
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
uboot_end_data = .;
num_got_entries = (__got_end - __got_start) >> 2;
. = ALIGN(4);
.sbss : { *(.sbss) }
.bss : { *(.bss) }
uboot_end = .;
}
注釋:
0xbf000000 是mips 24kc Flash起始的位置,也是reset
0x80000000是ar9132平台DDR的起始位置。
鏈接腳本中的0x00000000會被這個TEXT_BASE替代,可以觀察編譯時候的輸出,你會發現有一個-DTEXT_BASE=0xbf000000的選項。
Relocate的代碼在start.S中。
啟動的大致順序如下,假設代碼固化於flash起始位置。
CPU 上電
Reset(初始化cp0寄存器)
設置GOT
lowlevel_init(初始化SDRAM)
初始化cache
Relocate代碼
下面是代碼的入口
la t9, board_init_f
j t9
nop
這個board_init_f定義在lib_mips/board.c中。
這個程序為下列元素分配合適的內存空間:
[1] u-boot代碼(.text .data .bss)
[2] malloc空間 (相當於heap)
[3] Board Info
[4] Global Data
[5] Stack
這里可以看出malloc的空間位於heap中,即內存的高端,而函數中的局部變量,都在stack中的,在內存低端。
void board_init_f(ulong bootflag)
{
gd_t gd_data, *id;
bd_t *bd;
init_fnc_t **init_fnc_ptr;
ulong addr, addr_sp, len = (ulong)&uboot_end - CFG_MONITOR_BASE;
ulong *s;
/* Pointer is writable since we allocated a register for it.
*/
gd = &gd_data;
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
memset ((void *)gd, 0, sizeof (gd_t));
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
/*
* Now that we have DRAM mapped and working, we can
* relocate the code and continue running from DRAM.
*/
addr = CFG_SDRAM_BASE + gd->ram_size;
/* We can reserve some RAM "on top" here.
*/
/* round down to next 4 kB limit.
*/
addr &= ~(4096 - 1);
debug ("Top of RAM usable for U-Boot at: %08lx\n", addr);
/* Reserve memory for U-Boot code, data & bss
* round down to next 16 kB limit
*/
addr -= len;
addr &= ~(16 * 1024 - 1);
debug ("Reserving %ldk for U-Boot at: %08lx\n", len >> 10, addr);
/* Reserve memory for malloc() arena.
*/
addr_sp = addr - TOTAL_MALLOC_LEN;
debug ("Reserving %dk for malloc() at: %08lx\n",
TOTAL_MALLOC_LEN >> 10, addr_sp);
/*
* (permanently) allocate a Board Info struct
* and a permanent copy of the "global" data
*/
addr_sp -= sizeof(bd_t);
bd = (bd_t *)addr_sp;
gd->bd = bd;
debug ("Reserving %d Bytes for Board Info at: %08lx\n",
sizeof(bd_t), addr_sp);
addr_sp -= sizeof(gd_t);
id = (gd_t *)addr_sp;
debug ("Reserving %d Bytes for Global Data at: %08lx\n",
sizeof (gd_t), addr_sp);
/* Reserve memory for boot params.
*/
addr_sp -= CFG_BOOTPARAMS_LEN;
bd->bi_boot_params = addr_sp;
debug ("Reserving %dk for boot params() at: %08lx\n",
CFG_BOOTPARAMS_LEN >> 10, addr_sp);
/*
* Finally, we set up a new (bigger) stack.
*
* Leave some safety gap for SP, force alignment on 16 byte boundary
* Clear initial stack frame
*/
addr_sp -= 16;
addr_sp &= ~0xF;
s = (ulong *)addr_sp;
*s-- = 0;
*s-- = 0;
addr_sp = (ulong)s;
debug ("Stack Pointer at: %08lx\n", addr_sp);
memcpy (id, (void *)gd, sizeof (gd_t));
/* On the purple board we copy the code in a special way
* in order to solve flash problems
*/
#ifdef CONFIG_PURPLE
copy_code(addr);
#endif
relocate_code (addr_sp, id, addr);
/* NOTREACHED - relocate_code() does not return */
}
從代碼中可以看出,U-boot被relocate到內存的最高端。Relocate的實際部分在start.S中,通過relocate_code (addr_sp, id, addr)進入匯編,mips體系中函數參數被保存在a0,a1,a2中,所以看start.S中的注釋有:
/*
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
* a0 = addr_sp
* a1 = gd
* a2 = destination address
*/
Relocate的核心代碼如下,分析一下能體會到mips匯編的delay branch
relocate_code:
move sp, a0 /* Set new stack pointer */
li t0, CFG_MONITOR_BASE
la t3, in_ram
lw t2, -12(t3) /* t2 <-- uboot_end_data */
move t1, a2
/*
* t0 = source address
* t1 = target address
* t2 = source end address
*/
/* On the purple board we copy the code earlier in a special way
* in order to solve flash problems
*/
1:
lw t3, 0(t0)
sw t3, 0(t1)
addu t0, 4
ble t0, t2, 1b
addu t1, 4 /* delay slot */
/* If caches were enabled, we would have to flush them here.
*/
/* Jump to where we've relocated ourselves.
*/
addi t0, a2, in_ram - _start
j t0
nop
上面計算u-boot end地址lw t2, -12(t3)是因為有下面的定義,
.word uboot_end_data
.word uboot_end
.word num_got_entries
in_ram:
一個word四個字節,所以是in_ram的位置-12個字節。拷貝代碼的時候,增加target指針位置的代碼放在跳轉代碼之后,就是由於mips的流水線。等拷貝完代碼之后,就跳轉到ram中執行了。也就是in_ram的地方(此時的in_ram在relocate后的內存高端)。
注意到在u-boot的連接腳本里面專門有一個.u_boot_cmd段,專門設置這樣一個段有什麼好處呢?可以看一下find_cmd這個函數,就可以理解了,通過把所有cmd結構指針放在一個統一的段里面在查找起來非常方便,要添加新的命令,也不用改變原來的結構。看看它是怎麼定義的吧:
原理:
每個命令都有一個命令結構體
struct cmd_tbl_s {
char*name; /* Command Name*/
intmaxargs; /* maximum number of arguments*/
intrepeatable; /* autorepeat allowed?*/
int (*cmd)(struct cmd_tbl_s *, int, int, char *[]); /* Implementation function*/
char*usage;/* Usage message(short)*/
char*help;/* Help message(long)*/
};
去定義它。Cmd為要調用的命令函數!name為該命令名字符串。
在u-boot里面有這樣的宏
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}
宏U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)就是將
cmd_tbl_s{
name,
maxargs,
rep,
cmd,
usage,
help
}這樣的一個命令結構體放入內存.u_boot_cmd這個區域,.u_boot_cmd這個域在board/smdk2410/u-boot.lds中定義!在U-boot中的shell中,根據用戶輸入的命令,就會在.u_boot_cmd這個內存區域中查找,當.u_boot_cmd中某一個cmd_tbl_s命令結構體的cmd_tbl_s.name和輸入的命令字符串相符時,就調用該命令
結構體的cmd_tbl_s.cmd( ….)函數!
這里有一個要注意的是,cmd是一個函數指針,由於u-boot代碼是要relocate的,所以在代碼relocate之后,每個這樣的指針也要加上相應的偏移才能正常動作,代碼在board_init_r函數中。
最后是板子上電啟動時的輸出信息,看了很有幫助。
U-Boot 1.1.4-RAM VSC7395@MAC1 (Mar 21 2008 - 15:57:42)
AP83 (ar9100 with SPI flash)
DRAM: 16 MB
Top of RAM usable for U-Boot at: 81000000
Reserving 263k for U-Boot at: 80fbc000
Reserving 192k for malloc() at: 80f8c000
Reserving 56 Bytes for Board Info at: 80f8bfc8
Reserving 36 Bytes for Global Data at: 80f8bfa4
Reserving 128k for boot params() at: 80f6bfa4
Stack Pointer at: 80f6bf88
Now running in RAM - U-Boot at: 80fbc000
Found MXIC Flash. ID c22018
Flash: 16 MB
Relocate代碼中還包含PIC GOT的東西,學懂了也要分析一下。
從代碼調試中的一個小地方可以看出GOT的作用,你只要把代碼relocate前后的&__u_boot_cmd_start的值打印出來,你會發現它們是不一樣的,這就是我們在start.S中修改GOT指針的作用。
本文来自: (www.91linux.com) 详细出处参考:http://www.91linux.com/html/article/qianrushiyingyong/20081201/14171.html
';$(".articleExtAd").append(notVIP);setTimeout(function() {$('.top-toolbar').data('top-toolbar').setAD({title: "MIPS u-boot \u4e2dcode Relocate\u6d41\u7a0b\u5206\u6790",label_id: 163,label_name: "\u96fb\u8166\u786c\u9ad4"});}, 2000);


- 日誌
- 相簿
- 影音
tzeng015's 新文章
- ARM 編譯後記憶體分布
- include header 檔的使用和介紹
- fgets 改成 fread 資料讀取就會變正確
- rotate_180 方法的作用就是把buffer 中的數據按像素倒轉過來(如果說一個 PIXEL = R,G,B)
- rotate_180 方法的作用就是把buffer 中的數據按像素倒轉過來(如果說一個 PIXEL = R,G,B,A)
- Recovery 和Charger 模式下屏幕旋轉180 度, 尚未進入 android
- memset/memcpy/memcmp --- 簡單的實作
- 把陣列資料反轉
- 有關C語言的struct進階初始化
- GPS information





Powered by Xuite

tzeng015's 新回應
- 沒有新回應!
離婚證人