Bootloader移植下

1. u-boot的启动分析

{//-----------------------------启动步骤(重点)-----------------------------
 1. 上电启动bootloader
	//阶段一(汇编)
    设置为SVC模式,关闭中断,MMU,看门狗	//准备
    硬件基本初始化	//初始化时钟,串口,flash,内存  见cpu/xxxx/start.S的 cpu_init_crit
    自搬移到内存	//copy_uboot_to_arm 或relocate
    设置好栈		//stack_setup
    跳转到二阶段代码入口	//ldr pc,_start_armboot
	//阶段二(C语言)
    大部分硬件初始化	//lib_arm/board.c/start_armboot->init_sequence
    搬移内核到内存	//common/main.c main_loop->getenv("bootcmd") bootdelay>= 0 && s && !abortboot(bootdelay)下的run_command(bootcmd)
    传递内核启动参数(parmer_struct 或taglist)
 2. 加载内核
    a. 自解压内核  decompess   //arch/arm/boot/compressed/head.S
    b. 运行内核汇编部分 head.S 入口stext  //arch/arm/kernel/head.S
        检测合法性(CPU 类型,机器类型)
    c. 运行内核C部分  start_kernel  //init/main.c
        CPU,机器参数的安装   setup_arch
        中断,定时,终端,内存等最基本的初始化
        创建核心进程 kernel_init运行,启动多任务调度,原父进程空转cpu_ide 
 3. 挂载rootfs    (mount_root)      
 4. 运行应用程序  //第一个应用程序是init  (由u-boot的bootargs里的init=/linuxrc来指定)  
    a. 运行启动脚本  (run_init_process("/etc/init.d/rcS"))  //由init来解析脚本执行
    b. 其它应用程序 	 //一般添加在脚本的最后(如在rcS末尾加 ./app)
}	

2. cortex A9 exynos4412 源代码分析

  1. 第一条指令位置
{//---u-boot.lds  或 u-boot.map    指明了第一条指令位置
	arch/arm/cpu/armv7/start.o     
}   

  1. u-boot的启动入口
{//---arch/arm/cpu/armv7/start.S    u-boot的启动入口
_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	
	
reset:
	/*
	 * set the cpu to SVC32 mode
	 */
	mrs	r0, cpsr
	bic	r0, r0, #0x1f
	orr	r0, r0, #0xd3
	msr	cpsr,r0	
	
	bl	cpu_init_cp15   //关闭中断 cache MMU等
	bl	cpu_init_crit

	bl	_main	         //跳到C部分  位置  arch/arm/lib/board.c   ( 在u-boot.map里搜索_main) 
		

ENTRY(relocate_code)   //自搬移 重定位   (运行时机见  u-boot.map 里执行位置)
	adr	r0, _start
	cmp	r0, r6
	moveq	r9, #0		/* no relocation. relocation offset(r9) = 0 */
	beq	relocate_done		/* 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		
ENDPROC(relocate_code)		
		
		
ENTRY(cpu_init_cp15)
	/*
	 * Invalidate L1 I/D
	 */
	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

	/*
	 * disable MMU stuff and caches
	 */
	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	pc, lr			@ back to my caller
ENDPROC(cpu_init_cp15)	

	
ENTRY(cpu_init_crit)
	b	lowlevel_init		@ go setup pll,mux,memory   //位置board/samsung/fs4412/libfs4412.o( 在u-boot.map里搜索lowlevel_init) 
ENDPROC(cpu_init_crit)	
	
	
}	  
  1. 基本硬件初始化
{//---board/samsung/fs4412/lowlevel_init.S   基本硬件初始化   (关闭看门狗中断  时钟初始化 串口初始化 nand初始化 dram初始化)
lowlevel_init:      //有些初始化,已被三星剥离到 BLO或BL1	中  
	/* init system clock */
	bl system_clock_init

	/* Memory initialize */
	bl mem_ctrl_asm_init

	/* for UART */
	bl uart_asm_init	
	mov	pc, lr	
}	 
  1. 大部分硬件初始化
{//---arch/arm/lib/board.c   大部分硬件初始化,  调用主循环main_loop(见common/main.c)
	init_fnc_t *init_sequence[] = {
		arch_cpu_init,		/* basic arch cpu dependent setup */
		mark_bootstage,
	#if defined(CONFIG_BOARD_EARLY_INIT_F)
		board_early_init_f,
	#endif
		timer_init,		/* initialize timer */
		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 */
		dram_init,		/* configure available RAM banks */
		NULL,
	};	
		
	
	void board_init_r(gd_t *id, ulong dest_addr)
	{
		board_init();	/* Setup chipselects */
		
		/* main_loop() can return to retry autoboot, if so just run it again. */
		for (;;) {
			main_loop(); //调用主循环main_loop
		}
	}	
	
	void board_init(ulong bootflag)
	{
		for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {  //大部分硬件初始化
			if ((*init_fnc_ptr)() != 0) {
				hang ();
			}
		}
	}
	
	
	
}
  1. bootdelay延迟 等待用户选择u-boot模式
{//5.common/main.c   //主循环main_loop 实现 bootdelay延时时间到之前无输入,则加载bootcmd进入自启动模式;如果有输入则进入交互模式
  void main_loop (void)
	{
	
		s = getenv ("bootdelay");   //获取env环境变量中的 bootdelay 参数
		bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
	
	  s = getenv ("bootcmd");  //获取自启动命令如 bootcmd = tftp 20008000 zImage ; go zImage 表示从网络加载内核运行
	
	
	  if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
        run_command (s, 0);            //如果延时大于等于零,并且没有在延时过程中接收到按键,则运行bootcmd命令,引导内核。进入自启动模式
    }
	
	 //否则进入交互模式 
		/*
		 * Main Loop for Monitor Command Processing
		 */
		for (;;) {
				len = readline (CONFIG_SYS_PROMPT);      //读取命令
		
				rc = run_command (lastcommand, flag);    //运行命令

		}
  }	
}  
   
}	

u-boot的移植方法

一般厂商 或者 方案提供商都会给出demo,比如4412参考的就是origen这个demo,模仿着写即可。

  1. beyond对比工具使用
    将要比较的两个版本的u-boot文件分别打开,点击ctrl+A 全选,然后点右键,选择比较,按2进制方式。然后点确定即可。


    文件/文件夹 的颜色:灰色 无任何改动,红色 有修改 ,紫色 有新增。

  2. 选择官方源码版本下载, 配置编译
    a. 指定交叉编译工具链
    b. 指定cpu 和board(参考最类似配置如origen)
    c. 编译

  3. 实现串口信息输出
    a. 跟踪运行路径(led点灯法)
    b. 串口输出(检查uart初始化相关部分代码 见lowlevel_init.s)

  4. 网卡移植(实现能用tftp nfs 方便开发调试)
    a. 寄存器地址
    b. 参数设置

  5. FLASH移植(实现能下载软件到FLASH,产品能离线运行)