4412 uboot啓動分析

感謝sea1105, https://blog.csdn.net/sea1105/article/details/52142772html

在學習過程當中,因爲tiny4412資料太過於少,所以參考210的視屏,但友善提供的uboot算是比較新。啓動過程不太同樣,我分析出來的board_init_f 已經超出了16K的範圍,但relocate_code,及後面的棧設置stack_setup,和copy_loop後搬移還在board_init_f以後調用。這兩天一直難以理解。忽然翻到了這部帖子,感受解釋的比較清楚過程,api

對uboot 反編譯。數組

_start : 0xc3e00000數據結構

reset:  0xc3e00050app

borad_init_f  : 0xc3e051fcide

relocate_code  :  0xc3e00074函數

stack_setup  :  0xc3e00080oop

copy_loop  :   0xc3e000a0post

 

 ——————————————————————————————————————————————————————學習

主要參考:www.cnblogs.com/CoderTian/p/5995409.html

 

首先從連接庫分析(board/samsung/tiny4412/u-boot.lds)

 1 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")  2 OUTPUT_ARCH(arm)  3 ENTRY(_start)  4 SECTIONS  5 {  6  . = 0x00000000;  7  . = ALIGN(4);  8  .text :  9  { 10   arch/arm/cpu/armv7/start.o (.text) 11   board/samsung/tiny4412/libtiny4412.o (.text) 12   arch/arm/cpu/armv7/exynos/libexynos.o (.text) 13   *(.text) 14  } 15  . = ALIGN(4); 16  .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } 17  . = ALIGN(4); 18  .data : { 19   *(.data) 20  } 21  . = ALIGN(4); 22  . = .; 23  __u_boot_cmd_start = .; 24  .u_boot_cmd : { *(.u_boot_cmd) } 25  __u_boot_cmd_end = .; 26  . = ALIGN(4); 27  .rel.dyn : { 28   __rel_dyn_start = .; 29   *(.rel*) 30   __rel_dyn_end = .; 31  } 32  .dynsym : { 33   __dynsym_start = .; 34   *(.dynsym) 35  } 36  .bss __rel_dyn_start (OVERLAY) : { 37   __bss_start = .; 38   *(.bss) 39    . = ALIGN(4); 40   _end = .; 41  } 42  /DISCARD/ : { *(.dynstr*) } 43  /DISCARD/ : { *(.dynamic*) } 44  /DISCARD/ : { *(.plt*) } 45  /DISCARD/ : { *(.interp*) } 46  /DISCARD/ : { *(.gnu*) } 47 }
u-boot.lds

 

從第三行可看出,指定_start 爲入口 ,文本段.text 爲入口文件。

在本連接腳本文件中,定義了起始地址爲0x00000000,每一個段使用4字節對齊(.ALIGN(4)),幾個段分別爲代碼段(.text)、只讀數據段(.rodata)、數據段(.data)。

下面打開start.o

.globl _start
_start: b	reset
	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
_software_interrupt:	.word software_interrupt
_prefetch_abort:	.word prefetch_abort
_data_abort:		.word data_abort
_not_used:		.word not_used
_irq:			.word irq
_fiq:			.word fiq
_pad:			.word 0x12345678 /* now 16*4=64 */
.global _end_vect
_end_vect:

  開始,先跳轉至reset處

 1 reset:  2     /*
 3  * set the cpu to SVC32 mode  4      */
 5  mrs r0, cpsr  6     bic    r0, r0, #0x1f
 7     orr    r0, r0, #0xd3
 8  msr cpsr,r0  9 
10 #if (CONFIG_OMAP34XX)
11     /* Copy vectors to mask ROM indirect addr */
12     adr    r0, _start        @ r0 <- current position of code 13     add    r0, r0, #4 @ skip reset vector 14     mov    r2, #64            @ r2 <- size to copy 15     add    r2, r0, r2        @ r2 <- source end address 16  mov r1, #SRAM_OFFSET0 @ build vect addr 17  mov r3, #SRAM_OFFSET1 18  add r1, r1, r3 19  mov r3, #SRAM_OFFSET2 20  add r1, r1, r3 21 next: 22     ldmia    r0!, {r3 - r10}        @ copy from source address [r0] 23     stmia    r1!, {r3 - r10} @ copy to target address [r1] 24  cmp r0, r2 @ until source end address [r2] 25     bne    next            @ loop until equal */
26 #if !defined(CONFIG_SYS_NAND_BOOT) && !defined(CONFIG_SYS_ONENAND_BOOT)
27     /* No need to copy/exec the clock code - DPLL adjust already done 28  * in NAND/oneNAND Boot. 29      */
30  bl cpy_clk_code @ put dpll adjust code behind vectors 31 #endif /* NAND Boot */
32 #endif
33     /* the mask ROM code should have PLL and others stable */
34 #ifndef CONFIG_SKIP_LOWLEVEL_INIT 35  bl cpu_init_crit 36 #endif
37 
38 /* Set stackpointer in internal RAM to call board_init_f */
39 call_board_init_f: 40     ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR) 41     bic    sp, sp, #7 /* 8-byte alignment for ABI compliance */
42     ldr    r0,=0x00000000
43     bl    board_init_f
reset

   可看出,首先將CPU設置爲SVC32模式,而後在146行 調用  bl cpu_init_crit  ,調用cpu_init_crit函數後返回reset。在調用board_init_f (arch/arm/lib/board.c),因爲函數寫在C語言中,不止lr 一個寄存器,因此首先須要設置sp堆棧,進行8字節對齊

 1 cpu_init_crit:  2 
 3  bl cache_init  4     
 5     /* 使L1 I/D 無效  6  * Invalidate L1 I/D  7      */
 8     mov    r0, #0            @ set up for MCR  9     mcr    p15, 0, r0, c8, c7, 0 @ invalidate TLBs 10     mcr    p15, 0, r0, c7, c5, 0 @ invalidate icache 11 
12     /*關閉MMU和caches 13  * disable MMU stuff and caches 14      */
15     mrc    p15, 0, r0, c1, c0, 0
16     bic    r0, r0, #0x00002000    @ clear bits 13 (--V-) 17     bic    r0, r0, #0x00000007    @ clear bits 2:0 (-CAM) 18     orr    r0, r0, #0x00000002    @ set bit 1 (--A-) Align 19     orr    r0, r0, #0x00000800    @ set bit 12 (Z---) BTB 20     mcr    p15, 0, r0, c1, c0, 0
21 
22     /*
23  * Jump to board specific initialization... 24  * The Mask ROM will have already initialized 25  * basic memory. Go here to bump up clock rate and handle 26  * wake up conditions. 27      */
28  mov ip, lr @ persevere link reg across call 29  bl lowlevel_init @ go setup pll,mux,memory 30  mov lr, ip @ restore link 31     mov    pc, lr            @ back to my caller
cpu_init_crit

       cache_init ,被定義在  board/samsung/tiny4412/lowlevel_init.S 文件中

.globl cache_init
cache_init:
	mov	pc, lr

  並無什麼做用,接下來  bl lowlevel_init   ,此函數主要做用使初始化系統時鐘,內存,串口等。爲BL2代碼搬移作準備

 1  .globl lowlevel_init  2 lowlevel_init:  3 
 4     /* use iROM stack in bl2 */
 5     ldr    sp, =0x02060000
 6  push {lr}  7 
 8     /* check reset status */
 9     ldr    r0, =(INF_REG_BASE + INF_REG1_OFFSET) 10  ldr r1, [r0] 11 
12     /* Sleep wakeup reset */
13     ldr    r2, =S5P_CHECK_SLEEP 14  cmp r1, r2 15  beq wakeup_reset 16 
17     /* set CP reset to low */
18     ldr    r0, =0x11000C60
19  ldr r1, [r0] 20     ldr    r2, =0xFFFFFF0F
21  and r1, r1, r2 22     orr    r1, r1, #0x10
23  str r1, [r0] 24     ldr    r0, =0x11000C68
25  ldr r1, [r0] 26     ldr    r2, =0xFFFFFFF3
27  and r1, r1, r2 28     orr    r1, r1, #0x4
29  str r1, [r0] 30     ldr    r0, =0x11000C64
31  ldr r1, [r0] 32     ldr    r2, =0xFFFFFFFD
33  and r1, r1, r2 34  str r1, [r0] 35 
36     /* led (GPM4_0~3) on */
37     ldr    r0, =0x110002E0
38     ldr    r1, =0x00001111
39  str r1, [r0] 40     ldr    r1, =0x0e
41     str    r1, [r0, #0x04] 42 
43     /* During sleep/wakeup or AFTR mode, pmic_init function is not available 44  * and it causes delays. So except for sleep/wakeup and AFTR mode, 45  * the below function is needed 46      */
47 #if defined(CONFIG_HAS_PMIC)
48  bl pmic_init 49 #endif
50 
51 #if defined(CONFIG_ONENAND)
52  bl onenandcon_init 53 #endif
54 
55 #if defined(NAND_BOOTING)
56  bl nand_asm_init 57 #endif
58 
59  bl read_om 60 
61     /* when we already run in ram, we don't need to relocate U-Boot. 62  * and actually, memory controller must be configured before U-Boot 63  * is running in ram. 64      */
65     ldr    r0, =0xff000fff
66     bic    r1, pc, r0        /* r0 <- current base addr of code */
67     ldr    r2, _TEXT_BASE    /* r1 <- original base addr in ram */
68     bic    r2, r2, r0        /* r0 <- current base addr of code */
69     cmp    r1, r2            /* compare r0, r1 */
70     beq    after_copy        /* r0 == r1 then skip sdram init and u-boot.bin loading */
71 
72 #ifndef CONFIG_SMDKC220 73     ldr    r0, =CHIP_ID_BASE 74  ldr r1, [r0] 75     lsr    r1, r1, #8
76     and    r1, r1, #3
77     cmp    r1, #2
78  bne v310_1 79 #endif
80 
81     /* init system clock */
82  bl system_clock_init 83 
84     /* Memory initialize */
85  bl mem_ctrl_asm_init 86 
87     /* init uart for debug */
88  bl uart_asm_init 89 
90 #if CONFIG_LL_DEBUG
91     mov    r4, #0x4000
lowlevel_init

   uart_asm_init:前一段是將GPIOA配置爲UART,至關於初始化。從S5PV310_UART_CONSOLE_BASE:(arch/arm/include/asm/arch-exynos/cpu.h)配置UART0

ldr    r1, =UART_UDIVSLOT_VAL str r1, [r0, #UDIVSLOT_OFFSET]

  UART_UDIVSLOT_VAL  爲 UFRACVALn  與波特率分頻有關 (tiny4412_val.h) 

  #UDIVSLOT_OFFSET   0x2C    UFRACVALn 基於基地址的偏移 (cpu.h)

  接着跳轉至board_init_f  (分析gd_t bd_t 結構)

 1 void board_init_f(ulong bootflag)  2 {  3     bd_t *bd;  4     init_fnc_t **init_fnc_ptr;  5     gd_t *id;  6     ulong addr, addr_sp;  7 
 8     /* Pointer is writable since we allocated a register for it  計算全局變量數據結構的地址,保存在gd中*/
 9     gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);  //8字節對齊,爲gd_t的空間。10   11     /* compiler optimization barrier needed for GCC >= 3.4 */
 12     __asm__ __volatile__("": : :"memory");  //空函數,告訴系統要寫一個內存,防止優化13 
 14     memset((void*)gd, 0, sizeof (gd_t));  15 
 16     gd->mon_len = _bss_end_ofs;  17 
 18     for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {  // 逐個調用init_sequence數組的初始化函數 19         if ((*init_fnc_ptr)() != 0) {  20  hang();  21  }  22  }  23 
 24     debug ("monitor len: %08lX\n", gd->mon_len);  25     /*
 26  * Ram is setup, size stored in gd !!  27      */
 28     debug ("ramsize: %08lX\n", gd->ram_size);  29 #if defined(CONFIG_SYS_MEM_TOP_HIDE)
 30     /*
 31  * Subtract specified amount of memory to hide so that it won't  32  * get "touched" at all by U-Boot. By fixing up gd->ram_size  33  * the Linux kernel should now get passed the now "corrected"  34  * memory size and won't touch it either. This should work  35  * for arch/ppc and arch/powerpc. Only Linux board ports in  36  * arch/powerpc with bootwrapper support, that recalculate the  37  * memory size from the SDRAM controller setup will have to  38  * get fixed.  39      */
 40     gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;  41 #endif
 42 
 43     addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;  44 
 45 #ifdef CONFIG_LOGBUFFER  46 #ifndef CONFIG_ALT_LB_ADDR  47     /* reserve kernel log buffer */
 48     addr -= (LOGBUFF_RESERVE);  49     debug ("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN, addr);  50 #endif
 51 #endif
 52 
 53 #ifdef CONFIG_PRAM  54     /*
 55  * reserve protected RAM  56      */
 57     i = getenv_r("pram", (char *)tmp, sizeof (tmp));  58     reg = (i > 0) ? simple_strtoul((const char *)tmp, NULL, 10) : CONFIG_PRAM;  59     addr -= (reg << 10);        /* size is in kB */
 60     debug ("Reserving %ldk for protected RAM at %08lx\n", reg, addr);  61 #endif /* CONFIG_PRAM */
 62 
 63 #if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE))
 64     /* reserve TLB table */
 65     addr -= (4096 * 4);  66 
 67     /* round down to next 64 kB limit */
 68     addr &= ~(0x10000 - 1);  69 
 70     gd->tlb_addr = addr;  71     debug ("TLB table at: %08lx\n", addr);  72 #endif
 73 
 74     /* round down to next 4 kB limit */
 75     addr &= ~(4096 - 1);  76     debug ("Top of RAM usable for U-Boot at: %08lx\n", addr);  77 
 78 #ifdef CONFIG_VFD  79 # ifndef PAGE_SIZE  80 #      define PAGE_SIZE 4096
 81 # endif  82     /*
 83  * reserve memory for VFD display (always full pages)  84      */
 85     addr -= vfd_setmem(addr);  86     gd->fb_base = addr;  87 #endif /* CONFIG_VFD */
 88 
 89 #ifdef CONFIG_LCD  90     /* reserve memory for LCD display (always full pages) */
 91     addr = lcd_setmem(addr);  92     gd->fb_base = addr;  93 #endif /* CONFIG_LCD */
 94 
 95     /*
 96  * reserve memory for U-Boot code, data & bss  97  * round down to next 4 kB limit  98      */
 99     addr -= gd->mon_len; 100     addr &= ~(4096 - 1); 101 
102 #if defined(CONFIG_S5P) || defined(CONFIG_S5P6450)
103     addr = CONFIG_SYS_LOAD_ADDR; 104 #endif
105 
106     debug ("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr); 107 
108 #ifndef CONFIG_PRELOADER 109     /*
110  * reserve memory for malloc() arena 111      */
112     addr_sp = addr - TOTAL_MALLOC_LEN; 113     debug ("Reserving %dk for malloc() at: %08lx\n", 114             TOTAL_MALLOC_LEN >> 10, addr_sp); 115     /*
116  * (permanently) allocate a Board Info struct 117  * and a permanent copy of the "global" data 118      */
119     addr_sp -= sizeof (bd_t); 120     bd = (bd_t *) addr_sp; 121     gd->bd = bd; 122     debug ("Reserving %zu Bytes for Board Info at: %08lx\n", 123             sizeof (bd_t), addr_sp); 124     addr_sp -= sizeof (gd_t); 125     id = (gd_t *) addr_sp; 126     debug ("Reserving %zu Bytes for Global Data at: %08lx\n", 127             sizeof (gd_t), addr_sp); 128 
129     /* setup stackpointer for exeptions */
130     gd->irq_sp = addr_sp; 131 #ifdef CONFIG_USE_IRQ 132     addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ); 133     debug ("Reserving %zu Bytes for IRQ stack at: %08lx\n", 134         CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp); 135 #endif
136 
137     /* leave 3 words for abort-stack */
138     addr_sp -= 3; 139 
140     /* 8-byte alignment for ABI compliance */
141     addr_sp &= ~0x07; 142 #else
143     addr_sp += 128;    /* leave 32 words for abort-stack */
144     gd->irq_sp = addr_sp; 145 #endif
146 
147     debug ("New Stack Pointer is: %08lx\n", addr_sp); 148 
149 #ifdef CONFIG_POST 150  post_bootmode_init(); 151     post_run(NULL, POST_ROM | post_bootmode_get(0)); 152 #endif
153 
154     gd->bd->bi_baudrate = gd->baudrate; 155     /* Ram ist board specific, so move it to board code ... */
156  dram_init_banksize(); 157     display_dram_config();    /* and display it */
158 
159     gd->relocaddr = addr; 160     gd->start_addr_sp = addr_sp; 161     gd->reloc_off = addr - _TEXT_BASE; 162     debug ("relocation Offset is: %08lx\n", gd->reloc_off); 163     memcpy(id, (void *)gd, sizeof (gd_t)); 164 
165  relocate_code(addr_sp, id, addr); 166     /* NOTREACHED - relocate_code() does not return */
167 } 168 
169 #if !defined(CONFIG_SYS_NO_FLASH)
170 static char *failed = "*** failed ***\n"; 171 #endif
borad_init_f
 1 init_fnc_t *init_sequence[] = {  2 #if defined(CONFIG_ARCH_CPU_INIT)
 3     arch_cpu_init,        /* basic arch cpu dependent setup */
 4 #endif
 5 #if defined(CONFIG_BOARD_EARLY_INIT_F)
 6  board_early_init_f,  7 #endif
 8     timer_init,        /* initialize timer */
 9 #ifdef CONFIG_FSL_ESDHC 10  get_clocks, 11 #endif
12     env_init,        /* initialize environment */
13 #if defined(CONFIG_S5P6450) && !defined(CONFIG_S5P6460_IP_TEST)
14     init_baudrate,        /* initialze baudrate settings */
15     serial_init,        /* serial communications setup */
16 #endif
17     console_init_f,        /* stage 1 init of console */
18     display_banner,        /* say that we are here */
19 #if defined(CONFIG_DISPLAY_CPUINFO)
20     print_cpuinfo,        /* display cpu info (and speed) */
21 #endif
22 #if defined(CONFIG_DISPLAY_BOARDINFO)
23     checkboard,        /* display board info */
24 #endif
25 #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
26  init_func_i2c, 27 #endif
28     dram_init,        /* configure available RAM banks */
29 #if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)
30  arm_pci_init, 31 #endif
32  NULL, 33 };
init_seqence

  u-boot使用一個init_sequence數組來存儲大多數開發板都要執行的初始化函數的函數指針

  board_init_f函數在調用完初始化函數指針、填充完gd結構以後,調用了arch/arm/cpu/armv7/start.S中的relocate_code

 1  .globl relocate_code  2 relocate_code:  3     mov    r4, r0    /* save addr_sp */
 4     mov    r5, r1    /* save addr of gd */
 5     mov    r6, r2    /* save addr of destination */
 6 
 7     /* Set up the stack */
 8 stack_setup:  9  mov sp, r4  10 
 11  adr r0, _start  12 #if defined(CONFIG_S5PC110) && defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
 13     sub    r0, r0, #16
 14 #endif
 15 #ifndef CONFIG_PRELOADER  16  cmp r0, r6  17     beq    clear_bss        /* skip relocation */
 18 #endif
 19     mov    r1, r6            /* r1 <- scratch for copy_loop */
 20  ldr r2, _TEXT_BASE  21  ldr r3, _bss_start_ofs  22     add    r2, r0, r3        /* r2 <- source end address */
 23 
 24 copy_loop:  25     ldmia    r0!, {r9-r10}        /* copy from source address [r0] */
 26     stmia    r1!, {r9-r10}        /* copy to target address [r1] */
 27     cmp    r0, r2            /* until source end address [r2] */
 28  blo copy_loop  29 
 30 #ifndef CONFIG_PRELOADER  31     /*
 32  * fix .rel.dyn relocations  33      */
 34     ldr    r0, _TEXT_BASE        /* r0 <- Text base */
 35     sub    r9, r6, r0        /* r9 <- relocation offset */
 36     ldr    r10, _dynsym_start_ofs    /* r10 <- sym table ofs */
 37     add    r10, r10, r0        /* r10 <- sym table in FLASH */
 38     ldr    r2, _rel_dyn_start_ofs    /* r2 <- rel dyn start ofs */
 39     add    r2, r2, r0        /* r2 <- rel dyn start in FLASH */
 40     ldr    r3, _rel_dyn_end_ofs    /* r3 <- rel dyn end ofs */
 41     add    r3, r3, r0        /* r3 <- rel dyn end in FLASH */
 42 fixloop:  43     ldr    r0, [r2]        /* r0 <- location to fix up, IN FLASH! */
 44     add    r0, r0, r9        /* r0 <- location to fix up in RAM */
 45     ldr    r1, [r2, #4]  46     and    r7, r1, #0xff
 47     cmp    r7, #23            /* relative fixup? */
 48  beq fixrel  49     cmp    r7, #2            /* absolute fixup? */
 50  beq fixabs  51     /* ignore unknown type of fixup */
 52  b fixnext  53 fixabs:  54     /* absolute fix: set location to (offset) symbol value */
 55     mov    r1, r1, LSR #4        /* r1 <- symbol index in .dynsym */
 56     add    r1, r10, r1        /* r1 <- address of symbol in table */
 57     ldr    r1, [r1, #4]        /* r1 <- symbol value */
 58     add    r1, r1, r9        /* r1 <- relocated sym addr */
 59  b fixnext  60 fixrel:  61     /* relative fix: increase location by offset */
 62  ldr r1, [r0]  63  add r1, r1, r9  64 fixnext:  65  str r1, [r0]  66     add    r2, r2, #8        /* each rel.dyn entry is 8 bytes */
 67  cmp r2, r3  68  blo fixloop  69 
 70 clear_bss:  71  ldr r0, _bss_start_ofs  72  ldr r1, _bss_end_ofs  73     ldr    r3, _TEXT_BASE        /* Text base */
 74     mov    r4, r6            /* reloc addr */
 75  add r0, r0, r4  76  add r1, r1, r4  77     mov    r2, #0x00000000        /* clear */
 78 
 79 clbss_l:str    r2, [r0]        /* clear loop... */
 80     add    r0, r0, #4
 81  cmp r0, r1  82  bne clbss_l  83 #endif    /* #ifndef CONFIG_PRELOADER */
 84 
 85 /*
 86  * We are done. Do not return, instead branch to second part of board  87  * initialization, now running from RAM.  88  */
 89 jump_2_ram:  90  ldr r0, _board_init_r_ofs  91  adr r1, _start  92  add lr, r0, r1  93 @ add lr, lr, r9  94     /* setup parameters for board_init_r */
 95     mov    r0, r5        /* gd_t */
 96     mov    r1, r6        /* dest_addr */
 97     /* jump to it ... */
 98  mov pc, lr  99 
100 
101 
102 
103 _board_init_r_ofs: 104     .word board_init_r - _start 105
relocate_code

   搬移uboot.bin

  轉入borad_init_r

 1 void board_init_r(gd_t *id, ulong dest_addr)  2 {  3     char *s;  4     bd_t *bd;  5     ulong malloc_start;  6 #if !defined(CONFIG_SYS_NO_FLASH)
 7     ulong flash_size;  8 #endif
 9 
 10     gd = id;  11     bd = gd->bd;  12 
 13     gd->flags |= GD_FLG_RELOC;    /* tell others: relocation done */
 14 
 15     monitor_flash_len = _bss_start_ofs;  16     debug ("monitor flash len: %08lX\n", monitor_flash_len);  17     board_init();    /* Setup chipselects */
 18 
 19 #ifdef CONFIG_SERIAL_MULTI  20     //serial_initialize();
 21 #endif
 22 
 23     debug ("Now running in RAM - U-Boot at: %08lx\n", dest_addr);  24 
 25 #ifdef CONFIG_LOGBUFFER  26  logbuff_init_ptrs();  27 #endif
 28 #ifdef CONFIG_POST  29  post_output_backlog();  30 #endif
 31 
 32     /* The Malloc area is immediately below the monitor copy in DRAM */
 33     malloc_start = dest_addr - TOTAL_MALLOC_LEN;  34  mem_malloc_init(malloc_start, TOTAL_MALLOC_LEN);  35 
 36 #if !defined(CONFIG_SYS_NO_FLASH)
 37     puts("FLASH:\t");  38 
 39     if ((flash_size = flash_init()) > 0) {  40 # ifdef CONFIG_SYS_FLASH_CHECKSUM  41         print_size(flash_size, "");  42         /*
 43  * Compute and print flash CRC if flashchecksum is set to 'y'  44  *  45  * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX  46          */
 47         s = getenv("flashchecksum");  48         if (s && (*s == 'y')) {  49             printf(" CRC: %08X",  50                 crc32 (0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size)  51  );  52  }  53         putc('\n');  54 # else    /* !CONFIG_SYS_FLASH_CHECKSUM */
 55         print_size(flash_size, "\n");  56 # endif /* CONFIG_SYS_FLASH_CHECKSUM */
 57     } else {  58  puts(failed);  59  hang();  60  }  61 #endif
 62 
 63 #if defined(CONFIG_CMD_NAND)
 64     puts("NAND:\t");  65     nand_init();        /* go init the NAND */
 66 #endif
 67 
 68 #if defined(CONFIG_CMD_ONENAND)
 69  onenand_init();  70 #endif
 71 
 72 #ifdef CONFIG_GENERIC_MMC  73  mmc_initialize(bd);  74 #endif
 75 
 76 #ifdef CONFIG_HAS_DATAFLASH  77  AT91F_DataflashInit();  78  dataflash_print_info();  79 #endif
 80 
 81     /* initialize environment */
 82  env_relocate();  83 
 84 #ifdef CONFIG_VFD  85     /* must do this after the framebuffer is allocated */
 86  drv_vfd_init();  87 #endif /* CONFIG_VFD */
 88 
 89     /* IP Address */
 90     gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");  91 
 92     stdio_init();    /* get the devices list going. */
 93 
 94  jumptable_init();  95 
 96 #if defined(CONFIG_API)
 97     /* Initialize API */
 98  api_init();  99 #endif
100 
101     //console_init_r(); /* fully init console as a device */
102 
103 #if defined(CONFIG_ARCH_MISC_INIT)
104     /* miscellaneous arch dependent initialisations */
105  arch_misc_init(); 106 #endif
107 #if defined(CONFIG_MISC_INIT_R)
108     /* miscellaneous platform dependent initialisations */
109  misc_init_r(); 110 #endif
111 
112      /* set up exceptions */
113  interrupt_init(); 114     /* enable exceptions */
115  enable_interrupts(); 116 
117     /* Perform network card initialisation if necessary */
118 #if defined(CONFIG_DRIVER_SMC91111) || defined(CONFIG_DRIVER_LAN91C96)
119     /* XXX: this needs to be moved to board init */
120     if (getenv("ethaddr")) { 121         uchar enetaddr[6]; 122         eth_getenv_enetaddr("ethaddr", enetaddr); 123  smc_set_mac_addr(enetaddr); 124  } 125 #endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
126 
127 #if defined(CONFIG_DRIVER_DM9000)
128     /* XXX: this needs to be moved to board init */
129     if (getenv("ethaddr")) { 130         uchar enetaddr[6]; 131         eth_getenv_enetaddr("ethaddr", enetaddr); 132  dm9000_set_mac_addr(enetaddr); 133  } 134 #endif
135 
136     /* Initialize from environment */
137     if ((s = getenv("loadaddr")) != NULL) { 138         load_addr = simple_strtoul(s, NULL, 16); 139  } 140 #if defined(CONFIG_CMD_NET)
141     if ((s = getenv("bootfile")) != NULL) { 142         copy_filename(BootFile, s, sizeof (BootFile)); 143  } 144 #endif
145 
146 #ifdef BOARD_LATE_INIT 147  board_late_init(); 148 #endif
149 
150 #ifdef CONFIG_BITBANGMII 151  bb_miiphy_init(); 152 #endif
153 #if defined(CONFIG_CMD_NET)
154 #if defined(CONFIG_NET_MULTI)
155     puts("Net:\t"); 156 #endif
157     eth_initialize(gd->bd); 158 #if defined(CONFIG_RESET_PHY_R)
159     debug ("Reset Ethernet PHY\n"); 160  reset_phy(); 161 #endif
162 #endif
163 
164 #ifdef CONFIG_POST 165     post_run(NULL, POST_RAM | post_bootmode_get(0)); 166 #endif
167 
168 #if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)
169     /*
170  * Export available size of memory for Linux, 171  * taking into account the protected RAM at top of memory 172      */
173  { 174         ulong pram; 175         uchar memsz[32]; 176 #ifdef CONFIG_PRAM 177         char *s; 178 
179         if ((s = getenv("pram")) != NULL) { 180             pram = simple_strtoul(s, NULL, 10); 181         } else { 182             pram = CONFIG_PRAM; 183  } 184 #else
185         pram=0; 186 #endif
187 #ifdef CONFIG_LOGBUFFER 188 #ifndef CONFIG_ALT_LB_ADDR 189         /* Also take the logbuffer into account (pram is in kB) */
190         pram += (LOGBUFF_LEN+LOGBUFF_OVERHEAD)/1024; 191 #endif
192 #endif
193         sprintf((char *)memsz, "%ldk", (bd->bi_memsize / 1024) - pram); 194         setenv("mem", (char *)memsz); 195  } 196 #endif
197 
198     /* main_loop() can return to retry autoboot, if so just run it again. */
199     for (;;) { 200  main_loop(); 201  } 202 
203     /* NOTREACHED - no way out of command loop except booting */
204 }
borad_init_r

 

  最後,轉入mian_loop

 1 void main_loop (void)  2 {  3 #ifndef CONFIG_SYS_HUSH_PARSER  4     static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };  5     int len;  6     int rc = 1;  7     int flag;  8 #endif
 9 
 10 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
 11     char *s;  12     int bootdelay;  13 #endif
 14 #ifdef CONFIG_PREBOOT  15     char *p;  16 #endif
 17 #ifdef CONFIG_BOOTCOUNT_LIMIT  18     unsigned long bootcount = 0;  19     unsigned long bootlimit = 0;  20     char *bcs;  21     char bcs_set[16];  22 #endif /* CONFIG_BOOTCOUNT_LIMIT */
 23 
 24 #if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
 25     ulong bmp = 0;        /* default bitmap */
 26     extern int trab_vfd (ulong bitmap);  27 
 28 #ifdef CONFIG_MODEM_SUPPORT  29     if (do_mdm_init)  30         bmp = 1;    /* alternate bitmap */
 31 #endif
 32  trab_vfd (bmp);  33 #endif    /* CONFIG_VFD && VFD_TEST_LOGO */
 34 
 35 #ifdef CONFIG_BOOTCOUNT_LIMIT  36     bootcount = bootcount_load();  37     bootcount++;  38  bootcount_store (bootcount);  39     sprintf (bcs_set, "%lu", bootcount);  40     setenv ("bootcount", bcs_set);  41     bcs = getenv ("bootlimit");  42     bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;  43 #endif /* CONFIG_BOOTCOUNT_LIMIT */
 44 
 45 #ifdef CONFIG_MODEM_SUPPORT  46     debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);  47     if (do_mdm_init) {  48         char *str = strdup(getenv("mdm_cmd"));  49         setenv ("preboot", str);  /* set or delete definition */
 50         if (str != NULL)  51  free (str);  52         mdm_init(); /* wait for modem connection */
 53  }  54 #endif  /* CONFIG_MODEM_SUPPORT */
 55 
 56 #ifdef CONFIG_VERSION_VARIABLE  57  {  58         extern char version_string[];  59 
 60         setenv ("ver", version_string);  /* set version variable */
 61  }  62 #endif /* CONFIG_VERSION_VARIABLE */
 63 
 64 #ifdef CONFIG_SYS_HUSH_PARSER  65  u_boot_hush_start ();  66 #endif
 67 
 68 #if defined(CONFIG_HUSH_INIT_VAR)
 69  hush_init_var ();  70 #endif
 71 
 72 #ifdef CONFIG_AUTO_COMPLETE  73  install_auto_complete();  74 #endif
 75 
 76 #ifdef CONFIG_PREBOOT  77     if ((p = getenv ("preboot")) != NULL) {  78 # ifdef CONFIG_AUTOBOOT_KEYED  79         int prev = disable_ctrlc(1);    /* disable Control C checking */
 80 # endif  81 
 82 # ifndef CONFIG_SYS_HUSH_PARSER  83         run_command (p, 0);  84 # else
 85         parse_string_outer(p, FLAG_PARSE_SEMICOLON |
 86  FLAG_EXIT_FROM_LOOP);  87 # endif  88 
 89 # ifdef CONFIG_AUTOBOOT_KEYED  90         disable_ctrlc(prev);    /* restore Control C checking */
 91 # endif  92  }  93 #endif /* CONFIG_PREBOOT */
 94 
 95 #if defined(CONFIG_UPDATE_TFTP)
 96  update_tftp ();  97 #endif /* CONFIG_UPDATE_TFTP */
 98 
 99 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
100     s = getenv ("bootdelay"); 101     bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; 102 
103     debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay); 104 
105 # ifdef CONFIG_BOOT_RETRY_TIME 106  init_cmd_timeout (); 107 # endif    /* CONFIG_BOOT_RETRY_TIME */
108 
109 #ifdef CONFIG_POST 110     if (gd->flags & GD_FLG_POSTFAIL) { 111         s = getenv("failbootcmd"); 112  } 113     else
114 #endif /* CONFIG_POST */
115 #ifdef CONFIG_BOOTCOUNT_LIMIT 116     if (bootlimit && (bootcount > bootlimit)) { 117         printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n", 118  (unsigned)bootlimit); 119         s = getenv ("altbootcmd"); 120  } 121     else
122 #endif /* CONFIG_BOOTCOUNT_LIMIT */
123         s = getenv ("bootcmd"); 124 
125     debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); 126 
127     if (bootdelay >= 0 && s && !abortboot (bootdelay)) { 128 # ifdef CONFIG_AUTOBOOT_KEYED 129         int prev = disable_ctrlc(1);    /* disable Control C checking */
130 # endif 131 
132 # ifndef CONFIG_SYS_HUSH_PARSER 133         run_command (s, 0); 134 # else
135         parse_string_outer(s, FLAG_PARSE_SEMICOLON |
136  FLAG_EXIT_FROM_LOOP); 137 # endif 138 
139 # ifdef CONFIG_AUTOBOOT_KEYED 140         disable_ctrlc(prev);    /* restore Control C checking */
141 # endif 142  } 143 
144 # ifdef CONFIG_MENUKEY 145     if (menukey == CONFIG_MENUKEY) { 146         s = getenv("menucmd"); 147         if (s) { 148 # ifndef CONFIG_SYS_HUSH_PARSER 149         run_command (s, 0); 150 # else
151         parse_string_outer(s, FLAG_PARSE_SEMICOLON |
152  FLAG_EXIT_FROM_LOOP); 153 # endif 154  } 155  } 156 #endif /* CONFIG_MENUKEY */
157 #endif /* CONFIG_BOOTDELAY */
158 
159     /*
160  * Main Loop for Monitor Command Processing 161      */
162 #ifdef CONFIG_SYS_HUSH_PARSER 163  parse_file_outer(); 164     /* This point is never reached */
165     for (;;); 166 #else
167     for (;;) { 168 #ifdef CONFIG_BOOT_RETRY_TIME 169         if (rc >= 0) { 170             /* Saw enough of a valid command to 171  * restart the timeout. 172              */
173  reset_cmd_timeout(); 174  } 175 #endif
176         len = readline (CONFIG_SYS_PROMPT); 177 
178         flag = 0;    /* assume no special flags for now */
179         if (len > 0) 180  strcpy (lastcommand, console_buffer); 181         else if (len == 0) 182             flag |= CMD_FLAG_REPEAT; 183 #ifdef CONFIG_BOOT_RETRY_TIME 184         else if (len == -2) { 185             /* -2 means timed out, retry autoboot 186              */
187             puts ("\nTimed out waiting for command\n"); 188 # ifdef CONFIG_RESET_TO_RETRY 189             /* Reinit board to run initialization code again */
190             do_reset (NULL, 0, 0, NULL); 191 # else
192             return;        /* retry autoboot */
193 # endif 194  } 195 #endif
196 
197         if (len == -1) 198             puts ("<INTERRUPT>\n"); 199         else
200             rc = run_command (lastcommand, flag); 201 
202         if (rc <= 0) { 203             /* invalid command or not repeatable, forget it */
204             lastcommand[0] = 0; 205  } 206  } 207 #endif /*CONFIG_SYS_HUSH_PARSER*/
208 } 209 
210 #ifdef CONFIG_BOOT_RETRY_TIME 211 /*************************************************************************** 212  * initialize command line timeout 213  */
214 void init_cmd_timeout(void) 215 { 216     char *s = getenv ("bootretry"); 217 
218     if (s != NULL) 219         retry_time = (int)simple_strtol(s, NULL, 10); 220     else
221         retry_time = CONFIG_BOOT_RETRY_TIME; 222 
223     if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN) 224         retry_time = CONFIG_BOOT_RETRY_MIN; 225 }
main_loop

其中,主要是

#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
	s = getenv ("bootdelay");    //獲取bootdelay參數
	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;

	debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);

  

s = getenv ("bootcmd");     //獲取bootcmd 參數

	debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");

  在/include/configs/ting4412.h中 ,可找到

#define CONFIG_BOOTDELAY	3
/* Default boot commands for Android booting. */
#define CONFIG_BOOTCOMMAND	"movi read kernel 0 40008000;movi read rootfs 0 41000000 100000;bootm 40008000 41000000"
#define CONFIG_BOOTARGS	""

  咱們能夠看到,bootcmd默認執行的是"movi read kernel 0 40008000;movi read rootfs 0 41000000400000;bootm 40008000 41000000",首先讀取kernel,再讀取rootfs,以後跳轉到40008000地址運行

——————————————————————————————————————————————————————————

命令獲取

  其實原理很簡單,就是獲取輸入的第一個單詞,從掃描全部的cmd_tbl_t結構體,與name成員進行比較,若是匹配,則將後續輸入整理成參數列表,調用cmd指針指向的函數完成命令行。

for (;;) {

	len = readline (CONFIG_SYS_PROMPT);     
        // 在readline中首先先顯示CONFIG_SYS_PROMPT定義的字符串, 而後等待鍵盤輸入
        // 每次從終端讀入一個字符, 先判斷是不是正常字符(ctrl+c, 回車等屬於非正常字符)
        // 對與正常字符那麼將其存入console_buffer中, 並在終端回顯
       //查看/include/configs/ting4412.h知,#define CONFIG_SYS_PROMPT "TINY4412 # " 至關於用戶名
flag = 0;	/* assume no special flags for now */
		if (len > 0)
			strcpy (lastcommand, console_buffer);
		else if (len == 0)
			flag |= CMD_FLAG_REPEAT;

		if (len == -1)
			puts ("<INTERRUPT>\n");
		else
			rc = run_command (lastcommand, flag);
          // 命令從console_buffer搬運到lastcommand中

  readline -->readline_into_buffer()  --> , read_line()讀取到命令行後會調用common/main.c文件中的run_command(). 如今是分析run_command()的時候了, 不論是從環境變量仍是終端得到命令, 都是由run_command()來處理的. 


cmd_tbl_t *cmdtp;
char cmdbuf[CONFIG_SYS_CBSIZE];         /* working copy of cmd */
char *token;                     /* start of token in cmdbuf */
char *sep;                      /*end of token (separator) in cmdbuf */
char finaltoken[CONFIG_SYS_CBSIZE];
char *str = cmdbuf;
char *argv[CONFIG_SYS_MAXARGS + 1];       /* NULL terminated   空終止*/
int argc, inquotes;
int repeatable = 1;
int rc = 0;

 

     clear_ctrlc(); /* forget any previous Control C 忽略以前C的控制*/
    //下面if語句判斷命令是否太長, 仍是避免輸入了超過CONFIG_SYS_CBSIZE個字符的命令
     if (!cmd || !*cmd) { return -1; /* empty command */ } if (strlen(cmd) >= CONFIG_SYS_CBSIZE) { puts ("## Command too long!\n"); return -1; } strcpy (cmdbuf, cmd); /* Process separators and check for invalid * repeatable commands 處理分隔符並檢查是否有無效的可重複命令
      */ #ifdef DEBUG_PARSER printf ("[PROCESS_SEPARATORS] %s\n", cmd); #endif
     //str就是指向cmdbuf的指針 while (*str) { /* * Find separator, or string end * Allow simple escape of ';' by writing "\;"
           *找到;做爲命令結束符, 由於多個命令能夠一次輸入, 並以;分割. 忽略'\;' */ for (inquotes = 0, sep = str; *sep; sep++) { if ((*sep=='\'') && (*(sep-1) != '\\')) inquotes=!inquotes; if (!inquotes && (*sep == ';') && /* separator */ ( sep != str) && /* past string start */ (*(sep-1) != '\\')) /* and NOT escaped */ break; }//若是上面for循環找到一條以';'結束的命令, 那麼sep指向命令末尾 /* * Limit the token to data between separators將命令限制爲分隔符之間的數據 */ token = str; if (*sep) { str = sep + 1; /* str爲下一條命令開始start of command for next pass */ *sep = '\0';/* 做爲token的結束 */ } else str = sep; /* no more commands for next pass */ /* find macros in this token and replace them 在此命令中查找宏並替換它們*/ process_macros (token, finaltoken);           /*將命令行中的關鍵詞取出放入argv中, 注意, 命令行被分解到argv數組中, Extract arguments */ if ((argc = parse_line (finaltoken, argv)) == 0) { rc = -1; /* no command at all */ continue; } /* Look up command in command table */ if ((cmdtp =
find_cmd(argv[0])) == NULL) { printf ("Unknown command '%s' - try 'help'\n", argv[0]); rc = -1; /* give up after bad command */ continue; } /* found - check max args */ if (argc > cmdtp->maxargs) { cmd_usage(cmdtp); rc = -1; continue; } —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— #if defined(CONFIG_CMD_BOOTD) /* avoid "bootd" recursion 避免「bootd」遞歸*/ if (cmdtp->cmd == do_bootd) { #ifdef DEBUG_PARSER printf ("[%s]\n", finaltoken); #endif if (flag & CMD_FLAG_BOOTD) { puts ("'bootd' recursion detected\n"); rc = -1; continue; } else { flag |= CMD_FLAG_BOOTD; } } #endif /* OK - call function to do the command調用函數執行命令 */ if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) { rc = -1; } repeatable &= cmdtp->repeatable; /* ctrl+c 終止命令 。。 Did the user stop this? */ if (had_ctrlc ()) return -1; /* if stopped then not repeatable */ } return rc ? rc : repeatable; }

————————————————————————————————————————————————————————————————————

命令執行

  首要會執行find_cmd()在.u_boot_cmd段中尋找該命令的cmd_tbl_t結構, 找到後返回該結構. 該命令的結構是經過定義在include/command.h中的宏定義U_BOOT_CMD登記進.u_boot_cmd段中的.

#ifdef  CONFIG_SYS_LONGHELP

#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}

#define U_BOOT_CMD_MKENT(name,maxargs,rep,cmd,usage,help) \
{#name, maxargs, rep, cmd, usage, help}

#else	/* no long help info */

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}

#define U_BOOT_CMD_MKENT(name,maxargs,rep,cmd,usage,help) \
{#name, maxargs, rep, cmd, usage}

  這裏有兩種定義方式,區別在因而否保留幫助信息

  這個宏的做用是定義一個cmd_tbl_t結構體,而且將此結構體的存儲區域經過Struct_Section限制在了u_boot_cmd域。同時咱們看一下u-boot.lds文件中u_boot_cmd域的定義

  u-boot.lds

__u_boot_cmd_start = .;
	.u_boot_cmd : { *(.u_boot_cmd) }
	__u_boot_cmd_end = .;

  

這裏定義了u_boot_cmd域的位置,同時也定義了兩個變量:__u_boot_cmd_start和__u_boot_cmd_end,用來標識存儲空間的起始位置,在查找命令時,防止數組溢出。

經過U_BOOT_CMD宏,uboot能夠在一塊連續的空間中定義若干個cmd_tbl_t變量。cmd_tbl_t的定義以下:

/*
 * Monitor Command Table
 */

struct cmd_tbl_s {
	char		*name;		/* Command Name			*/
	int		maxargs;	/* maximum number of arguments	最大參數*/
	int		repeatable;	/* autorepeat allowed?		是否是能夠重複運行*/
					/* Implementation function	功能*/
	int		(*cmd)(struct cmd_tbl_s *, int, int, char * const []);
	char		*usage;		/* Usage message	(short)	*/
#ifdef	CONFIG_SYS_LONGHELP
	char		*help;		/* Help  message	(long)	*/
#endif
#ifdef CONFIG_AUTO_COMPLETE
	/* do auto completion on the arguments */
	int		(*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
#endif
};

  這個結構體將一個命令行與參數個數、用法信息、幫助信息和對應的執行函數關聯起來。

cmd_tbl_t *find_cmd(const char *cmd);
cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len);

具體函數在/common/command.c下

extern cmd_tbl_t  __u_boot_cmd_bdinfo;
extern cmd_tbl_t  __u_boot_cmd_showvar;

cmd_tbl_t *find_cmd (const char *cmd)
{
	//int len = &__u_boot_cmd_end - &__u_boot_cmd_start;
	int len = &__u_boot_cmd_showvar - &__u_boot_cmd_bdinfo + 1;
	//return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);
	return find_cmd_tbl(cmd, &__u_boot_cmd_bdinfo, len);
}
 函數會找到命令區的入口以及命令總數,最後調用find_cmd_tbl(); * find command table entry for a command 查找命令的命令表條目,找到指定函數入口
 */
cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len)
{
	cmd_tbl_t *cmdtp;
	cmd_tbl_t *cmdtp_temp = table;	/*Init value */
	const char *p;
	int len;
	int n_found = 0;

	if (!cmd)
		return NULL;
	/*
	 * Some commands allow length modifiers (like "cp.b");
	 * compare command name only until first dot.
	 */
	len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);

//這個for循環是find_cmd()的核心, _table指定的是在__.u_boot_cmd的開始地址, table + table_len就是相對應的結束地址. 
//注意:for中的cmdtp++每次加的不是1二是sizeof(cmd_tbl_t). 因此在這個循環中將會遍歷在__.u_boot_cmd段中的全部命令, 並查找與本次命令向對應的那個命令的結構體. for (cmdtp = table; cmdtp != table + table_len; cmdtp++) { if (strncmp (cmd, cmdtp->name, len) == 0) { if (len == strlen (cmdtp->name)) return cmdtp; /* 命令徹底匹配, 返回命令結構體 full match */ cmdtp_temp = cmdtp; /* 部分匹配, 後面會返回cmdtp_temp, abbreviated command ? */ n_found++; } } if (n_found == 1) { /* exactly one match */ return cmdtp_temp; } return NULL; /* not found or ambiguous command */ }

  簡單的例子:

#include <common.h>
#include <command.h>

extern char version_string[];

int do_version(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	printf("\n%s\n", version_string);

	return 0;
}
// 在u_boot_cmd中註冊命令 U_BOOT_CMD( version, 1, 1, do_version, "print monitor version", "" );

  

.weak關鍵字,在網上找了到的解釋,個人理解是.weak至關於聲明一個函數,若是該函數在其餘地方沒有定義,則爲空函數,有定義則調用該定義的函數。

相關文章
相關標籤/搜索