uboot启动之第一次运行C函数到uboot重定位

2023-05-16

接上一篇博文《uboot启动流程之上电启动到第一次准备好C语言运行环境》,本文从board_init_f()开始。

board_init_f定义在uboot/common/board_f.c中(CONFIG_SYS_GENERIC_BOARD=y)。

这里全局变量gd定义在uboot/arch/arm/include/asm/global_data.h中,在29行间接包含(uboot/include/common.h ->uboot/arch/arm/include/asm/global_data.h):

uboot/common/board_f.c

uboot/include/common.h

这个#include中的asm在uboot编译工程中讲过,是一个软连接,连接到uboot/arch/arm/include/asm/

我们去这个uboot/arch/arm/include/asm/global_data.h中看看全局变量gd的定义:

uboot/arch/arm/include/asm/global_data.h

从定义看,gd是一个全局的寄存器变量,占用的寄存器位r8, gd即r8。

前面分析过,r8存储了的数据为地址(0x80000000+16K – GD_SIZE), 即全局变量gd指向(0x80000000+16K – GD_SIZE)。

在行1020-1022在栈上定义一个gd_t变量,并且让gd指向这个地址。

这里为什么要在栈上定义一个gd_t,然后再让gd指向它?这不是改变了gd的指向了吗?

实际上,并没有改变gd指向,gd还是指向r8保存的栈地址。因为arm使用的是空递减栈,即sp指向的是下一次使用的内存地址。在crt0.S中,我们让sp预留了gd_t的内存,即这个预留出的内存就是这里定义的data局部变量。

1025行设置gd->flags为0(r0寄存器值在C函数board_init_f被调用前清零了)。

1027行通过initcall_run_list循环调用init_sequence_f的函数列表。

uboot/lib/initcall.c

init_sequence_f定义了很多函数list:

uboot/common/board_f.c

zero_global_data:将gd指向的内存清零。

mark_bootstage: 设置bootstage为board_init_f。

env_init: 设置环境变量保存的地址。在uboot/common/Makefile中定义如下:

                 CONFIG_ENV_IS_IN_SPI在uboot/include/autoconf.mk中定义:

                 

                 所以, env_init为定义在uboot/common/env_spi.c中的env_init, 如下:

                

                 default_environment[]定义在uboot/include/env_default.h, 定义了默认的环境变量的值。

                 所有的默认boot环境变量配置都在文件uboot/include/common.cfg中定义,比如:

                 bootcmd=bootfmh

                 bootdelay=0

                 uboot/include/env_default.h

                

init_baud_rate: 配置串口波特率为默认值115200

                

                  CONFIG_BAUDRATE定义在uboot/include/common.cfg中:

                  

                  这个CONFIG_SPX_FEATURE_BAUDRATE_CONSOLE_TTY在工程配置文件*.PRJ定义:

                 

                  这个是特定厂商的配置文件,不做进一步介绍。总之,这个*.PRJ定义的东西,会替换

                  common.h中对应的宏。

serial_init:初始化一个串口,为uboot cmd交互提供交互控制台。

                      定义在uboot/drivers/serial/serial.c

                    

                   

                     serial_init直接调用default_serial_console串口设备start()函数。

                     在ast2500evb板子中,使用的UART为ns16550, 且CONFIG_SYS_NS16550_SERIAL=y

                     故, 这里这个default_serial_console定义在uboot/drivers/serial/serial_ns16550.c,

                    且配置的CONFIG_CONS_INDEX为5.

                   

                    所以,serial_init就是调用了eserial5_device->start(), 即eserial5_init().

                   

                     

                     

                     100行中serial_ports[port-1]为CONFIG_SYS_NS16550_COM5(0x1E784000):

                    

                     serial_ns16550.c -> uboot/include/common.h -> uboot/include/config.h

                           ->  uboot/include/ configs/ast2500evb.h  -> uboot/include/configs/ast.cfg

                                          

                  calc_divisor()用于计算每传输一个码元需要的时钟滴答数,计算方式如下:

                 

                   CONFIG_SYS_NS16550_CLK定义:

                   uboot/include/configs/ast.cfg

                  

                   uboot/arch/arm/cpu/astcommon/ast_clk.c.

                 

                   计算出clock_divisor后,调用NS16550_init()处理:

                   uboot/drivers/serial/ns16550.c

                   

                   

                   NS16550_init就是对UART port的寄存器进行配置。

console_init_f:

                   这个时候还没有std,所以,前面的UART串口就用作console。

                   如果配置了CONFIG_PRE_CONSOLE_BUFFER=y, 那么

                   console_init_f就是向UART口输出打印。

                   uboot/common/console.c

                  

                  

                    这个putc就是向UART口发送一个字符。

                   

                   

                    如果没有配置CONFIG_PRE_CONSOLE_BUFFER=y,

                   那这个print_pre_console_buffer()就是空,什么都不做。

                 

init_func_i2c:

                   初始化i2c总线。

                   

                    对于ast2500evb, i2c_init什么也不做,见uboot/arch/arm/cpu/astcommon/ast_i2c.c

                    

                      uboot/arch/arm/cpu/astcommon/Makefile

                     

                      uboot/include/autoconf.mk

                     

dram_init:

                     这里dram初始化就是sdram的信息记录,定义如下:

                     uboot/board/ast2500evb/ast2500evb.c

                     

                     sdram寄存器的配置和初始化在*.S中就做过了

                    (不然你怎么能跑到C语言环境,堆栈指针可是指向这个)

                    这里保存了sdram的基址CONFIG_SYS_SDRAM_BASE(2G),

                   大小为CONFIG_SYS_SDRAM_SYS_USED(480M)。

setup_dest_addr:

                   这里主要是设置uboot relocate到sdram中的地址为sdram的最大地址: 2G+480M.

                  

                  

reserve_mmu:

                   reserve_mmu主要是在sdram顶端预留TLB的内存(16k).

                  

reserve_uboot:

                  reserve_uboot主要就是设置uboot monitor relocate的内存地址(整个uboot image size)

                  大小为bss_end - _start, 见setup_mon_len()

                  

                   uboot/arch/arm/cpu/arm1176/start.S

                 

                 

reserve_malloc:

                  reserve malloc区间内存,大小为TOTAL_MALLOC_LEN, 即64k+64k

                

reserve_board:

                reserve gd->bd内存。

               

reserve_global_data:

                  在sdram中reserve全局变量内存struct global_data *gd.

                 

                  uboot/include/common.h

                 

                  这里将新的gd放在TLB, uboot monitor下面。

reserve_fdt:

                  reserve FDT(flat device tree)内存。

                 

reserve_stacks:

                  reserve 中断IRQ使用的堆栈。

                 

                    

                     

                      IRQ使用的堆栈大小为CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ, 即4k + 4k.

setup_dram_config:

                     将sdram的基址,以及大小,保存到gd->bd中。

                    

                     

                    

setup_baud_rate:

                      保存波特率配置到gd->bd.

                     

setup_board_extra:

                      保存额外信息到gd->bd, 比如处理器时钟,plb和pci总线频率等。

                      

reloc_fdt:

                     将FDT信息拷贝到新的FDT内存地址处。

                    

setup_reloc:

                   计算uboot被relocated后的地址和原始地址之间的偏移offset.

                  

至此,board_init_f的所有工作完成。下面我们总结一下,relocate之后的内存布局:

在uboot/arch/arm/lib/crt0.S, 我们使用了”bl”来跳转到board_init_f,当board_init_f执行完后,程序回到了该跳转语句的下一条指令:

上面的代码很直观:

100行,改变sp到gd->start_addr_sp地址处,即上图中的sp域高地址处。

102-103行,r8为gd新地址处,即上图中的gd域。

105行设置返回地址为”here”。

106-107行改变lr为uboot relocate之后返回地址(当前here地址+uboot relocate offset)。

108行设置uboot relocate到的新地址。

109行跳转到relocate_code处执行.

我们先来看relocate_code怎么做的(注意,此时的sp已经指向sdram内存了,见上图的sp).

uboot/arch/arm/lib/relocate.S

40行设置uboot image当前的start地址。

41行计算relocate addr和当前uboot image的start地址的偏移。

43行设置uboot image当前的end地址。

46-49行从r1(uboot image 当前start地址)处将数据加载到r10-r11, 然后再将r10-r11寄存器的数据存到r0(uboot新地址)处,即完成一次uboot image数据的一次搬移;之后重复这个动作,直到uboot image的__image_copy_start到__image_copy_end段的数据全部被搬移到新地址。

从50行一直到69行在做的就是将uboot image中的”Label”段fix成relocate之后的地址。有关这一段的描写,参考https://blog.csdn.net/skyflying2012/article/details/37660265。

下图是uboot.lds描述的uboot段:

搬运完之后,来到relocate_done。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

uboot启动之第一次运行C函数到uboot重定位 的相关文章

  • 【ROS学习2】创建ROS工作空间及功能包

    目录 创建ROS工作空间及功能包工作空间 workspace src 代码空间 Source Space build 编译空间 Build Space devel 开发空间 Development Space install 安装空间 In
  • 【GStreamer 】5-5-总结USB相机转RTSP网络视频流-推流usb摄像头JPEG

    我们使用gstreamer rtsp server xff0c 实现了USB相机转RTSP网络流的基本功能 xff0c 之前很多篇都讲了如何实现 xff0c 这一次我们集中精力解决之前的一些问题 文章 GStreamer 5 4 USB相机
  • C程序设计语言 5-3

    练习5 3 用指针方式实现第2章中的函数strcat 函数strcat s t 将t指向的字符串复制到s指向的字符串的尾部 include lt stdio h gt int my strcat char char int main cha
  • NuttX 文件系统架构介绍(7.14)

  • 谈谈memcpy函数的优化(纯C)

    在使用C语言编程时 xff0c 我们常用memcpy来复制内存数据 xff0c 但很少有人会关注到memcpy怎么实现 最简单的memcpy功能实现如下 xff1a void low memcpy void dst const void s
  • USB DEVICE调试心得

    一 USB设备链接后无法HUB不上报发现新设备 USB控制器未打开 xff0c USB DP DM引脚配置不正确 二 能够发现设备 xff0c 但HOST端提示获取描述符失败 获取描述符是 USB DEVICE 链接后 HOST 向 DEV
  • PX4uORB介绍[4]-对象和数据结构

  • ubuntu禁止显示器休眠的方法

    近期在firefly RK3399开发板上调试代码 xff0c 经常遇到显示器自动休眠 xff0c 并且发现每次休眠都对系统实时性产生一些影响 xff0c 最终在万能的CSDN博客上找到解决办法 xff1a Linux不让显示器休眠的方法
  • STM32F4 SPI RX/TX DMA 读写FLASH数据

    STM32 使用DMA读写FLASH数据需要注意以下几点 xff1a 1 SPI全双工模式下 xff0c 无论读写FLASH数据均需要同时使能RX TX DMA 2 写数据时回读数据应当丢弃 xff0c 读数据时应当发送0xff来启动SPI
  • C++ vector的用法总结(整理)

    vector 是向量类型 xff0c 它可以容纳许多类型的数据 xff0c 如若干个整数 xff0c 所以称其为容器 它相当于一个动态的数组 当程序员无法知道自己需要的数组的规模多大时 用其来解决问题可以达到最大节约空间的目的 vector
  • 【问题已解决】无法定位程序输入点XXX于动态链接库xxxxxx

    因为刚接触OSG需要用CMake进行编译 xff0c 在操作上的问题还可以适应 xff0c 主要是电脑环境的影响比较大 编译成功后 xff0c 运行程序提示缺少一些dll文件 这里的主要处理办法是下载缺失的部分 xff0c 加到对应的文件夹
  • [python]重新安装pip

    目录 pip简介 一 恢复easy install文件 二 安装pip pip简介 python中一开始的import指令大家都不陌生 xff0c 也是因为可以调用不同模块的功能 xff0c 被称为 胶水语言 一般安装外部库有很多种方式 x
  • 【ROS2 入门】Jeston TX1 JetPack_4.6.3环境 ubuntu 18.04 ROS2 安装

    大家好 xff0c 我是虎哥 xff0c 从今天开始 xff0c 我将花一段时间 xff0c 开始将自己从ROS1切换到ROS2 xff0c 在上一篇中 xff0c 我们再虚拟机环境中安装了 ROS2 eloquent版本 xff0c 并完
  • 【已解决】拯救者Y7000不能调节亮度

    在上午的时候 xff0c 电脑突然有一些进程失控 xff0c 在任务管理器中一些服务关不掉 xff0c 电脑接近死机 xff0c 只能重启来解决 但是重启之后电脑突然很暗 回顾今天发生的情况 xff0c 应该是软件的锅了 应该是因为该型号的
  • 【已解决】win10 “你不能访问此共享文件夹,因为你组织的安全策略阻止未经身份验证的来宾访问。

    在访问局域网共享盘的时候 xff0c 突然出现报错 通过强大的网友 xff0c 通过改变组策略权限可以解决 1 按下win 43 R xff0c 输入gpedit msc 2 打开 管理模板 gt 网络 gt Lanman工作站 gt 启动
  • 【已解决】win10离线安装.net framework 3.5(错误:0x8024402c)

    首先说一下问题的背景 xff0c PC是离线环境win10系统 xff0c 主要在在离线安装VS2008的时候需要先安装这个低版本 Net 网上有很多方式 xff0c 这次参考价值最大的是这两个 Win10离线安装 net framewor
  • 【已解决可更新】VS2008 写入位置 0xCDCDCDCD 时发生访问冲突

    这个问题分两个小问题来细说 问题的背景是VS2008项目中封装了网络协议接口类 xff0c 对象成员有一个SOCKET类型成员变量和封装的进行三次握手的成员函数 在调用成员函数时报错发生访问冲突 1 写入位置 0xCDCDCDCD 时发生访
  • 【python】删除python代码中的简单注释

    可以当作一个简单的小工具来使用 xff0c 不过也是比较有局限性 xff0c 只能去掉 开头的注释行 使用内置函数 xff0c 没有引入模块 filename 61 34 xxx txt 34 打开名为xxx的txt文件 file 61 o
  • 再见2022,加油2023

    其实变化最大的一点就是 xff0c 这一年自己变成了一个北漂 没有很多的成熟的规划 xff0c 没有很多预算准备来到了北京 那会儿和之前的同事合租 xff0c 也给他添了不少麻烦 最开始到北京的时候 xff0c 因为口罩问题入职前生活状态比
  • 有效解决“SyntaxError: Non-UTF-8 code starting with” 语法错误

    在程序中出现中文的时候会有这种报错 xff0c 在代码的第一行加一句注释 xff0c 说明一下字符类型可以解决 coding 61 gbk coding utf 8这两种在我的程序里是亲测有效的

随机推荐

  • STM32F407定时器编码器接口模式

    STM32F407定时器编码器接口模式 16位定时器扩展32位 span class token comment TIM5初始化为编码器接口模式 xff0c 读取光栅尺数值 span span class token keyword voi
  • STM32F407的USB_HID 基础配置STM32CubeMX

    STM32F407的USB HID 基础配置 示例详解 参考 xff1a https blog csdn net zhanglifu3601881 article details 89675307 工具 xff1a STM32CubeMX5
  • STM32F407通过FSMC连接W5100S进行TCP网络通信

    STM32F407通过FSMC连接W5100S进行TCP网络通信 一 W5100S硬件 1 HS NM5100SA模块 模块厂家 xff1a 成都浩然电子http www hschip com HS NM5100SA以太网络控制器接口模块是
  • 【ROS2 入门】ROS2 创建工作空间

    大家好 xff0c 我是虎哥 xff0c 从今天开始 xff0c 我将花一段时间 xff0c 开始将自己从ROS1切换到ROS2 xff0c 在上几篇中 xff0c 我们一起了解ROS 2中很多基础概念 xff0c 从今天开始我们逐步就开始
  • STM32F407通过SPI连接W5100S进行TCP网络通信

    STM32F407通过SPI连接W5100S进行网络通信 一 W5100S硬件 1 HS NM5100SA模块 模块厂家 xff1a 成都浩然电子http www hschip com HS NM5100SA以太网络控制器接口模块是将W51
  • STM32F407 内部自带FLASH 模拟 EEPROM

    STM32F407 内部自带FLASH 模拟 EEPROM 一 STM32F407自带FLASH STM32F4 本身没有自带 EEPROM xff0c 但是 STM32F4 具有 IAP xff08 在应用编程 xff09 功能 xff0
  • 国标GB/T 18384.1 绝缘检测算法 推导公式

    国标GB T 18384 1 绝缘检测算法 推导公式 国标中关于绝缘检测算法只有结果 xff0c 没有推导公式 xff0c 如下 xff1a 根据电流回路相等原则 xff0c 推导出公式1 xff1a V1 V1 为正常情况下电池正负极电压
  • LTC6820和isoSPI使用笔记

    一 LTC6820使用笔记 1 MSTR主控 受控 MSTR 引脚 11 引脚 12 xff1a 串行接口主 从选择器输入 位于隔离式接口的主控器侧 xff08 SPI主机 xff09 xff0c 引脚接 VDD 位于隔离式接口的受控器侧
  • ESP8266学习笔记1--硬件

    1 ESP12F模块 原理图 自制开发板 原理图
  • ESP8266学习笔记2--Arduino环境搭建

    1 安装Arduino IDE https www arduino cn thread 5838 1 1 html 2 安装esp8266扩展 https www arduino cn thread 76029 1 1 html 安装成功后
  • ESP8266学习笔记3-闪存文件系统

    3 3 1 闪存文件SPIFFS基本操作 程序来源 xff1a 太极创客http www taichi maker com homepage esp8266 nodemcu iot iot c spiffs spiffs operation
  • 同一寄存器不同位域赋值的两种方法

    当一个寄存器有不同位域时 xff0c 我们需要给不同位域赋值 如何赋值方便呢 xff1f 下面有两种方法 xff0c 总结一下 个人觉得位域写法更简洁 整体寄存器法 typedef struct StrNa uint32 t reg1 re
  • mavlink解析

    之前看了mavlink协议 xff0c 网上关于mavlink的资料不多 本系列共三篇 xff0c 这是第一篇 本文大概总结了下对mavlink协议的理解 以下如不说明都是说mavlink v1 0版本 首先附上mavlink的各个消息的简
  • Tomcat部署及优化

    目录 1 Tomcat概述 1 Tomcat的概念 2 Tomcat的核心组件 3 Java Servlet 的概念 4 JSP的概念 5 Tomcat中最顶层的容器 server 6 四个子容器的作用 7 Tomcat请求过程 2 Tom
  • STC89C52系列单片机内部资源——串口通信

    计算机通信是将计算机技术和通信技术的相结合 xff0c 完成计算机与外部设备或计算机与计算机之间的信息交换 可以分为两大类 xff1a 并行通信与串行通信 并行通信通常是将数据字节的各位用多条数据线同时进行传送 并行通信控制简单 传输速度快
  • 用TCP/UDP 网络调试助手(PC版)无法获取网页信息

    以前的网页均是http开头的 xff0c 是没有加密的 xff0c 以前用GET就能获取网页的信息 xff0c 但是现在的基本是https开头的 xff0c 是加密的 xff0c 所以现在用以前的方法 xff0c 只能返回301错误 现在想
  • Ubuntu 20.04安装Ros Noetic及Ubuntu 18.04安装ROS Melodic(两版本详细填坑)

    Ubuntu 20 04安装Ros Noetic及18 04安装ROS Melodic 表1 1 ROS的历史版本 1 设置安装源2 添加秘钥3 更新列表4 开始安装5 配置ROS环境变量6 安装rosinstall6 1 初始化核心组件r
  • linux 根文件系统,根设备,sys_open, sys_read, sys_write, sys_mount, sys_mknod

    笔者语 xff1a 1 内容涉及比较多 xff0c 自己也没有分章节 xff0c 因为觉得这些内容关联性很强 xff0c 自己也懒的去弄了 2 本文涉及以下内容 xff1a 2 1 内核启动过程中 xff0c 第一个文件系统为rootfs
  • uboot的配置(make xxx_config)和编译(make)工程解读

    uboot编译三步走 make xxx configmakemake install 第一步make xxx config 这一步是产生板子的配置文件 我们假设是配置ast2500evb板子 xff0c 那么这里的配置命令就是 make a
  • uboot启动之第一次运行C函数到uboot重定位

    接上一篇博文 uboot启动流程之上电启动到第一次准备好C语言运行环境 xff0c 本文从board init f 开始 board init f定义在uboot common board f c中 CONFIG SYS GENERIC B