天天看點

uboot啟動流程webee210啟動第二階段

又重新回到原點了,但是此時運作的環境是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%[email protected]%sMHz\n",
	//		s5p_cpu_id, strmhz(buf, get_arm_clk()));
	
	printf("CPU:\[email protected]%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的配置,如下圖:

uboot啟動流程webee210啟動第二階段

最後還要看一下重要的資料結構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 構成了一個連結清單

uboot啟動流程webee210啟動第二階段

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->[email protected]\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->[email protected]\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

這樣就能在編譯 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,應該很快就能找到原因。

不忘初心,方得始終。