版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ooonebook/article/details/53013545

以下例子都以project X项目tiny210(s5pv210平台,armv7架构)为例

[uboot] uboot流程系列:
[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)
[uboot] (第一章)uboot流程——概述
[uboot] (第二章)uboot流程——uboot-spl编译流程

===================================================================================
一、global_data功能
1、global_data存在的意义

在某些情况下,uboot是在某些只读存储器上运行,比如ROM、nor flash等等。
在uboot被重定向到RAM(可读可写)之前,我们都无法写入数据,更无法通过全局变量来传递数据。
而global_data则是为了解决这个问题。
这里顺便一下,后续的uboot的relocation操作,也就是uboot的重定向操作,最主要的目的也是为了解决这个问题,后续会专门说明。
2、 global_data简单介绍

global_data又称之为GD.
简单地说,uboot把global_data放在RAM区,并且使用global_data来存储全局数据。由此来解决上述场景中无法使用全局变量的问题。
二、global_data数据结构
1、数据结构说明

global_data数据结构结构体定义为struct global_data,被typedef为gd_t。
也就是说可以直接通过struct global_data或者gd_t来进行声明。
struct global_data定义如下(过滤掉一些被宏定义包含的部分):
include/asm-generic/global_data.h

typedef struct global_data {
    bd_t *bd;
    unsigned long flags;
    unsigned int baudrate;
    unsigned long cpu_clk;  /* CPU clock in Hz!     */
    unsigned long bus_clk;
    /* We cannot bracket this with CONFIG_PCI due to mpc5xxx */
    unsigned long pci_clk;
    unsigned long mem_clk;
    unsigned long have_console; /* serial_init() was called */
    unsigned long env_addr; /* Address  of Environment struct */
    unsigned long env_valid;    /* Checksum of Environment valid? */
    unsigned long ram_top;  /* Top address of RAM used by U-Boot */
    unsigned long relocaddr;    /* Start address of U-Boot in RAM */
    phys_size_t ram_size;   /* RAM size */
    unsigned long mon_len;  /* monitor len */
    unsigned long irq_sp;       /* irq stack pointer */
    unsigned long start_addr_sp;    /* start_addr_stackpointer */
    unsigned long reloc_off;
    struct global_data *new_gd; /* relocated global data */
    const void *fdt_blob;   /* Our device tree, NULL if none */
    void *new_fdt;      /* Relocated FDT */
    unsigned long fdt_size; /* Space reserved for relocated FDT */
    struct jt_funcs *jt;        /* jump table */
    char env_buf[32];   /* buffer for getenv() before reloc. */
    unsigned long timebase_h;
    unsigned long timebase_l;
    struct udevice *cur_serial_dev; /* current serial device */
    struct arch_global_data arch;   /* architecture-specific data */

} gd_t;

2、成员说明

重点说明
        bd_t *bd:board info数据结构定义,位于文件 include/asm-arm/u-boot.h定义,主要是保存开发板的相关参数。
        unsigned long env_addr:环境变量的地址。
        unsigned long ram_top:RAM空间的顶端地址
        unsigned long relocaddr:UBOOT重定向后地址
        phys_size_t ram_size:物理ram的size
        unsigned long irq_sp:中断的堆栈地址
        unsigned long start_addr_sp:堆栈地址
        unsigned long reloc_off:uboot的relocation的偏移
        struct global_data *new_gd:重定向后的struct global_data结构体
        const void *fdt_blob:我们设备的dtb地址
        void *new_fdt:relocation之后的dtb地址
        unsigned long fdt_size:dtb的长度
        struct udevice *cur_serial_dev:当前使用的串口设备。

其他成员在后续时候到的时候在进行说明。
三、global_data存放位置以及如何获取其地址
1、global_data区域设置代码

(1)首先参考一下分配global_data的代码。
common/init/board_init.c

// 这个函数用于给global_data分配空间,在relocation之前调用
// 传入的参数是顶部地址,但是不一定是要内存顶部的地址,可以自己进行规划,后面_main函数会说明
ulong board_init_f_alloc_reserve(ulong top)
{
    /* Reserve early malloc arena */
#if defined(CONFIG_SYS_MALLOC_F)
    top -= CONFIG_SYS_MALLOC_F_LEN;
// 先从顶部向下分配一块CONFIG_SYS_MALLOC_F_LEN大小的空间给early malloc使用
// 关于CONFIG_SYS_MALLOC_F_LEN可以参考README
// 这块内存是用于在relocation前用于给malloc函数提供内存池。
#endif

/* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
    top = rounddown(top-sizeof(struct global_data), 16);
// 继续向下分配sizeof(struct global_data)大小的内存给global_data使用,向下16byte对齐
// 这时候得到的地址就是global_data的地址。

return top;
// 将top,也就是global_data的地址返回
}

(2)然后看一下初始化global_data区域的代码。
common/init/board_init.c
去除无关代码的部分

// 这个函数用于对global_data区域进行初始化,也就是清空global_data区域
// 传入的参数就是global_data的基地址
void board_init_f_init_reserve(ulong base)
{
    struct global_data *gd_ptr;

/*
     * clear GD entirely and set it up.
     * Use gd_ptr, as gd may not be properly set yet.
     */

gd_ptr = (struct global_data *)base;
    /* zero the area */
    memset(gd_ptr, '\0', sizeof(*gd));
// 先通过memset函数对global_data数据结构进行清零

/* next alloc will be higher by one GD plus 16-byte alignment */
    base += roundup(sizeof(struct global_data), 16);
// 因为global_data区域是16Byte对齐的,对齐后,后面的地址就是early malloc的内存池的地址,具体参考上述board_init_f_alloc_reserve
// 所以这里就获取了early malloc的内存池的地址

/*
     * record early malloc arena start.
     * Use gd as it is now properly set for all architectures.
     */
#if defined(CONFIG_SYS_MALLOC_F)
    /* go down one 'early malloc arena' */
    gd->malloc_base = base;
// 将内存池的地址写入到gd->malloc_base中
    /* next alloc will be higher by one 'early malloc arena' size */
    base += CONFIG_SYS_MALLOC_F_LEN;
//加上CONFIG_SYS_MALLOC_F_LEN,获取early malloc的内存池的末尾地址,这里并没有什么作用,是为了以后在early malloc的内存池后面多加一个区域时的修改方便。
#endif
}

(3)arm平台如何分配global_data区域,并保存其地址。
代码如下,去除掉被宏定义包含的无关代码部分
arch/arm/lib/crt0.S

ENTRY(_main)
/*
 * Set up initial C runtime environment and call board_init_f(0).
 */
    ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
@@ 预设堆栈指针为CONFIG_SYS_INIT_SP_ADDR
@@ 在tiny210中初步设置为如下(include/configs/tiny210.h):
@@ #define CONFIG_SYS_SDRAM_BASE           0x20000000
@@ #define MEMORY_BASE_ADDRESS  CONFIG_SYS_SDRAM_BASE
@@ #define PHYS_SDRAM_1     MEMORY_BASE_ADDRESS
@@ #define CONFIG_SYS_LOAD_ADDR     (PHYS_SDRAM_1 + 0x1000000)  /* default load address */
@@ #define CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_LOAD_ADDR
@@ 最终可以得到CONFIG_SYS_INIT_SP_ADDR是0x3000_0000,也就是uboot relocation的起始地址
@@ 补充一下,DDR的空间是0x2000_0000-0x4000_0000

@@ 注意!!!这里只是预设的堆栈地址,而不是最终的堆栈地址!!!

bic sp, sp, #7  /* 8-byte alignment for ABI compliance */
@@ 8byte对齐

mov r0, sp
    bl  board_init_f_alloc_reserve
@@ 将sp的值放到r0中,也就是作为board_init_f_alloc_reserve的参数
@@ 返回之后,r0里面存放的是global_data的地址
@@ 注意,同时也是堆栈地址,因为堆栈是向下增长的,所以不必担心和global_data冲突的问题

@@ 综上,此时r0存放的,既是global_data的地址,也是堆栈的地址

mov sp, r0
@@ 把堆栈地址r0存放到sp中

/* set up gd here, outside any C code */
    mov r9, r0
@@ 把global_data的地址存放在r9中
@@ 此时r0存放的还是global_data的地址

bl  board_init_f_init_reserve
@@ 调用board_init_f_init_reserve对global_data进行初始化,r0也就是其参数。

注意:最终global_data的地址存放在r9中了。
2、global_data内存分布

内存分布如下:
———————-CONFIG_SYS_LOAD_ADDR —————————–高地址

…………………………….. early malloc 内存池

————————-early malloc 内存池基地址 —————————

………………………………… global_data区域

—————-global_data基地址(r9), 也是堆栈的起始地址————-

………………………………………堆栈空间

————————————–堆栈结束—————————————-低地址
注意:最终global_data的地址存放在r9中了。
四、global_data使用方式
1、原理说明

前面我们一直强调了global_data的地址存放在r9中了。
所以当我们需要global_data的时候,直接从r9寄存器中获取其地址即可。

uboot中定义了一个宏DECLARE_GLOBAL_DATA_PTR,使我们可以更加简单地获取global_data。
定义如下:
arch/arm/include/asm/global_data.h

#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r9")

DECLARE_GLOBAL_DATA_PTR定义了gd_t *gd,并且其地址是r9中的值。
一旦使用了DECLARE_GLOBAL_DATA_PTR声明之后,后续就可以直接使用gd变量,也就是global_data了。
2、使用示例

DECLARE_GLOBAL_DATA_PTR定义了gd_t *gd,并且其地址是r9中的值。
一旦使用了DECLARE_GLOBAL_DATA_PTR声明之后,后续就可以直接使用gd变量,也就是global_data了。
简单例子如下:
common/board_r.c

DECLARE_GLOBAL_DATA_PTR
// 通过DECLARE_GLOBAL_DATA_PTR定义了gd_t *gd
// 相当于如下:
// #define DECLARE_GLOBAL_DATA_PTR      register volatile gd_t *gd asm ("r9")

static int initr_reloc(void)
{
    /* tell others: relocation done */
    gd->flags |= GD_FLG_RELOC | GD_FLG_FULL_MALLOC_INIT;
// 直接使用gd变量,也就是uboot的global_data。

return 0;
}

global_data相对比较简单,也就不多说了。
————————————————
版权声明:本文为CSDN博主「ooonebook」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ooonebook/article/details/53013545

[uboot] (番外篇)global_data介绍(转)的更多相关文章

  1. [uboot] (番外篇)uboot之fdt介绍

    http://blog.csdn.net/ooonebook/article/details/53206623 以下例子都以project X项目tiny210(s5pv210平台,armv7架构)为 ...

  2. [uboot] (番外篇)uboot之fdt介绍 (转)

    以下例子都以project X项目tiny210(s5pv210平台,armv7架构)为例 [uboot] uboot流程系列:[project X] tiny210(s5pv210)上电启动流程(B ...

  3. [uboot] (番外篇)uboot串口&console&stdio设备工作流程 (转)

    [uboot] uboot流程系列:[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)[project X] tiny210(s5pv210)从存储设备加载代码到D ...

  4. [uboot] (番外篇)uboot 驱动模型(转)重要

    [uboot] uboot流程系列:[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)[project X] tiny210(s5pv210)从存储设备加载代码到D ...

  5. 【番外篇】ASP.NET MVC快速入门之免费jQuery控件库(MVC5+EF6)

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...

  6. iOS冰与火之歌(番外篇) - 基于PEGASUS(Trident三叉戟)的OS X 10.11.6本地提权

    iOS冰与火之歌(番外篇) 基于PEGASUS(Trident三叉戟)的OS X 10.11.6本地提权 蒸米@阿里移动安全 0x00 序 这段时间最火的漏洞当属阿联酋的人权活动人士被apt攻击所使用 ...

  7. 给深度学习入门者的Python快速教程 - 番外篇之Python-OpenCV

    这次博客园的排版彻底残了..高清版请移步: https://zhuanlan.zhihu.com/p/24425116 本篇是前面两篇教程: 给深度学习入门者的Python快速教程 - 基础篇 给深度 ...

  8. 可视化(番外篇)——在Eclipse RCP中玩转OpenGL

    最近在看有关Eclipse RCP方面的东西,鉴于Gephi是使用opengl作为绘图引擎,所以,萌生了在Eclipse RCP下添加画布,使用opengl绘图的想法,网上有博文详细介绍这方面的内容, ...

  9. 可视化(番外篇)——SWT总结

    本篇主要介绍如何在SWT下构建一个应用,如何安装SWT Designer并破解已进行SWT的可视化编程,Display以及Shell为何物.有何用,SWT中的常用组件.面板容器以及事件模型等. 1.可 ...

  10. 番外篇 之 C#委托

    对于上一节 番外篇之C#多线程的反思 反思一:   Thread th = new Thread(参数); ////参数的总结 ////首先,第一情况,对于 Thread th = new Threa ...

随机推荐

  1. springboot子模块 @Autowired无法找到其他模块的接口和类的解决方法

    在main的启动类上添加 @SpringBootApplication(scanBasePackages = {"com.shangsheng"})或者@ComponentScan ...

  2. Squirrel GUI+ Phoenix 连接Hbase

    一. 参考 http://blog.csdn.net/maomaosi2009/article/details/45598823 二. 问题解决 >Squirrel Client Connect ...

  3. java:nginx(java代码操作ftp服务器)

    1.检查是否安装了vsftpd [root@linux01 ~]# rpm -qa|grep vsftpd 2.安装vsftpd [root@linux01 ~]# yum -y install vs ...

  4. 从gopath到go mod的一次尝试

    windows下的尝试: gomod初尝试下载官方包1.11(及其以上版本将会自动支持gomod) 默认GO111MODULE=auto(auto是指如果在gopath下不启用mod)go mod h ...

  5. Number 和 Math 类

    Java Number & Math 类 一般地,当需要使用数字的时候,我们通常使用内置数据类型,如:byte.int.long.double 等. 然而,在实际开发过程中,我们经常会遇到需要 ...

  6. DVD Cloner 2019MAC如何使用?

    DVD Cloner 2019 for mac是一款应用在Mac上的DVD刻录软件,它可以将DVD克隆到任何空白光盘,包括具有多种复制模式的DVD + R / RW,DVD-R / RW,DVD + ...

  7. java线程中start和run的区别

    public class Test1 extends Thread { @Override public void run() { while (true) { System.out.println( ...

  8. 【VS开发】【Linux开发】【DSP开发】如何截获以太网帧并解析

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...

  9. Javascript原型、构造函数、实例的关系

    1. 原型.构造函数.实例的关系 原型: 原型通过constructor指向构造函数,原型如果是自定义对象且没有明确将constructor指向构造函数,则原型的constructor指向函数的基类F ...

  10. flutter环境配置(windows)

    参考以下链接 下载安装步骤: https://www.cnblogs.com/yangyxd/p/8809512.html 安装Flutter环境遇到Android license status un ...