global_data又称为GD,顾名思义,global_data就是用来存储u-boot的全局数据的。
typedef struct global_data {
bd_t *bd; /* bd_info结构体定义,位于include/asm-generic/u-boot.h中,用于保存开发板相关参数 */
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;
#if defined(CONFIG_LCD) || defined(CONFIG_VIDEO)
unsigned long fb_base; /* Base address of framebuffer mem */
#endif
#if defined(CONFIG_POST)
unsigned long post_log_word; /* Record POST activities */
unsigned long post_log_res; /* success of POST test */
unsigned long post_init_f_time; /* When post_init_f started */
#endif
#ifdef CONFIG_BOARD_TYPES
unsigned long board_type;
#endif
unsigned long have_console; /* serial_init() was called */
#if CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER)
unsigned long precon_buf_idx; /* Pre-Console buffer index */
#endif
unsigned long env_addr; /* Address of Environment struct */ /* 环境变量的地址 */
unsigned long env_valid; /* Environment valid? enum env_valid */
unsigned long env_has_init; /* Bitmask of boolean of struct env_location offsets */
int env_load_prio; /* Priority of the loaded environment */
unsigned long ram_base; /* Base address of RAM used by U-Boot */ /* RAM基地址 */
unsigned long ram_top; /* Top address of RAM used by U-Boot */ /* RAM顶地址 */
unsigned long relocaddr; /* Start address of U-Boot in RAM */ /* RAM中,u-boot重定向后的起始地址 */
phys_size_t ram_size; /* RAM size */ /* RAM大小 */
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; /* u-boot的relocation的偏移 */
struct global_data *new_gd; /* relocated global data */ /* 重定向后的struct global_data */
#ifdef CONFIG_DM
struct udevice *dm_root; /* Root instance for Driver Model */
struct udevice *dm_root_f; /* Pre-relocation root instance */
struct list_head uclass_root; /* Head of core tree */
#endif
#ifdef CONFIG_TIMER
struct udevice *timer; /* Timer instance for Driver Model */
#endif
const void *fdt_blob; /* Our device tree, NULL if none */ /* fdt地址 */
void *new_fdt; /* Relocated FDT */ /* 重定向后的fdt地址 */
unsigned long fdt_size; /* Space reserved for relocated FDT */ /* 重定向后fdt的大小 */
#ifdef CONFIG_OF_LIVE
struct device_node *of_root;
#endif
struct jt_funcs *jt; /* jump table */
char env_buf[32]; /* buffer for env_get() before reloc. */
#ifdef CONFIG_TRACE
void *trace_buff; /* The trace buffer */
#endif
#if defined(CONFIG_SYS_I2C)
int cur_i2c_bus; /* current used i2c bus */
#endif
#ifdef CONFIG_SYS_I2C_MXC
void *srdata[10];
#endif
unsigned int timebase_h;
unsigned int timebase_l;
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
unsigned long malloc_base; /* base address of early malloc() */
unsigned long malloc_limit; /* limit address */
unsigned long malloc_ptr; /* current address */
#endif
#ifdef CONFIG_PCI
struct pci_controller *hose; /* PCI hose for early use */
phys_addr_t pci_ram_top; /* top of region accessible to PCI */
#endif
#ifdef CONFIG_PCI_BOOTDELAY
int pcidelay_done;
#endif
struct udevice *cur_serial_dev; /* current serial device */ /* 当前的串口设备 */
struct arch_global_data arch; /* architecture-specific data */
#ifdef CONFIG_CONSOLE_RECORD
struct membuff console_out; /* console output */
struct membuff console_in; /* console input */
#endif
#ifdef CONFIG_DM_VIDEO
ulong video_top; /* Top of video frame buffer area */
ulong video_bottom; /* Bottom of video frame buffer area */
#endif
#ifdef CONFIG_BOOTSTAGE
struct bootstage_data *bootstage; /* Bootstage information */
struct bootstage_data *new_bootstage; /* Relocated bootstage info */
#endif
#ifdef CONFIG_LOG
int log_drop_count; /* Number of dropped log messages */
int default_log_level; /* For devices with no filters */
struct list_head log_head; /* List of struct log_device */
int log_fmt; /* Mask containing log format info */
#endif
} gd_t;
(1)先看一下global_data的分配代码:(common/init/board_init.c)
// 这个函数用于给global_data分配空间,在relocation之前调用
// 传入的参数是栈顶地址,
ulong board_init_f_alloc_reserve(ulong top)
{
// 若SYS_MALLOC_F_LEN宏存在,从栈顶分配一块SYS_MALLOC_F_LEN大小的空间给early malloc使用
// 分配的这块内存是用于在relocation之前给malloc函数提供的内存池
/* Reserve early malloc arena */
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
top -= CONFIG_VAL(SYS_MALLOC_F_LEN);
#endif
// 继续向下分配sizeof(struct global_data)大小的内存给global_data使用,向下16Byte对齐
// 返回的值就是global_data的地址
/* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
top = rounddown(top-sizeof(struct global_data), 16);
// 返回top,就是返回global_data的地址
return top;
}
(2)再看一下global_data的初始化代码:(common/init/board_init.c)
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));
/* set GD unless architecture did it already */
#if !defined(CONFIG_ARM)
arch_setup_gd(gd_ptr);
#endif
/* next alloc will be higher by one GD plus 16-byte alignment */
base += roundup(sizeof(struct global_data), 16);
/*
* record early malloc arena start.
* Use gd as it is now properly set for all architectures.
*/
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
/* go down one 'early malloc arena' */
gd->malloc_base = base;
/* next alloc will be higher by one 'early malloc arena' size */
base += CONFIG_VAL(SYS_MALLOC_F_LEN);
#endif
}
(3)ARM平台下如何分配global_data区域,并保存其地址:(arch/arm/lib/crt0.S)
ENTRY(_main)
/*
* Set up initial C runtime environment and call board_init_f(0).
*/
// 若定义CONFIG_SPL_BUILD,则将栈顶设置为CONFIG_SPL_STACK;
// 若没有,则将栈顶设置为CONFIG_SYS_INIT_SP_ADDR
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr r0, =(CONFIG_SPL_STACK)
#else
ldr r0, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
// 8字节对齐
bic r0, r0, #7 /* 8-byte alignment for ABI compliance */
mov sp, r0
bl board_init_f_alloc_reserve
// 将sp的值放到r0中,也就是作为board_init_f_alloc_reserve的参数
// 函数返回以后,r0中存放的是global_data的地址
// 将
mov sp, r0
/* set up gd here, outside any C code */
// 把global_data的地址存放到r9中
mov r9, r0
bl board_init_f_init_reserve
注意:最终global_data的地址存放到r9中了。
在上一节的最后可以知道global_data的地址存放到了r9中,所以在后面当我们需要global_data的时候,直接从r9寄存器中获取即可。
在u-boot中定义了global_data的使用:(arch/arm/include/asm/global_data.h)
#define DECLARE_GLOBAL_DATA_PTR
#define gd get_gd()
static inline gd_t *get_gd(void)
{
gd_t *gd_ptr;
#ifdef CONFIG_ARM64
/*
* Make will already error that reserving x18 is not supported at the
* time of writing, clang: error: unknown argument: '-ffixed-x18'
*/
__asm__ volatile("mov %0, x18\n" : "=r" (gd_ptr));
#else
__asm__ volatile("mov %0, r9\n" : "=r" (gd_ptr));
#endif
return gd_ptr;
}
#else
#ifdef CONFIG_ARM64
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("x18")
#else
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r9")
#endif
#endif