第五章——u-boot源码启动流程

u-boot版本2010-12

.globl _start
_start: b	reset
	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq
	/*定义异常向量入口*/

_undefined_instruction: .word undefined_instruction
_software_interrupt:	.word software_interrupt
_prefetch_abort:	.word prefetch_abort
_data_abort:		.word data_abort
_not_used:		.word not_used
_irq:			.word irq
_fiq:			.word fiq
_pad:			.word 0x12345678 /* now 16*4=64 */
.global _end_vect
_end_vect:
	/*.word就是把后面的值赋给:前面*/

	.balignl 16,0xdeadbeef
	
	/*deadbeef是中断的意思,作用大概
	就是为内存做标记,有点儿像个
	小旗子,插在那里,表示从这个
	位置往后,就是干什么的内存,
	这个位置往前,禁止访问*/
	
reset:
	/*
	 * set the cpu to SVC32 mode
	 */
	mrs	r0, cpsr
	bic	r0, r0, #0x1f
	orr	r0, r0, #0xd3
	msr	cpsr,r0
/*设置CPU为SVC32模式*/
	bl	cpu_init_crit
	/*初始化时钟,内存和串口,使能MMU*/

这个函数有必要看一下

	.globl lowlevel_init
lowlevel_init:

	/* use iROM stack in bl2 */
	ldr	sp, =0x02060000
	push	{lr}

	/* check reset status */
	ldr	r0, =(INF_REG_BASE + INF_REG1_OFFSET)
	ldr	r1, [r0]

	/* Sleep wakeup reset */
	ldr	r2, =S5P_CHECK_SLEEP
	cmp	r1, r2
	beq	wakeup_reset

	/* set CP reset to low */
	ldr	r0, =0x11000C60
	ldr	r1, [r0]
	ldr	r2, =0xFFFFFF0F
	and	r1, r1, r2
	orr	r1, r1, #0x10
	str	r1, [r0]
	ldr	r0, =0x11000C68
	ldr	r1, [r0]
	ldr	r2, =0xFFFFFFF3
	and	r1, r1, r2
	orr	r1, r1, #0x4
	str	r1, [r0]
	ldr	r0, =0x11000C64
	ldr	r1, [r0]
	ldr	r2, =0xFFFFFFFD
	and	r1, r1, r2
	str	r1, [r0]

	/* led (GPM4_0~3) on */
	ldr	r0, =0x110002E0
	ldr	r1, =0x00001111
	str	r1, [r0]
	ldr	r1, =0x0e
	str	r1, [r0, #0x04]

	/* During sleep/wakeup or AFTR mode, pmic_init function is not available
	 * and it causes delays. So except for sleep/wakeup and AFTR mode,
	 * the below function is needed
	 */

	bl	read_om

	/* 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, =0xff000fff
	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	after_copy		/* r0 == r1 then skip sdram init and u-boot.bin loading */

一些设置,然后代码是否始终在片内内存中运行,如果是则跳过后面的初始化SDRAM

	/* init system clock */
	bl	system_clock_init

	/* Memory initialize */
	bl	mem_ctrl_asm_init

	/* init uart for debug */
	bl	uart_asm_init
初始化时钟,内存和串口

	bl	tzpc_init

	b	load_uboot
初始化tzpc,加载uboot

我们来看一下如何加载,从哪里加载到哪里?

load_uboot:
	ldr	r0, =INF_REG_BASE
	ldr	r1, [r0, #INF_REG3_OFFSET]
	cmp	r1, #BOOT_NAND
	beq	nand_boot
	cmp	r1, #BOOT_ONENAND
	beq	onenand_boot
	cmp	r1, #BOOT_MMCSD
	beq	mmcsd_boot
	cmp	r1, #BOOT_EMMC
	beq	emmc_boot
	cmp	r1, #BOOT_EMMC_4_4
	beq	emmc_boot_4_4
	cmp	r1, #BOOT_NOR
	beq	nor_boot
	cmp	r1, #BOOT_SEC_DEV
	beq	mmcsd_boot
比较r1中的值,判断是何种启动,,r1中数值是在前面read_om函数中设置的


mmcsd_boot:

	ldr	r0, =ELFIN_CLOCK_BASE
	ldr	r2, =CLK_DIV_FSYS2_OFFSET
	ldr	r1, [r0, r2]
	orr	r1, r1, #0xf
	str	r1, [r0, r2]
	bl	movi_uboot_copy
	b	after_copy

在movi_uboot_copy函数中通过

	SDMMC_ReadBlocks(MOVI_UBOOT_POS, MOVI_UBOOT_BLKCNT, CONFIG_PHY_UBOOT_BASE);
把u-boot从SD卡读到内存

	SDMMC_ReadBlocks(49, 328, 0x43e00000);
从第49块开始读,读328字节,读到0x43e00000

after_copy:

	/* led (GPM4_0~3) on */
	ldr	r0, =0x110002E0
	ldr	r1, =0x0c
	str	r1, [r0, #0x04]

	/* set up C2C */
	ldr	r0, =S5PV310_SYSREG_BASE
	ldr	r2, =GENERAL_CTRL_C2C_OFFSET
	ldr	r1, [r0, r2]
	ldr	r3, =0x4000
	orr	r1, r1, r3
	str	r1, [r0, r2]

	bl	enable_mmu

	/* store second boot information in u-boot C level variable */
	ldr	r0, =CONFIG_PHY_UBOOT_BASE
	sub	r0, r0, #8
	ldr	r1, [r0]
	ldr	r0, _second_boot_info
	str	r1, [r0]

	/* Print 'K' */
	ldr	r0, =S5PV310_UART_CONSOLE_BASE
	ldr	r1, =0x4b4b4b4b
	str	r1, [r0, #UTXH_OFFSET]

	ldr	r0, _board_init_f
	mov	pc, r0

_board_init_f:
	.word board_init_f

_second_boot_info:
	.word second_boot_info

这段代码中使能MMU了,之后的地址都要使用虚拟地址了


call_board_init_f:
	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
	bic	sp, sp, #7 /* 8-byte alignment for ABI compliance */
	ldr	r0,=0x00000000
	bl	board_init_f
/*设置栈进入C函数,board_init_f在arch/arm/lib/borad.c中定义*/

我们进入borad.c看一下board_init_f    函数做了什么


void board_init_f(ulong bootflag)
{
	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);

	/* compiler optimization barrier needed for GCC >= 3.4 */
	__asm__ __volatile__("": : :"memory");

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

	gd->mon_len = _bss_end_ofs;

gd为结构体指针,并为这个结构体分配了空间,用于存一些参数

	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		if ((*init_fnc_ptr)() != 0) {
			hang();
		}
	}
循环调用init_sequence函数指针数组中的函数指针,进行一系列的初始化

	addr = CONFIG_SYS_LOAD_ADDR;

	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;
	debug ("relocation Offset is: %08lx\n", gd->reloc_off);
	memcpy(id, (void *)gd, sizeof (gd_t));

设置重定位信息,又设置了RAM,把gd复制到新地址

函数dram_init_banksize()百度了一下作用

A、 分配SDRAM高64KB为TLB,用于U-BOOT
B、分配SDRAM下一单元为U-BOOT代码段,数据段,BSS段

	relocate_code(addr_sp, id, addr);

返回start.s,并传重定位参数

	.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
	beq	clear_bss		/* skip relocation */
	mov	r1, r6			/* r1 <- scratch for copy_loop */
	ldr	r2, _TEXT_BASE
	ldr	r3, _bss_start_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

重定位代码,如果代码所在地址不是链接地址就要拷贝,


jump_2_ram:
	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

void board_init_r(gd_t *id, ulong dest_addr)
{
	char *s;
	bd_t *bd;
	ulong malloc_start;

	gd = id;
	bd = gd->bd;

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

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

board_init函数是一些关于tiny4412的设置,并且通过判断OmPin的值,知道开发板是何种启动方式并打印

   	OmPin = INF_REG3_REG;
	printf("\n\nChecking Boot Mode ...");
	if (OmPin == BOOT_ONENAND) {
		printf(" OneNand\n");
	} else if (OmPin == BOOT_NAND) {
		printf(" NAND\n");
	} else if (OmPin == BOOT_MMCSD) {
		printf(" SDMMC\n");
	} else if (OmPin == BOOT_EMMC) {
		printf(" EMMC4.3\n");
	} else if (OmPin == BOOT_EMMC_4_4) {
		printf(" EMMC4.41\n");
	}

这和开发板上电的输出Checking Boot Mode ... SDMMC刚好对应上

接着看board_init_r

	/* 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);

实现堆的分配

#if defined(CONFIG_CMD_NAND)
	puts("NAND:\t");
	nand_init();		/* go init the NAND */
#endif

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

#ifdef CONFIG_GENERIC_MMC
	mmc_initialize(bd);
#endif

接着是nand,onenand,mmc的初始化,估计这里面就有对SD卡的操作,以后再去搞明白

	env_relocate();

初始化环境变量

	gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");

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

	jumptable_init();

	 /* set up exceptions */
	interrupt_init();
	/* enable exceptions */
	enable_interrupts();

	 /* set up exceptions */
	interrupt_init();
	/* enable exceptions */
	enable_interrupts();

	eth_initialize(gd->bd);

这又是一大堆初始化,以后再细分析

	for (;;) {
		main_loop();
	}

最后死循环,调用main_loop();

main_loop中

</pre><pre name="code" class="cpp">	s = getenv ("bootdelay");
	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;

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

	init_cmd_timeout ();

	s = getenv ("bootcmd");

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

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

		run_command (s, 0);
		parse_string_outer(s, FLAG_PARSE_SEMICOLON |
				    FLAG_EXIT_FROM_LOOP);

		disable_ctrlc(prev);	/* restore Control C checking */
	}
这段代码实现了倒计时,如果超时执行run_command(s,o);

如果有输入则继续执行下面的语句

	for (;;) {
		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;

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

死循环readline,然后解析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值