Uboot启动流程(一)
Uboot启动流程简要概括
Uboot可以看作是一个比较复杂的综合裸机程序,学习之余对其启动流程进行一个简要的概括,理清自己的思路。
详细内容参考STM32MP1嵌入式Linux驱动开发指南
Uboot程序入口 _start
根据链接脚本 u-boot.lds找到代码入口:_start
该函数定义在:arch/arm/lib/vectors.S
开始是中断向量表,然后跳转到reset函数
reset函数概要
定义在arch/arm/cpu/armv7/start.S
分别调用函数:
- save_boot_params
该函数中又调用了save_boot_params_ret函数,设置处理器进入SVC模式,关闭 FIQ 和 IRQ这两个中断,向量表重定位。 - cpu_init_cp15
用来设置CP15 相关的内容,比如关闭MMU - cpu_init_crit
其中只是调用了lowlevel_init函数。 - _main
下面详解
_main函数
该函数定义在文件 arch/arm/lib/crt0.S 中
首先设置sp指针指向0XC0100000
调用board_init_f_alloc_reserve预留出早期malloc区和gd内存区
初始化(清零)gd指针
调用board_init_f , 该函数定义在common/board_f.c中,主要完成外设初始化和uboot重定位
调用relocate_code函数进行uboot重定位
调用relocate_vectors对中断向量表重定位
调用函数 c_runtime_cpu_setup, board_init_f并没有初始化所有的外设,还需要做一些后续工作,这 些后续工作就是由函数 board_init_r 来完成的
board_init_f函数概要
函数定义在文件 common/board_f.c
该函数中重点:通过函数 initcall_run_list 来运行初始化序列 init_sequence_f里面的一些 列函数,init_sequence_f 里面包含了一系列的初始化函数
/* 初始化序列函数数组 */
static init_fnc_t init_sequence_f[] = {setup_mon_len, /* 设置gd的mon_len成员,表示uboot代码的长度 */initf_malloc, /* 初始化gd中与malloc相关的成员 */initf_console_record,/* 初始化arm架构相关的东西 */arch_cpu_init, /* basic arch cpu dependent setup */initf_dm, /* 初始化驱动模型相关 */arch_cpu_init_dm,mark_bootstage, /* need timer, go after init dm */
#if defined(CONFIG_BOARD_EARLY_INIT_F)board_early_init_f, /* 与板子的早期外设初始化,imx6ul用来初始化串口 */
#endif#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || \defined(CONFIG_BLACKFIN) || defined(CONFIG_NDS32) || \defined(CONFIG_SPARC)timer_init, /* initialize timer */ /* 初始化Cortex-A7中的定时器 */
#endif#if defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K)get_clocks, /* 获取时钟值 */
#endif/* 和环境变量有关,设置gd的env_addr成员 */env_init, /* initialize environment */ init_baud_rate, /* initialze baudrate settings */ /* 初始化串口波特率 */serial_init, /* serial communications setup */ /* 初始化串口 */console_init_f, /* stage 1 init of console */ /* 设置console标志位 */display_options, /* say that we are here */ /* 显示uboot版本和编译时间字符串 */display_text_info, /* show debugging info if required *//* 显示cpu的相关信息 */print_cpuinfo, /* display cpu info (and speed) */ #if defined(CONFIG_DISPLAY_BOARDINFO)show_board_info, /* 显示board的相关信息 */
#endifINIT_FUNC_WATCHDOG_INITINIT_FUNC_WATCHDOG_RESET#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)init_func_i2c, /* 初始化i2c接口(实际初始化的是SPD_BUS) */
#endif#if defined(CONFIG_HARD_SPI)init_func_spi, /* i.mx6ul并没有初始化SPI接口 */
#endifannounce_dram_init, /* 输出"DRAM:"字符串 */
#if defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_NDS32) || \defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32)dram_init, /* configure available RAM banks */ /* 获取DDR的大小 */
#endif/** Now that we have DRAM mapped and working, we can* relocate the code and continue running from DRAM.** Reserve memory at end of RAM for (top down in that order):* - area that won't get touched by U-Boot and Linux (optional)* - kernel log buffer* - protected RAM* - LCD framebuffer* - monitor code* - board info struct*/setup_dest_addr,/* 设置目的地址(gd->ram_size,gd->ram_top,gd->relocaddr) */reserve_round_4k, /* 对gd->relocaddr做4K对齐 */#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && \defined(CONFIG_ARM)reserve_mmu, /* 留出mmu的TLB表位置 */
#endifreserve_trace, /* 留出ddr调试追踪的内存 */
#if !defined(CONFIG_BLACKFIN)reserve_uboot, /* 留出重定位uboot占用的位置 */
#endif
#ifndef CONFIG_SPL_BUILDreserve_malloc, /* 留出malloc的内存位置和ENV的内存大小 */reserve_board, /* 留出bd所占用的内存大小(80字节) */
#endifsetup_machine, reserve_global_data, /* 留出gd_t结构的内存大小(248字节) */reserve_fdt, /* 留出设备树的内存大小 */reserve_arch, /* 空函数 */reserve_stacks, /* 留出栈空间(16字节)并做16字节对齐 */setup_dram_config, /* 设置DRAM的信息 */show_dram_config, /* 显示DRAM的位置 */display_new_sp, /* 显示新的sp位置 */INIT_FUNC_WATCHDOG_RESETreloc_fdt, /* 重定位fdt(没有用) */setup_reloc, /* 设置gd结构体的一些其他成员 */NULL,
};
代码段参考链接:https://www.cnblogs.com/Cqlismy/p/12006287.html
最终内存分配图如下:
relocate_code 函数概要
relocate_code 函数是用于代码拷贝的,此函数定义在文件 arch/arm/lib/relocate.S 中
ENTRY(relocate_code)ldr r1, =__image_copy_start /* r1 <- SRC &__image_copy_start */ //r1保存源image开始地址 __image_copy_start=0XC0100000.//r0 = gd->relocaddr,r4 = r0-r1 = 0XF5C46000 - 0XC0100000 = 0X35B46000, r4保存的是偏移量subs r4, r0, r1 /* r4 <- relocation offset */ //r4 = gd->reloc_off,保存偏移地址beq relocate_done /* skip relocation */ //如果r0和r1相等,则不需要uboot重定位ldr r2, =__image_copy_end /* r2 <- SRC &__image_copy_end */ //r2保存源image结束地址, __image_copy_end = 0XC01ACD98.copy_loop:ldmia r1!, {r10-r11} /* copy from source address [r1] */ //拷贝uboot代码到r10和r1, 拷贝结束后更新r1.stmia r0!, {r10-r11} /* copy to target address [r0] */ //将uboot代码写到目的地址, 结束后更新r0.cmp r1, r2 /* until source end address [r2] */ //判断uboot是否拷贝完成blo copy_loop //循环拷贝/** fix .rel.dyn relocations //修复(重定位).rel.dyn段*/ldr r2, =__rel_dyn_start /* r2 <- SRC &__rel_dyn_start */ldr r3, =__rel_dyn_end /* r3 <- SRC &__rel_dyn_end */
fixloop:ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup) */and r1, r1, #0xffcmp r1, #23 /* relative fixup? */bne fixnext/* relative fix: increase location by offset */add r0, r0, r4ldr r1, [r0]add r1, r1, r4str r1, [r0]
fixnext:cmp r2, r3blo fixlooprelocate_done:ENDPROC(relocate_code)
参考链接:https://www.cnblogs.com/Cqlismy/p/12152400.html
编译链接 uboot 的时候会使用到 “-pie”选项,使用“-pie”选项以后会生成一个.rel.dyn 段,uboot 就是靠这个.rel.dyn 来解决重定位问题。
relocate_vectors 函数概要
函数 relocate_vectors 用于重定位向量表,此函数定义在文件 relocate.S 中
board_init_r 函数
board_init_r 函数定义在文件 common/board_r.c 中
board_init_f 并没有初始化所有的外设,还需要做一些后续工作,这 些后续工作就是由函数 board_init_r 来完成的
程序中调用 initcall_run_list 函数来执行初始化序列 init_sequence_r
init_fnc_t init_sequence_r[] = {initr_trace, /* 初始化buffer跟踪相关 */initr_reloc, /* 标记重定位完成 */#ifdef CONFIG_ARMinitr_caches, /* 使能caches */
#endifinitr_reloc_global_data, /* 初始化gd的一些成员变量 */initr_barrier,initr_malloc, /* 初始化malloc区域 */initr_console_record, /* 初始化控制台相关内容 */bootstage_relocate, /* 启动状态重定位 */initr_bootstage, /* 初始化bootstage */#if defined(CONFIG_ARM) || defined(CONFIG_NDS32)board_init, /* Setup chipselects */
#endifstdio_init_tables, /* stdio相关初始化 */initr_serial, /* serial接口初始化 */initr_announce,INIT_FUNC_WATCHDOG_RESETpower_init_board,#ifndef CONFIG_SYS_NO_FLASHinitr_flash,
#endifINIT_FUNC_WATCHDOG_RESET#ifdef CONFIG_CMD_NANDinitr_nand, /* 初始化nand flash */
#endif#ifdef CONFIG_GENERIC_MMC initr_mmc, #endifinitr_env, /* 环境变量初始化 */INIT_FUNC_WATCHDOG_RESETinitr_secondary_cpu,stdio_add_devices,initr_jumptable,console_init_r, /* fully init console as a device */interrupt_init,#if defined(CONFIG_ARM) || defined(CONFIG_AVR32)initr_enable_interrupts,
#endif#ifdef CONFIG_CMD_NETinitr_ethaddr, /* 获取mac地址 */
#endif#ifdef CONFIG_BOARD_LATE_INITboard_late_init, /* 板子后期外设初始化 */
#endif#ifdef CONFIG_CMD_NETINIT_FUNC_WATCHDOG_RESETinitr_net, /* 初始化板子的网络设备 */
#endifrun_main_loop,
};
初始化完成后进入run_main_loop函数,该函数为处理命令的主循环。
Uboot启动流程(一)相关推荐
- uboot流程——uboot启动流程
[uboot] (第五章)uboot流程--uboot启动流程 2016年11月07日 20:12:07 阅读数:2230 以下例子都以project X项目tiny210(s5pv210平台,arm ...
- U-Boot启动流程详解
参考:U-Boot顶层目录链接脚本文件(u-boot.lds)介绍 作者:一只青木呀 发布时间: 2020-10-23 13:52:23 网址:https://blog.csdn.net/weixin ...
- linux uboot启动流程分析,uboot启动流程分析
uboot版本为NXP维护的2016.03版本 下载地址为http://git.freescale.com/git/... 分析uboot的启动流程,需要编译一下uboot,然后打开链接脚本 u-bo ...
- Exynos4412 Uboot 移植(二)—— Uboot 启动流程分析
uboot启动流程分析如下: 第一阶段: a -- 设置cpu工作模式为SVC模式 b -- 关闭中断,mmu,cache v -- 关看门狗 d -- 初始化内存,串口 e -- 设置栈 f -- ...
- Uboot 启动流程分析
uboot启动流程 复位CPU 设置异常向量表 设置cpu为SVC模式 但是从U-Boot方面考虑,其要做的事情是初始化系统的相关硬件资源,因此需要获取尽量多的权限,以方便操作硬件,初始化硬件. 关闭 ...
- uboot启动流程详细分析(基于i.m6ull)
uboot介绍 uboot就是一段引导程序,在加载系统内核之前,完成硬件初始化,内存映射,为后续内核的引导提供一个良好的环境.uboot是bootloader的一种,全称为universal boot ...
- uboot启动流程详解
要分析boot启动流程,首先要找到程序入口地址,可以通过编译uboot生成u-boot.lds,通过查看链接脚本u-boot.lds知道入口点是 arch/arm/lib/vectors.S 文件中的 ...
- 基于IMX6Q的uboot启动流程分析(3):_main函数之relocate_code与board_init_r
基于IMX6Q的uboot启动流程分析(1):uboot入口函数 基于IMX6Q的uboot启动流程分析(2):_main函数之board_init_f 基于IMX6Q的uboot启动流程分析(3): ...
- u-boot启动流程分析
u-boot启动流程分析 以smdk2410为例,分析u-boot的启动流程.u-boot的启动流程是指从cpu上电开机执行u-boot到u-boot成功加载完操作系统的过程.这一过程可以分为两个阶段 ...
- U-boot启动流程
目录 uboot启动流程如下: 1.首先查看arch/arm/cpu/u-boot.lds链接脚本 2. _start位于arch/arm/cpu/arm920t/start.S 3. 从上面看到, ...
最新文章
- 他们拿走腾讯百万奖金,我有点泪目
- Java 14 :NullPointerException的处理新方式
- 第二章 第三节 创建第一个程序
- 数据挖掘导论读书笔记1
- 2017年本博客知识体系引导(更新至2017.8.11)
- 《软件工程课程总结》
- Python使用matplotlib画图,设置曲线颜色、类型及标记
- ashx 跨域_ASP.NET通用HTTP处理程序(ashx的),支持JSONP
- 大话数据结构05: 双向链表
- java综合项目推荐,推荐20个5月最热门的Java开源项目
- 第二十八期:Java线程池的四种用法与使用场景
- http 302错误_http面试题
- 创新品牌体验团队_如何推动软件团队创新
- 软件关闭excel但是进程中还存在原因_从软件视角看波音737事故系列述评之一:软件普适化下的能力建设...
- 【ROS学习笔记】(五)话题消息的定义与使用
- 节约里程法—单配送中心CVRP求解
- 基于HTML5的电子病历编辑方法及系统与流程
- 征途服务器修改,征途【改版教程】-装备程序的修改-转载于-喜欢玩网游单机站...
- C#生成word的几种方式。过程及问题记录。
- Creo二次开发 Creo4.0 Qt5 动态部署发布
热门文章
- 程序员是怎么挑选礼物的?对直男说不!
- [附源码]Java计算机毕业设计SSM大学生二手物品交易网站
- 声卡硬件架构 ICH-HDA-CODEC
- 用c++写文本(.txt)文件编辑器
- Python实现数据的线性拟合
- rust木炭有用吗_半个月使用rust语言的体验
- 对流matlab程序,方腔内自然对流MATLAB程序数值传热学.pdf
- c语言:编程找出1000之内的所有完数。
- 京东Q2财报表现亮眼,无界零售为核心驱动力
- k8s的nodeport端口范围provided port is not in the valid range. The range of valid ports is 30000-32767 解决