天天看点

uboot几个重要数据结构

1、bd_t结构体:用于保存开发板相关的参数

在include\asm-arm\u-boot.h

typedef struct bd_info {
    int      bi_baudrate;	/* serial console baudrate */
    unsigned long	bi_ip_addr;	/* IP Address */
    unsigned char	bi_enetaddr[6]; /* Ethernet adress MAC地址*/
    struct   environment_s	  *bi_env;
    ulong    bi_arch_number;	/* unique id for this board 板子ID*/
    ulong    bi_boot_params;	/* where this board expects params 启动参数*/
    struct	 /* RAM configuration :RAM配置*/
    {
		ulong start;
		ulong size;
    } 	bi_dram[CONFIG_NR_DRAM_BANKS];
#ifdef CONFIG_HAS_ETH1//如果有定义第二块网卡就···,实际没有定义,忽略
    /* second onboard ethernet port */
    unsigned char   bi_enet1addr[6];
#endif
} bd_t;
           

主要使用于armlinux.c文件用来定义u-boot传递给kernel的参数

================================================================================================

2、gd_t结构体:成员主要是系统的初始化参数

在include/am-arm/global_data.h定义:

typedef	struct	global_data {
	bd_t		*bd;
	unsigned long	flags;  //状态标志
	unsigned long	baudrate; //波特率
	unsigned long	have_console;	/* serial_init() was called 串口初始化标识*/
	unsigned long	reloc_off;	/* Relocation Offset 重定位偏移,实际定向的位置与编译连接时指定的位置之差,一般为0*/
	unsigned long	env_addr;	/* Address  of Environment struct */
	unsigned long	env_valid;	/* Checksum of Environment valid? */
	unsigned long	fb_base;	/* base address of frame buffer */
#ifdef CONFIG_VFD
	unsigned char	vfd_type;	/* display type */
#endif
#if 0
	unsigned long	cpu_clk;	/* CPU clock in Hz!		*/
	unsigned long	bus_clk;
	unsigned long	ram_size;	/* RAM size */
	unsigned long	reset_status;	/* reset status register at boot */
#endif
	void		**jt;		/* jump table */
} gd_t;
           
#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8") //指定使用r8通用寄存器来传递参数
           

//这是一个全局的数据结构型指针。使用:

在include/asm-arm/global_data.h中有:

#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")   //定义一个指向gd_t结构体的寄存器指针变量gd

在lib_arm/board.c中:

gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

在bd_t结构体中:

ulong        bi_boot_params;

在board\tq2440\tq2440.c中:

gd->bd->bi_boot_params = 0x30000100;   //这就设定了uboot传递给内核的启动参数的存放地址0x30000100

========================================================================================================

3、建立启动参数tags

上面说明了内核启动参数的存放地址,下面就来分析这些启动参数uboot是如何建立的。

首先建立tag的结构体,在include/asm-arm/setup.h中

(1)先定义tag成员的结构体:

struct tag_header {
	u32 size;//这个tag的大小
	u32 tag;//我觉得是用来标记这个tag的身份,就是kernel读每一个tag的时候要靠这些来识别tag
};
struct tag_core {
	u32 flags;		/* bit 0 = read-only */
	u32 pagesize;
	u32 rootdev;
};
struct tag_mem32 {
	u32	size;
	u32	start;	/* physical start address */
};
struct tag_mem32 {
	u32	size;
	u32	start;	/* physical start address */
};
           

还有其他的,这里没有一一列出来

(2)接着又在这个文件的后面定义tag的数据结构:

static struct tag *params;
struct tag {
	struct tag_header hdr;
	
	union {
		struct tag_core		core;
		struct tag_mem32	mem;
		struct tag_videotext	videotext;
		struct tag_ramdisk	ramdisk;
		struct tag_initrd	initrd;
		struct tag_serialnr	serialnr;
		struct tag_revision	revision;
		struct tag_videolfb	videolfb;
		struct tag_cmdline	cmdline;

		/*
		 * Acorn specific
		 */
		struct tag_acorn	acorn;

		/*
		 * DC21285 specific
		 */
		struct tag_memclk	memclk;
	} u;
};
           

中间定义了一个union共同体,这样可以节省空间。

用函数来建立每一个tag,即初始化每一个tag成员的初值,在lib_arm/armlinux.c文件里头定义tag的初始化函数:

(1)先设置可以指向tag的指针变量:

static struct tag *params;

(2)接着开始初始化第一个tag:setup_start_tag

static void setup_start_tag (bd_t *bd)
{
	params = (struct tag *) bd->bi_boot_params;

	params->hdr.tag = ATAG_CORE;//0x54410001
	params->hdr.size = tag_size (tag_core);

	params->u.core.flags = 0;
	params->u.core.pagesize = 0;
	params->u.core.rootdev = 0;

	params = tag_next (params);
}
           

函数里面是先设置params指针,让他能够指向bi_boot_params启动参数的起始地址,接着设置其他东西,最后指向下一个tag的地址。

其他tag函数的功能分析和这个大同小异,不再一一分析。

还有就是这些函数是在do_bootm_linux()函数里面被调用。

========================================================================================================================

4、uboot要附加到zImage的头部数据结构

首先是在include/image.h头文件里面定义了tag的头的结构体:

typedef struct image_header {
	uint32_t	ih_magic;	/* Image Header Magic Number	*/
	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
	uint32_t	ih_time;	/* Image Creation Timestamp	*/
	uint32_t	ih_size;	/* Image Data Size		*/
	uint32_t	ih_load;	/* Data	 Load  Address		*/
	uint32_t	ih_ep;		/* Entry Point Address		*/
	uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/
	uint8_t		ih_os;		/* Operating System		*/
	uint8_t		ih_arch;	/* CPU architecture		*/
	uint8_t		ih_type;	/* Image Type			*/
	uint8_t		ih_comp;	/* Compression Type		*/
	uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/
} image_header_t;
           

在lib_arm/armlinux.c的do_bootm_linux()函数里面有引用image_header_t结构体:

image_header_t *hdr = &header;//这个header地址是内核的头部起始地址,即内核的加载地址

最终这个结构体是正真要被mkimage工具固化到zImage头部的。 uboot的重要的数据结构就基本是这些了。

===========================================================================================================

5、uboot自身的环境变量:

在include/configs/ta2440.h里面设定环境变量的存放地址:

#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x1F0000)

//#define CFG_ENV_IS_IN_FLASH1 //不存放在nor Flash中

#define CFG_ENV_IS_IN_NAND 1 //将环境变量存放到nand Flash中

#define CFG_ENV_OFFSET 0x40000    //环境变量存放处的偏移地址

#define CFG_ENV_SIZE64 0xc000

#define CFG_ENV_SIZE 0x20000

#define CFG_NAND_BASE 0

“saveenv”看看究竟存放的地址,具体实现函数先不分析,“print”看看环境变量存放了哪些信息

EmbedSky> print

bootargs=noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0

【其实是:

bootargs=“noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0”

root=/dev/mtdblock2:

指定根文件系统位于第三个Flash分区(noinitrd当没有使用ramdisk启动系统时要加上这个参数)

ramdisk就是把内存当做硬盘来使用

init=/linuxrc:

指定第一个应用程序是谁

console=ttySAC0:指定内核的打印信息从哪里打印出来】

bootcmd=nboot 0x32000000 kernel; bootm 0x32000000

bootdelay=0

baudrate=115200

ethaddr=0a:1b:2c:3d:4e:5f

ipaddr=192.168.1.6

serverip=192.168.1.8

netmask=255.255.255.0

stdin=serial

stdout=serial

stderr=serial

mtdids=nand0=nandflash0

mtdparts=mtdparts=nandflash0:[email protected](bios),128k(params),128k(toc),512k(eboot),1024k(logo),2m(kernel),-(root)

partition=nand0,0

mtddevnum=0

mtddevname=bios

Environment size: 453/131068 bytes