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

在学习过程中,由于tiny4412资料太过于少,因此参考210的视屏,但友善提供的uboot算是比较新。启动过程不太一样,我分析出来的board_init_f 已经超出了16K的范围,但relocate_code,及后面的栈设置stack_setup,和copy_loop后搬移还在board_init_f之后调用。这两天一直难以理解。突然翻到了这部帖子,感觉解释的比较清楚过程,

对uboot 反编译。

_start : 0xc3e00000

reset:  0xc3e00050

borad_init_f  : 0xc3e051fc

relocate_code  :  0xc3e00074

stack_setup  :  0xc3e00080

copy_loop  :   0xc3e000a0

 

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

主要参考: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相当于声明一个函数,如果该函数在其他地方没有定义,则为空函数,有定义则调用该定义的函数。

posted on 2019-01-13 22:02  ._初一  阅读(1625)  评论(0编辑  收藏  举报