【u-boot-2018.11】源码分析之gd_t(struct golobal_data)

一、global_data功能

global_data又称为GD,顾名思义,global_data就是用来存储u-boot的全局数据的。

二、global_data结构体介绍

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;

三、global_data存放

1.global_data的存放

(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的使用

在上一节的最后可以知道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

 

你可能感兴趣的:(u-boot)