您的位置:首页 > 其它

uboot启动流程webee210启动第二阶段

2015-12-21 23:30 429 查看
又重新回到原点了,但是此时运行的环境是sdram中,好再次分析.

前面的都是相同的,但是在lowlevel_init中会有不同。

/* when we already run in ram, we don't need to relocate U-Boot.
* and actually, memory controller must be configured before U-Boot
* is running in ram.
*/
ldr	r0, =0x00ffffff
bic	r1, pc, r0		/* r0 <- current base addr of code */
ldr	r2, _TEXT_BASE		/* r1 <- original base addr in ram */
bic	r2, r2, r0		/* r0 <- current base addr of code */
cmp     r1, r2                  /* compare r0, r1                  */
beq     1f			/* r0 == r1 then skip sdram init   */

/* init system clock */
bl system_clock_init

/* Memory initialize */
bl mem_ctrl_asm_init

1:
/* for UART */
bl uart_asm_init

bl tzpc_init
会判断当前运行的环境是内部的RAM还是外部的RAM,现在运行的环境是外部的RAM,那么会跳过系统时钟的初始化以及内存的初始化,会重新初始化串口,webee210的板子上串口初始化后会打印2次的ok,这一点也验证了这个地方会重新运行。

接着回到调用函数的地方。start.s中:

/* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic	sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr	r0,=0x00000000
#if defined(CONFIG_WEBEE210) || defined(CONFIG_MINI210)
adr	r4, _start
ldr	r5,_TEXT_BASE
cmp     r5,r4
beq	board_init_in_ram
此时我们是跑在了外部的ram中,这里还会进行判断,假如是外部的RAM,直接跳转到board_init_in_ram处:

board_init_in_ram:
bl	board_init_f
好吧,调到board_init_f中了,Board.c (arch\arm\lib)

bd_t *bd;
init_fnc_t **init_fnc_ptr;
gd_t *id;
ulong addr, addr_sp;

/* Pointer is writable since we allocated a register for it */
gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);                           //gd webee 210 上的地址是
//	gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");

memset((void *)gd, 0, sizeof(gd_t));                                       //清0

gd->mon_len = _bss_end_ofs;                                               //uboot的长度,bss段的结束地址

for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {      //初始化函数指针
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}


其中init_sequence定义如下:

init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)                                   // 有定义  初始化和CPU相关的ARCH
arch_cpu_init,		/* basic arch cpu dependent setup */
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_F)                            //未定义
board_early_init_f,
#endif
timer_init,		/* initialize timer */
#ifdef CONFIG_FSL_ESDHC                                                    //未定义
get_clocks,
#endif
env_init,		/* initialize environment */
init_baudrate,		/* initialze baudrate settings */
serial_init,		/* serial communications setup */
console_init_f,		/* stage 1 init of console */
display_banner,		/* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo,		/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard,		/* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)   //未定义
init_func_i2c,
#endif
dram_init,		/* configure available RAM banks */
NULL,
};


@1:arch_cpu_init:

#ifdef CONFIG_ARCH_CPU_INIT
int arch_cpu_init(void)
{
s5p_set_cpu_id();

return 0;
}
#endif
s5p_set_cpu_id函数从cpu内部读取了相关的id值到s5p_cpu_id的全局的变量。

@2:

int timer_init(void)
{
/* PWM Timer 4 */
pwm_init(4, MUX_DIV_2, 0);
pwm_config(4, 0, 0);
pwm_enable(4);

return 0;
}


初始化了pwm4的定时器,具体细节不讲了。

@3:env_init

int env_init(void)
{
//carl_Wang add
#if defined(ENV_IS_EMBEDDED) || defined(CONFIG_NAND_ENV_DST)
int crc1_ok = 0, crc2_ok = 0;
env_t *tmp_env1;

#ifdef CONFIG_ENV_OFFSET_REDUND
env_t *tmp_env2;

tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE);
crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
#endif

tmp_env1 = env_ptr;

crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);

if (!crc1_ok && !crc2_ok) {
gd->env_addr  = 0;
gd->env_valid = 0;

return 0;
} else if (crc1_ok && !crc2_ok) {
gd->env_valid = 1;
}
#ifdef CONFIG_ENV_OFFSET_REDUND
else if (!crc1_ok && crc2_ok) {
gd->env_valid = 2;
} else {
/* both ok - check serial */
if(tmp_env1->flags == 255 && tmp_env2->flags == 0)
gd->env_valid = 2;
else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)
gd->env_valid = 1;
else if(tmp_env1->flags > tmp_env2->flags)
gd->env_valid = 1;
else if(tmp_env2->flags > tmp_env1->flags)
gd->env_valid = 2;
else /* flags are equal - almost impossible */
gd->env_valid = 1;
}

if (gd->env_valid == 2)
env_ptr = tmp_env2;
else
#endif
if (gd->env_valid == 1)
env_ptr = tmp_env1;

gd->env_addr = (ulong)env_ptr->data;

#else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
gd->env_addr  = (ulong)&default_environment[0];
gd->env_valid = 1;
#endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */

return (0);
}
看见了一堆的代码,但是经过查找之后,发现没用的很多,有用的是

#else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
gd->env_addr  = (ulong)&default_environment[0];
gd->env_valid = 1;


gd已经知道了,是一个全局的变量,gd->env_addr 赋值了默认的env 参数表,同时置位env_valid有效。好看一下这个env参数表

即gd->env_addr = (ulong)&default_environment[0];

gd->env_valid = 1;

const uchar default_environment[] = {
#ifdef	CONFIG_BOOTARGS
"bootargs="	CONFIG_BOOTARGS			"\0"
#endif
#ifdef	CONFIG_BOOTCOMMAND
"bootcmd="	CONFIG_BOOTCOMMAND	"nand read 0x30007fc0 0x100000 0x500000;bootm 0x30007fc0\0"
#endif
#ifdef	CONFIG_RAMBOOTCOMMAND
"ramboot="	CONFIG_RAMBOOTCOMMAND		"\0"
#endif
#ifdef	CONFIG_NFSBOOTCOMMAND
"nfsboot="	CONFIG_NFSBOOTCOMMAND		"\0"
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
"bootdelay="	MK_STR(CONFIG_BOOTDELAY)	"\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
"baudrate="	MK_STR(CONFIG_BAUDRATE)		"\0"
#endif
#ifdef	CONFIG_LOADS_ECHO
"loads_echo="	MK_STR(CONFIG_LOADS_ECHO)	"\0"
#endif
#ifdef	CONFIG_ETHADDR
"ethaddr="	MK_STR(CONFIG_ETHADDR)		"\0"
#endif
#ifdef	CONFIG_ETH1ADDR
"eth1addr="	MK_STR(CONFIG_ETH1ADDR)		"\0"
#endif
#ifdef	CONFIG_ETH2ADDR
"eth2addr="	MK_STR(CONFIG_ETH2ADDR)		"\0"
#endif
#ifdef	CONFIG_ETH3ADDR
"eth3addr="	MK_STR(CONFIG_ETH3ADDR)		"\0"
#endif
#ifdef	CONFIG_ETH4ADDR
"eth4addr="	MK_STR(CONFIG_ETH4ADDR)		"\0"
#endif
#ifdef	CONFIG_ETH5ADDR
"eth5addr="	MK_STR(CONFIG_ETH5ADDR)		"\0"
#endif
#ifdef	CONFIG_IPADDR
"ipaddr="	MK_STR(CONFIG_IPADDR)		"\0"
#endif
#ifdef	CONFIG_SERVERIP
"serverip="	MK_STR(CONFIG_SERVERIP)		"\0"
#endif
#ifdef	CONFIG_SYS_AUTOLOAD
"autoload="	CONFIG_SYS_AUTOLOAD			"\0"
#endif
#ifdef	CONFIG_PREBOOT
"preboot="	CONFIG_PREBOOT			"\0"
#endif
#ifdef	CONFIG_ROOTPATH
"rootpath="	MK_STR(CONFIG_ROOTPATH)		"\0"
#endif
#ifdef	CONFIG_GATEWAYIP
"gatewayip="	MK_STR(CONFIG_GATEWAYIP)	"\0"
#endif
#ifdef	CONFIG_NETMASK
"netmask="	MK_STR(CONFIG_NETMASK)		"\0"
#endif
#ifdef	CONFIG_HOSTNAME
"hostname="	MK_STR(CONFIG_HOSTNAME)		"\0"
#endif
#ifdef	CONFIG_BOOTFILE
"bootfile="	MK_STR(CONFIG_BOOTFILE)		"\0"
#endif
#ifdef	CONFIG_LOADADDR
"loadaddr="	MK_STR(CONFIG_LOADADDR)		"\0"
#endif
#ifdef  CONFIG_CLOCKS_IN_MHZ
"clocks_in_mhz=1\0"
#endif
#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
"pcidelay="	MK_STR(CONFIG_PCI_BOOTDELAY)	"\0"
#endif
#ifdef  CONFIG_EXTRA_ENV_SETTINGS
CONFIG_EXTRA_ENV_SETTINGS
#endif
"\0"
};
这个有点类似于linux中的devicetree机制,根据“”中的字符串可以取到后面的相应的命令或者参数。注意一下bootcmd 的指令,启动linux时会用到。。。。。

@4:init_baudrate

初始化波特率,看一下env参数表中是否有这个命令,在 Webee210.h (include\configs) 中定义了

#define CONFIG_BAUDRATE 115200

所以gd->baudrate = 115200

static int init_baudrate(void)
{
char tmp[64];	/* long enough for environment variables */
int i = getenv_f("baudrate", tmp, sizeof(tmp));

gd->baudrate = (i > 0)
? (int) simple_strtoul(tmp, NULL, 10)
: CONFIG_BAUDRATE;

return (0);
}


@5: serial_init Serial.c (common)

int serial_init (void)
{
//carl_wang
if (!(gd->flags & GD_FLG_RELOC) || !serial_current) {
struct serial_device *dev = default_serial_console ();

return dev->init ();
}

return serial_current->init ();
}
struct serial_device 是一个关于串行设备的一些属性以及方法的(面向对象的思想)结构体,可以使用它构成一个链表。

struct serial_device {
char name[NAMESIZE];

int  (*init) (void);
int  (*uninit) (void);
void (*setbrg) (void);
int (*getc) (void);
int (*tstc) (void);
void (*putc) (const char c);
void (*puts) (const char *s);
#if CONFIG_POST & CONFIG_SYS_POST_UART
void (*loop) (int);
#endif

struct serial_device *next;
};


dev = default_serial_console()获取到了关于默认设备的实例,

__weak struct serial_device *default_serial_console(void)
{
#if defined(CONFIG_SERIAL0)            //定义了串口0
return &s5p_serial0_device;       //实例化
#elif defined(CONFIG_SERIAL1)
return &s5p_serial1_device;
#elif defined(CONFIG_SERIAL2)
return &s5p_serial2_device;
#elif defined(CONFIG_SERIAL3)
return &s5p_serial3_device;
#else
#error "CONFIG_SERIAL? missing."
#endif
}
这里获取的是s5p_serial0_device,所以调用dev->init则是调用了serial_init_dev,dev_index则是0

/*
* Initialise the serial port with the given baudrate. The settings
* are always 8 data bits, no parity, 1 stop bit, no start bits.
*/
int serial_init_dev(const int dev_index)
{
//carl_wang add
struct s5p_uart *const uart = s5p_get_base_uart(dev_index);

/* reset and enable FIFOs, set triggers to the maximum */
writel(0, &uart->ufcon);
writel(0, &uart->umcon);
/* 8N1 */
writel(0x3, &uart->ulcon);
/* No interrupts, no DMA, pure polling */
writel(0x245, &uart->ucon);

serial_setbrg_dev(dev_index);

return 0;
}
@6:console_init_f,实际上只是置为标位,此时

gd->have_console = 1;

/* Called before relocation - use serial functions */
int console_init_f(void)
{
gd->have_console = 1;

#ifdef CONFIG_SILENT_CONSOLE              //未定义
if (getenv("silent") != NULL)
gd->flags |= GD_FLG_SILENT;
#endif

return 0;
}
@7:display_banner 哎,就是log输出点版本信息,这里还log输出了uboot的起始地址,bss 段起始地址,bss段的结束地址。

打印出的log如下:

U-Boot 2011.06 (Dec 15 2015 - 22:32:20) for Webee_210_V2
U-Boot code: 33E00000 -> 33E66A30 BSS: -> 33E9CAFC

static int display_banner(void)
{
printf("\n\n%s\n\n", version_string);
printf("U-Boot code: %08lX -> %08lX  BSS: -> %08lX\n",
_TEXT_BASE,
_bss_start_ofs + _TEXT_BASE, _bss_end_ofs + _TEXT_BASE);
#ifdef CONFIG_MODEM_SUPPORT
debug("Modem Support enabled\n");
#endif
#ifdef CONFIG_USE_IRQ
debug("IRQ Stack: %08lx\n", IRQ_STACK_START);
debug("FIQ Stack: %08lx\n", FIQ_STACK_START);
#endif

return (0);
}


@8:print_cpuinfo

log出了一点信息,其中你想写的,还有是芯片的频率 。

#ifdef CONFIG_DISPLAY_CPUINFO
int print_cpuinfo(void)
{
char buf[32];

printf("\n");
printf("##############################################\n");
printf("#                                            #\n");
printf("#         i love wunana      #\n");
printf("#                                            #\n");
printf("##############################################\n\n");
//printf("CPU:\tS5P%X@%sMHz\n",
//		s5p_cpu_id, strmhz(buf, get_arm_clk()));

printf("CPU:\tS5PV210@%sMHz\n",
strmhz(buf, get_arm_clk()));

return 0;
}
#endif


@9:checkboard:没有特殊的作用,还是log

#ifdef CONFIG_DISPLAY_BOARDINFO
int checkboard(void)
{
//carl_wang
printf("\nBoard:   Webee_210_V2\n");
return (0);
}
#endif


@10 dram_init 其实是初始化了

gd->ram_size = 512M

int dram_init(void)
{
/* Since we have discontinuous RAM configuration, just put
* bank1 here for relocation
*/
gd->ram_size    = get_ram_size((long *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE+PHYS_SDRAM_2_SIZE);

return 0;
}

ok,假如中间有任何错误的化都会挂起等待。接着往下走

#if defined(CONFIG_SYS_MEM_TOP_HIDE)
/*
* Subtract specified amount of memory to hide so that it won't
* get "touched" at all by U-Boot. By fixing up gd->ram_size
* the Linux kernel should now get passed the now "corrected"
* memory size and won't touch it either. This should work
* for arch/ppc and arch/powerpc. Only Linux board ports in
* arch/powerpc with bootwrapper support, that recalculate the
* memory size from the SDRAM controller setup will have to
* get fixed.
*/
gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
#endif

addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;

#ifdef CONFIG_LOGBUFFER
#ifndef CONFIG_ALT_LB_ADDR
/* reserve kernel log buffer */
addr -= (LOGBUFF_RESERVE);
debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN,
addr);
#endif
#endif


其实就有一句话被编译到了,addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size; 其中CONFIG_SYS_SDRAM_BASE 定义是0x30000000,而ram_size是536870912

ok 往下

#ifdef CONFIG_PRAM                                                      //未定义
/*
* reserve protected RAM
*/
i = getenv_r("pram", (char *)tmp, sizeof(tmp));
reg = (i > 0) ? simple_strtoul((const char *)tmp, NULL, 10) :
CONFIG_PRAM;
addr -= (reg << 10);		/* size is in kB */
debug("Reserving %ldk for protected RAM at %08lx\n", reg, addr);
#endif /* CONFIG_PRAM */

#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))                //会编译到
/* reserve TLB table */
addr -= (4096 * 4);

/* round down to next 64 kB limit */
addr &= ~(0x10000 - 1);

gd->tlb_addr = addr;
printf("TLB table at: %08lx\n", addr);
#endif

/* round down to next 4 kB limit */
addr &= ~(4096 - 1);
printf("Top of RAM usable for U-Boot at: %08lx\n", addr);
这个就是给TLB table分出了一些空间,然后禁止访问。

接着往下

#ifdef CONFIG_LCD                                                                                 //未定义
#ifdef CONFIG_FB_ADDR
gd->fb_base = CONFIG_FB_ADDR;

debug("Top the fb_base addr is : %08lx\n", gd->fb_base);
#else
/* reserve memory for LCD display (always full pages) */
addr = lcd_setmem(addr);
gd->fb_base = addr;
debug("Top the fb_base addr is : %08lx\n", gd->fb_base);
#endif /* CONFIG_FB_ADDR */
#endif /* CONFIG_LCD */

/*
* reserve memory for U-Boot code, data & bss
* round down to next 4 kB limit
*/
addr -= gd->mon_len;
addr &= ~(4096 - 1);

debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);


这个又是在为uboot预留空间,然后进行4Kb的四舍五入。

往下:

#ifndef CONFIG_SPL_BUILD                                        //会编译到
/*
* reserve memory for malloc() arena
*/
addr_sp = addr - TOTAL_MALLOC_LEN;
debug("Reserving %dk for malloc() at: %08lx\n",
TOTAL_MALLOC_LEN >> 10, addr_sp);
/*
* (permanently) allocate a Board Info struct
* and a permanent copy of the "global" data
*/
addr_sp -= sizeof (bd_t);
bd = (bd_t *) addr_sp;
gd->bd = bd;
debug("Reserving %zu Bytes for Board Info at: %08lx\n",
sizeof (bd_t), addr_sp);

#ifdef CONFIG_MACH_TYPE
gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
#endif

addr_sp -= sizeof (gd_t);
id = (gd_t *) addr_sp;
debug("Reserving %zu Bytes for Global Data at: %08lx\n",
sizeof (gd_t), addr_sp);

/* setup stackpointer for exeptions */
gd->irq_sp = addr_sp;
#ifdef CONFIG_USE_IRQ
addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
debug("Reserving %zu Bytes for IRQ stack at: %08lx\n",
CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);
#endif
/* leave 3 words for abort-stack    */
addr_sp -= 12;

/* 8-byte alignment for ABI compliance */
addr_sp &= ~0x07;
#else
addr_sp += 128;	/* leave 32 words for abort-stack   */
gd->irq_sp = addr_sp;
#endif


一部分预留空间给malloc使用,uboot,TLB table,board info,gd,异常退出栈(abort stack),按照webee210板子的sdram的配置,如下图:



最后还要看一下重要的数据结构gd发生了什么变化:

gd->mon_len = 0x9cd2c //uboot的长度(_start 到bss_ends)

gd->ram_size = 512M = 0x20000000 //实际的物理内存大小

gd->tlb_addr = 0x4fff0000 // TLB table 内存地址

gd->bd = bd = 0x4fe6afe0 //board info 的地址

gd->bd->bi_arch_number = 2456 //传递给linux内核的机器码

gd->irq_sp = 0x4fe6af68 //中断栈指针

此时的addr 以及addrsp 也有相对应的值了

addr = 0x4ff53000

addr_sp = 0x4fe6af58

接着往下:

#ifdef CONFIG_POST                                                                      //未定义
post_bootmode_init();
post_run(NULL, POST_ROM | post_bootmode_get(0));
#endif

gd->bd->bi_baudrate = gd->baudrate;
/* Ram ist board specific, so move it to board code ... */
dram_init_banksize();
display_dram_config();	/* and display it */

gd->relocaddr = addr;
gd->start_addr_sp = addr_sp;
gd->reloc_off = addr - _TEXT_BASE;
printf("relocation Offset is: %08lx\n", gd->reloc_off);

//	printf("relocaddr is: %08lx\n", gd->relocaddr);
//	printf("start_addr_sp is: %08lx\n", gd->start_addr_sp);
//	printf("relocation Offset is: %08lx\n", gd->reloc_off);

memcpy(id, (void *)gd, sizeof(gd_t));

relocate_code(addr_sp, id, addr);
dram_init_banksize(); Webee210.c (board\samsung\webee210)初始化了gd的 参数,表明起始地址,长度。这些参数都要传递到linux内核中去。

void dram_init_banksize(void)
{
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = get_ram_size((long *)PHYS_SDRAM_1, \
PHYS_SDRAM_1_SIZE);

gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
gd->bd->bi_dram[1].size = get_ram_size((long *)PHYS_SDRAM_2,PHYS_SDRAM_2_SIZE);
}
gd->bd->bi_baudrate = gd->baudrate = 115200

gd->bd->bi_dram[0].start = 0x30000000

gd->bd->bi_dram[0].size = 0x10000000

gd->bd->bi_dram[1].start = 0x40000000

gd->bd->bi_dram[1].size = 0x10000000
而后调用显示Dram的大小的函数,打印显示DRAM:512M
static int display_dram_config(void)
{
int i;

#ifdef DEBUG
puts("RAM Configuration:\n");

for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
printf("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start);
print_size(gd->bd->bi_dram[i].size, "\n");
}
#else
ulong size = 0;

for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++)
size += gd->bd->bi_dram[i].size;

puts("DRAM:  ");
print_size(size, "\n");
puts("                                                                              \n\n");
#endif

return (0);
}
最后赋值几个相关的gd的参数
gd->relocaddr = addr = 0x4ff53000

gd->start_addr_sp = addr_sp = 0x4fe6af58

gd->reloc_off = addr - _TEXT_BASE = 0x1c153000

memcpy(id, (void *)gd, sizeof(gd_t));

relocate_code(addr_sp, id, addr);


将gd的地址拷贝到id作为参数传递给relocate_code,同时addr_sp,addr 作为参数传递给relocate_code了。

好往下走:

relocate_code是start.s 中一段代码:

/*------------------------------------------------------------------------------*/

/*
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
*/
.globl	 relocate_code
relocate_code:

mov	r4, r0	/* save addr_sp */
mov	r5, r1	/* save addr of gd */
mov	r6, r2	/* save addr of destination */

/* Set up the stack						    */
stack_setup:
mov	sp, r4

adr	r0, _start
cmp	r0, r6
moveq	r9, #0		/* no relocation. relocation offset(r9) = 0 */
beq	clear_bss		/* skip relocation */
mov	r1, r6			/* r1 <- scratch for copy_loop */
ldr	r3, _image_copy_end_ofs
add	r2, r0, r3		/* r2 <- source end address	    */

copy_loop:
ldmia	r0!, {r9-r10}		/* copy from source address [r0]    */
stmia	r1!, {r9-r10}		/* copy to   target address [r1]    */
cmp	r0, r2			/* until source end address [r2]    */
blo	copy_loop

/////////////////////////////////////////////////////////////////////////////////
#ifndef CONFIG_SPL_BUILD

/*
* fix .rel.dyn relocations
*/
ldr	r0, _TEXT_BASE		/* r0 <- Text base */
sub	r9, r6, r0		/* r9 <- relocation offset */
ldr	r10, _dynsym_start_ofs	/* r10 <- sym table ofs */
add	r10, r10, r0		/* r10 <- sym table in FLASH */
ldr	r2, _rel_dyn_start_ofs	/* r2 <- rel dyn start ofs */
add	r2, r2, r0		/* r2 <- rel dyn start in FLASH */
ldr	r3, _rel_dyn_end_ofs	/* r3 <- rel dyn end ofs */
add	r3, r3, r0		/* r3 <- rel dyn end in FLASH */
fixloop:
ldr	r0, [r2]		/* r0 <- location to fix up, IN FLASH! */
add	r0, r0, r9		/* r0 <- location to fix up in RAM */
ldr	r1, [r2, #4]
and	r7, r1, #0xff
cmp	r7, #23			/* relative fixup? */
beq	fixrel
cmp	r7, #2			/* absolute fixup? */
beq	fixabs
/* ignore unknown type of fixup */
b	fixnext
fixabs:
/*
*/
/* absolute fix: set location to (offset) symbol value */
mov	r1, r1, LSR #4		/* r1 <- symbol index in .dynsym */
add	r1, r10, r1		/* r1 <- address of symbol in table */
ldr	r1, [r1, #4]		/* r1 <- symbol value */
add	r1, r1, r9		/* r1 <- relocated sym addr */
b	fixnext
fixrel:
/* relative fix: increase location by offset */
ldr	r1, [r0]
add	r1, r1, r9
fixnext:
str	r1, [r0]
add	r2, r2, #8		/* each rel.dyn entry is 8 bytes */
cmp	r2, r3
blo	fixloop

b	clear_bss
_rel_dyn_start_ofs:
.word __rel_dyn_start - _start
_rel_dyn_end_ofs:
.word __rel_dyn_end - _start
_dynsym_start_ofs:
.word __dynsym_start - _start

#endif	/* #ifndef CONFIG_SPL_BUILD */

/////////////////////////////////////////////////////////////////////////////////////
clear_bss:
#ifdef CONFIG_SPL_BUILD
/* No relocation for SPL */
ldr	r0, =__bss_start
ldr	r1, =__bss_end__
#else
ldr	r0, _bss_start_ofs
ldr	r1, _bss_end_ofs
mov	r4, r6			/* reloc addr */
add	r0, r0, r4
add	r1, r1, r4
#endif
mov	r2, #0x00000000		/* clear			    */

clbss_l:str	r2, [r0]		/* clear loop...		    */
add	r0, r0, #4
cmp	r0, r1
bne	clbss_l

/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
jump_2_ram:
/*
* If I-cache is enabled invalidate it
*/

#ifndef CONFIG_SYS_ICACHE_OFF
mcr	p15, 0, r0, c7, c5, 0	@ invalidate icache
mcr     p15, 0, r0, c7, c10, 4	@ DSB
mcr     p15, 0, r0, c7, c5, 4	@ ISB
#endif
ldr	r0, _board_init_r_ofs
adr	r1, _start
add	lr, r0, r1
add	lr, lr, r9
/* setup parameters for board_init_r */
mov	r0, r5		/* gd_t */
mov	r1, r6		/* dest_addr */
/* jump to it ... */
mov	pc, lr

_board_init_r_ofs:
.word board_init_r - _start


这部分又将内存中的数据进行了一番拷贝将uboot的运行地址迁移到了gd->relocaddr处,继续执行。在完成搬运工作之后,回跳转到board_init_r的函数中,r5,r6 作为参数传入了这个函数中。

往下:void board_init_r(gd_t *id, ulong dest_addr) 这个函数将是uboot的最后一程,完成这个将完成自己的使命转入linux了。

/*
************************************************************************
*
* This is the next part if the initialization sequence: we are now
* running from RAM and have a "normal" C environment, i. e. global
* data can be written, BSS has been cleared, the stack size in not
* that critical any more, etc.
*
************************************************************************
*/

void board_init_r(gd_t *id, ulong dest_addr)
{
char *s;
bd_t *bd;
ulong malloc_start;
#if !defined(CONFIG_SYS_NO_FLASH)
ulong flash_size;
#endif

gd = id;
bd = gd->bd;

gd->flags |= GD_FLG_RELOC;	/* tell others: relocation done */

monitor_flash_len = _end_ofs;

//carl_wang add
printf("hello board_init_r \n");
printf("hello dest_addr:%x %x\n,",(int)dest_addr,id);

/* Enable caches */
enable_caches();

printf("monitor flash len: %08lX\n", monitor_flash_len);
board_init();	/* Setup chipselects */

#ifdef CONFIG_SERIAL_MULTI
serial_initialize();
#endif

printf("Now running in RAM - U-Boot at: %08lx\n", dest_addr);
@1:

gd = id;

bd = gd->bd;又重新回到了以前的状态,monitor_flash_len 实际上应该是uboot(除去bss段)的长度吧(有疑问)

.globl _end_ofs
_end_ofs:
.word _end - _start
以下是整个uboot的段布局,可以看出_end 是在uboot中从_start到bss段之前的内容。最后告诉别人自己已经RELOC了。

gd->flags |= GD_FLG_RELOC

ENTRY(_start)
SECTIONS
{
. = 0x00000000;

. = ALIGN(4);
.text	:
{
arch/arm/cpu/armv7/start.o	(.text)
*(.text)
}

. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }

. = ALIGN(4);
.data : {
*(.data)
}

. = ALIGN(4);

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

. = ALIGN(4);

__image_copy_end = .;

.rel.dyn : {
__rel_dyn_start = .;
*(.rel*)
__rel_dyn_end = .;
}

.dynsym : {
__dynsym_start = .;
*(.dynsym)
}

_end = .;

.bss __rel_dyn_start (OVERLAY) : {
__bss_start = .;
*(.bss)
. = ALIGN(4);
__bss_end__ = .;
}

/DISCARD/ : { *(.dynstr*) }
/DISCARD/ : { *(.dynamic*) }
/DISCARD/ : { *(.plt*) }
/DISCARD/ : { *(.interp*) }
/DISCARD/ : { *(.gnu*) }
}


@2:使能caches,不必多讲

板级初始化board_init();

int board_init(void)
{

writel(0x22222222, GPF0CON);    //GPF0CON set GPF0[0:7] as HSYNC,VSYNC,VDEN,VCLK,VD[0:3]
writel(0x0, GPF0PUD);      //GPF0PUD set pull-up,down disable
writel(0x22222222, GPF1CON);    //set GPF1CON[7:0] as VD[11:4]
writel(0x0, GPF1PUD);      //GPF1PUD set pull-up,down disable
writel(0x22222222, GPF2CON);    //set GPF2CON[7:0] as VD[19:12]
writel(0x0, GPF2PUD);      //GPF2PUD set pull-up,down disable
writel(0x00002222, GPF3CON);    //set GPF3CON[3:0] as VD[23:20]
writel(0x0, GPF3PUD);      //GPF3PUD set pull-up,down disable
//--------- S5PC110 EVT0 needs MAX drive strength---------//
writel(0xffffffff, GPF0DRV);    //set GPF0DRV drive strength max by WJ.KIM(09.07.17)
writel(0xffffffff, GPF1DRV);    //set GPF1DRV drive strength max by WJ.KIM(09.07.17)
writel(0xffffffff, GPF2DRV);    //set GPF2DRV drive strength max by WJ.KIM(09.07.17)
writel(0x3ff, GPF3DRV);     //set GPF3DRV drive strength max by WJ.KIM(09.07.17)
/* Set Initial global variables */
s5pc110_gpio = (struct s5pc110_gpio *)S5PC110_GPIO_BASE;

/***Modified by lk ***/

//smc9115_pre_init();
pwm_pre_init();

#ifdef CONFIG_DRIVER_DM9000
dm9000_pre_init();
#endif

gd->bd->bi_arch_number = CONFIG_MACH_TYPE;
gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);

return 0;
}
和板子的硬件相关的不要关心,只需要知道的是

gd->bd->bi_arch_number = CONFIG_MACH_TYPE;

gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);

好宏定义展开

gd->bd->bi_arch_number = 2456 //传入linux的机器码

gd->bd->bi_boot_params = 0x30000000 +0x100 = 0x30000100  //启动参数的存放地址

往下:

#ifdef CONFIG_SERIAL_MULTI
serial_initialize();
#endif

printf("Now running in RAM - U-Boot at: %08lx\n", dest_addr);

#ifdef CONFIG_LOGBUFFER           //未定义
logbuff_init_ptrs();
#endif
#ifdef CONFIG_POST             //未定义
post_output_backlog();
#endif

/* The Malloc area is immediately below the monitor copy in DRAM */
malloc_start = dest_addr - TOTAL_MALLOC_LEN;
mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);


@1:串口的初始化 注意我们的平台是S5P,所以应该可以猜到是用哪个函数了,没错是

void serial_initialize (void)
{
#if defined(CONFIG_8xx_CONS_SMC1) || defined(CONFIG_8xx_CONS_SMC2)
serial_register (&serial_smc_device);
#endif
#if defined(CONFIG_8xx_CONS_SCC1) || defined(CONFIG_8xx_CONS_SCC2) \
|| defined(CONFIG_8xx_CONS_SCC3) || defined(CONFIG_8xx_CONS_SCC4)
serial_register (&serial_scc_device);
#endif

#if defined(CONFIG_SYS_NS16550_SERIAL)
#if defined(CONFIG_SYS_NS16550_COM1)
serial_register(&eserial1_device);
#endif
#if defined(CONFIG_SYS_NS16550_COM2)
serial_register(&eserial2_device);
#endif
#if defined(CONFIG_SYS_NS16550_COM3)
serial_register(&eserial3_device);
#endif
#if defined(CONFIG_SYS_NS16550_COM4)
serial_register(&eserial4_device);
#endif
#endif /* CONFIG_SYS_NS16550_SERIAL */
#if defined (CONFIG_FFUART)
serial_register(&serial_ffuart_device);
#endif
#if defined (CONFIG_BTUART)
serial_register(&serial_btuart_device);
#endif
#if defined (CONFIG_STUART)
serial_register(&serial_stuart_device);
#endif
#if defined(CONFIG_S3C2410)
serial_register(&s3c24xx_serial0_device);
serial_register(&s3c24xx_serial1_device);
serial_register(&s3c24xx_serial2_device);
#endif
#if defined(CONFIG_S5P)                //有定义
serial_register(&s5p_serial0_device);
serial_register(&s5p_serial1_device);
serial_register(&s5p_serial2_device);
serial_register(&s5p_serial3_device);
#endif
#if defined(CONFIG_MPC512X)
#if defined(CONFIG_SYS_PSC1)
serial_register(&serial1_device);
#endif
#if defined(CONFIG_SYS_PSC3)
serial_register(&serial3_device);
#endif
#if defined(CONFIG_SYS_PSC4)
serial_register(&serial4_device);
#endif
#if defined(CONFIG_SYS_PSC6)
serial_register(&serial6_device);
#endif
#endif
#if defined(CONFIG_SYS_BFIN_UART)
serial_register_bfin_uart();
#endif
serial_assign (default_serial_console ()->name);
}
实际上调用的是下面5个函数。好看看具体在干什么

serial_register(&s5p_serial0_device);
serial_register(&s5p_serial1_device);
serial_register(&s5p_serial2_device);
serial_register(&s5p_serial3_device);
<pre name="code" class="cpp">serial_assign (default_serial_console ()->name);



void serial_register(struct serial_device *dev)
{
#ifdef CONFIG_NEEDS_MANUAL_RELOC
dev->init += gd->reloc_off;
dev->setbrg += gd->reloc_off;
dev->getc += gd->reloc_off;
dev->tstc += gd->reloc_off;
dev->putc += gd->reloc_off;
dev->puts += gd->reloc_off;
#endif

dev->next = serial_devices;
serial_devices = dev;
}
你会发现serial_devices是静态的全局变量,这个函数将serial_devices 构成了一个链表



serial_assign (default_serial_console ()->name);

其实是在根据所配置的串口选出当前的串口。

__weak struct serial_device *default_serial_console(void)
{
#if defined(CONFIG_SERIAL0)           //有定义的
return &s5p_serial0_device;
#elif defined(CONFIG_SERIAL1)
return &s5p_serial1_device;
#elif defined(CONFIG_SERIAL2)
return &s5p_serial2_device;
#elif defined(CONFIG_SERIAL3)
return &s5p_serial3_device;
#else
#error "CONFIG_SERIAL? missing."
#endif
}
所以返回的是s5p_serial0_device的name ->s5pser0

serial_assign 会根据name遍历整个serial_devices来决定当前的串口是哪一个,并将serial_current赋值,显然最后serial_current = s5p_serial0_device。

int serial_assign (char *name)
{
struct serial_device *s;

for (s = serial_devices; s; s = s->next) {
if (strcmp (s->name, name) == 0) {
serial_current = s;
return 0;
}
}

return 1;
}
@2:
mem_malloc_init


就是在给malloc分配起始地址,空间大小等

往下:

#if !defined(CONFIG_SYS_NO_FLASH)           // <span style="font-family: Arial, Helvetica, sans-serif;">CONFIG_SYS_NO_FLASH有定义</span>
     
puts("Flash: ");

flash_size = flash_init();
if (flash_size > 0) {
# ifdef CONFIG_SYS_FLASH_CHECKSUM
print_size(flash_size, "");
/*
* Compute and print flash CRC if flashchecksum is set to 'y'
*
* NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
*/
s = getenv("flashchecksum");
if (s && (*s == 'y')) {
printf("  CRC: %08X", crc32(0,
(const unsigned char *) CONFIG_SYS_FLASH_BASE,
flash_size));
}
putc('\n');
# else	/* !CONFIG_SYS_FLASH_CHECKSUM */
print_size(flash_size, "\n");
# endif /* CONFIG_SYS_FLASH_CHECKSUM */
} else {
puts(failed);
hang();
}
#endif

#if defined(CONFIG_CMD_NAND)
puts("NAND:  ");
nand_init();
#endif

#if defined(CONFIG_CMD_ONENAND)
onenand_init();
#endif

#ifdef CONFIG_GENERIC_MMC
puts("MMC:   ");
mmc_initialize(bd);
#endif

#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif
这部分主要是在初始化存储器,webee210的板子支持nand以及SDcard,所以你懂得会调用

nand_init();
mmc_initialize(bd);


nand以及mmc的初始化应该是标配的,uboot的自带的,不在详细的讲解。

接着往下:

/* initialize environment */
env_relocate();

#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)        //未定义
arm_pci_init();
#endif

/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");

stdio_init();	/* get the devices list going. */

printf("carl_wang->nimei@1\r\n");
jumptable_init();

#if defined(CONFIG_API)                     //未定义
/* Initialize API */
api_init();
#endif
//carl_wang fix
console_init_r();	/* fully init console as a device */

printf("carl_wang->nimei@2\r\n");

#if defined(CONFIG_ARCH_MISC_INIT)             //未定义
/* miscellaneous arch dependent initialisations */
arch_misc_init();
#endif
#if defined(CONFIG_MISC_INIT_R)             //未定义
/* miscellaneous platform dependent initialisations */
misc_init_r();
#endif

/* set up exceptions */
interrupt_init();                  //设置中断
/* enable exceptions */
enable_interrupts();               //使能中断 由于我们并未使用中断,所以为空函数


@1 :设置env表

env_relocate();

void env_relocate (void)
{
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
extern void env_reloc(void);

env_reloc();
#endif
if (gd->env_valid == 0) {
#if defined(CONFIG_ENV_IS_NOWHERE)	/* Environment not changable */
set_default_env(NULL);
#else
show_boot_progress (-60);
set_default_env("!bad CRC");
#endif
} else {
env_relocate_spec ();
}
}


env_valid 在之前已经设置为1了,显然走的是env_relocate_spec。

void env_relocate_spec (void)
{
printf("env_relocate_spec\n");
#if !defined(ENV_IS_EMBEDDED)
int ret;
char buf[CONFIG_ENV_SIZE];

#if defined(CONFIG_ENV_OFFSET_OOB)
ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);
/*
* If unable to read environment offset from NAND OOB then fall through
* to the normal environment reading code below
*/
if (!ret) {
printf("Found Environment offset in OOB..\n");
} else {
set_default_env("!no env offset in OOB");
return;
}
#endif

//ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);
//////////////////////////////////////////////////
ret = readenv(0x15000000, (u_char *)buf);
/////////////////////////////////////////////////
if (ret) {
printf("carl_Wang readenv fail\n");
set_default_env("!readenv() failed");
return;
}

env_import(buf, 1);
#endif /* ! ENV_IS_EMBEDDED */
}


这个env是存储在nand中的,首先会读取nandflash上的是否存在env,假如存在的话则退出,假如不存在的话会设置默认的env的环境。注意CONFIG_ENV_SIZE的大小是16KB,读取到buf中,0x15000000是nandflash存储env的起始地址,大小是16KB

分为两种情况:

@1已经存在env

读取env到buf中直接调用env_import(buf, 1);env_import(buf, 1)的作用是将env导入到env_htab中去

/*
* Check if CRC is valid and (if yes) import the environment.
* Note that "buf" may or may not be aligned.
*/
int env_import(const char *buf, int check)
{
env_t *ep = (env_t *)buf;

if (check) {
uint32_t crc;

memcpy(&crc, &ep->crc, sizeof(crc));

if (crc32(0, ep->data, ENV_SIZE) != crc) {
set_default_env("!bad CRC");
return 0;
}
}

if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0)) {
gd->flags |= GD_FLG_ENV_READY;
return 1;
}

error("Cannot import environment: errno = %d\n", errno);

set_default_env("!import failed");

return 0;
}


@2不存在env或者env不对

写入默认的env导入到env的hashtable中即env_htab中去,然后返回

默认的env是default_environment

void set_default_env(const char *s)
{
if (sizeof(default_environment) > ENV_SIZE) {
puts("*** Error - default environment is too large\n\n");
return;
}

if (s) {
if (*s == '!') {
printf("*** Warning - %s, "
"using default environment\n\n",
s+1);
} else {
puts(s);
}
} else {
puts("Using default environment\n\n");
}

if (himport_r(&env_htab, (char *)default_environment,
sizeof(default_environment), '\0', 0) == 0) {
error("Environment import failed: errno = %d\n", errno);
}
gd->flags |= GD_FLG_ENV_READY;
}


这二者的结果都是要将env导入到env_htab中去,然后将

gd->flags |= GD_FLG_ENV_READY;

以后所有和env相关的操作都要从env_htab从去获取或者写入

好的往下:

/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");


获得IP地址,ip地址从env_htab中获取,但是并非是实际的ip地址,而是经过一定的算法得到的。具体算法如下:

IPaddr_t string_to_ip(const char *s)
{
IPaddr_t addr;
char *e;
int i;

if (s == NULL)
return(0);
printf("carl_Wang->ip:%s\n",s);
for (addr=0, i=0; i<4; ++i) {
ulong val = s ? simple_strtoul(s, &e, 10) : 0;
addr <<= 8;
addr |= (val & 0xFF);
if (s) {
s = (*e) ? e+1 : e;
}
}

return (htonl(addr));
}
gd->bd->bi_ip_addr  = 2063640768

接下来是比较重要的部分:

stdio_init();

nt stdio_init (void)
{
#if defined(CONFIG_NEEDS_MANUAL_RELOC)                  //未定义
/* already relocated for current ARM implementation */
ulong relocation_offset = gd->reloc_off;
int i;

/* relocate device name pointers */
for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {
stdio_names[i] = (char *) (((ulong) stdio_names[i]) +
relocation_offset);
}
#endif /* CONFIG_NEEDS_MANUAL_RELOC */

/* Initialize the list */
INIT_LIST_HEAD(&(devs.list));

#ifdef CONFIG_ARM_DCC_MULTI                 //未定义
drv_arm_dcc_init ();
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)   //未定义
i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
#endif
#ifdef CONFIG_LCD                      //未定义
drv_lcd_init ();
#endif
#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)  //有定义
drv_video_init ();
#endif
#ifdef CONFIG_KEYBOARD                  //未定义
drv_keyboard_init ();
#endif
#ifdef CONFIG_LOGBUFFER                 //未定义
drv_logbuff_init ();
#endif
drv_system_init ();
#ifdef CONFIG_SERIAL_MULTI
serial_stdio_init ();
#endif
#ifdef CONFIG_USB_TTY                  //未定义
drv_usbtty_init ();
#endif
#ifdef CONFIG_NETCONSOLE               //未定义
drv_nc_init ();
#endif
#ifdef CONFIG_JTAG_CONSOLE              //未定义
drv_jtag_console_init ();
#endif

return (0);
}
@1:初始化devs.lists链表。devs存储设备,而且是能够构成设备的链表

@2:drv_video_init 真正的video 初始化

int drv_video_init(void)
{
int skip_dev_init;
struct stdio_dev console_dev;

/* Check if video initialization should be skipped */
if (board_video_skip())                //空函数
return 0;

/* Init video chip - returns with framebuffer cleared */
skip_dev_init = (video_init() == -1);          //真正初始化video的函数

#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
debug("KBD: Keyboard init ...\n");
skip_dev_init |= (VIDEO_KBD_INIT_FCT == -1);
#endif

if (skip_dev_init)
return 0;

/* Init vga device */
memset(&console_dev, 0, sizeof(console_dev));
strcpy(console_dev.name, "vga");
console_dev.ext = DEV_EXT_VIDEO;	/* Video extensions */
console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
console_dev.putc = video_putc;	/* 'putc' function */
console_dev.puts = video_puts;	/* 'puts' function */
console_dev.tstc = NULL;	/* 'tstc' function */
console_dev.getc = NULL;	/* 'getc' function */

#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
/* Also init console device */
console_dev.flags |= DEV_FLAGS_INPUT;
console_dev.tstc = VIDEO_TSTC_FCT;	/* 'tstc' function */
console_dev.getc = VIDEO_GETC_FCT;	/* 'getc' function */
#endif /* CONFIG_VGA_AS_SINGLE_DEVICE */

if (stdio_register(&console_dev) != 0)
return 0;

/* Return success */
return 1;
}
video初始化函数

static int video_init(void)
{
unsigned char color8;

pGD = video_hw_init();
if (pGD == NULL)
return -1;

video_fb_address = (void *) VIDEO_FB_ADRS;
#ifdef CONFIG_VIDEO_HW_CURSOR
video_init_hw_cursor(VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT);
#endif

/* Init drawing pats */
switch (VIDEO_DATA_FORMAT) {
case GDF__8BIT_INDEX:
video_set_lut(0x01, CONSOLE_FG_COL, CONSOLE_FG_COL,
CONSOLE_FG_COL);
video_set_lut(0x00, CONSOLE_BG_COL, CONSOLE_BG_COL,
CONSOLE_BG_COL);
fgx = 0x01010101;
bgx = 0x00000000;
break;
case GDF__8BIT_332RGB:
color8 = ((CONSOLE_FG_COL & 0xe0) |
((CONSOLE_FG_COL >> 3) & 0x1c) |
CONSOLE_FG_COL >> 6);
fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
color8;
color8 = ((CONSOLE_BG_COL & 0xe0) |
((CONSOLE_BG_COL >> 3) & 0x1c) |
CONSOLE_BG_COL >> 6);
bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
color8;
break;
case GDF_15BIT_555RGB:
fgx = (((CONSOLE_FG_COL >> 3) << 26) |
((CONSOLE_FG_COL >> 3) << 21) |
((CONSOLE_FG_COL >> 3) << 16) |
((CONSOLE_FG_COL >> 3) << 10) |
((CONSOLE_FG_COL >> 3) <<  5) |
(CONSOLE_FG_COL >> 3));
bgx = (((CONSOLE_BG_COL >> 3) << 26) |
((CONSOLE_BG_COL >> 3) << 21) |
((CONSOLE_BG_COL >> 3) << 16) |
((CONSOLE_BG_COL >> 3) << 10) |
((CONSOLE_BG_COL >> 3) <<  5) |
(CONSOLE_BG_COL >> 3));
break;
case GDF_16BIT_565RGB:
fgx = (((CONSOLE_FG_COL >> 3) << 27) |
((CONSOLE_FG_COL >> 2) << 21) |
((CONSOLE_FG_COL >> 3) << 16) |
((CONSOLE_FG_COL >> 3) << 11) |
((CONSOLE_FG_COL >> 2) <<  5) |
(CONSOLE_FG_COL >> 3));
bgx = (((CONSOLE_BG_COL >> 3) << 27) |
((CONSOLE_BG_COL >> 2) << 21) |
((CONSOLE_BG_COL >> 3) << 16) |
((CONSOLE_BG_COL >> 3) << 11) |
((CONSOLE_BG_COL >> 2) <<  5) |
(CONSOLE_BG_COL >> 3));
break;
case GDF_32BIT_X888RGB:
fgx =	(CONSOLE_FG_COL << 16) |
(CONSOLE_FG_COL <<  8) |
CONSOLE_FG_COL;
bgx =	(CONSOLE_BG_COL << 16) |
(CONSOLE_BG_COL <<  8) |
CONSOLE_BG_COL;
break;
case GDF_24BIT_888RGB:
fgx =	(CONSOLE_FG_COL << 24) |
(CONSOLE_FG_COL << 16) |
(CONSOLE_FG_COL <<  8) |
CONSOLE_FG_COL;
bgx =	(CONSOLE_BG_COL << 24) |
(CONSOLE_BG_COL << 16) |
(CONSOLE_BG_COL <<  8) |
CONSOLE_BG_COL;
break;
}
eorx = fgx ^ bgx;

#ifdef CONFIG_VIDEO_LOGO                  //有定义
/* Plot the logo and get start point of console */
printf("Video: Drawing the logo ...\n");
video_console_address = video_logo();
#else
video_console_address = video_fb_address;
#endif

/* Initialize the console */
console_col = 0;
console_row = 0;

return 0;
}
@1:video_hw_init 会初始化和屏相关的参数,包括x,y等,这个内容涉及较多了,不再详细讲述了。需要注意一点,大部分的video的移植也在这部分做主要修改。返回了一个GraphicDevice的指针,这个参数基本已经包括了所有的LCD的参数了。

@2:video_fb_address是LCD framebuf的初始写地址。然后根据具体使用的位数来确定fgx以及bgx,具体的我也不清楚了。

@3:不过重要的是怎么drawlogo:

video_console_address = video_logo();

static void *video_logo(void)
{
char info[128];
int space, len, y_off = 0;

#ifdef CONFIG_SPLASH_SCREEN             //有定义
char *s;
ulong addr;

s = getenv("splashimage");            //env 中并没有
if (s != NULL) {
int x = 0, y = 0;

addr = simple_strtoul(s, NULL, 16);
#ifdef CONFIG_SPLASH_SCREEN_ALIGN
s = getenv("splashpos");
if (s != NULL) {
if (s[0] == 'm')
x = BMP_ALIGN_CENTER;
else
x = simple_strtol(s, NULL, 0);

s = strchr(s + 1, ',');
if (s != NULL) {
if (s[1] == 'm')
y = BMP_ALIGN_CENTER;
else
y = simple_strtol(s + 1, NULL, 0);
}
}
#endif /* CONFIG_SPLASH_SCREEN_ALIGN */

if (video_display_bitmap(addr, x, y) == 0) {
video_logo_height = 0;
return ((void *) (video_fb_address));
}
}
#endif /* CONFIG_SPLASH_SCREEN */
/*change the plot of logo*/
logo_plot(video_fb_address, VIDEO_COLS, VIDEO_LOGO_X, VIDEO_LOGO_Y);

#ifdef DEBUG_CFB_CONSOLE_LCD
sprintf(info, " %s"," " );
#else
sprintf(info, " %s", version_string);
#endif
space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH;
len = strlen(info);

if (len > space) {
video_drawchars(VIDEO_INFO_X, VIDEO_INFO_Y,
(uchar *) info, space);
video_drawchars(VIDEO_INFO_X + VIDEO_FONT_WIDTH,
VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
(uchar *) info + space, len - space);
y_off = 1;
} else
video_drawstring(VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *) info);

#ifdef CONFIG_CONSOLE_EXTRA_INFO
{
int i, n =
((video_logo_height -
VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT);

for (i = 1; i < n; i++) {
video_get_info_str(i, info);
if (!*info)
continue;

len = strlen(info);
if (len > space) {
video_drawchars(VIDEO_INFO_X,
VIDEO_INFO_Y +
(i + y_off) *
VIDEO_FONT_HEIGHT,
(uchar *) info, space);
y_off++;
video_drawchars(VIDEO_INFO_X +
VIDEO_FONT_WIDTH,
VIDEO_INFO_Y +
(i + y_off) *
VIDEO_FONT_HEIGHT,
(uchar *) info + space,
len - space);
} else {
video_drawstring(VIDEO_INFO_X,
VIDEO_INFO_Y +
(i + y_off) *
VIDEO_FONT_HEIGHT,
(uchar *) info);
}
}
}
#endif

return (video_fb_address + video_logo_height * VIDEO_LINE_LEN);
}
#endif


@1:画图:logo_plot 整体思路就是将对应的logo变化成16进制的数组,这里对应的数组是bmp_logo_palette,那么如何将图转变成数组好接下来讲具体步骤:

#ifdef CONFIG_VIDEO_LOGO
void logo_plot(void *screen, int width, int x, int y)
{

int xcount, i;
int skip = (width - VIDEO_LOGO_WIDTH) * VIDEO_PIXEL_SIZE;
int ycount = video_logo_height;
unsigned char r, g, b, *logo_red, *logo_blue, *logo_green;
unsigned char *source;
unsigned char *dest = (unsigned char *) screen +
((y * width * VIDEO_PIXEL_SIZE) + x * VIDEO_PIXEL_SIZE);
printf("carl_wang->logo_plot\n");
#ifdef CONFIG_VIDEO_BMP_LOGO
source = bmp_logo_bitmap;

/* Allocate temporary space for computing colormap */
logo_red = malloc(BMP_LOGO_COLORS);
logo_green = malloc(BMP_LOGO_COLORS);
logo_blue = malloc(BMP_LOGO_COLORS);
/* Compute color map */
for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4;
logo_green[i] = (bmp_logo_palette[i] & 0x00f0);
logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4;
}
#else
source = linux_logo;
logo_red = linux_logo_red;
logo_green = linux_logo_green;
logo_blue = linux_logo_blue;
#endif

if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
video_set_lut(i + VIDEO_LOGO_LUT_OFFSET,
logo_red[i], logo_green[i],
logo_blue[i]);
}
}

while (ycount--) {
#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
int xpos = x;
#endif
xcount = VIDEO_LOGO_WIDTH;
while (xcount--) {
r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET];
g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET];
b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET];

switch (VIDEO_DATA_FORMAT) {
case GDF__8BIT_INDEX:
*dest = *source;
break;
case GDF__8BIT_332RGB:
*dest = ((r >> 5) << 5) |
((g >> 5) << 2) |
(b >> 6);
break;
case GDF_15BIT_555RGB:
#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
fill_555rgb_pswap(dest, xpos++, r, g, b);
#else
*(unsigned short *) dest =
SWAP16((unsigned short) (
((r >> 3) << 10) |
((g >> 3) <<  5) |
(b >> 3)));
#endif
break;
case GDF_16BIT_565RGB:
*(unsigned short *) dest =
SWAP16((unsigned short) (
((r >> 3) << 11) |
((g >> 2) <<  5) |
(b >> 3)));
break;
case GDF_32BIT_X888RGB:
*(unsigned long *) dest =
SWAP32((unsigned long) (
(r << 16) |
(g <<  8) |
b));
break;
case GDF_24BIT_888RGB:
#ifdef VIDEO_FB_LITTLE_ENDIAN
dest[0] = b;
dest[1] = g;
dest[2] = r;
#else
dest[0] = r;
dest[1] = g;
dest[2] = b;
#endif
break;
}
source++;
dest += VIDEO_PIXEL_SIZE;
}
dest += skip;
}
#ifdef CONFIG_VIDEO_BMP_LOGO
free(logo_red);
free(logo_green);
free(logo_blue);
#endif
}
@1:在tools/logos下面有放置一张.jpg的图,然后webee提供了一个脚本可以将.jpg转为.bmp.好公布脚本

#!/bin/sh
#install Netpbm first
jpegtopnm $1 | ppmquant 31 | ppmtobmp -bpp 8 > $2


@2:转成bmp图之后将其拷贝到tools下,然后有一个bmp_logo的可执行文件,其对应的代码是bmp_logo.c,对应的指令是./bmp_logo ./logos/webee210.bmp > 1.txt,其生成的数组就在1.txt中了,将其全部替换写入Bmp_logo.h (include)

@3ok,大功告成,看看你的图片修改成功没。

@4 其实我还是遇到了一些不顺心的事就是我的图片很大,但是显示的时候发现照片数据显示不完整,所以百度了一番,发现是bmp_logo.c的问题,uboot是轻量化的启动,支持较小图片的显示,不过我还是找到了,可以参照http://blog.csdn.net/lutao614/article/details/17507951中说的,进行修改,但是我的图片好像是实在太大了,虽然可以显示全了,但是发现图片有移位的现象,像是生成的bmp数组越界之后重新来过了。这个我就不再考虑了。假如哪天显示全了我再重新写个博客。

@5最后返回了新的framebuf的地址

返回到drv_video_init的函数中,此时又新建了一个console_dev的实例化设备并将其填入到devs的链表中,同时初始化对应的函数指针。

/* Init vga device */
memset(&console_dev, 0, sizeof(console_dev));
strcpy(console_dev.name, "vga");
console_dev.ext = DEV_EXT_VIDEO;	/* Video extensions */
console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
console_dev.putc = video_putc;	/* 'putc' function */
console_dev.puts = video_puts;	/* 'puts' function */
console_dev.tstc = NULL;	/* 'tstc' function */
console_dev.getc = NULL;	/* 'getc' function */

#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
/* Also init console device */
console_dev.flags |= DEV_FLAGS_INPUT;
console_dev.tstc = VIDEO_TSTC_FCT;	/* 'tstc' function */
console_dev.getc = VIDEO_GETC_FCT;	/* 'getc' function */
#endif /* CONFIG_VGA_AS_SINGLE_DEVICE */

if (stdio_register(&console_dev) != 0)
return 0;

/* Return success */
return 1;


好往下:

drv_system_init ();
其实没有干什么,将一个叫做serial的dev放入到devs的链表中,并将其指针初始化

static void drv_system_init (void)
{
struct stdio_dev dev;

memset (&dev, 0, sizeof (dev));

strcpy (dev.name, "serial");
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
dev.putc = serial_putc;
dev.puts = serial_puts;
dev.getc = serial_getc;
dev.tstc = serial_tstc;
stdio_register (&dev);

#ifdef CONFIG_SYS_DEVICE_NULLDEV                      //未定义
memset (&dev, 0, sizeof (dev));

strcpy (dev.name, "nulldev");
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
dev.putc = nulldev_putc;
dev.puts = nulldev_puts;
dev.getc = nulldev_input;
dev.tstc = nulldev_input;

stdio_register (&dev);
#endif
}


serial_stdio_init ();  
这个函数实际上是将之前注册在serial_devices链表中的串口设备全部注册在了devs的链表中了。

void serial_stdio_init (void)
{
struct stdio_dev dev;
struct serial_device *s = serial_devices;

while (s) {
memset (&dev, 0, sizeof (dev));

strcpy (dev.name, s->name);
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;

dev.start = s->init;
dev.stop = s->uninit;
dev.putc = s->putc;
dev.puts = s->puts;
dev.getc = s->getc;
dev.tstc = s->tstc;

stdio_register (&dev);

s = s->next;
}
}


好 stdio_init(); 已经结束了

回到Board.c (arch\arm\lib)

jumptable_init();

申请空间并初始化了一部分的常用函数额跳转表

void jumptable_init(void)
{
gd->jt = malloc(XF_MAX * sizeof(void *));
#include <_exports.h>
}


_exports.h

EXPORT_FUNC(get_version)
EXPORT_FUNC(getc)
EXPORT_FUNC(tstc)
EXPORT_FUNC(putc)
EXPORT_FUNC(puts)
EXPORT_FUNC(printf)
EXPORT_FUNC(install_hdlr)
EXPORT_FUNC(free_hdlr)
EXPORT_FUNC(malloc)
EXPORT_FUNC(free)
EXPORT_FUNC(udelay)
EXPORT_FUNC(get_timer)
EXPORT_FUNC(vprintf)
EXPORT_FUNC(do_reset)
EXPORT_FUNC(getenv)
EXPORT_FUNC(setenv)
EXPORT_FUNC(simple_strtoul)
EXPORT_FUNC(strict_strtoul)
EXPORT_FUNC(simple_strtol)
EXPORT_FUNC(strcmp)
EXPORT_FUNC(i2c_write)
EXPORT_FUNC(i2c_read)
EXPORT_FUNC(spi_init)
EXPORT_FUNC(spi_setup_slave)
EXPORT_FUNC(spi_free_slave)
EXPORT_FUNC(spi_claim_bus)
EXPORT_FUNC(spi_release_bus)
EXPORT_FUNC(spi_xfer)


console_init_r 其实是将stdin,stdout,stderr 的函数重定向了,重定向到了名为serial 的设备上。

int console_init_r(void)
{
char *stdinname, *stdoutname, *stderrname;
struct stdio_dev *inputdev = NULL, *outputdev = NULL, *errdev = NULL;
#ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE
int i;
#endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */
#ifdef CONFIG_CONSOLE_MUX
int iomux_err = 0;
#endif

/* set default handlers at first */
gd->jt[XF_getc] = serial_getc;
gd->jt[XF_tstc] = serial_tstc;
gd->jt[XF_putc] = serial_putc;
gd->jt[XF_puts] = serial_puts;
gd->jt[XF_printf] = serial_printf;

/* stdin stdout and stderr are in environment */
/* scan for it */
stdinname  = getenv("stdin");
stdoutname = getenv("stdout");
stderrname = getenv("stderr");

if (OVERWRITE_CONSOLE == 0) {	/* if not overwritten by config switch */
inputdev  = search_device(DEV_FLAGS_INPUT,  stdinname);
outputdev = search_device(DEV_FLAGS_OUTPUT, stdoutname);
errdev    = search_device(DEV_FLAGS_OUTPUT, stderrname);
#ifdef CONFIG_CONSOLE_MUX
iomux_err = iomux_doenv(stdin, stdinname);
iomux_err += iomux_doenv(stdout, stdoutname);
iomux_err += iomux_doenv(stderr, stderrname);
if (!iomux_err)
/* Successful, so skip all the code below. */
goto done;
#endif
}
/* if the devices are overwritten or not found, use default device */
if (inputdev == NULL) {
inputdev  = search_device(DEV_FLAGS_INPUT,  "serial");
}
if (outputdev == NULL) {
outputdev = search_device(DEV_FLAGS_OUTPUT, "serial");
}
if (errdev == NULL) {
errdev    = search_device(DEV_FLAGS_OUTPUT, "serial");
}
/* Initializes output console first */
if (outputdev != NULL) {
/* need to set a console if not done above. */
console_doenv(stdout, outputdev);
}
if (errdev != NULL) {
/* need to set a console if not done above. */
console_doenv(stderr, errdev);
}
if (inputdev != NULL) {
/* need to set a console if not done above. */
console_doenv(stdin, inputdev);
}

#ifdef CONFIG_CONSOLE_MUX
done:
#endif

gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */

stdio_print_current_devices();

#ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE                 //未定义<span style="white-space:pre">	</span>
/* set the environment variables (will overwrite previous env settings) */
for (i = 0; i < 3; i++) {
setenv(stdio_names[i], stdio_devices[i]->name);
}
#endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */

#if 0
/* If nothing usable installed, use only the initial console */
if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
return 0;
#endif
return 0;
}
@1:首先从env中获取stdin,stdout,stderr 的环境变量,但我找了半天没找到,但是全局搜索了一遍,发现有野生的。在webee21.h中定义的,哈哈,stdin,stderr是在serial上的,但是呢stdout是vga上的

#ifdef DEBUG_CFB_CONSOLE_LCD
#define DEBUG_CFB_CONSOLE
#define CONFIG_EXTRA_ENV_SETTINGS     \
"stdin=serial\0"      \
"stdout=vga\0"       \
"stderr=serial\0"	    \
""
#define VIDEO_LOGO_X 180
#define VIDEO_LOGO_Y  18
#else
#define VIDEO_LOGO_X 180
#define VIDEO_LOGO_Y  120
#endif
@2:当找到对应的名称后,会调用console_doenv将以下的重新赋值

  gd->jt[XF_getc] = serial_getc;
gd->jt[XF_tstc] = serial_tstc;
gd->jt[XF_putc] = serial_putc;
gd->jt[XF_puts] = serial_puts;
gd->jt[XF_printf] = serial_printf;
@3:可以看到从这个函数之后,所有的log信息都打印在了LCD上了。

往下了:

/* Perform network card initialisation if necessary */
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)        //未定义
/* XXX: this needs to be moved to board init */
if (getenv("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
smc_set_mac_addr(enetaddr);
}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */

/* Initialize from environment */
s = getenv("loadaddr");
if (s != NULL)
load_addr = simple_strtoul(s, NULL, 16);
#if defined(CONFIG_CMD_NET)                         //未定义
s = getenv("bootfile");
if (s != NULL)
copy_filename(BootFile, s, sizeof(BootFile));
#endif

#ifdef BOARD_LATE_INIT                         
board_late_init();                           //暂时不知道什么意思
#endif

#ifdef CONFIG_BITBANGMII
bb_miiphy_init();
#endif
#if defined(CONFIG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
puts("Net:   ");
#endif
eth_initialize(gd->bd);
puts("\n ");
puts("\n");
#if defined(CONFIG_RESET_PHY_R)                  //未定义
debug("Reset Ethernet PHY\n");
reset_phy();
#endif
#endif

#ifdef CONFIG_POST                       //未定义
post_run(NULL, POST_RAM | post_bootmode_get(0));
#endif
@1:获取env中的loadaddr,虽然env中有定义,但是呢config不惯用,所以直接跳过了。

@2:board_late_init();这两个幻数搞的我有点蒙圈了,希望有人指点

int board_late_init (void)
{
uint *magic = (uint*)(PHYS_SDRAM_1);
char boot_cmd[100];

if ((0x24564236 == magic[0]) && (0x20764316 == magic[1])) {
printf("carl_Wang haha\n");
sprintf(boot_cmd, "nand erase 0 40000;nand write %08x 0 40000", PHYS_SDRAM_1 + 0x8000);
magic[0] = 0;
magic[1] = 0;
printf("\nready for self-burning U-Boot image\n\n");
setenv("bootdelay", "0");
setenv("bootcmd", boot_cmd);
}

return 0;
}
@3:接下来就是网络的初始化

int eth_initialize(bd_t *bis)
{
int eth_number = 0;

eth_devices = NULL;
eth_current = NULL;

show_boot_progress (64);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
miiphy_init();
#endif

#ifdef CONFIG_PHYLIB
phy_init();
#endif

/*
* If board-specific initialization exists, call it.
* If not, call a CPU-specific one
*/
if (board_eth_init != __def_eth_init) {
if (board_eth_init(bis) < 0)
printf("Board Net Initialization Failed\n");
} else if (cpu_eth_init != __def_eth_init) {
if (cpu_eth_init(bis) < 0)
printf("CPU Net Initialization Failed\n");
} else
printf("Net Initialization Skipped\n");

#if defined(CONFIG_DB64360) || defined(CONFIG_CPCI750)
mv6436x_eth_initialize(bis);
#endif
#if defined(CONFIG_DB64460) || defined(CONFIG_P3Mx)
mv6446x_eth_initialize(bis);
#endif
if (!eth_devices) {
puts ("No ethernet found.\n");
show_boot_progress (-64);
} else {
struct eth_device *dev = eth_devices;
char *ethprime = getenv ("ethprime");

show_boot_progress (65);
do {
if (eth_number)
puts (", ");

printf("%s", dev->name);

if (ethprime && strcmp (dev->name, ethprime) == 0) {
eth_current = dev;
puts (" [PRIME]");
}

if (strchr(dev->name, ' '))
puts("\nWarning: eth device name has a space!\n");
//printf("eth_number = %d\n",eth_number);
/***Modified by lk ***/
if (eth_write_hwaddr(dev, "eth", eth_number))
puts("Warning: failed to set MAC address\n");

eth_number++;
dev = dev->next;
} while(dev != eth_devices);

eth_current_changed();
putc ('\n');
}

return eth_number;
}
网络这方面不是太清楚,这段略过了,但是基本可以肯定的是关于网络芯片基本移植和修改的地方就在此地。

接着往下:

#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)                //未定义
/*
* Export available size of memory for Linux,
* taking into account the protected RAM at top of memory
*/
{
ulong pram;
uchar memsz[32];
#ifdef CONFIG_PRAM                                //未定义
char *s;

s = getenv("pram");
if (s != NULL)
pram = simple_strtoul(s, NULL, 10);
else
pram = CONFIG_PRAM;
#else
pram = 0;
#endif
#ifdef CONFIG_LOGBUFFER
#ifndef CONFIG_ALT_LB_ADDR
/* Also take the logbuffer into account (pram is in kB) */
pram += (LOGBUFF_LEN + LOGBUFF_OVERHEAD) / 1024;
#endif
#endif
sprintf((char *)memsz, "%ldk", (gd->ram_size / 1024) - pram);
setenv("mem", (char *)memsz);
}
#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 */
}
main_loop 同时倒计时并等待用户输入

void main_loop (void)
{
#ifndef CONFIG_SYS_HUSH_PARSER                     //有定义,所以不跑
static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
int len;
int rc = 1;
int flag;
#endif

#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)       //有定义启动延时
char *s;
int bootdelay;
#endif
#ifdef CONFIG_PREBOOT                        //未定义
char *p;
#endif
#ifdef CONFIG_BOOTCOUNT_LIMIT                   //未定义
unsigned long bootcount = 0;
unsigned long bootlimit = 0;
char *bcs;
char bcs_set[16];
#endif /* CONFIG_BOOTCOUNT_LIMIT */

#ifdef CONFIG_BOOTCOUNT_LIMIT                 //未定义
bootcount = bootcount_load();
bootcount++;
bootcount_store (bootcount);
sprintf (bcs_set, "%lu", bootcount);
setenv ("bootcount", bcs_set);
bcs = getenv ("bootlimit");
bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
#endif /* CONFIG_BOOTCOUNT_LIMIT */

#ifdef CONFIG_MODEM_SUPPORT                 .//未定义
debug ("DEBUG: main_loop:   do_mdm_init=%d\n", do_mdm_init);
if (do_mdm_init) {
char *str = strdup(getenv("mdm_cmd"));
setenv ("preboot", str);  /* set or delete definition */
if (str != NULL)
free (str);
mdm_init(); /* wait for modem connection */
}
#endif  /* CONFIG_MODEM_SUPPORT */

#ifdef CONFIG_VERSION_VARIABLE               //未定义
{
setenv ("ver", version_string);  /* set version variable */
}
#endif /* CONFIG_VERSION_VARIABLE */

#ifdef CONFIG_SYS_HUSH_PARSER
u_boot_hush_start ();
#endif

#if defined(CONFIG_HUSH_INIT_VAR)            //未定义
hush_init_var ();
#endif

#ifdef CONFIG_PREBOOT                 //未定义
if ((p = getenv ("preboot")) != NULL) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1);	/* disable Control C checking */
# endif

# ifndef CONFIG_SYS_HUSH_PARSER
run_command (p, 0);
# else
parse_string_outer(p, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif

# ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev);	/* restore Control C checking */
# endif
}
#endif /* CONFIG_PREBOOT */            

#if defined(CONFIG_UPDATE_TFTP)          //未定义
update_tftp (0UL);
#endif /* CONFIG_UPDATE_TFTP */

#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
s = getenv ("bootdelay");
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;   //<span style="font-family: Arial, Helvetica, sans-serif;">bootdelay = </span><span style="font-family: Arial, Helvetica, sans-serif;">CONFIG_BOOTDELAY = 5</span><span style="font-family: Arial, Helvetica, sans-serif;">
</span>

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

# ifdef CONFIG_BOOT_RETRY_TIME         //未定义
init_cmd_timeout ();
# endif	/* CONFIG_BOOT_RETRY_TIME */

#ifdef CONFIG_POST                                               //未定义
if (gd->flags & GD_FLG_POSTFAIL) {
s = getenv("failbootcmd");
}
else
#endif /* CONFIG_POST */
#ifdef CONFIG_BOOTCOUNT_LIMIT         <span style="font-family: Arial, Helvetica, sans-serif;">//未定义</span>

if (bootlimit && (bootcount > bootlimit)) {
printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
(unsigned)bootlimit);
s = getenv ("altbootcmd");
}
else
#endif /* CONFIG_BOOTCOUNT_LIMIT */
s = getenv ("bootcmd");                                  //@2

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

if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
board_video_reset();
# ifdef CONFIG_AUTOBOOT_KEYED                               //未定义
int prev = disable_ctrlc(1);	/* disable Control C checking */
# endif

# ifndef CONFIG_SYS_HUSH_PARSER
run_command (s, 0);
# else
printf("carl_wang->%s\n",s);
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif

# ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev);	/* restore Control C checking */
# endif
}
printf("carl_wang->%d\n",bootdelay);

//run_command("sound",0);
run_command("menu",0);
# ifdef CONFIG_MENUKEY
if (menukey == CONFIG_MENUKEY) {
s = getenv("menucmd");
if (s) {
# ifndef CONFIG_SYS_HUSH_PARSER
run_command(s, 0);
# else
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif
}
}
#endif /* CONFIG_MENUKEY */
#endif /* CONFIG_BOOTDELAY */

/*
* Main Loop for Monitor Command Processing
*/
#ifdef CONFIG_SYS_HUSH_PARSER
parse_file_outer();
/* This point is never reached */
for (;;);
board_video_reset();
#else
for (;;) {
#ifdef CONFIG_BOOT_RETRY_TIME
if (rc >= 0) {
/* Saw enough of a valid command to
* restart the timeout.
*/
reset_cmd_timeout();
}
#endif
len = readline (CONFIG_SYS_PROMPT);

flag = 0;	/* assume no special flags for now */
if (len > 0)
strcpy (lastcommand, console_buffer);
else if (len == 0)
flag |= CMD_FLAG_REPEAT;
#ifdef CONFIG_BOOT_RETRY_TIME
else if (len == -2) {
/* -2 means timed out, retry autoboot
*/
puts ("\nTimed out waiting for command\n");
# ifdef CONFIG_RESET_TO_RETRY
/* Reinit board to run initialization code again */
do_reset (NULL, 0, 0, NULL);
# else
return;		/* retry autoboot */
# endif
}
#endif

if (len == -1)
puts ("<INTERRUPT>\n");
else
rc = run_command (lastcommand, flag);

if (rc <= 0) {
/* invalid command or not repeatable, forget it */
lastcommand[0] = 0;
}
}
#endif /*CONFIG_SYS_HUSH_PARSER*/
}


@1:u_boot_hush_start 初始化了一个top_vars全局变量。

int u_boot_hush_start(void)
{
if (top_vars == NULL) {
top_vars = malloc(sizeof(struct variables));
top_vars->name = "HUSH_VERSION";
top_vars->value = "0.01";
top_vars->next = 0;
top_vars->flg_export = 0;
top_vars->flg_read_only = 1;
#ifdef CONFIG_NEEDS_MANUAL_RELOC
u_boot_hush_reloc();
#endif
}
return 0;
}


@2:从env中读取bootcmd,发现有定义的,"bootcmd=" CONFIG_BOOTCOMMAND
"nand read 0x30007fc0 0x100000 0x500000;bootm 0x30007fc0\0"

s = getenv ("bootcmd");                              @2

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

if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
board_video_reset();


那么真正的是在abortboot (bootdelay)做文章。

static inline int abortboot(int bootdelay)
{
int abort = 0;

#ifdef CONFIG_MENUPROMPT
printf(CONFIG_MENUPROMPT);
#else
printf("Hit any key to stop autoboot: %2d ", bootdelay);
#endif

#ifdef CONFIG_UBOOT_KEY

//run_command("drawstring 280 330 hit-S1-to-burn-*.img..........",0);
udelay(10000);
udelay(10000);
udelay(10000);

if(0 == check_key(0))
{
abort =1 ;
}

#endif

#if defined CONFIG_ZERO_BOOTDELAY_CHECK
/*
* Check if key already pressed
* Don't check if bootdelay < 0
*/
if (bootdelay >= 0) {
if (tstc()) {	/* we got a key press	*/
(void) getc();  /* consume input	*/
puts ("\b\b\b 0");
abort = 1;	/* don't auto boot	*/
}
}
#endif

while ((bootdelay > 0) && (!abort)) {
int i;

--bootdelay;
/* delay 100 * 10ms */

#ifdef CONFIG_UBOOT_KEY

if(0 == check_key(0))
{
abort =1 ;
}
#endif

for (i=0; !abort && i<100; ++i) {
if (tstc()) {	/* we got a key press	*/
abort  = 1;	/* don't auto boot	*/
bootdelay = 0;	/* no more delay	*/
#ifdef CONFIG_MENUKEY
menukey = getc();
#else
(void) getc();  /* consume input	*/
# endif
break;
}
udelay(10000);
}

printf("\b\b\b%2d ", bootdelay);
}

putc('\n');

#ifdef CONFIG_SILENT_CONSOLE
if (abort)
gd->flags &= ~GD_FLG_SILENT;
#endif

return abort;
}
# endif	/* CONFIG_AUTOBOOT_KEYED */
#endif	/* CONFIG_BOOTDELAY >= 0  */


首先延时了30ms,然后检测是否有键按下,有的话 abort=1;或者30ms之后是否有终端有消息有的话,abort = 1;然后跳入while循环,wihle循环中一直检测是否有串口数据。有的话直接跳出后返回abort=1;没有的话是abort = 0;

有两种情况:

1.倒计时完成仍然没有数据:将s的启动指令传递到parse_string_outer,指令是 nand read 0x30007fc0 0x100000 0x500000;bootm 0x30007fc0,

parse_string_outer(s, FLAG_PARSE_SEMICOLON |

FLAG_EXIT_FROM_LOOP);

这个其实会传递执行两个命令,一个是将linux 的镜像读取到0x30007fc0,然后从0x30007fc0启动,其中要讲一下关于bootm的命令会干一件事情将我们之前的gd参数打包并传递到linux内核,内核完成解析。

int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
ulong		iflag;
ulong		load_end = 0;
int		ret;
boot_os_fn	*boot_fn;
#ifdef CONFIG_NEEDS_MANUAL_RELOC
static int relocated = 0;

/* relocate boot function table */
if (!relocated) {
int i;
for (i = 0; i < ARRAY_SIZE(boot_os); i++)
if (boot_os[i] != NULL)
boot_os[i] += gd->reloc_off;
relocated = 1;
}
#endif

/* determine if we have a sub command */
if (argc > 1) {
char *endp;

simple_strtoul(argv[1], &endp, 16);
/* endp pointing to NULL means that argv[1] was just a
* valid number, pass it along to the normal bootm processing
*
* If endp is ':' or '#' assume a FIT identifier so pass
* along for normal processing.
*
* Right now we assume the first arg should never be '-'
*/
if ((*endp != 0) && (*endp != ':') && (*endp != '#'))
return do_bootm_subcommand(cmdtp, flag, argc, argv);
}

if (bootm_start(cmdtp, flag, argc, argv))
return 1;

/*
* We have reached the point of no return: we are going to
* overwrite all exception vector code, so we cannot easily
* recover from any failures any more...
*/
iflag = disable_interrupts();

#if defined(CONFIG_CMD_USB)
/*
* turn off USB to prevent the host controller from writing to the
* SDRAM while Linux is booting. This could happen (at least for OHCI
* controller), because the HCCA (Host Controller Communication Area)
* lies within the SDRAM and the host controller writes continously to
* this area (as busmaster!). The HccaFrameNumber is for example
* updated every 1 ms within the HCCA structure in SDRAM! For more
* details see the OpenHCI specification.
*/
usb_stop();
#endif

ret = bootm_load_os(images.os, &load_end, 1);

if (ret < 0) {
if (ret == BOOTM_ERR_RESET)
do_reset (cmdtp, flag, argc, argv);
if (ret == BOOTM_ERR_OVERLAP) {
if (images.legacy_hdr_valid) {
if (image_get_type (&images.legacy_hdr_os_copy) == IH_TYPE_MULTI)
puts ("WARNING: legacy format multi component "
"image overwritten\n");
} else {
puts ("ERROR: new format image overwritten - "
"must RESET the board to recover\n");
show_boot_progress (-113);
do_reset (cmdtp, flag, argc, argv);
}
}
if (ret == BOOTM_ERR_UNIMPLEMENTED) {
if (iflag)
enable_interrupts();
show_boot_progress (-7);
return 1;
}
}

lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load));

if (images.os.type == IH_TYPE_STANDALONE) {
if (iflag)
enable_interrupts();
/* This may return when 'autostart' is 'no' */
bootm_start_standalone(iflag, argc, argv);
return 0;
}

show_boot_progress (8);

#ifdef CONFIG_SILENT_CONSOLE
if (images.os.os == IH_OS_LINUX)
fixup_silent_linux();
#endif

boot_fn = boot_os[images.os.os];

if (boot_fn == NULL) {
if (iflag)
enable_interrupts();
printf ("ERROR: booting os '%s' (%d) is not supported\n",
genimg_get_os_name(images.os.os), images.os.os);
show_boot_progress (-8);
return 1;
}

arch_preboot_os();

boot_fn(0, argc, argv, &images);

show_boot_progress (-9);
#ifdef DEBUG
puts ("\n## Control returned to monitor - resetting...\n");
#endif
do_reset (cmdtp, flag, argc, argv);

return 1;
}


因为要启动linux,所以最后调用的是do_bootm_linux。

int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
{
bd_t	*bd = gd->bd;
char	*s;
int	machid = bd->bi_arch_number;
void	(*kernel_entry)(int zero, int arch, uint params);

#ifdef CONFIG_CMDLINE_TAG
char *commandline = getenv ("bootargs");
#endif

if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;

s = getenv ("machid");
if (s) {
machid = simple_strtoul (s, NULL, 16);
printf ("Using machid 0x%x from environment\n", machid);
}

show_boot_progress (15);

#ifdef CONFIG_OF_LIBFDT
if (images->ft_len)
return bootm_linux_fdt(machid, images);
#endif

kernel_entry = (void (*)(int, int, uint))images->ep;

debug ("## Transferring control to Linux (at address %08lx) ...\n",
(ulong) kernel_entry);

#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
defined (CONFIG_CMDLINE_TAG) || \
defined (CONFIG_INITRD_TAG) || \
defined (CONFIG_SERIAL_TAG) || \
defined (CONFIG_REVISION_TAG)
setup_start_tag (bd);
#ifdef CONFIG_SERIAL_TAG
setup_serial_tag (¶ms);
#endif
#ifdef CONFIG_REVISION_TAG
setup_revision_tag (¶ms);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGS
setup_memory_tags (bd);
#endif
#ifdef CONFIG_CMDLINE_TAG
setup_commandline_tag (bd, commandline);
#endif
#ifdef CONFIG_INITRD_TAG
if (images->rd_start && images->rd_end)
setup_initrd_tag (bd, images->rd_start, images->rd_end);
#endif
setup_end_tag(bd);
#endif

announce_and_cleanup();

kernel_entry(0, machid, bd->bi_boot_params);
/* does not return */

return 1;
}
下面是网峰写的《》

当 内 核 启 动 时 , 启 动 参 数 一 般 是 从 Bootloader 中 传 递 而 来 的 。 那 么
Bootloader 传递参数的存放地址和参数的数据结构就都是需要关心的。
由于 Bootloader 和内核不是同时启动运行的,因此 Bootloader 要向内核传
递参数只有将参数存放在一个指定的地址,然后内核再从这个地址中读取启动参
数。
在 U-Boot 中,传递参数的数据结构是以标记的形式来体现的。而参数的传
递通过标记列表的形式来实现。标记列表由 ATAG_CORE 开始,以 ATAG_NONE
标记结束。这里的 ATAG_CORE,ATAG_NONE 是各个参数的标记,本身是一
个 32 位值。标记的数据结构为 tag,它由一个 tag_header 结构体和一个联合体
组成。tag_header 结构体表示标记的长度和类型,比如是表示内存还是命令行
参数。对于不同类型的标记使用不同的联合体。对于 tag 和 tag_header 的定义
可以在网蜂提供的 U-Boot 的源码中 arch/arm/include/asm/setup.h 文件中找到,
即:
struct tag
{
struct tag_header hdr;
union {
struct tag_core
core;
struct tag_mem32
mem;
struct tag_videotext
videotext;
struct tag_ramdisk
ramdisk;
struct tag_initrd
initrd;
struct tag_serialnr
serialnr;
struct tag_revision
revision;
struct tag_videolfb
videolfb;
struct tag_cmdline
cmdline;
struct tag_acorn
acorn;
struct tag_memclk
memclk;
} u;
177};
除 了 ATAG_CORE 和 ATAG_NONE 之外,其他的参数标记 还包括:
ATAG_MEM,ATAG_COMDLINE 和 ATAG_INITRD2 等。每个参数标记就代表
一个参数结构体,由各个参数结构体构成了标记列表。
在网蜂提供的 U-Boot 的源码中 arch/arm/lib/bootm.c 文件中有以下代码,说
明参数是如何传递的。
static void setup_start_tag (bd_t *bd)
{
/* 参数存放地址 */
params = (struct tag *) bd->bi_boot_params;
/* 标记 ATAG_CORE 开始 */
params->hdr.tag = ATAG_CORE;
params->hdr.size = tag_size (tag_core);
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
/* 使 params 指向下一个标记 */
params = tag_next (params);
}
static void setup_memory_tags (bd_t *bd)
{
int i;
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
/* 设置内存标记 */
params->hdr.tag = ATAG_MEM;
params->hdr.size = tag_size (tag_mem32);
/* 设置内存起始地址 */
params->u.mem.start = bd->bi_dram[i].start;
/* 设置内存大小 */
params->u.mem.size = bd->bi_dram[i].size;
/* 使 params 指向下一个标记 */
params = tag_next (params);
}
}
static void setup_end_tag (bd_t *bd)
{
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
}
/* 标记 ATAG_NONE 结束 */
1
当设置好这些参数之后呢,会进入OS,kernel_entry(0, machid, bd->bi_boot_params);就是OS的入口地址,然后就永远不会来了。
kernel_entry(0, machid, bd->bi_boot_params);


2:倒计时中间有终端数据回来,执行menu的cmd 

run_command("menu",0);

这就是一个简单的cmd的实现,具体实现我摘抄了网峰上的部分东西。

一、 制作 hello 命令

1. 创建 U-Boot 目录下的 common 目录中的 cmd_hello.c 文件,用命令:

vim common/cmd_hello.c

2. 在 cmd_hello.c 中添加下图内容,然后保存:

249#include <common.h>

#include <command.h>

#include <image.h>

#include <u-boot/zlib.h>

#include <bzlib.h>

#include <environment.h>

#include <lmb.h>

#include <linux/ctype.h>

#include <asm/byteorder.h>

#include <linux/compiler.h>

int do_hello(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])

{

printf("\nHello world\n\n");

}

U_BOOT_CMD(hello, 4, 1, do_hello,

"test:hello",

"test:hello"

);

上面 U_BOOT_CMD 其实是一个宏,它在 include/command.h 头文件中被定义:

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) /

cmd_tbl_t __u_boot_cmd_##name Struct_Section =

{#name, maxargs, rep, cmd, usage, help

}

U_BOOT_CMD 中有四个参数:

name  命令的名字。

maxargs 命令执行函数中的最大参数个数。

rep   重复数。

cmd   命令执行函数名字。

usage命令用法信息。

help命令帮助信息。

也就是当我们在 U-Boot 中输入 hello,U-Boot 就会执行 do_hello 函数。

3. 打开 common 目录下的 Makefile 文件,用命令:

vim common/Makefile

4. 在 common/Makefile 文件中添加以下一行:

COBJS-y += cmd_hello.o

/* 在第 29 行添加 */

这样就能在编译 U-Boot 时,把 cmd_hello.c 编译成 cmd_hello.o,再链接到

最终生成的 bin 文件中。

5. 编译,用命令:

make webee210_config

make

把生成的 webee210-uboot.bin 烧到 SD 卡上(参考使用手册的烧写说明),然

后插到开发板,从 SD 方式启动开发板,在 U-Boot 上输入 help 命令:

可以看到,hello 命令已经存在。

好了,uboot的整体大概流程分析已经步入尾声了,还是有很多地方不懂,但是起码懂得流程后就知道哪儿有问题,到哪里去找,然后一头扎进去,借助log,应该很快就能找到原因。

不忘初心,方得始终。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: