Uboot的启动流程--以友善之臂tiny4412开发板为例

2024-06-12 04:08

本文主要是介绍Uboot的启动流程--以友善之臂tiny4412开发板为例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前一段时间看了一遍UBOOT的源码,一直想找个时间写点东西记录一下,可是一直很忙,最近终于可以挤点时间慢慢的开始写吧~

本文是基于友善之臂tiny4412开发板的uboot为例写的心得,uboot版本是2010.12,其他平台和版本类似,用东哥的话说就是:一理通,百理明!


一般我们将UBOOT分为2个阶段,第一阶段主要为汇编代码,用于初始化必要的硬件并将UBOOT copy到SDRAM中并跳转到SDRAM执行,第二阶段主要为c代码,主要作用是加载kernel到SDRAM,准备启动kernel的参数最后跳转到kernel处执行,当然uboot里也可以有许多扩展功能,比如下载功能,实现各种驱动程序等.


第一阶段:

1.首先就是uboot的入口的地址是arch/arm/cpu/armv7/start.S, 这可以从相同路径下的连接脚本u-boot.lds 中知道,如下:

ENTRY(_start)
SECTIONS
{. = 0x00000000;. = ALIGN(4);.text	:{arch/arm/cpu/armv7/start.o	(.text)*(.text)}
关于链接脚本的其他内容,大家可以自行研读,因为uboot代码中会用到连接脚本的东西,所以大概要能看懂,这里不再赘述~


2.下面开始结合代码分析启动流程

一开始就会无条件跳转到reset 处执行:

.globl _start
_start: b	reset //直接跳到reset处执行ldr	pc, _undefined_instruction/* 设置异常向量表 */ldr	pc, _software_interruptldr	pc, _prefetch_abortldr	pc, _data_abortldr	pc, _not_usedldr	pc, _irqldr	pc, _fiq
3.然后找到reset 处,先关中断,进SVC32模式
/** the actual reset code*/reset:/** set the cpu to SVC32 mode*/mrs	r0, cpsrbic	r0, r0, #0x1f //cpsr的低五位被清零orr	r0, r0, #0xd3 //关中断(irq, fiq),并进入SVC32模式 msr	cpsr,r0
4.然后 跳转到cpu_init_crit 处执行

	/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT /** not define **/bl	cpu_init_crit  //跳转到cpu_init_crit,初始化内存,时钟等关键寄存器 ,就在本文件内,在稍后的地方
#endif
5. cpu_init_cri t,主要工作就是对cache,MMU的操作,另一个非常重要的事情就是会调用执行板级初始化的文件,具体看注释吧

/*************************************************************************** CPU_init_critical registers** setup important registers* setup memory timing**************************************************************************/
cpu_init_crit:bl cache_init /** 在本版本中此函数为空函数,什么也不做,直接返回 **///初始化cache,位置在 ./board/samsung/tiny4412/lowlevel_init.S:cache_init:/** Invalidate L1 I/D*/mov	r0, #0			@ set up for MCRmcr	p15, 0, r0, c8, c7, 0	@ invalidate TLBs   /** armv7手册P1374 */ //清页表  //ARM最多可支持16个协处理器p0-p15mcr	p15, 0, r0, c7, c5, 0	@ invalidate icache /** 看注释应该是关指令cache,armv7手册P1730,未定义此处的命令,不知道什么意思,期待大神现身说法,fix me **/ /** disable MMU stuff and cachescp15 c1寄存器的操作在armv7手册p1334*/mrc	p15, 0, r0, c1, c0, 0 /* 读cp15 c1寄存器到r0 */bic	r0, r0, #0x00002000	@ clear bits 13 (--V-) /** 设置异常向量表基地址为0x00000000?<==此地址不是IROM地址码?,记得好像此地址应该设置为0xffff0000,fixme */bic	r0, r0, #0x00000007	@ clear bits 2:0 (-CAM) // 关数据 cache,关 MMUorr	r0, r0, #0x00000002	@ set bit 1 (--A-) Align //strict alignment fault checking enabled.orr	r0, r0, #0x00000800	@ set bit 12 (Z---) BTB//打开指令cachemcr	p15, 0, r0, c1, c0, 0/** Jump to board specific initialization...* The Mask ROM will have already initialized* basic memory. Go here to bump up clock rate and handle* wake up conditions.*/mov	ip, lr			@ persevere link reg across callbl	lowlevel_init		@ go setup pll,mux,memory,/* 进行板级的初始化,主要是时钟,内存,串口,nand等,位置在:/board/samsung/tiny4412/lowlevel_init.S lowlevel_init: */mov	lr, ip			@ restore linkmov	pc, lr			@ back to my caller /* 返回 */
6.下面进入lowlevel_init.S的 lowlevel_init() 进行板级相关的初始化,其位置在/board/samsung/tiny4412/lowlevel_init.S中

这里面先进行的是一些设置:设置栈指针,判断启动方式,点亮一个LED等

.globl lowlevel_init
lowlevel_init:  /***主要对PLL及memory初始化,此函数需要移植来完成 ***//* use iROM stack in bl2 */ldr	sp, =0x02060000 //设置栈指针,Iram的最高地址push	{lr}/* check reset statusINF_REG_BASE的值为0x10020800,为power management info 寄存器的基地址此处INF_REG1_OFFSET的值为4故此处为取INFORM1 寄存器的值此处的意思为判断系统是否为从sleep状态唤醒而来*/ldr	r0, =(INF_REG_BASE + INF_REG1_OFFSET)ldr	r1, [r0]/* Sleep wakeup reset */ldr	r2, =S5P_CHECK_SLEEPcmp	r1, r2beq	wakeup_reset/* set CP reset to low */ldr	r0, =0x11000C60  ldr	r1, [r0]ldr	r2, =0xFFFFFF0Fand	r1, r1, r2orr	r1, r1, #0x10str	r1, [r0]/*** 此处0x11000C60 为寄存器GPX3CON的地址,此处将此寄存器[4:7]置1,即将GPX3DAT_1 设为output */ldr	r0, =0x11000C68ldr	r1, [r0]ldr	r2, =0xFFFFFFF3and	r1, r1, r2orr	r1, r1, #0x4str	r1, [r0]/*** 此处0x11000C68 为寄存器 GPX3PUD的地址,此处将此寄存器[2]置1,即enable GPX3PUD_1 pull_down */ldr	r0, =0x11000C64ldr	r1, [r0]ldr	r2, =0xFFFFFFFDand	r1, r1, r2str	r1, [r0]/*** 此处0x11000C64 为寄存器 GPX3DAT的地址,此处将此寄存器[2]置1,即enable GPX3DAT_1 置0 *//** 经查电路发现,GPX3DAT_1的信号为XEINT25,外部连的是Gsensor MMA7660的中断信号启动系统时为何将此引脚设为GPIO output 并clear to 0?? fixme!!**//* led (GPM4_0~3) on0x110002E0 为寄存器GPM4CON的地址,将GPM4DAT 0~3设为output,GPM4DATA 4~7 设为input最后两句将GPM4DATA0设为0,查看电路图发现就是点亮LED1*/ldr	r0, =0x110002E0ldr	r1, =0x00001111str	r1, [r0]ldr	r1, =0x0estr	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*/
#if defined(CONFIG_HAS_PMIC) /* 未定义此宏,即开发板上没有PMIC,都是分立元件产生的power,tiny4412.h中已显性取消此宏的定义,#undef CONFIG_HAS_PMIC */bl	pmic_init
#endif#if defined(CONFIG_ONENAND) /* 未定义此宏 */bl	onenandcon_init
#endif#if defined(NAND_BOOTING)/* 未定义此宏 */bl	nand_asm_init
#endif
7.下面就会去判断启动的位置,

bl	read_om /** 读取启动设备,在本文件的稍后面 */
这个函数的实现由兴趣的可以看一次下,看这里:

read_om: /** 读取启动设备 **//* Read booting information */ldr	r0, =S5PV310_POWER_BASE /* power management 寄存器的基地址 */ldr	r1, [r0,#OMR_OFFSET] /* 0x0,读 OM_STAT 寄存器的值 */bic	r2, r1, #0xffffffc1 /* 除[1:5] 位外,其他位清零,并存入r2 *//* NAND BOOT */
@	cmp	r2, #0x0		@ 512B 4-cycle
@	moveq	r3, #BOOT_NAND@	cmp	r2, #0x2		@ 2KB 5-cycle
@	moveq	r3, #BOOT_NAND@	cmp	r2, #0x4		@ 4KB 5-cycle	8-bit ECC
@	moveq	r3, #BOOT_NAND/** 真正的决定硬件连接的启动方式有下面的与r2做比较的常数决定,本开发板中的启动选择开关只能选择从EMMC or SD卡启动,而此处EMMC启动的寄存器数字为0x6,SD卡启动为0x4,故启动选择开关只会影响XOM1的值 **/cmp	r2, #0xAmoveq	r3, #BOOT_ONENANDcmp	r2, #0x10		@ 2KB 5-cycle	16-bit ECCmoveq	r3, #BOOT_NAND/* SD/MMC BOOT */cmp	r2, #0x4moveq	r3, #BOOT_MMCSD/* eMMC BOOT */cmp	r2, #0x6moveq	r3, #BOOT_EMMC/* eMMC 4.4 BOOT */cmp	r2, #0x8moveq	r3, #BOOT_EMMC_4_4cmp	r2, #0x28moveq	r3, #BOOT_EMMC_4_4ldr	r0, =INF_REG_BASE str	r3, [r0, #INF_REG3_OFFSET] /** 将读到的启动设备的结果写入INFORM3 寄存器 **/mov	pc, lr /* 返回 */
8.回来接着主程序往下看,下面会判断一下程序是否已经运行在RAM里,显然这是公版uboot里的代码,友善之臂并没有删减掉
/* 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.*//* 此处比较PC与0xc3e00000中间3位的值,如果相等则判断现在已经运行在SDRAM里* 就会跳过SDRAM的初始化,但此时程序还运行在IRAM里,PC的值显然不可能指向SDRAM*/ldr	r0, =0xff000fffbic	r1, pc, r0		/* r0 <- current base addr of code */ldr	r2, _TEXT_BASE	/* r1 <- original base addr in ram ,值为0xc3e00000,在本文件开始处定义 */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 */
9.既然程序还未运行在SDRAM里,那么系统肯定还处于“远古时代”,接着就要进行三个最重要的硬件初始化,

	/* init system clock */bl	system_clock_init  /** 看名字就知道是系统时钟初始化,定义在./board/samsung/tiny4412/clock_init_tiny4412.S **//* Memory initialize */bl	mem_ctrl_asm_init /* 内存初始化,在/board/samsung/tiny4412/mem_init_tiny4412.S *//* init uart for debug */bl	uart_asm_init /* 串口初始化,定义在本文件稍后的地方 */
这三个初始化程序相对过于复杂,本文重点在于理清uboot的启动流程,这里不再赘述,有兴趣的童鞋可以另寻时间study,

10.下面uboot还贴心的给出了一段测试的代码

/* 至此PLL, SDRAM, UART已全部初始化OK, 启动时要用的最基本的硬件已准备就绪 *//** 下面一段代码是对上面硬件初始化的测试,经验证后已OK,表示到此CLK, SDRAM, UART都已初始化OK **/
#if CONFIG_LL_DEBUGmov	r4, #0x4000
.L0:sub	r4, r4, #1cmp	r4, #0	bne	.L0mov	r0, #'\r'bl	uart_asm_putcmov	r0, #'\n'bl	uart_asm_putcldr	r1, =0x40000000 /*内存首地址*/ldr	r2, =0x87654321str	r2, [r1]str	r2, [r1, #0x04]str	r2, [r1, #0x08]ldr	r2, =0x55aaaa55str	r2, [r1, #0x10]nopmov	r4, #0xC0000
.L1:subs	r4, r4, #1bne	.L1ldr	r0, [r1]bl	uart_asm_putxmov	r0, #'.'bl	uart_asm_putcldr	r0, [r1, #0x04]bl	uart_asm_putxmov	r0, #'.'bl	uart_asm_putcldr	r0, [r1, #0x08]bl	uart_asm_putxmov	r0, #'.'bl	uart_asm_putcldr	r0, [r1, #0x10]bl	uart_asm_putxmov	r0, #'>'bl	uart_asm_putc
#endif /* CONFIG_LL_DEBUG */
11.继续走起,trustzone 这东西真心不懂...,之前有一次编译内核没把trustzone disable 掉,启动kernel时会卡住
	bl	tzpc_init /** 初始化trust zone protection controller,定义在本文件稍后位置 **/b	load_uboot /** 将u-boot完整代码copy到内存0x43e00000开始的SDRAM地址上,定义在本文件稍后位置 **/
不过这个load_uboot要看一次下,他就是将uboot完整源码copy到SDRAM的函数, 调试的时候一般从sd卡启动的多,故以SD卡启动为例,

load_uboot:/* 根据启动设备跳转到相应处执行 */ldr	r0, =INF_REG_BASEldr	r1, [r0, #INF_REG3_OFFSET] read_om将判断结果放在寄存器INF_REG3_OFFSETcmp	r1, #BOOT_NANDbeq	nand_bootcmp	r1, #BOOT_ONENANDbeq	onenand_bootcmp	r1, #BOOT_MMCSD /** SD卡启动 **/beq	mmcsd_bootcmp	r1, #BOOT_EMMCbeq	emmc_bootcmp	r1, #BOOT_EMMC_4_4beq	emmc_boot_4_4cmp	r1, #BOOT_NORbeq	nor_bootcmp	r1, #BOOT_SEC_DEVbeq	mmcsd_bootnand_boot:mov	r0, #0x1000bl	copy_uboot_to_ramb	after_copyonenand_boot:bl	onenand_bl2_copy /* goto 0x1010 */b	after_copymmcsd_boot:#ifdef CONFIG_SMDKC220 /** tiny4412.h 中已定义 **/
//#ifdef CONFIG_CLK_BUS_DMC_200_400ldr	r0, =ELFIN_CLOCK_BASE /** CLK寄存器首地址,0x10030000 **/ldr	r2, =CLK_DIV_FSYS2_OFFSET /** Sets clock divider ratio for FSYS_BLK **/ldr	r1, [r0, r2]orr	r1, r1, #0xf  /** DIVMMC2 Clock Divider Ratio DOUTMMC2 = MOUTMMC2/(MMC2_RATIO + 1)设置分频系数为16查看电路图发现SD卡用的即为第2路MMC总线 **/str	r1, [r0, r2]  /* 设置时钟,此处将SCLK_MMC2的时钟设为EPLL/16 */
//#endif
#else
/** 下面几个宏都未设置,不会执行下面的代码 **/
#if defined(CONFIG_CLK_1000_400_200) || defined(CONFIG_CLK_1000_200_200) || defined(CONFIG_CLK_800_400_200)ldr	r0, =ELFIN_CLOCK_BASEldr	r2, =CLK_DIV_FSYS2_OFFSETldr	r1, [r0, r2]orr	r1, r1, #0xfstr	r1, [r0, r2]
#endif
#endifbl	movi_uboot_copy/* 将uboot copy到SDRAM中,定义在arch/arm/cpu/armv7/exynos/Irom_copy.c */b	after_copy

12.下面进movi_uboot_copy看一下,定义在定义在arch/arm/cpu/armv7/exynos/Irom_copy.c中,

void movi_uboot_copy(void)
{
#ifdef CONFIG_RAM_TEST /* 已定义此宏 */uboot_mem_test();/* 测试初始化的CLK, SDRAM, UART */
#endif#ifdef CONFIG_CORTEXA5_ENABLE /* 未定义 */SDMMC_ReadBlocks(MOVI_UBOOT_POS, MOVI_UBOOT_BLKCNT, 0x40000000);
#endif/* 此函数即是将uboot完整程序复制到SDRAM 0x43e0000开始的内存中,此函数实际调用的是放在IRAM 0x02023030处的一个函数指针函数的实现代码是在IROM里,函数的功能为将SD卡中的数据复制到SDRAM中,详见Android_Exynos4412_iROM_Secure_Booting_Guide_Ver.1.00.00 P21三个参数分别为开始块,要copy的块数,copy到内存的起始地址,故此处传入的参数为17,32,0x43e00000此处的内存地址是物理地址,当开启MMU后对应的地址的0XC3E00000, 与uboot的链接地址一致
*/SDMMC_ReadBlocks(MOVI_UBOOT_POS, MOVI_UBOOT_BLKCNT, CONFIG_PHY_UBOOT_BASE);#ifdef CONFIG_SECURE_BOOT /* 未定义 */if (Check_Signature((SB20_CONTEXT *)SECURE_CONTEXT_BASE,(unsigned char*)CONFIG_PHY_UBOOT_BASE, PART_SIZE_UBOOT-256,(unsigned char*)(CONFIG_PHY_UBOOT_BASE+PART_SIZE_UBOOT-256), 256) != 0){while(1);}
#endif
}
13.接下来就是after_copy了,即将进入第二阶段,

after_copy:/* led (GPM4_0~3) on */ldr	r0, =0x110002E0ldr	r1, =0x0cstr	r1, [r0, #0x04] /*LED1~LED2 on*/#ifdef CONFIG_SMDKC220 /*tiny4412.h中已定义*//* set up C2C */ldr	r0, =S5PV310_SYSREG_BASEldr	r2, =GENERAL_CTRL_C2C_OFFSETldr	r1, [r0, r2]ldr	r3, =0x4000orr	r1, r1, r3str	r1, [r0, r2] /*将GENERAL_CTRL_C2C的bit[14]置1,dram_init_done signal for wake up sequence */
#endif#ifdef CONFIG_ENABLE_MMU /*tiny4412中已定义*/bl	enable_mmu /*打开MMU*/
#endif/* store second boot information in u-boot C level variable */ldr	r0, =CONFIG_PHY_UBOOT_BASE /** 0X43E00000 **/sub	r0, r0, #8ldr	r1, [r0]ldr	r0, _second_boot_info  /* 在tiny4412.c里定义的全局变量unsigned int second_boot_info = 0xffffffff */str	r1, [r0]  /* 不知为何意,fix me *//* Print 'K' */ldr	r0, =S5PV310_UART_CONSOLE_BASEldr	r1, =0x4b4b4b4bstr	r1, [r0, #UTXH_OFFSET] /* 打印字符'K',与UART初始化时最后显示的'O'组成UBOOT最开始显示的"OK" */ldr	r0, _board_init_f /* 取函数board_init_f 的地址,该函数在\arch\arm\lib\board.c中实现,主要实现gd全局结构体的填充及SDRAM的空间分配 */mov	pc, r0 /* 跳转到函数board_init_f处执行,从此处开始在SDRAM中执行 *//* uboot第一阶段 结束,将进入第二阶段C代码的执行 */_board_init_f:.word board_init_f_second_boot_info:.word second_boot_info




这篇关于Uboot的启动流程--以友善之臂tiny4412开发板为例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1053154

相关文章

工作流Activiti初体验—流程撤回【二】

已经玩工作流了,打算还是研究一下撤回的功能。但是流程图里面并不带撤回的组件,所以需要自己动态改造一下,还是延续上一个流程继续试验撤回功能。《工作流Activiti初体验【一】》 完整流程图 我们研究一下分发任务撤回到发起任务,其他环节的撤回类似 撤回的原理大概如下: 将分发任务后面的方向清空,把发起任务拼接到原来的判断网关,然后结束分发任务,这样流程就到发起任务了 此时的流程如上图,

ROS话题通信流程自定义数据格式

ROS话题通信流程自定义数据格式 需求流程实现步骤定义msg文件编辑配置文件编译 在 ROS 通信协议中,数据载体是一个较为重要组成部分,ROS 中通过 std_msgs 封装了一些原生的数据类型,比如:String、Int32、Int64、Char、Bool、Empty… 但是,这些数据一般只包含一个 data 字段,结构的单一意味着功能上的局限性,当传输一些复杂的数据,比如:

Docker启动异常

报错信息: failed to start daemon: Error initializing network controller: error creating default "bridge" network: cannot create network b8fd8c684f0ba865d4a13d36e5282fd694bbd37b243c7ec6c9cd29416db98d4b (d

ROS2从入门到精通4-4:局部控制插件开发案例(以PID算法为例)

目录 0 专栏介绍1 控制插件编写模板1.1 构造控制插件类1.2 注册并导出插件1.3 编译与使用插件 2 基于PID的路径跟踪原理3 控制插件开发案例(PID算法)常见问题 0 专栏介绍 本专栏旨在通过对ROS2的系统学习,掌握ROS2底层基本分布式原理,并具有机器人建模和应用ROS2进行实际项目的开发和调试的工程能力。 🚀详情:《ROS2从入门到精通》 1 控制插

完整的申请邓白氏编码的流程(手把手教你申请邓白氏编码

完整的申请邓白氏编码的流程(手把手教你申请邓白氏编码)  标签: 编码邓白氏编码申请流程苹果开发者账号申请 2016-07-08 16:13  2274人阅读  评论(2)  收藏  举报   分类: 技术  苹果开发  邓白氏编码申请 版权声明:本文为博主原创文章,未经博主允许不得转载。     申请公司的苹果开发者账号和企业级的苹

办理河南建筑工程乙级设计资质的流程与要点

办理河南建筑工程乙级设计资质的流程与要点 办理河南建筑工程乙级设计资质的流程与要点主要包括以下几个方面: 流程: 工商注册与资质规划:确保企业具有独立法人资格,完成工商注册,并明确乙级设计资质的具体要求,包括注册资本、人员配置、技术条件等。 专业技术人员配置: 雇佣或签约符合资质要求的专业技术人员,包括但不限于:一级注册结构工程师2名、一级注册建筑师2名、注册暖通工程师1名、注册供配电工

小车启动底盘功能包

传感器与小车底盘的集成 新建功能包 catkin_create_pkg mycar_start roscpp rospy std_msgs ros_arduino_python usb_cam ydlidar_ros_driver 功能包下创建launch文件夹,launch文件夹中新建launch文件,文件名start.launch。 内容如下 <!-- 机器人启动文件:1.启动底盘2

黑龙江等保测评的具体流程是怎样的

黑龙江等保测评的具体流程 黑龙江等保测评是根据《中华人民共和国网络安全法》及相关法律法规,对信息系统安全保护能力进行评估和验证的过程。以下是黑龙江等保测评的具体流程: 系统定级:根据业务、资产、安全技术、安全管理等方面的情况,对企业的安全防护水平进行评估,编制定级报告,为客户提供技术支持,协助客户编制定级报告,并组织相关专家对定级报告进行评估。 系统备案:持定级报告及登记表到当地的公安网监

Eclipse使用git最基本流程

Eclipse使用git最基本流程,eclipsegit流程 git有诸多好处,网上都说的很清楚了,在这里我不再赘述。对于我来说,私下里想做一些项目,而又不能很好的保存自己的代码和进行版本控制,这时候,就用到了git。下面,就以我个人为例讲讲git从0开始如何安装使用。 Step1 准备工作 msysgit,下载地址为http://msysgit.github.io/

Web容器启动时加载Spring分析

在应用程序web.xml中做了以下配置信息时,当启动Web容器时就会自动加载Spring容器。 [java]  view plain copy print ? <listener>          <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>