Uboot启动流程简要概括

Uboot可以看作是一个比较复杂的综合裸机程序,学习之余对其启动流程进行一个简要的概括,理清自己的思路。
详细内容参考STM32MP1嵌入式Linux驱动开发指南

Uboot程序入口 _start

根据链接脚本 u-boot.lds找到代码入口:_start
该函数定义在:arch/arm/lib/vectors.S
开始是中断向量表,然后跳转到reset函数

reset函数概要

定义在arch/arm/cpu/armv7/start.S
分别调用函数:

  1. save_boot_params
    该函数中又调用了save_boot_params_ret函数,设置处理器进入SVC模式,关闭 FIQ 和 IRQ这两个中断,向量表重定位。
  2. cpu_init_cp15
    用来设置CP15 相关的内容,比如关闭MMU
  3. cpu_init_crit
    其中只是调用了lowlevel_init函数。
  4. _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启动流程(一)相关推荐

  1. uboot流程——uboot启动流程

    [uboot] (第五章)uboot流程--uboot启动流程 2016年11月07日 20:12:07 阅读数:2230 以下例子都以project X项目tiny210(s5pv210平台,arm ...

  2. U-Boot启动流程详解

    参考:U-Boot顶层目录链接脚本文件(u-boot.lds)介绍 作者:一只青木呀 发布时间: 2020-10-23 13:52:23 网址:https://blog.csdn.net/weixin ...

  3. linux uboot启动流程分析,uboot启动流程分析

    uboot版本为NXP维护的2016.03版本 下载地址为http://git.freescale.com/git/... 分析uboot的启动流程,需要编译一下uboot,然后打开链接脚本 u-bo ...

  4. Exynos4412 Uboot 移植(二)—— Uboot 启动流程分析

    uboot启动流程分析如下: 第一阶段: a -- 设置cpu工作模式为SVC模式 b -- 关闭中断,mmu,cache v -- 关看门狗 d -- 初始化内存,串口 e -- 设置栈 f -- ...

  5. Uboot 启动流程分析

    uboot启动流程 复位CPU 设置异常向量表 设置cpu为SVC模式 但是从U-Boot方面考虑,其要做的事情是初始化系统的相关硬件资源,因此需要获取尽量多的权限,以方便操作硬件,初始化硬件. 关闭 ...

  6. uboot启动流程详细分析(基于i.m6ull)

    uboot介绍 uboot就是一段引导程序,在加载系统内核之前,完成硬件初始化,内存映射,为后续内核的引导提供一个良好的环境.uboot是bootloader的一种,全称为universal boot ...

  7. uboot启动流程详解

    要分析boot启动流程,首先要找到程序入口地址,可以通过编译uboot生成u-boot.lds,通过查看链接脚本u-boot.lds知道入口点是 arch/arm/lib/vectors.S 文件中的 ...

  8. 基于IMX6Q的uboot启动流程分析(3):_main函数之relocate_code与board_init_r

    基于IMX6Q的uboot启动流程分析(1):uboot入口函数 基于IMX6Q的uboot启动流程分析(2):_main函数之board_init_f 基于IMX6Q的uboot启动流程分析(3): ...

  9. u-boot启动流程分析

    u-boot启动流程分析 以smdk2410为例,分析u-boot的启动流程.u-boot的启动流程是指从cpu上电开机执行u-boot到u-boot成功加载完操作系统的过程.这一过程可以分为两个阶段 ...

  10. U-boot启动流程

    目录 uboot启动流程如下: 1.首先查看arch/arm/cpu/u-boot.lds链接脚本 2. _start位于arch/arm/cpu/arm920t/start.S 3. 从上面看到, ...

最新文章

  1. 他们拿走腾讯百万奖金,我有点泪目
  2. Java 14 :NullPointerException的处理新方式
  3. 第二章 第三节 创建第一个程序
  4. 数据挖掘导论读书笔记1
  5. 2017年本博客知识体系引导(更新至2017.8.11)
  6. 《软件工程课程总结》
  7. Python使用matplotlib画图,设置曲线颜色、类型及标记
  8. ashx 跨域_ASP.NET通用HTTP处理程序(ashx的),支持JSONP
  9. 大话数据结构05: 双向链表
  10. java综合项目推荐,推荐20个5月最热门的Java开源项目
  11. 第二十八期:Java线程池的四种用法与使用场景
  12. http 302错误_http面试题
  13. 创新品牌体验团队_如何推动软件团队创新
  14. 软件关闭excel但是进程中还存在原因_从软件视角看波音737事故系列述评之一:软件普适化下的能力建设...
  15. 【ROS学习笔记】(五)话题消息的定义与使用
  16. 节约里程法—单配送中心CVRP求解
  17. 基于HTML5的电子病历编辑方法及系统与流程
  18. 征途服务器修改,征途【改版教程】-装备程序的修改-转载于-喜欢玩网游单机站...
  19. C#生成word的几种方式。过程及问题记录。
  20. Creo二次开发 Creo4.0 Qt5 动态部署发布

热门文章

  1. 程序员是怎么挑选礼物的?对直男说不!
  2. [附源码]Java计算机毕业设计SSM大学生二手物品交易网站
  3. 声卡硬件架构 ICH-HDA-CODEC
  4. 用c++写文本(.txt)文件编辑器
  5. Python实现数据的线性拟合
  6. rust木炭有用吗_半个月使用rust语言的体验
  7. 对流matlab程序,方腔内自然对流MATLAB程序数值传热学.pdf
  8. c语言:编程找出1000之内的所有完数。
  9. 京东Q2财报表现亮眼,无界零售为核心驱动力
  10. k8s的nodeport端口范围provided port is not in the valid range. The range of valid ports is 30000-32767 解决