AM335x uboot 移植

uBOOT的編譯命令
直接一次性編譯
make O=am335x CROSS_COMPILE=arm-arago-linux-gnueabi ARCH=arm 
am335x_evm
配置
make ARCH=arm CROSS_COMPILE=arm-arago-linux-gnueabi- am335x_evm_config
編譯
make ARCH=arm CROSS_COMPILE=arm-arago-linux-gnueabi-清理
make clean ARCH=arm CROSS_COMPILE=arm-arago-linux-gnueabi-make distclean ARCH=arm CROSS_COMPILE=arm-arago-linux-gnueabi-編譯器環境變量的設置
這個環境變量是TI的SDK包裏面帶的編譯器,不是之前的arm-gcc-export PATH=$PATH:/mnt/disk1/ti-sdk-am335x-evm-05.05.00.00/linux-devkit/bin/
UBOOT裏面的MLO(u-boot-spl)
如果使用NAND啓動,那麼這個文件就是相當於NBOOT,進行第一次的引導
這個MLO實際上就是u-boot-spl.bin生成的,
在編譯完uboot後,SPL的目錄裏面會產生了許多的.o文件,這裏文件就是uboot的文件,
可以打開Makefile,有一些對應的宏定義,可以取消,減少MLO文件的大小
UBOOT的鏈接腳本lds
UBOOT\arch\arm\cpu\armv7\u-boot.lds
正常運行UBOOT的lds
UBOOT\arch\arm\cpu\armv7\omap-common\u-boot.lds
這個是nboot,加載uboot用
有2個lds,不同的作用,注意要區別開
增加新的單板支持
在boards.cfg文件中,找到加入,例如
單板名字   arm   armv7   對應board的目錄      ti       ti81xx
以後就可以執行make 單板名字    來生成uboot,這裏被ti改寫了,所以不是原版的uboot
生成方法
一些代碼的定位
u-boot-2011.09-psp04.06.00.08/arch/arm/cpu/armv7
這個目錄下的幾個文件,start.s這個是程序的入口執行文件
u-boot-2011.09-psp04.06.00.08/arch/arm/cpu/armv7/omap-common
u-boot-2011.09-psp04.06.00.08/arch/arm/cpu/armv7/ti81xx
這2個目錄是和平臺板子相關,AM335X是ti81xx的版本
以上都是和CPU有關
u-boot-2011.09-psp04.06.00.08/arch/lib
ARM平臺的公用代碼
u-boot-2011.09-psp04.06.00.08/lib
通用的庫代碼,無論什麼平臺都編譯
board/ti/xxx    這個目錄就是單板的配置


Makefile文件分析
在終端中輸入後
make  ARCH=arm  CROSS_COMPILE=arm-arago-linux-gnueabi- am335x_evm_config
命令後,會生成3個文件
1、.boards.depend
2、include/config.h
/* Automatically generated - do not edit */
#define CONFIG_BOARDDIR board/ti/am335x
#include <config_cmd_defaults.h>
#include <config_defaults.h>
#include <configs/am335x_evm.h>
#include <asm/config.h>
3、include/config.mk
ARCH   = arm
CPU    = armv7
BOARD  = am335x
VENDOR = ti
SOC    = ti81xx
終端中會輸出
awk '(NF && $1 !~ /^#/) { print $1 ": " $1 "_config; $(MAKE)" }' 
boards.cfg > .boards.depend
Configuring for am335x_evm board...
支持的配置am335x配置有
am335x_evm
am335x_evm_restore_flash
am335x_evm_spiboot
解析Makefile文件,
sinclude $(obj).boards.depend
$(obj).boards.depend: boards.cfg
awk '(NF &&
1 !~ /^#/) { print
1 ": "
1"config;
(MAKE)" }' $< > $@
我們搜索am335x_evm並沒有在makefile文件中找到對應的關鍵字,但是發現boards.cfg
中有此關鍵詞,
可能am335x_evm_config輸入後,是到boards.cfg中尋找的
通過TI CCS調試uboot
通過makefile文件建立ccs工程
1、打開CCS,選擇File->New->Project
2、打開新建窗口後,選擇c/c++下的Makefile Project with Existing Code
3、點擊下一步,選擇uboot的存放的目錄,然後點擊完成
4、等待右下角的進度,一直到達100%後,在繼續操作
5、最後在屬性設置裏,取消C的自動編譯
調試的時候,如果目標代碼是彙編,則不會現實源碼,只有C纔會現實出
uboot的代碼運行流程
u-boot-2011.09-psp04.06.00.08/arch/arm/cpu/armv7
start.s 入口運行文件
bl save_boot_params跳轉到lowlevel_init.S 
該文 件 在(arch\arm\cpu\armv7\omap-common) , 如 果 是MLO則會 定 義
CONFIG_SPL_BUILD宏,uboot沒有定義,保存CPU ROM的參數到一個地方中
bl cpu_init_crit   SPL裏面調用,初始化底層相關的(函數就在本文件中最下面)
bl lowlevel_init 保存舊的堆棧指針,設置新的堆棧指針
在lowlevel_init.S (arch\arm\cpu\armv7\omap-common)文件中
bl s_init     此函數在Evm.c (board\ti\am335xwecon)文件中,
不同的平臺初始化不同的內容
初始化堆棧指針
跳轉到C語言,board_init_f,C 言從 個函數開始 行 語 這 執
board_init_f  在Board.c (arch\arm\lib)文件中
init_sequence數 , 行初始化 組繼續進
relocate_code  函數,重新回到 彙編 start.s文件中
relocate_code:在start.s文件中
主要 了 實現 uboot的重新定位代 ,和 碼 bss段的清零
ldr r0, _board_init_r_ofs   通 個方式 取 過這 獲 board_init_r函數入口
adr r1, _start
add lr, r0, r1
mov pc, lr   最後 裏個到 這 C函數,board_init_r裏面
board_init_r   第2 段的初始化,在 階 board.c文件中
enable_caches    個函數沒有做什麼內容 這
board_init      第2次初始化平臺, 裏可以初始化其他內容了,和平臺相關 這
mem_malloc_init 初始化malloc內存
nand_init       初始化NAND(CONFIG_CMD_NAND需要定 ) 義
mmc_initialize  初始化SD(CONFIG_GENERIC_MMC需要定 ) 義
/drivers/mmc/mmc.c
文件中
board_mmc_init 平臺相關
omap_mmc_init(ID)/drivers/mmc/omap_hsmmc.c
文件中
env_relocate    初始化 境 量 環 變 /common/env_common.c
文件中
stdio_init      
jumptable_init
console_init_r
misc_init_r      平臺相關,目前不知道什麼用
interrupt_init   
enable_interrupts
eth_initialize(gd->bd);   初始化以太網 /net/eth.c文件中
board_eth_init         平臺相關的代 中 碼
cpsw_register      /driver/net/cpsw.c 註冊一個以太網設備
main_loop();  入控制檯 進
init_sequence數 裏的內容 組
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init, /* basic arch cpu dependent setup */
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_F)
board_early_init_f,
#endif
timer_init,  Timer.c (arch\arm\cpu\armv7\omap-common)默 的定 器, 開始運行 認 時 剛
uboot ,那個倒 多少 後按空格 入 時 計時 時間 進uboot
#ifdef CONFIG_FSL_ESDHC
get_clocks,
#endif
env_init, Env_nand.c (common)  uboot默 的參數,都在 裏初始化 認 這
init_baudrate, 本文件中,初始化uboot使用的默 的串口波特率 認
serial_init,   Serial.c (drivers\serial)初始化串口,在UBOOT中,使用的默 串口名 認
字是叫NS16550,可能是因 原來就存在此代 的 故,然後 用了 爲 碼緣 繼續調 ns16550.c裏面的函數初
始化串口
console_init_f, Console.c (common)初始化控制檯
display_banner, 本文件中, 出一些信息,代表運行到了 裏 輸 這
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c, 本文件中,初始化IIC,然後 用 繼續調 Omap24xx_i2c.c (drivers\i2c),
具體的CPU IIC初始化的實現
#endif
dram_init, /* configure available RAM banks */
UBOOT用到的結構體
register volatile gd_t *gd asm ("r8")
此結構體記錄了UBOOT所有的參數內容
typedef struct global_data {
bd_t *bd;   個 是一個 構體 這還 結
unsigned long flags;
unsigned long baudrate;  UBOOT串口 端所使用的串口波特率 終
unsigned long have_console; 串口控制檯是否初始化 ? 過=1初始化過
//UBOOT 境 量相關的 量 環 變 變
unsigned long env_addr; 個是地址,存放了 這 uboot使用的 境 量參數存放在內 環 變
存中 的地址,例如 了 對應 記錄uboot的ip地址, 入 進uboot默 的延 等,和 認 時時間
default_environment 起來 對應
unsigned long env_valid; 默 的 境 量是否有效, 認環 變 =1代表有效
unsigned long fb_base;/* base address of frame buffer */
#ifdef CONFIG_FSL_ESDHC
unsigned long sdhc_clk;
#endif
#ifdef CONFIG_AT91FAMILY
/* "static data" needed by at91's clock.c */
unsigned long cpu_clk_rate_hz;
unsigned long main_clk_rate_hz;
unsigned long mck_rate_hz;
unsigned long plla_rate_hz;
unsigned long pllb_rate_hz;
unsigned long at91_pllb_usb_init;
#endif
#ifdef CONFIG_ARM
/* "static data" needed by most of timer.c on ARM platforms */
unsigned long timer_rate_hz;
unsigned long tbl;
unsigned long tbu;
unsigned long long timer_reset_value;
unsigned long lastinc;
#endif
#ifdef CONFIG_IXP425
unsigned long timestamp;
#endif
unsigned long relocaddr; /* Start address of U-Boot in RAM */
phys_size_t ram_size; 內存的大小
unsigned long mon_len; uboot整個bin文件的大小 代碼段+bss段
unsigned long irq_sp; IRQ中斷堆 指 棧 針
unsigned long start_addr_sp; /* start_addr_stackpointer */
unsigned long reloc_off;
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
unsigned long tlb_addr;
#endif
void **jt; /* jump table */
char env_buf[32];/* buffer for getenv() before reloc. */
} gd_t;
typedef struct bd_info {
    int bi_baudrate; 串口控制檯波特率
    unsigned long bi_ip_addr; IP地址
    ulong         bi_arch_number; 傳遞給LINUX內核,告訴當前是板子的ID
    ulong         bi_boot_params; 傳遞給linux 內核,告訴其參數存放的位置
    struct /* RAM configuration */
    {
ulong start;
ulong size;
    }bi_dram[CONFIG_NR_DRAM_BANKS];這個用於給LINUX傳遞啓動信息的,內存大小和起始
地址,如果有多塊內存,則這個變量是一個數組
} bd_t;
SPL的代碼
/arch/arm/cpu/armv7/start.s  入口
/arch/arm/cpu/armv7/omap-common  C文件,
Uboot的重定位
relocate_code:   要有pie選項(arm-linux-ld命令中)
movr4, r0 /* save addr_sp */             新的堆棧地址
movr5, r1 /* save addr of gd */           gd_t變量的內容地址,因爲重定位後,這個地址會
改變
movr6, r2 /* save addr of destination */    目標地址
/* Set up the stack     */
stack_setup:
movsp, r4           設置堆棧
adr r0, _start      uboot的起始運行地址
cmpr0, r6
moveq r9, #0 /* no relocation. relocation offset(r9) = 0 */   如果代碼段已經是目
標了,那麼不要複製了直接跳轉到clear_bss
beqclear_bss /* skip relocation */
movr1, r6 /* r1 <- scratch for copy_loop */   代碼段的目標地址
ldr r3, _image_copy_end_ofs                        要複製的長度
addr2, r0, r3 /* r2 <- source end address     */   代碼段的結束地址
開始循環複製代碼段
copy_loop:
ldmia r0!, {r9-r10} /* copy from source address [r0]    */
stmia r1!, {r9-r10} /* copy to   target address [r1]    */
cmpr0, r2 /* until source end address [r2]    */
blo copy_loop
重定位代碼,修改代碼爲新的地址
#ifndef CONFIG_SPL_BUILD
R0是目標內存,修改後放入目標的內存中
ldr r0, _TEXT_BASE /* r0 <- Text base */  代碼段的基地址
sub r9, r6, r0 /* r9 <- relocation offset */    重定位的偏移值   r9=代碼段目標地址 – 
代碼段的基地址
ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */ r10=動態起始地址
addr10, r10, r0 /* r10 <- sym table in FLASH */ r10 = 動態符號表的目標存放地址
r2是rel_dyn段的內容,這個段就是代表要修改的數據.
這個段都是放一個要修改的值,然後放一個標記.
偏移值分爲兩種:相對位移和絕對位移
ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */ 要修改地址的信息的一些變量都
放在這裏
addr2, r2, r0 /* r2 <- rel dyn start in FLASH */
r3是放結束的地址,用來判斷是否結束
ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */
addr3, r3, r0 /* r3 <- rel dyn end in FLASH */
fixloop:
從R2取出要修改的值,
ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */
addr0, r0, r9 /* r0 <- location to fix up in RAM */
從R2的下一個位置讀取一個值,這個值是用來判斷是運行fixrel還是fixabs用
ldr r1, [r2, #4]
andr7, r1, #0xff
這裏判斷是相對位移還是絕對位移,然後修改
cmpr7, #23 /* relative fixup? */
beqfixrel
cmpr7, #2 /* absolute fixup? */
beqfixabs
/* ignore unknown type of fixup */
b fixnext
fixabs:   修改絕對位移,就是運行前纔可以確定的
/* absolute fix: set location to (offset) symbol value */
movr1, r1, LSR #4 /* r1 <- symbol index in .dynsym */
addr1, r10, r1 /* r1 <- address of symbol in table */
ldr r1, [r1, #4] /* r1 <- symbol value */
addr1, r1, r9 /* r1 <- relocated sym addr */
b fixnext
fixrel:   修改相對位移,編譯時就確定了地址
/* relative fix: increase location by offset */
ldr r1, [r0]
addr1, r1, r9
fixnext:  寫入本次修改的內容,判斷是否運行完成, 
str r1, [r0]    將r1寫入目標內存
addr2, r2, #8 /* each rel.dyn entry is 8 bytes */
cmpr2, r3     判斷是否結束,
blo fixloop    沒有結束,繼續循環
b clear_bss  結束了
#endif /* #ifndef CONFIG_SPL_BUILD */
uboot命令
環境變量
printenv 打印當前的環境變量
運行
go 
bootm 0x82000000
boot    - boot default, i.e., run 'bootcmd'
  根據bootcmd環境變量運行命令
bootd   - boot default, i.e., run 'bootcmd' 根據bootcmd環境變量運行命令
nand flash
以太網
ping 192.168.1.2
tftp
發佈了17 篇原創文章 · 獲贊 14 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章