5-global_data介绍

2024-08-30 17:38
文章标签 介绍 data global

本文主要是介绍5-global_data介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

[uboot] (番外篇)global_data介绍

以下例子都以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;
  • 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

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的地址返回
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

(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
}
  • 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

(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, spbl  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也就是其参数。
  • 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
  • 37
  • 38

注意:最终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")
  • 1

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

global_data相对比较简单,也就不多说了。

这篇关于5-global_data介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

MySQL中慢SQL优化的不同方式介绍

《MySQL中慢SQL优化的不同方式介绍》慢SQL的优化,主要从两个方面考虑,SQL语句本身的优化,以及数据库设计的优化,下面小编就来给大家介绍一下有哪些方式可以优化慢SQL吧... 目录避免不必要的列分页优化索引优化JOIN 的优化排序优化UNION 优化慢 SQL 的优化,主要从两个方面考虑,SQL 语

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程

Python实现html转png的完美方案介绍

《Python实现html转png的完美方案介绍》这篇文章主要为大家详细介绍了如何使用Python实现html转png功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 1.增强稳定性与错误处理建议使用三层异常捕获结构:try: with sync_playwright(

Java使用多线程处理未知任务数的方案介绍

《Java使用多线程处理未知任务数的方案介绍》这篇文章主要为大家详细介绍了Java如何使用多线程实现处理未知任务数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 知道任务个数,你可以定义好线程数规则,生成线程数去跑代码说明:1.虚拟线程池:使用 Executors.newVir

JAVA SE包装类和泛型详细介绍及说明方法

《JAVASE包装类和泛型详细介绍及说明方法》:本文主要介绍JAVASE包装类和泛型的相关资料,包括基本数据类型与包装类的对应关系,以及装箱和拆箱的概念,并重点讲解了自动装箱和自动拆箱的机制,文... 目录1. 包装类1.1 基本数据类型和对应的包装类1.2 装箱和拆箱1.3 自动装箱和自动拆箱2. 泛型2

HTML5 data-*自定义数据属性的示例代码

《HTML5data-*自定义数据属性的示例代码》HTML5的自定义数据属性(data-*)提供了一种标准化的方法在HTML元素上存储额外信息,可以通过JavaScript访问、修改和在CSS中使用... 目录引言基本概念使用自定义数据属性1. 在 html 中定义2. 通过 JavaScript 访问3.

四种Flutter子页面向父组件传递数据的方法介绍

《四种Flutter子页面向父组件传递数据的方法介绍》在Flutter中,如果父组件需要调用子组件的方法,可以通过常用的四种方式实现,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录方法 1:使用 GlobalKey 和 State 调用子组件方法方法 2:通过回调函数(Callb

Python进阶之Excel基本操作介绍

《Python进阶之Excel基本操作介绍》在现实中,很多工作都需要与数据打交道,Excel作为常用的数据处理工具,一直备受人们的青睐,本文主要为大家介绍了一些Python中Excel的基本操作,希望... 目录概述写入使用 xlwt使用 XlsxWriter读取修改概述在现实中,很多工作都需要与数据打交

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.

Python实现NLP的完整流程介绍

《Python实现NLP的完整流程介绍》这篇文章主要为大家详细介绍了Python实现NLP的完整流程,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 编程安装和导入必要的库2. 文本数据准备3. 文本预处理3.1 小写化3.2 分词(Tokenizatio