tiny4412 uboot 2018移植(二)分析uboot代码框架

简介

uboot代码分为两部分 uboot-spl和uboot,uboot-spl为上一节所说的BL2。使用三星提供的工具,可以把uboot-spl.bin转化成BL2。
tiny4412 uboot 2018移植(二)分析uboot代码框架_第1张图片

uboot-spl

通过编译uboot-2018我们可以产生uboot-spl镜像,由于BL1会负责把BL2拷贝到0x02023400处,所以需要定义uboot-spl的链接地址为0x02023400

#define CONFIG_SPL_TEXT_BASE	0x02023400

下面是spl部分的简要流程

1.vectors.S (arch/arm/lib)
.macro  ARM_VECTORS    //macro  用来定义一段宏,可以类比成c语言的内联函数
b    reset
ldr    pc, _undefined_instruction
....
.endm	//结束宏
_start:   //最开始执行的地方
    ARM_VECTORS    //跳到定义处,在定义处可以看出 是b reset
2.start.S (arch/arm/cpu/armv7)
reset:
    b    save_boot_params
	/*
	 * 如果不是处于HYP模式,则失能FIQ和IRQ,设置cpu为SVC32模式
	 * ARM的主要工作模式
	 * 处理器工作模式 说明
	 * 	用户模式(usr) ARM处理器正常的程序执行状态
	 * 	系统模式(sys) 运行具有特权的操作系统任务
	 * 	快中断模式(fiq) 支持高速数据传输或通道处理
	 * 	管理模式(svc) 操作系统保护模式
	 * 	数据访问终止模式(abt) 用于虚拟存储器及存储器保护
	 * 	中断模式(irq) 用于通用的中断处理
	 * 	用户模式和系统模式之外的5种模式称为异常模式
	 */
	mrs	r0, cpsr		// mrs:把程序状态寄寄存器的数据传输到通用寄存器中
	and	r1, r0, #0x1f		@ mask mode bits
	teq	r1, #0x1a		@ test for HYP mode
	bicne	r0, r0, #0x1f		@ clear all mode // bits bic=bic+ne=if teq not equal,excute bic
	orrne	r0, r0, #0x13		@ set SVC mode
	orr	r0, r0, #0xc0		@ disable FIQ and IRQ
	msr	cpsr,r0		// msr:把通用寄存器的数据传输到程序状态寄存器中
	
	bl	cpu_init_cp15  ----->
	----> ENTRY(cpu_init_cp15)
				/*
				 * 失能 L1 I/D
				 * Cache
				 *   1) Cache 是位于 CPU与主存储器DRAM之间一个模块,为了解决cpu和内存之间的速度匹配问题
				 *        Cache又分为I-cache(用来存指令)和D-cache(用来存数据)
				 *        为什么要让Cache失效?
				 *   2)我们在使用cache的时候要经过一系列的配置,在没配置之前是不能使用的。所以我们要关闭cache,但是在关闭
				 *       cache之前cache里面可能已经有数据了,为了不影响我们 的代码,所以要先让其失效,在进行关闭
				 */
				mov	r0, #0			@ set up for MCR
				mcr	p15, 0, r0, c8, c7, 0	@ invalidate TLBs
				mcr	p15, 0, r0, c7, c5, 0	@ invalidate icache
				mcr	p15, 0, r0, c7, c5, 6	@ invalidate BP array
				mcr     p15, 0, r0, c7, c10, 4	@ DSB
				mcr     p15, 0, r0, c7, c5, 4	@ ISB
				/*
				 * 关闭mmu 
				 * 关闭mmu后cpu发出来的内存地址不会被mmu捕获,相当于直通内存地址到设备,
				 * 这样我们可以直接定义物理地址,比如定义uboot的加载地址:
				 * 		CONFIG_SYS_TEXT_BASE=0x43e00000
				 * 0x43e00000处于外部ram的地址范围内
				 * 外部ram的地址空间为0x4000_0000 到 0xA000_0000
				 */
				mrc	p15, 0, r0, c1, c0, 0
				bic	r0, r0, #0x00002000	@ clear bits 13 (--V-)
				bic	r0, r0, #0x00000007	@ clear bits 2:0 (-CAM)
				......
				mcr	p15, 0, r0, c1, c0, 0
				mov	r5, lr			@ Store my Caller //前面的bl指令在跳转的时候会保存地址到链接寄存器lr
				mov	pc, r5			@ back to my caller //赋值给pc寄存器,这样下一条指令就会跳回去调用处了
			ENDPROC(cpu_init_cp15)
		<------
	#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY 
	/*
	 * arm-linux-objdump -S u-boot-spl > u-boot-spl.S 查看反汇编代码
	 * 没有看到有bl cpu_init_crit相关的机器码,说明这个宏定义定义了,不会执行cpu_init_crit
	 * ldr	r0, =_start
	 * 2023470:	e59f006c 	ldr	r0, [pc, #108]	; 20234e4 
	 * mcr	p15, 0, r0, c12, c0, 0	@Set VBAR
	 * 2023474:	ee0c0f10 	mcr	15, 0, r0, cr12, cr0, {0}
	 * #ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
	 * bl	cpu_init_crit
	 * #endif
	 * #endif
	 * bl	_main
	 * 2023478:	eb000528 	bl	2024920 <_main>
	 */
	bl	cpu_init_crit 
	#endif
    bl    _main
3.crt0.S (arch/arm/lib)
ENTRY(_main)
    ldr	r0, =(CONFIG_SYS_INIT_SP_ADDR)   //等于0x2040000
    bic	r0, r0, #7	//8字节对其
    mov	sp, r0		//保存到栈指针寄存器sp 下面可以使用c语言了
    bl    board_init_f    //跳到spl_boot.c d的void board_init_f(unsigned long bootflag)
4.spl_boot.c (arch/arm/mach-exynos)
void board_init_f(unsigned long bootflag){
	do_lowlevel_init() --->
	---->   ......
			system_clock_init();  //配置时钟树
			debug_uart_init();  //设置窗口
				_debug_uart_init(); \
					s5p_serial_init(uart);
						/* enable FIFOs, auto clear Rx FIFO */
						writel(0x3, &uart->ufcon);
						writel(0, &uart->umcon);
						/* 8N1 */
						writel(0x3, &uart->ulcon);
						/* No interrupts, no DMA, pure polling */
						writel(0x245, &uart->ucon);
    copy_uboot_to_ram();---->
    ---->   .....
    		copy_bl2_from_emmc = get_irom_func(EMMC44_INDEX);//获取三星固话的拷贝函数,不开源的直接使用就行
    		//这里把uboot归为bl2了,命名不用管它。
    		//#define CONFIG_SYS_TEXT_BASE 0x43E00000
            copy_bl2_from_emmc(0x400, CONFIG_SYS_TEXT_BASE);  //拷贝uboot所在的emmc地址到0x43E00000,大小为0x400 block
    uboot = (void *)CONFIG_SYS_TEXT_BASE;	//运行uboot
    (*uboot)();
}

uboot

通过编译uboot-2018我们可以产生uboot镜像,前面的uboot-spl会把uboot拷贝到指定地址,我这里指定的地址为外部ram的地址0x43e00000

CONFIG_SYS_TEXT_BASE=0x43e00000

上面个的代码(*uboot)();会运行uboot,下面是uboot部分的简要流程。

1.vectors.S (arch/arm/lib)
.macro  ARM_VECTORS    //macro  用来定义一段宏,可以类比成c语言的内联函数
b    reset
ldr    pc, _undefined_instruction
....
.endm
_start:   //最开始执行的地方
    ARM_VECTORS    //跳到定义处,在定义处可以看出 是b reset
2.start.S (arch/arm/cpu/armv7)
reset:
    b    save_boot_params
    .....   @ set SVC mode ...
    bl    _main
3.crt0.S (arch/arm/lib)
ENTRY(_main)
    .....
    bl    board_init_f         //跳到board_f.c的void board_init_f(ulong boot_flags)
#if ! defined(CONFIG_SPL_BUILD)
    ldr    r0, [r9, #GD_START_ADDR_SP]    /* sp = gd->start_addr_sp */    
    bic    r0, r0, #7    /* 8-byte alignment for ABI compliance */
    mov    sp, r0
    ldr    r9, [r9, #GD_BD]        /* r9 = gd->bd */
    sub    r9, r9, #GD_SIZE        /* new GD is below bd */
/* 下面三句代码是 很有意思的,我们来重点分析一下 */
/* adr是个位置无关的加载指令,及无论 here的链接地址是多少,adr加载的都是当前pc + 偏移(adr lr,here到here的偏移)
    然后得到新的规划的uboot和旧的uboot之家的偏移量给r0
    之后把偏移和旧的uboot的here加起来,最终得到新的uboot里面的here的地址,然后放进lr
    等进入下面的relocate_code函数,返回的时候就直接返回到新的uboot的代码段运行了
*/
    adr    lr, here
    ldr    r0, [r9, #GD_RELOC_OFF]        /* r0 = gd->reloc_off看下面的图 */
    add    lr, lr, r0
    ldr    r0, [r9, #GD_RELOCADDR]        /* r0 = gd->relocaddr,给relocate的传参是将要重定位的起始地址 */
    /* 这里会调到relocate_code是重定位代码,然后再return */
    b    relocate_code                /* 注意这里必须使用b跳转,这样返回时才能用前面设置的lr中设置的here地址 */
here:
    ldr    pc, =board_init_r    /* this is auto-relocated! 跳到board_init_r    */ 
4.Board_r.c (common)
//这一部分就是去调用各种各样的初始化函数,网上有很多博客去分析这些代码,这里我就不分析了,具体可以参考文章尾部的参考
void board_init_r(gd_t *new_gd, ulong dest_addr){
	initcall_run_list(init_sequence_r)--->
	----> static init_fnc_t init_sequence_r[] = {
			initr_trace,
			initr_reloc,
			log_init,
			initr_bootstage,
			board_init
			......
		  }
}

下面这张图仅用来参考reloc这个操作(地址不对应本文的地址)。其实从这张图就可以直观的看出重定位代码是做了什么操作,重定位代码就是把uboot搬移到高地址,并且在搬移的过程中要保障搬移后的uboot执行不会出现跳转异常之类的内存错误。
tiny4412 uboot 2018移植(二)分析uboot代码框架_第2张图片
更加具体的流程我就不分析,可以参考这几篇文章,这几篇文章分析的不错,有很大的参考意义:
u-boot v2018.01 启动流程分析.
从零开始之uboot、移植uboot2017.01(五、board_init_f分析).

你可能感兴趣的:(Tiny4412,u-boot,2018,移植)