uboot 分析之 启动流程
生活随笔
收集整理的這篇文章主要介紹了
uboot 分析之 启动流程
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
uboot的啟動(dòng)流程:
看一幅圖:
1.第一階段:start.s的內(nèi)容:
#include <config.h> @該文件是第二步中mkconfig文件執(zhí)行時(shí)創(chuàng)建的。include/config.h #include <version.h> #include <status_led.h> @在include目錄下。 /* ************************************************************************* * * Jump vector table as in table 3.1 in [1] * ************************************************************************* */ @這是一個(gè)異常跳轉(zhuǎn)表, .globl _start _start:? b start_code? @start_code才是真正的啟動(dòng)代碼 ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used ldr pc, _irq ldr pc, _fiq
_undefined_instruction: .word undefined_instruction @在標(biāo)號(hào)_undefined_instruction處存儲(chǔ)了一個(gè)變量,該變量也是一個(gè)標(biāo)號(hào)地址 _software_interrupt: .word software_interrupt @執(zhí)行上面的ldr pc, _undefined_instruction;指令會(huì)將變量undefined_instruction的值裝入PC _prefetch_abort: .word prefetch_abort @pc指向一個(gè)地址,CPU從該地址中取指執(zhí)行 _data_abort: .word data_abort _not_used: .word not_used _irq: .word irq _fiq: .word fiq .balignl 16,0xdeadbeef /* ************************************************************************* * * Startup Code (called from the ARM reset exception vector) * * do important init only if we don't start from memory! * relocate armboot to ram * setup stack * jump to second stage * ************************************************************************* */ _TEXT_BASE: .word?TEXT_BASE @變量TEXT_BASE由連接腳本指定,
.globl _armboot_start
_armboot_start: .word?_start @_start是在起始代碼處定義的標(biāo)號(hào),當(dāng)跳到_armboot_start后還是會(huì)跳轉(zhuǎn)到_start /* * These are defined in the board-specific linker script. */ .globl _bss_start
_bss_start: .word?__bss_start? @這是board/mini2440/u-boot.lds腳本中的變量,
.globl _bss_end _bss_end: .word?_end? @這也是board/mini2440/u-boot.lds腳本中的變量,
#ifdef CONFIG_USE_IRQ? @這個(gè)宏在include/configs/$(board_name).h中定義。可以取消 /* IRQ stack memory (calculated at run-time) */ .globl IRQ_STACK_START IRQ_STACK_START: .word 0x0badc0de /* IRQ stack memory (calculated at run-time) */ .globl FIQ_STACK_START FIQ_STACK_START: .word 0x0badc0de #endif /* * the actual start code */
start_code:? @這是真正的啟動(dòng)代碼 /*?set the cpu to SVC32 mode*/ mrs r0,cpsr bic r0,r0,#0x1f orr r0,r0,#0xd3 msr cpsr,r0 bl coloured_LED_init @這個(gè)函數(shù)在status_led.h中被提升了作用域,但是在哪里面實(shí)現(xiàn)??status_led.h文件 bl red_LED_on @同上 @下面這些宏開關(guān)也是在include/configs/$(board_name).h中定義?? #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
/* * relocate exception table */ ldr r0, =_start ldr r1, =0x0 mov r2, #16
copyex: subs r2, r2, #1 ldr r3, [r0], #4 str r3, [r1], #4 bne copyex #endif
@下面這些宏開關(guān)是在include/configs/$(board_name).h中定義 #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)||defined(CONFIG_S3C2440) /* turn off the watchdog */ # if defined(CONFIG_S3C2400) # define pWTCON 0x15300000 # define INTMSK 0x14400008 /* Interupt-Controller base addresses */ # define CLKDIVN 0x14800014 /* clock divisor register */ #else # define pWTCON 0x53000000 # define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ # define INTSUBMSK 0x4A00001C # define CLKDIVN 0x4C000014 /* clock divisor register */ # endif #define CLK_CTL_BASE 0x4c000000 #define MDIV_405 0x7f<<12 #define PSDIV_405 0x21 #define UPLL_MDIV_48 0x38<<12 #define UPLL_PSDIV_48 0x22 #define MDIV_200 0xa1<<12 #define PSDIV_200 0x31 ldr r0, =pWTCON mov r1, #0x0 str r1, [r0]
/* * mask all IRQs by setting all bits in the INTMR - default */ mov r1, #0xffffffff ldr r0, =INTMSK str r1, [r0] # if defined(CONFIG_S3C2410) ldr r1, =0x3ff ldr r0, =INTSUBMSK str r1, [r0] # endif
/*add by gray*/ #if defined(CONFIG_S3C2440) ldr r1, =0x7fff ldr r0, =INTSUBMSK str r1, [r0] #endif
/*add by gray,這里是修改后的,其實(shí)可以在uboot啟動(dòng)的第二階段start_armboot()函數(shù)里調(diào)用board_init()函數(shù)時(shí)重置CPU鐘 對(duì)于S3C2440,MPLL(clk)=(2 * m * Fin) / p * 2^s, m = MDIV + 8, p = PDIV + 2, s =?SDIV. 這里MDIV =? 0x7f, PDIV = 0x2 ,SDIV = 0x1? */ #if defined(CONFIG_S3C2440) /*FCLK:HCLK:PCLK=1:2:4*/ ldr r0,?=CLKDIVN mov r1, #5 str r1,[r0] mrc p15,0,r1,c1,c0,0 /*read ctrl reg*/ orr r1,r1,#0xc0000000 /*ASYN*/ mcr p15,0,r1,c1,c0,0 /*write ctrl reg*/ mov r1,#CLK_CTL_BASE mov r2,#UPLL_MDIV_48 add r2, r2,#UPLL_PSDIV_48 str r2,[r1,#0x08] /*write UPLL first,48MHZ*/ mov r2,#MDIV_405 add r2,r2,#PSDIV_405? /*mpll_405MHZ*/ str r2,[r1,#0x04]? /*MPLLCON*/ #else /*F:H:P=1:2:4*/ ldr r0, =CLKDIVN mov r1, #3 str r1,[r0] mrc p15,0,r1,c1,c0,0? /*read ctrl reg*/ orr r1,r1,#0xc0000000 mcr p15,0,r1,c1,c0,0 mov r1,#CLK_CTL_BASE mov r2,#MDIV_200 add r2,r2,#PSDIV_200? /*mpll_200MHZ*/ str r2,[r1,#0x04]? /*MPLLCON*/ #endif #endif /*CONFIG_S3C2400 || CONFIG_S3C2410 || CONFIG_S3C2440*/
/* * we do sys-critical inits only at reboot, * not when booting from ram! */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit @如果沒有定義CONFIG_SKIP_LOWLEVEL_INIT,就進(jìn)行嚴(yán)格的初始化,調(diào)用lowlevel_init函數(shù) #endif #ifndef CONFIG_AT91RM9200 @AT91RM9200評(píng)估板,基于ARM920T內(nèi)核 #ifndef CONFIG_SKIP_RELOCATE_UBOOT
/* relocate U-Boot to RAM */ relocate:? 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 ? /*如果_start與_TEXT_BASE相等,就直接跳去stack_setup進(jìn)行棧的設(shè)置, 否則就要進(jìn)行代碼的拷貝,把代碼拷貝到內(nèi)存中*/
ldr r2, _armboot_start ldr r3, _bss_start? @計(jì)算代碼段大小=_bss_start-_armboot_start sub r2, r3, r2? /* r2 <- size of armboot */ add r2, r0, r2? /* r2 <- source end address */ @ r2 = _start的地址+代碼段大小 copy_loop: ldmia r0!, {r3-r10}? /* copy from source address [r0] */ stmia r1!, {r3-r10}? /* copy to target address [r1] */ cmp r0, r2? /* until source end addreee [r2] */ ble copy_loop #endif? /* CONFIG_SKIP_RELOCATE_UBOOT */ #endif /* Set up the stack,設(shè)置棧 */ stack_setup: ldr r0,?_TEXT_BASE?/*?upper 128 KiB: relocated uboot?*/ sub r0, r0, #CFG_MALLOC_LEN? /* malloc area,這是堆區(qū) */ sub r0, r0, #CFG_GBL_DATA_SIZE? /* bdinfo */ #ifdef CONFIG_USE_IRQ @如果定義了IRQ,就要為IRQ,FIQ分配中斷棧。 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) #endif sub sp, r0, #12? /* leave 3 words for abort-stack */ clear_bss:? @清除bss段,_bss_start 和_bss_end就是u-boot.lds腳本傳入的變量 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
ldr pc, _start_armboot _start_armboot: .word?start_armboot?@跳到start_armboot()函數(shù)執(zhí)行,進(jìn)入uboot的第二階段 /* ************************************************************************* * * CPU_init_critical registers * * setup important registers * setup memory timing * ************************************************************************* */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT cpu_init_crit:? @進(jìn)行嚴(yán)格的初始化,關(guān)閉I/D caches,MMU,
/* * 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 #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF) #else
bl lowlevel_init? @這個(gè)函數(shù)是重點(diǎn)。。在lowlevel_init.S中 #endif
mov lr, ip mov pc, lr #endif? /* CONFIG_SKIP_LOWLEVEL_INIT */ lowlevel_init.S的內(nèi)容: _TEXT_BASE: .word TEXT_BASE .globl lowlevel_init
lowlevel_init:? @很明顯,是初始化SDRAM /* memory control configuration */ /* make r0 relative the current location so that it */ /* reads SMRDATA out of FLASH rather than memory ! */ ldr r0, =SMRDATA ldr r1, _TEXT_BASE sub r0, r0, r1 ldr r1, =BWSCON? /* Bus Width Status Controller */ add r2, r0, #13*4
0: ldr r3, [r0], #4 str r3, [r1], #4 cmp r2, r0 bne 0b
/* everything is fine now */ mov pc, lr .ltorg
2.進(jìn)入uboot啟動(dòng)的第二階段:start_armboot()
start_armboot()在board.c中,處于lib_arm/下,在進(jìn)入lib_arm目錄下編譯LIBS目標(biāo)時(shí)依賴board.o文件
void start_armboot?(void)
{
?init_fnc_t?**init_fnc_ptr;
?char?*s;
#if?!defined(CFG_NO_FLASH)?||?defined?(CONFIG_VFD)?||?defined(CONFIG_LCD)
?ulong size;
#endif
#if?defined(CONFIG_VFD)?||?defined(CONFIG_LCD)
?unsigned long addr;
#endif
?//gd是個(gè)寄存器變量,ARM平臺(tái)對(duì)應(yīng)R8寄存器
?/*?Pointer?is?writable since we allocated a register?for?it
??*_armboot_start是代碼的起始地址,鏈接腳本指定為0x33f80000,CFG_MALLOC_LEN=192k,
??*所以gd的起始地址=0x33F50000
??*/
?gd?=?(gd_t*)(_armboot_start?-?CFG_MALLOC_LEN?-?sizeof(gd_t));
?/*?compiler optimization barrier needed?for?GCC?>=?3.4?*/
?__asm__ __volatile__("":?:?:"memory");
?memset?((void*)gd,?0,?sizeof?(gd_t));//清空gd_t結(jié)構(gòu)體
?gd->bd?=?(bd_t*)((char*)gd?-?sizeof(bd_t));//bd_t結(jié)構(gòu)體
?memset?(gd->bd,?0,?sizeof?(bd_t));?
?gd->flags?|=?GD_FLG_RELOC;
?monitor_flash_len?=?_bss_start?-?_armboot_start;//uboot代碼的長度
?//對(duì)結(jié)構(gòu)體init_fnc_t?*init_sequence[]數(shù)組中的函數(shù)指針挨個(gè)調(diào)用。
?for?(init_fnc_ptr?=?init_sequence;?*init_fnc_ptr;?++init_fnc_ptr)?{
??if?((*init_fnc_ptr)()?!=?0)?{
???hang?();
??}
?}
?/*?初始化flash*/
?size?=?flash_init?();
?。。。。。。
?/*?初始化一個(gè)堆空間?*/
?mem_malloc_init?(_armboot_start?-?CFG_MALLOC_LEN);
?nand_init();?/*?go init the NAND?*/
?/*?初始化環(huán)境變量,將環(huán)境參數(shù)讀入內(nèi)存指定位置?*/
?env_relocate?();
?/*?must?do?this after the framebuffer?is?allocated,串口初始化?*/
?serial_initialize();
?/*?IP Address?*/
?gd->bd->bi_ip_addr?=?getenv_IPaddr?("ipaddr");
?/*?MAC Address,省略?*/
?devices_init?();?/*?get?the devices list going.?*/
?jumptable_init?();?/*?跳轉(zhuǎn)表初始化?*/
?console_init_r?();?/*?fully init console as a device?*/
?/*?使能異常中斷?*/
?enable_interrupts?();
?/*?Perform network card initialisation?if?necessary?*/
#ifdef CONFIG_DRIVER_CS8900
?cs8900_get_enetaddr?(gd->bd->bi_enetaddr);
#endif
?/*?main_loop()?can return?to?retry autoboot,?if?so just run it again.?*/
?for?(;;)?{
??main_loop?();
?}
?/*?NOTREACHED?-?no way out of command?loop?except booting?*/
}
??init_fnc_t?*init_sequence[]?=?{
?????????cpu_init,?/*?基本的處理器相關(guān)配置,初始化IRQ/FIQ模式的棧?--?cpu/arm920t/cpu.c?*/
?????????board_init,?/*?基本的板級(jí)相關(guān)配置,設(shè)置系統(tǒng)時(shí)鐘等?--?board/smdk2410/smdk2410.c?*/
?????????interrupt_init,?/*?初始化定時(shí)器處理?--?cpu/arm920t/s3c24x0/interrupt.c?*/
?????????env_init,?/*?初始化環(huán)境變量,檢查Flash上的環(huán)境參數(shù)是否有效?--?common/env_flash.c?*/
?????????init_baudrate,?/*?初始化波特率設(shè)置?--?lib_arm/board.c?*/
?????????serial_init,?/*?串口通訊設(shè)置?--?cpu/arm920t/s3c24x0/serial.c?*/
?????????console_init_f,?/*?控制臺(tái)初始化階段1?--?common/console.c?*/
?????????display_banner,?/*?打印u-boot信息?--?lib_arm/board.c?*/
?????????dram_init,?/*?配置可用的RAM,檢測系統(tǒng)內(nèi)存映射?--?board/smdk2410/smdk2410.c?*/
?????????display_dram_config,?/*?顯示RAM的配置大小?--?lib_arm/board.c?*/
?????????NULL,
??};
??下面逐個(gè)分析初始化函數(shù):
1.int?cpu_init?(void)
{
?/*?setup up stacks?if?necessary?*/
#ifdef CONFIG_USE_IRQ
?IRQ_STACK_START?=?_armboot_start?-?CFG_MALLOC_LEN?-?CFG_GBL_DATA_SIZE?-?4;
?FIQ_STACK_START?=?IRQ_STACK_START?-?CONFIG_STACKSIZE_IRQ;
#endif
?return 0;
}
2.int?board_init?(void)//設(shè)置系統(tǒng)時(shí)鐘,配置引腳,使能緩存
{
?S3C24X0_CLOCK_POWER?*?const?clk_power?=?S3C24X0_GetBase_CLOCK_POWER();
?S3C24X0_GPIO?*?const?gpio?=?S3C24X0_GetBase_GPIO();
?/*?to?reduce PLL lock?time,?adjust the LOCKTIME register?*/
?clk_power->LOCKTIME?=?0xFFFFFF;
?/*?configure MPLL?*/
?clk_power->MPLLCON?=?((M_MDIV?<<?12)?+?(M_PDIV?<<?4)?+?M_SDIV);
?......
?/*?configure UPLL?*/
?clk_power->UPLLCON?=?((U_M_MDIV?<<?12)?+?(U_M_PDIV?<<?4)?+?U_M_SDIV);
?......
?/*?set?up the I/O ports?*/
?gpio->GPACON?=?0x007FFFFF;
?gpio->GPBCON?=?0x00044555;
?gpio->GPBUP?=?0x000007FF;
?gpio->GPCCON?=?0xAAAAAAAA;
?gpio->GPCUP?=?0x0000FFFF;
?gpio->GPDCON?=?0xAAAAAAAA;
?gpio->GPDUP?=?0x0000FFFF;
?gpio->GPECON?=?0xAAAAAAAA;
?gpio->GPEUP?=?0x0000FFFF;
?gpio->GPFCON?=?0x000055AA;
?gpio->GPFUP?=?0x000000FF;
?gpio->GPGCON?=?0xFF95FFBA;
?gpio->GPGUP?=?0x0000FFFF;
?gpio->GPHCON?=?0x002AFAAA;
?gpio->GPHUP?=?0x000007FF;
?/*?arch number of SMDK2410-Board?*/
?gd->bd->bi_arch_number?=?MACH_TYPE_SMDK2410;
?/*?address of boot parameters?*/
?gd->bd->bi_boot_params?=?0x30000100;//為什么是這個(gè)地址
?icache_enable();//下面這兩個(gè)函數(shù)都是設(shè)置協(xié)處理器的相關(guān)寄存器,使能緩存
?dcache_enable();
}
3.int?interrupt_init?(void) //初始化2410的PWM timer 4,使其能自動(dòng)裝載計(jì)數(shù)值,
??? //恒定的產(chǎn)生時(shí)間中斷信號(hào),但是中斷被屏蔽了用不上。
{
?S3C24X0_TIMERS?*?const?timers?=?S3C24X0_GetBase_TIMERS();
?/*?use PWM Timer 4 because it has no output?*/
?/*?prescaler?for?Timer 4?is?16?*/
?timers->TCFG0?=?0x0f00;
?if?(timer_load_val?==?0)
?{
??/*
???*?for?10 ms clock period @ PCLK with 4 bit divider?=?1/2
???*?(default)?and?prescaler?=?16.?Should be 10390
???*?@33.25MHz?and?15625 @ 50 MHz
???*/
??timer_load_val?=?get_PCLK()/(2?*?16?*?100);
?}
?/*?load value?for?10 ms timeout?*/
?lastdec?=?timers->TCNTB4?=?timer_load_val;
?/*?auto load,?manual update of Timer 4?*/
?timers->TCON?=?(timers->TCON?&?~0x0700000)?|?0x600000;
?/*?auto load,?start Timer 4?*/
?timers->TCON?=?(timers->TCON?&?~0x0700000)?|?0x500000;
?timestamp?=?0;
?return?(0);
}
4.int?env_init(void)
{
?int?crc1_ok?=?0,?crc2_ok?=?0;
?uchar flag1?=?flash_addr->flags;
?uchar flag2?=?flash_addr_new->flags;
?ulong addr_default?=?(ulong)&default_environment[0];
?ulong addr1?=?(ulong)&(flash_addr->data);
?ulong addr2?=?(ulong)&(flash_addr_new->data);
?crc1_ok?=?(crc32(0,?flash_addr->data,?ENV_SIZE)?==?flash_addr->crc);
?crc2_ok?=?(crc32(0,?flash_addr_new->data,?ENV_SIZE)?==?flash_addr_new->crc);
?if?(crc1_ok?&&?!?crc2_ok)?{
??gd->env_addr?=?addr1;
??gd->env_valid?=?1;
?}?else?if?(!?crc1_ok?&&?crc2_ok)?{
??gd->env_addr?=?addr2;
??gd->env_valid?=?1;
?}?else?if?(!?crc1_ok?&&?!?crc2_ok)?{
??gd->env_addr?=?addr_default;
??gd->env_valid?=?0;
?}?else?if?(flag1?==?ACTIVE_FLAG?&&?flag2?==?OBSOLETE_FLAG)?{
??gd->env_addr?=?addr1;
??gd->env_valid?=?1;
?}?else?if?(flag1?==?OBSOLETE_FLAG?&&?flag2?==?ACTIVE_FLAG)?{
??gd->env_addr?=?addr2;
??gd->env_valid?=?1;
?}?else?if?(flag1?==?flag2)?{
??gd->env_addr?=?addr1;
??gd->env_valid?=?2;
?}?else?if?(flag1?==?0xFF)?{
??gd->env_addr?=?addr1;
??gd->env_valid?=?2;
?}?else?if?(flag2?==?0xFF)?{
??gd->env_addr?=?addr2;
??gd->env_valid?=?2;
?}
?return?(0);
}
PS:
uboot的重要的數(shù)據(jù)結(jié)構(gòu)
1)gd 全局?jǐn)?shù)據(jù)變量指針,它保存了u-boot運(yùn)行需要的全局?jǐn)?shù)據(jù),類型定義:
? typedef struct global_data {
?????????? bd_t? *bd;????? //board data pointor板子數(shù)據(jù)指針
?????????? unsigned long flags; ?//指示標(biāo)志,如設(shè)備已經(jīng)初始化標(biāo)志等。
?????????? unsigned long baudrate; //串口波特率
?????????? unsigned long have_console; /* 串口初始化標(biāo)志*/
?????????? unsigned long reloc_off;?? /* 重定位偏移,就是實(shí)際定向的位置與編譯連接時(shí)指定的位置之差,一般為0 */
?????????? unsigned long env_addr; /* 環(huán)境參數(shù)地址*/
?????????? unsigned long env_valid; /* 環(huán)境參數(shù)CRC檢驗(yàn)有效標(biāo)志 */
?????????? unsigned long fb_base; /* base address of frame buffer */
????????? #ifdef CONFIG_VFD
?????????? unsigned char vfd_type; /* display type */
????????? #endif
?????????? void? **jt;? /* 跳轉(zhuǎn)表,1.1.6中用來函數(shù)調(diào)用地址登記 */
????????? } gd_t;
2)bd 板子數(shù)據(jù)指針。板子很多重要的參數(shù)。 類型定義如下:????
?? typedef struct bd_info {
???????????? int?? bi_baudrate;???? /* 串口波特率 */
???????????? unsigned long bi_ip_addr;?? /* IP 地址 */
???????????? unsigned char bi_enetaddr[6]; /* MAC地址*/
???????????? struct environment_s??????? *bi_env;
???????????? ulong???????? bi_arch_number; /* unique id for this board */
???????????? ulong???????? bi_boot_params; /* 啟動(dòng)參數(shù) */
???????????? struct??? ???/* RAM 配置 */
???????????? {
??????????? ulong start;
??????????? ulong size;
???????????? }bi_dram[CONFIG_NR_DRAM_BANKS];
???????? } bd_t;?
3)環(huán)境變量指針 env_t *env_ptr = (env_t *)(&environment[0]);(common/env_flash.c)
? env_ptr指向環(huán)境參數(shù)區(qū),系統(tǒng)啟動(dòng)時(shí)默認(rèn)的環(huán)境參數(shù)environment[],定義在common/environment.c中。
? 參數(shù)解釋:
??? bootdelay 定義執(zhí)行自動(dòng)啟動(dòng)的等候秒數(shù)?
??? baudrate 定義串口控制臺(tái)的波特率?
??? netmask 定義以太網(wǎng)接口的掩碼?
??? ethaddr 定義以太網(wǎng)接口的MAC地址?
??? bootfile 定義缺省的下載文件?
??? bootargs 定義傳遞給Linux內(nèi)核的命令行參數(shù)?
??? bootcmd 定義自動(dòng)啟動(dòng)時(shí)執(zhí)行的幾條命令?
??? serverip 定義tftp服務(wù)器端的IP地址?
??? ipaddr 定義本地的IP地址?
??? stdin 定義標(biāo)準(zhǔn)輸入設(shè)備,一般是串口?
??? stdout 定義標(biāo)準(zhǔn)輸出設(shè)備,一般是串口?
??? stderr 定義標(biāo)準(zhǔn)出錯(cuò)信息輸出設(shè)備,一般是串口?
? 4)設(shè)備相關(guān):
?? 標(biāo)準(zhǔn)IO設(shè)備數(shù)組?evice_t *stdio_devices[] = { NULL, NULL, NULL };
?? 設(shè)備列表 list_t??? devlist = 0;
?? device_t的定義:include\devices.h中:
??? typedef struct {
???? int flags;??? /* Device flags: input/output/system */
???? int ext;????? /* Supported extensions?? */
???? char name[16];?? /* Device name??? */????
??? /* GENERAL functions */????
???? int (*start) (void);? /* To start the device?? */
???? int (*stop) (void);? /* To stop the device?? */????
??? /* 輸出函數(shù) */????
???? void (*putc) (const char c); /* To put a char?? */
???? void (*puts) (const char *s); /* To put a string (accelerator) */???
??? /* 輸入函數(shù) */???
???? int (*tstc) (void);? /* To test if a char is ready... */
???? int (*getc) (void);? /* To get that char?? */???
??? /* Other functions */????
???? void *priv;?? /* Private extensions?? */
??? } device_t;
? u-boot把可以用為控制臺(tái)輸入輸出的設(shè)備添加到設(shè)備列表devlist,并把當(dāng)前用作標(biāo)準(zhǔn)IO的設(shè)備指針加入stdio_devices數(shù)組中。
? 在調(diào)用標(biāo)準(zhǔn)IO函數(shù)如printf()時(shí)將調(diào)用stdio_devices數(shù)組對(duì)應(yīng)設(shè)備的IO函數(shù)如putc()。
5)命令相關(guān)的數(shù)據(jù)結(jié)構(gòu),后面介紹。
6)與具體設(shè)備有關(guān)的數(shù)據(jù)結(jié)構(gòu),
???? 如flash_info_t flash_info[CFG_MAX_FLASH_BANKS];記錄nor flash的信息。
???? nand_info_t nand_info[CFG_MAX_NAND_DEVICE]; nand flash塊設(shè)備信息
?????
?????
5.static int init_baudrate (void)
{
?char tmp[64];?/* long enough for environment variables */
?int i = getenv_r ("baudrate", tmp, sizeof (tmp));//環(huán)境變量存于tmp緩沖中
?gd->bd->bi_baudrate = gd->baudrate = (i > 0)
???? (int) simple_strtoul (tmp, NULL, 10)
???: CONFIG_BAUDRATE; return (0);
}
6.int serial_init()實(shí)際調(diào)用下面這個(gè)函數(shù),在移植時(shí)這個(gè)函數(shù)是第一個(gè)要修改的,因?yàn)橐玫酱谳敵鲂畔?br style="word-wrap:break-word" /> static int serial_init_dev(const int dev_index)
{
?S3C24X0_UART * const uart = S3C24X0_GetBase_UART(dev_index); /* FIFO enable, Tx/Rx FIFO clear */
?uart->UFCON = 0x07;?//這里使用的是串口0.
?uart->UMCON = 0x0; /* Normal,No parity,1 stop,8 bit */
?uart->ULCON = 0x3;
?/*
? * tx=level,rx=edge,disable timeout int.,enable rx error int.,
? * normal,interrupt or polling
? */
?uart->UCON = 0x245; #ifdef CONFIG_HWFLOW
?uart->UMCON = 0x1; /* RTS up */
#endif /* FIXME: This is sooooooooooooooooooo ugly */
#if defined(CONFIG_ARCH_GTA02_v1) || defined(CONFIG_ARCH_GTA02_v2)
?/* we need auto hw flow control on the gsm and gps port */
?if (dev_index == 0 || dev_index == 1)
??uart->UMCON = 0x10;
#endif
?_serial_setbrg(dev_index); return (0);
}
7.由于標(biāo)準(zhǔn)設(shè)備還沒有初始化(gd->flags & GD_FLG_DEVINIT=0),這時(shí)控制臺(tái)使用串口作為控制臺(tái)
??? 函數(shù)只有一句:gd->have_console = 1;
int console_init_f (void)
{
?gd->have_console = 1;?//將標(biāo)志位置1 #ifdef CONFIG_SILENT_CONSOLE
?if (getenv("silent") != NULL)
??gd->flags |= GD_FLG_SILENT;
#endif return (0);
}
8.int dram_init (void)
{//PHYS_SDRAM_1在整個(gè)include/configs.h文件中有很多定義,只在一個(gè)地方define為0x30000000
?//PHYS_SDRAM_1_SIZE定義為64MB
?gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
?gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; return 0;
}
9. ulong flash_init (void) 這里smdk2410的默認(rèn)flash是AMD的,mini2440的板子是SST39F1601,如果NOR Flash符合CFI接口標(biāo)準(zhǔn),可以使用drivers/cfi_flash.c
里面的接口函數(shù),否則就得重寫。如果使用cfi_flash.c,需要修改include/configs/$(board_name).h,在里面增加:
?#define CFG_FLASH_CFI_DRIVER ?1
在board/$(board_name)/Makefile中去掉flash.o
在《嵌入式linux完全手冊(cè)》上P273頁有說明。 首先是有一個(gè)變量flash_info_t flash_info[CFG_MAX_FLASH_BANKS]來記錄flash的信息。flash_info_t定義:
?? typedef struct {
??? ulong size;?? /* 總大小BYTE? */
??? ushort sector_count;? /* 總的sector數(shù)*/
??? ulong flash_id;? /* combined device & manufacturer code */
??? ulong start[CFG_MAX_FLASH_SECT];?? /* 每個(gè)sector的起始物理地址。 */
??? uchar protect[CFG_MAX_FLASH_SECT]; /* 每個(gè)sector的保護(hù)狀態(tài),如果置1,在執(zhí)行erase操作的時(shí)候?qū)⑻^對(duì)應(yīng)sector*/
???? #ifdef CFG_FLASH_CFI //我不管CFI接口。
??? .....
???? #endif
?? } flash_info_t;
??? flash_init()的操作就是讀取ID號(hào),ID號(hào)指明了生產(chǎn)商和設(shè)備號(hào),根據(jù)這些信息設(shè)置size,sector_count,flash_id.
??? 以及start[]、protect[]。 10.mem_malloc_init()
11.nand_init()
12.env_relocate()
13.devices_init ();?/* get the devices list going. */定義于common/devices.c
14.jumptable_init ()
15.console_init_r ();?/* fully init console as a device ,前面結(jié)構(gòu)體中的是前期控制臺(tái)初始化,這是后期*/
主要過程:查看環(huán)境參數(shù)stdin,stdout,stderr中對(duì)標(biāo)準(zhǔn)IO的指定的設(shè)備名稱,再按照環(huán)境指定的名稱搜索devlist,將搜到的設(shè)備指針賦給標(biāo)準(zhǔn)IO數(shù)組stdio_devices[]。置gd->flag標(biāo)志GD_FLG_DEVINIT。這個(gè)標(biāo)志影響putc,getc函數(shù)的實(shí)現(xiàn),未定義此標(biāo)志時(shí)直接由串口serial_getc和serial_putc實(shí)現(xiàn),定義以后通過標(biāo)準(zhǔn)設(shè)備數(shù)組stdio_devices[]中的putc和getc來實(shí)現(xiàn)IO。
?下面是相關(guān)代碼:
??? void putc (const char c)
???????? {
???????? #ifdef CONFIG_SILENT_CONSOLE
????????? if (gd->flags & GD_FLG_SILENT)//GD_FLG_SILENT無輸出標(biāo)志
?????????? return;
???????? #endif
????????? if (gd->flags & GD_FLG_DEVINIT) {//設(shè)備list已經(jīng)初始化
?????????? /* Send to the standard output */
?????????? fputc (stdout, c);
????????? } else {
?????????? /* Send directly to the handler */
?????????? serial_putc (c);//未初始化時(shí)直接從串口輸出。
????????? }
???????? }
?????? void fputc (int file, const char c)
??????? {
???????? if (file < MAX_FILES)
????????? stdio_devices[file]->putc (c);
??????? } 為什么要使用devlist,std_device[]? 為了更靈活地實(shí)現(xiàn)標(biāo)準(zhǔn)IO重定向,任何可以作為標(biāo)準(zhǔn)IO的設(shè)備,如USB鍵盤,LCD屏,串口等都可以對(duì)應(yīng)一個(gè)device_t的結(jié)構(gòu)體變量,只需要實(shí)現(xiàn)getc和putc等函數(shù),就能加入到devlist列表中去,也就可以被assign為標(biāo)準(zhǔn)IO設(shè)備std_device中去。如函數(shù) int console_assign (int file, char *devname); /* Assign the console 重定向標(biāo)準(zhǔn)輸入輸出*/ 這個(gè)函數(shù)功能就是把名為devname的設(shè)備重定向?yàn)闃?biāo)準(zhǔn)IO文件file(stdin,stdout,stderr)。其執(zhí)行過程是在devlist中查找devname的設(shè)備,返回這個(gè)設(shè)備的device_t指針,并把指針值賦給std_device[file]。
16.enable_interrupts (); (1)首先,需要設(shè)置系統(tǒng)時(shí)鐘、初始化串口,只要這兩個(gè)設(shè)置好,就能從串口看到打印信息。
? board_init函數(shù)設(shè)置MPLL,改變系統(tǒng)時(shí)鐘,這是一個(gè)開發(fā)板相關(guān)的函數(shù)。
? serial_init函數(shù)用來初始化串口,設(shè)置UART控制器,是CPU相關(guān)的函數(shù),
? (2)檢測系統(tǒng)內(nèi)存映射
? 對(duì)于特定的開發(fā)板,內(nèi)存分布是比較明確的,dram_init函數(shù)指定了目標(biāo)開發(fā)板的內(nèi)存起始地址為0x30000000,大小為64M
? (3)U-boot命令的格式
? uboot中的每個(gè)命令都是通過U_BOOT_CMD宏來定義,格式:U_BOOT_CMD(name,maxargs,repeatable,command,"usage","help")
? 這個(gè)宏定義在include/command.h中,
? (4)為內(nèi)核設(shè)置啟動(dòng)參數(shù)
? uboot是通過標(biāo)記列表向內(nèi)核傳遞參數(shù),設(shè)置內(nèi)存標(biāo)記、命令標(biāo)記的函數(shù)setup_memory_tags、setup_commandline_tag,
? 在lib_arm/armlinux.c中定義實(shí)現(xiàn)。如果要定義一個(gè)命令,需要在include/configs/$(board_name).h中增加一個(gè)關(guān)于
? 命令的配置項(xiàng):
? 如: #define CONFIG_CMDLINE_TAG? 1
? 對(duì)于arm架構(gòu)的CPU,都是通過lib_arm/armlinux.c中的do_bootm_linux函數(shù)來啟動(dòng)內(nèi)核,在這個(gè)函數(shù)中,設(shè)置標(biāo)記列表,最后通過
? the_kernel(0,bd->bi_arch_number,bd->bi_boot_params)調(diào)用內(nèi)核。 PS: 1.分析過程參照了一位網(wǎng)友的文章,很有參考價(jià)值,給我很大幫助。我只是按照配置->編譯->啟動(dòng)過程 的這么一個(gè)認(rèn)識(shí)過程來分析,可能會(huì)顯得比較混亂。 ?U-BOOT源碼分析及移植.txt?
??
2.博客鏈接:http://blog.csdn.net/liukun321/article/details/5680504
1.第一階段:start.s的內(nèi)容:
點(diǎn)擊(此處)折疊或打開
2.進(jìn)入uboot啟動(dòng)的第二階段:start_armboot()
點(diǎn)擊(此處)折疊或打開
PS:
uboot的重要的數(shù)據(jù)結(jié)構(gòu)
1)gd 全局?jǐn)?shù)據(jù)變量指針,它保存了u-boot運(yùn)行需要的全局?jǐn)?shù)據(jù),類型定義:
? typedef struct global_data {
?????????? bd_t? *bd;????? //board data pointor板子數(shù)據(jù)指針
?????????? unsigned long flags; ?//指示標(biāo)志,如設(shè)備已經(jīng)初始化標(biāo)志等。
?????????? unsigned long baudrate; //串口波特率
?????????? unsigned long have_console; /* 串口初始化標(biāo)志*/
?????????? unsigned long reloc_off;?? /* 重定位偏移,就是實(shí)際定向的位置與編譯連接時(shí)指定的位置之差,一般為0 */
?????????? unsigned long env_addr; /* 環(huán)境參數(shù)地址*/
?????????? unsigned long env_valid; /* 環(huán)境參數(shù)CRC檢驗(yàn)有效標(biāo)志 */
?????????? unsigned long fb_base; /* base address of frame buffer */
????????? #ifdef CONFIG_VFD
?????????? unsigned char vfd_type; /* display type */
????????? #endif
?????????? void? **jt;? /* 跳轉(zhuǎn)表,1.1.6中用來函數(shù)調(diào)用地址登記 */
????????? } gd_t;
2)bd 板子數(shù)據(jù)指針。板子很多重要的參數(shù)。 類型定義如下:????
?? typedef struct bd_info {
???????????? int?? bi_baudrate;???? /* 串口波特率 */
???????????? unsigned long bi_ip_addr;?? /* IP 地址 */
???????????? unsigned char bi_enetaddr[6]; /* MAC地址*/
???????????? struct environment_s??????? *bi_env;
???????????? ulong???????? bi_arch_number; /* unique id for this board */
???????????? ulong???????? bi_boot_params; /* 啟動(dòng)參數(shù) */
???????????? struct??? ???/* RAM 配置 */
???????????? {
??????????? ulong start;
??????????? ulong size;
???????????? }bi_dram[CONFIG_NR_DRAM_BANKS];
???????? } bd_t;?
3)環(huán)境變量指針 env_t *env_ptr = (env_t *)(&environment[0]);(common/env_flash.c)
? env_ptr指向環(huán)境參數(shù)區(qū),系統(tǒng)啟動(dòng)時(shí)默認(rèn)的環(huán)境參數(shù)environment[],定義在common/environment.c中。
? 參數(shù)解釋:
??? bootdelay 定義執(zhí)行自動(dòng)啟動(dòng)的等候秒數(shù)?
??? baudrate 定義串口控制臺(tái)的波特率?
??? netmask 定義以太網(wǎng)接口的掩碼?
??? ethaddr 定義以太網(wǎng)接口的MAC地址?
??? bootfile 定義缺省的下載文件?
??? bootargs 定義傳遞給Linux內(nèi)核的命令行參數(shù)?
??? bootcmd 定義自動(dòng)啟動(dòng)時(shí)執(zhí)行的幾條命令?
??? serverip 定義tftp服務(wù)器端的IP地址?
??? ipaddr 定義本地的IP地址?
??? stdin 定義標(biāo)準(zhǔn)輸入設(shè)備,一般是串口?
??? stdout 定義標(biāo)準(zhǔn)輸出設(shè)備,一般是串口?
??? stderr 定義標(biāo)準(zhǔn)出錯(cuò)信息輸出設(shè)備,一般是串口?
? 4)設(shè)備相關(guān):
?? 標(biāo)準(zhǔn)IO設(shè)備數(shù)組?evice_t *stdio_devices[] = { NULL, NULL, NULL };
?? 設(shè)備列表 list_t??? devlist = 0;
?? device_t的定義:include\devices.h中:
??? typedef struct {
???? int flags;??? /* Device flags: input/output/system */
???? int ext;????? /* Supported extensions?? */
???? char name[16];?? /* Device name??? */????
??? /* GENERAL functions */????
???? int (*start) (void);? /* To start the device?? */
???? int (*stop) (void);? /* To stop the device?? */????
??? /* 輸出函數(shù) */????
???? void (*putc) (const char c); /* To put a char?? */
???? void (*puts) (const char *s); /* To put a string (accelerator) */???
??? /* 輸入函數(shù) */???
???? int (*tstc) (void);? /* To test if a char is ready... */
???? int (*getc) (void);? /* To get that char?? */???
??? /* Other functions */????
???? void *priv;?? /* Private extensions?? */
??? } device_t;
? u-boot把可以用為控制臺(tái)輸入輸出的設(shè)備添加到設(shè)備列表devlist,并把當(dāng)前用作標(biāo)準(zhǔn)IO的設(shè)備指針加入stdio_devices數(shù)組中。
? 在調(diào)用標(biāo)準(zhǔn)IO函數(shù)如printf()時(shí)將調(diào)用stdio_devices數(shù)組對(duì)應(yīng)設(shè)備的IO函數(shù)如putc()。
5)命令相關(guān)的數(shù)據(jù)結(jié)構(gòu),后面介紹。
6)與具體設(shè)備有關(guān)的數(shù)據(jù)結(jié)構(gòu),
???? 如flash_info_t flash_info[CFG_MAX_FLASH_BANKS];記錄nor flash的信息。
???? nand_info_t nand_info[CFG_MAX_NAND_DEVICE]; nand flash塊設(shè)備信息
?????
?????
5.static int init_baudrate (void)
{
?char tmp[64];?/* long enough for environment variables */
?int i = getenv_r ("baudrate", tmp, sizeof (tmp));//環(huán)境變量存于tmp緩沖中
?gd->bd->bi_baudrate = gd->baudrate = (i > 0)
???? (int) simple_strtoul (tmp, NULL, 10)
???: CONFIG_BAUDRATE; return (0);
}
6.int serial_init()實(shí)際調(diào)用下面這個(gè)函數(shù),在移植時(shí)這個(gè)函數(shù)是第一個(gè)要修改的,因?yàn)橐玫酱谳敵鲂畔?br style="word-wrap:break-word" /> static int serial_init_dev(const int dev_index)
{
?S3C24X0_UART * const uart = S3C24X0_GetBase_UART(dev_index); /* FIFO enable, Tx/Rx FIFO clear */
?uart->UFCON = 0x07;?//這里使用的是串口0.
?uart->UMCON = 0x0; /* Normal,No parity,1 stop,8 bit */
?uart->ULCON = 0x3;
?/*
? * tx=level,rx=edge,disable timeout int.,enable rx error int.,
? * normal,interrupt or polling
? */
?uart->UCON = 0x245; #ifdef CONFIG_HWFLOW
?uart->UMCON = 0x1; /* RTS up */
#endif /* FIXME: This is sooooooooooooooooooo ugly */
#if defined(CONFIG_ARCH_GTA02_v1) || defined(CONFIG_ARCH_GTA02_v2)
?/* we need auto hw flow control on the gsm and gps port */
?if (dev_index == 0 || dev_index == 1)
??uart->UMCON = 0x10;
#endif
?_serial_setbrg(dev_index); return (0);
}
7.由于標(biāo)準(zhǔn)設(shè)備還沒有初始化(gd->flags & GD_FLG_DEVINIT=0),這時(shí)控制臺(tái)使用串口作為控制臺(tái)
??? 函數(shù)只有一句:gd->have_console = 1;
int console_init_f (void)
{
?gd->have_console = 1;?//將標(biāo)志位置1 #ifdef CONFIG_SILENT_CONSOLE
?if (getenv("silent") != NULL)
??gd->flags |= GD_FLG_SILENT;
#endif return (0);
}
8.int dram_init (void)
{//PHYS_SDRAM_1在整個(gè)include/configs.h文件中有很多定義,只在一個(gè)地方define為0x30000000
?//PHYS_SDRAM_1_SIZE定義為64MB
?gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
?gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; return 0;
}
9. ulong flash_init (void) 這里smdk2410的默認(rèn)flash是AMD的,mini2440的板子是SST39F1601,如果NOR Flash符合CFI接口標(biāo)準(zhǔn),可以使用drivers/cfi_flash.c
里面的接口函數(shù),否則就得重寫。如果使用cfi_flash.c,需要修改include/configs/$(board_name).h,在里面增加:
?#define CFG_FLASH_CFI_DRIVER ?1
在board/$(board_name)/Makefile中去掉flash.o
在《嵌入式linux完全手冊(cè)》上P273頁有說明。 首先是有一個(gè)變量flash_info_t flash_info[CFG_MAX_FLASH_BANKS]來記錄flash的信息。flash_info_t定義:
?? typedef struct {
??? ulong size;?? /* 總大小BYTE? */
??? ushort sector_count;? /* 總的sector數(shù)*/
??? ulong flash_id;? /* combined device & manufacturer code */
??? ulong start[CFG_MAX_FLASH_SECT];?? /* 每個(gè)sector的起始物理地址。 */
??? uchar protect[CFG_MAX_FLASH_SECT]; /* 每個(gè)sector的保護(hù)狀態(tài),如果置1,在執(zhí)行erase操作的時(shí)候?qū)⑻^對(duì)應(yīng)sector*/
???? #ifdef CFG_FLASH_CFI //我不管CFI接口。
??? .....
???? #endif
?? } flash_info_t;
??? flash_init()的操作就是讀取ID號(hào),ID號(hào)指明了生產(chǎn)商和設(shè)備號(hào),根據(jù)這些信息設(shè)置size,sector_count,flash_id.
??? 以及start[]、protect[]。 10.mem_malloc_init()
11.nand_init()
12.env_relocate()
13.devices_init ();?/* get the devices list going. */定義于common/devices.c
14.jumptable_init ()
15.console_init_r ();?/* fully init console as a device ,前面結(jié)構(gòu)體中的是前期控制臺(tái)初始化,這是后期*/
主要過程:查看環(huán)境參數(shù)stdin,stdout,stderr中對(duì)標(biāo)準(zhǔn)IO的指定的設(shè)備名稱,再按照環(huán)境指定的名稱搜索devlist,將搜到的設(shè)備指針賦給標(biāo)準(zhǔn)IO數(shù)組stdio_devices[]。置gd->flag標(biāo)志GD_FLG_DEVINIT。這個(gè)標(biāo)志影響putc,getc函數(shù)的實(shí)現(xiàn),未定義此標(biāo)志時(shí)直接由串口serial_getc和serial_putc實(shí)現(xiàn),定義以后通過標(biāo)準(zhǔn)設(shè)備數(shù)組stdio_devices[]中的putc和getc來實(shí)現(xiàn)IO。
?下面是相關(guān)代碼:
??? void putc (const char c)
???????? {
???????? #ifdef CONFIG_SILENT_CONSOLE
????????? if (gd->flags & GD_FLG_SILENT)//GD_FLG_SILENT無輸出標(biāo)志
?????????? return;
???????? #endif
????????? if (gd->flags & GD_FLG_DEVINIT) {//設(shè)備list已經(jīng)初始化
?????????? /* Send to the standard output */
?????????? fputc (stdout, c);
????????? } else {
?????????? /* Send directly to the handler */
?????????? serial_putc (c);//未初始化時(shí)直接從串口輸出。
????????? }
???????? }
?????? void fputc (int file, const char c)
??????? {
???????? if (file < MAX_FILES)
????????? stdio_devices[file]->putc (c);
??????? } 為什么要使用devlist,std_device[]? 為了更靈活地實(shí)現(xiàn)標(biāo)準(zhǔn)IO重定向,任何可以作為標(biāo)準(zhǔn)IO的設(shè)備,如USB鍵盤,LCD屏,串口等都可以對(duì)應(yīng)一個(gè)device_t的結(jié)構(gòu)體變量,只需要實(shí)現(xiàn)getc和putc等函數(shù),就能加入到devlist列表中去,也就可以被assign為標(biāo)準(zhǔn)IO設(shè)備std_device中去。如函數(shù) int console_assign (int file, char *devname); /* Assign the console 重定向標(biāo)準(zhǔn)輸入輸出*/ 這個(gè)函數(shù)功能就是把名為devname的設(shè)備重定向?yàn)闃?biāo)準(zhǔn)IO文件file(stdin,stdout,stderr)。其執(zhí)行過程是在devlist中查找devname的設(shè)備,返回這個(gè)設(shè)備的device_t指針,并把指針值賦給std_device[file]。
16.enable_interrupts (); (1)首先,需要設(shè)置系統(tǒng)時(shí)鐘、初始化串口,只要這兩個(gè)設(shè)置好,就能從串口看到打印信息。
? board_init函數(shù)設(shè)置MPLL,改變系統(tǒng)時(shí)鐘,這是一個(gè)開發(fā)板相關(guān)的函數(shù)。
? serial_init函數(shù)用來初始化串口,設(shè)置UART控制器,是CPU相關(guān)的函數(shù),
? (2)檢測系統(tǒng)內(nèi)存映射
? 對(duì)于特定的開發(fā)板,內(nèi)存分布是比較明確的,dram_init函數(shù)指定了目標(biāo)開發(fā)板的內(nèi)存起始地址為0x30000000,大小為64M
? (3)U-boot命令的格式
? uboot中的每個(gè)命令都是通過U_BOOT_CMD宏來定義,格式:U_BOOT_CMD(name,maxargs,repeatable,command,"usage","help")
? 這個(gè)宏定義在include/command.h中,
? (4)為內(nèi)核設(shè)置啟動(dòng)參數(shù)
? uboot是通過標(biāo)記列表向內(nèi)核傳遞參數(shù),設(shè)置內(nèi)存標(biāo)記、命令標(biāo)記的函數(shù)setup_memory_tags、setup_commandline_tag,
? 在lib_arm/armlinux.c中定義實(shí)現(xiàn)。如果要定義一個(gè)命令,需要在include/configs/$(board_name).h中增加一個(gè)關(guān)于
? 命令的配置項(xiàng):
? 如: #define CONFIG_CMDLINE_TAG? 1
? 對(duì)于arm架構(gòu)的CPU,都是通過lib_arm/armlinux.c中的do_bootm_linux函數(shù)來啟動(dòng)內(nèi)核,在這個(gè)函數(shù)中,設(shè)置標(biāo)記列表,最后通過
? the_kernel(0,bd->bi_arch_number,bd->bi_boot_params)調(diào)用內(nèi)核。 PS: 1.分析過程參照了一位網(wǎng)友的文章,很有參考價(jià)值,給我很大幫助。我只是按照配置->編譯->啟動(dòng)過程 的這么一個(gè)認(rèn)識(shí)過程來分析,可能會(huì)顯得比較混亂。 ?U-BOOT源碼分析及移植.txt?
??
2.博客鏈接:http://blog.csdn.net/liukun321/article/details/5680504
總結(jié)
以上是生活随笔為你收集整理的uboot 分析之 启动流程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Bootloader概述
- 下一篇: 嵌入式Linux系统中的.lds链接脚本