约定俗称tag标记(参数)。
在u-boot-1.1.6\include\asm-avr32\setup.h文件中
struct tag {
struct tag_header hdr; //结构体
union { //联合体
struct tag_core core;
struct tag_mem_range mem_range;
struct tag_cmdline cmdline;
struct tag_clock clock;
struct tag_ethernet ethernet;
} u;
};
在u-boot-1.1.6\lib_arm\armlinux.c中:
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
defined (CONFIG_CMDLINE_TAG) || \
defined (CONFIG_INITRD_TAG) || \
defined (CONFIG_SERIAL_TAG) || \
defined (CONFIG_REVISION_TAG) || \
defined (CONFIG_LCD) || \
defined (CONFIG_VFD)
setup_start_tag (bd); //初始化tag结构体
#ifdef CONFIG_SERIAL_TAG
setup_serial_tag (¶ms);
#endif
#ifdef CONFIG_REVISION_TAG
setup_revision_tag (¶ms);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGS
setup_memory_tags (bd); //设置RAM参数。告诉内核,内存从哪里开始,内存有多大
#endif
#ifdef CONFIG_CMDLINE_TAG
setup_commandline_tag (bd, commandline); //命令行参数
#endif
#ifdef CONFIG_INITRD_TAG
if (initrd_start && initrd_end)
setup_initrd_tag (bd, initrd_start, initrd_end);
#endif
#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
setup_videolfb_tag ((gd_t *) gd);
#endif
setup_end_tag (bd); //初始化tag结构体结束
#endif
函数setup_start_tag也在此文件中armlinux.c定义,如下:
static void setup_start_tag (bd_t *bd)
{
params = (struct tag *) bd->bi_boot_params; //bd->bi_boot_params=0x30000100,在此地址开始放参数,
//双方约定(bootloader和linux内核)的地址
params->hdr.tag = ATAG_CORE; //struct tag_header hdr结构体,ATAG_CORE=0x54410001,表示一个参数的开始
params->hdr.size = tag_size (tag_core); //tag_size(tag_core)=5
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next (params); //下一个tag = 当前位置+5*4
}
①对上述的bi_boot_params进行搜索,从u-boot-1.1.6\board\100ask24x0\100ask24x0.c 发现到 gd->bd->bi_boot_params = 0x30000100;
② hdr.tag: struct tag_header {
u32 size;u32 tag;
};
从u-boot-1.1.6\include\asm-avr32\setup.h中,可知ATAG_CORE=0x54410001。
③ struct tag_core {
u32 flags;
u32 pagesize;
u32 rootdev;
};
④ tag_size:
#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
(sizeof(struct tag_header):头部的大小,从上面的结构体tag_header可知,u32 + u32 = 64位,8字节
sizeof(struct type)=sizeof(tag_core) = u32 + u32 + u32 = 96位,12字节
((sizeof(struct tag_header) + sizeof(struct type)) >> 2) = ((8+12)>>2) = 20 / 4 = 5
所以tag_size=5。
⑤ u.core:
struct tag {
struct tag_header hdr; //结构体
union { //联合体
struct tag_core core;
…… …… ……
};
struct tag_core {
u32 flags; /* bit 0 = read-only */
u32 pagesize;
u32 rootdev;
};
⑥ #define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)),当前位置+头部的size,u32 *指针相加,指针加1,相当于加4。指针加5,相当于4*5,等于20
函数setup_memory_tags也在此文件中armlinux.c定义,如下:
static void setup_memory_tags (bd_t *bd)
{
int i;
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
params->hdr.tag = ATAG_MEM; //hdr.tag=0x54410002
params->hdr.size = tag_size (tag_mem32);
params->u.mem.start = bd->bi_dram[i].start; //起始地址=0x3000 0000
params->u.mem.size = bd->bi_dram[i].size; //大小等于64M,64*1024*1024
//所以u.mem.size=0x400 0000
params = tag_next (params);
}
}
#endif /* CONFIG_SETUP_MEMORY_TAGS */
① hdr.tag=0x54410002,当内核过来取参数时,根据这个值,知道这些参数代表什么意思
② #define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
tag_mem32=u32+u32=64位=8字节
(8字节+8字节) / 4 = 4字节
③ u.mem.start = 0x30000000
④ u.mem.size = 0x4000000
函数setup_commandline_tag也在此文件中armlinux.c定义,如下:
static void setup_commandline_tag (bd_t *bd, char *commandline)
{
char *p;
if (!commandline)
return;
/* eat leading white space */
for (p = commandline; *p == ' '; p++);
/* skip non-existent command lines so the kernel will still
* use its default command line.
*/
if (*p == '\0')
return;
params->hdr.tag = ATAG_CMDLINE; //hdr.tag=0x54410009
params->hdr.size =
(sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;
strcpy (params->u.cmdline.cmdline, p);
params = tag_next (params);
}
① hdr.tag=0x54410009,当内核过来取参数时,根据这个值,知道这些参数代表什么意思
函数setup_end_tag也在此文件中armlinux.c定义,如下:
static void setup_end_tag (bd_t *bd)
{
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
}
两个都是0。
最后写成:
#include "setup.h"
static struct tag *params;
void setup_start_tag(void)
{
params = (struct tag *) 0x30000100;
params->hdr.tag = ATAG_CORE;
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);
}
void setup_memory_tags(void)
{
params->hdr.tag = ATAG_MEM;
params->hdr.size = tag_size (tag_mem32);
params->u.mem.start = 0x30000000;
params->u.mem.size = 0x4000000;
params = tag_next (params);
}
int strlen(char *str)
{
int i = 0;
while (str[i])
{
i++;
}
return i;
}
void strcpy(char *dest, char *src)
{
char *tmp = dest;
while ((*dest++ = *src++) != '\0')
}
void setup_commandline_tag(char *cmdline)
{
int len = strlen(cmdline) + 1;
params->hdr.tag = ATAG_CMDLINE;
params->hdr.size = (sizeof (struct tag_header) + len + 3) >> 2;
strcpy (params->u.cmdline.cmdline, cmdline);
params = tag_next (params);
}
void setup_end_tag(void)
{
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
}
void main(void)
{
void (*theKernel)(int zero, int arch, unsigned int params);
/* 0. 帮内核设置串口 : 内核启动开始的部分会从串口打印一些信息,但是内核一开始没有初始化串口 */
uart0_init();
/* 1. 从NAND FLASH里把内核读入内存 */
puts("Copy kernel from nand\n\r");
nand_read(0x60000+64, 0x30008000, 0x200000);
/* 2. 设置参数 */
puts("Set boot params\n\r");
setup_start_tag(); //参数的开始
setup_memory_tags(); //告诉内核我的内存有多大
setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0"); //命令行参数
setup_end_tag(); //参数的结束
/* 3. 跳转执行 */
puts("Boot kernel\n\r");
theKernel = (void (*)(int, int, unsigned int))0x30008000;
theKernel(0, 362, 0x30000100);
/*
* mov r0, #0
* ldr r1, =362
* ldr r2, =0x30000100
* mov pc, #0x30008000 */
puts("Error\n\r");
/* 如果一切正常,不会执行到这里 */
}
参考:https://blog.csdn.net/lanmanck/article/details/4294685