WDS1期第9课 uboot 3 之Makefile, uboot启动第二段

WDS1期第9课 uboot 3 之Makefile, uboot启动第二段_第1张图片

uboot的目标是启动内核,从flash读出内核然后启动。
在start.S中start_armboot开始:

	ldr	pc, _start_armboot
_start_armboot:	.word start_armboot

在lib_arm/board.c中定义:
gd是结构体指针,申请得到部分内存,

void start_armboot (void)
{
	...
	/* Pointer is writable since we allocated a register for it */
	gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
	...
		for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		if ((*init_fnc_ptr)() != 0) {
			hang ();
		}
	}
	...
}

init_sequence是函数指针数组的首地址,在lib_arm/board.c中,其中包含了cpu等初始化函数的指针,

init_fnc_t *init_sequence[] = {
	cpu_init,		/* basic cpu dependent setup */
	board_init,		/* basic board dependent setup */
	interrupt_init,		/* set up exceptions */
	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
	dram_init,		/* configure available RAM banks */
	display_dram_config,
	NULL,
};

看board_init定义,在board/100ask24x0/100ask24x0.c中,设置管脚,gd指向那个128字节的内存,bi_arch_number叫机器id,bi_boot_params启动内核的时候传入的一些参数所存放的位置,

int board_init (void)
{
    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
    S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();


    /* set up the I/O ports */
    gpio->GPACON = 0x007FFFFF;
    gpio->GPBCON = 0x00044555;
    gpio->GPBUP = 0x000007FF;
    gpio->GPCCON = 0xAAAAAAAA;
    gpio->GPCUP = 0x0000FFFF;
    gpio->GPDCON = 0xAAAAAAAA;
    gpio->GPDUP = 0x0000FFFF;
    gpio->GPECON = 0xAAAAAAAA;
    gpio->GPEUP = 0x0000FFFF;
    gpio->GPFCON = 0x000055AA;
    gpio->GPFUP = 0x000000FF;
    gpio->GPGCON = 0xFF95FFBA;
    gpio->GPGUP = 0x0000FFFF;
    gpio->GPHCON = 0x002AFAAA;
    gpio->GPHUP = 0x000007FF;

    /* support both of S3C2410 and S3C2440, by www.100ask.net */
    if (isS3C2410)
    {
        /* arch number of SMDK2410-Board */
        gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
    }
    else
    {
        /* arch number of SMDK2440-Board */
        gd->bd->bi_arch_number = MACH_TYPE_S3C2440;
    }

    /* adress of boot parameters */
    gd->bd->bi_boot_params = 0x30000100;
#if 0
    icache_enable();
    dcache_enable();
#endif
    return 0;
}

既然要从flash中读数据,那么flash一定有读功能的实现,初始化flash

#ifndef CFG_NO_FLASH
	/* configure available FLASH banks */
	size = flash_init ();

以下是对堆的一些初始化 192K空间,实现了堆的分配和释放,

	/* armboot_start is defined in the board-specific linker script */
	mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);

nand_init

#if (CONFIG_COMMANDS & CFG_CMD_NAND)
	puts ("NAND:  ");
	nand_init();		/* go init the NAND */

一些环境变量的初始化,上电后去flash中找有没有环境变量,没有就使用默认的,

	/* initialize environment */
	env_relocate ();

往下网卡,设备,usb,调试,如果用调试器下载PreLoadedONRAM将被置1

	Port_Init();
	if (!PreLoadedONRAM) {
		/* enable exceptions */
		enable_interrupts ();
	    /* add by www.100ask.net */
	    usb_init();
	}

到此只是flash拥有了读写的功能,但是怎么读怎么启动内核还需要分析,这里是死循环,应该是uboot启动打印的那个循环信息,

	/* main_loop() can return to retry autoboot, if so just run it again. */
	for (;;) {
		main_loop ();
	}

在start_armboot中完成了nand nor的初始化。
main_loop在common/main.c中,环境变量通过getenv来获取得到,bootdelay,bootcmd。根据bootcmd run_command启动内核,

#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
	s = getenv ("bootdelay");
	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
	...
		s = getenv ("bootcmd");

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

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

# ifndef CFG_HUSH_PARSER
        {
            printf("Booting Linux ...\n");            
    	    run_command (s, 0);
        }

bootcmd指定了从nand的kernel分区读取到SDRAM,然后从SDRAM启动,
WDS1期第9课 uboot 3 之Makefile, uboot启动第二段_第2张图片在uboot倒计时结束前空格,进入menu,

    eth_init(gd->bd);
    run_command("menu", 0);

在这里readline读取串口交互的输入,根据输入的参数去启动系统run_command,

	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 (CFG_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 ("\n");
		else
			rc = run_command (lastcommand, flag);

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

在start.S中start_armboot开始,start_armboot在lib_arm/board.c中定义。
在start_armboot中,有各种初始化操作init_sequenceboard,其中的某些会调用/100ask24x0/100ask24x0.c的board_init等等。完成一些外设的初始化工作。

到这里uboot运行起来了,一些外设也运行起来了,马上就是串口交互界面,这个交互界面在main_loop函数中实现,main_loop在common/main.c中。
交互界面中主要通过getenv获取flash保存的环境变量,通过readline获取串口的输入,最终都是通过传递参数给run_command来启动内核的。

你可能感兴趣的:(嵌入式Linux)