1. 说明
uboot在引导kernel启动之前会将需要传递给Linux kernel的参数组织起来,传递给kernel。这个参数通过TAG的形式组织起来,然后存放在RAM的一个固定地址。kernel启动后从该地址读取TAG,获取uboot传递过来的参数。
2. TAG的结构
struct tag {
struct tag_header hdr; <span style="white-space:pre"> </span> /*TAG头部,每一种TAG都有*/
union {<span style="white-space:pre"> </span> /*TAG主体部分,不同TAG是不一样的*/
struct tag_core core;<span style="white-space:pre"> </span>/*标明TAG的开始*/
struct tag_mem32 mem;<span style="white-space:pre"> </span>/*系统内存*/
struct tag_videotext videotext; <span style="white-space:pre"> </span>/*VGA显示*/
struct tag_ramdisk ramdisk;
struct tag_initrd initrd; <span style="white-space:pre"> </span>/*initrd*/
struct tag_serialnr serialnr; <span style="white-space:pre"> </span>/*系列号*/
struct tag_revision revision; <span style="white-space:pre"> </span>/*版本号*/
struct tag_videolfb videolfb;<span style="white-space:pre"> </span>/*framebuffers*/
struct tag_cmdline cmdline;<span style="white-space:pre"> </span>/*cmdline命令,即bootargs*/
/*
* Acorn specific
*/
struct tag_acorn acorn;
/*
* DC21285 specific
*/
struct tag_memclk memclk;
} u;
};
下面列出常见的几种TAG的结构
1) header
struct tag_header {
u32 size; /*大小*/
u32 tag; /*标示*/
};
/* The list must start with an ATAG_CORE node */
#define ATAG_CORE 0x54410001
struct tag_core {
u32 flags; /* bit 0 = read-only */
u32 pagesize;
u32 rootdev;
};
3)memory
/* it is allowed to have multiple ATAG_MEM nodes */
#define ATAG_MEM 0x54410002
struct tag_mem32 {
u32 size;
u32 start; /* physical start address */
};
4) initrd
/* describes where the compressed ramdisk image lives (physical address) */
#define ATAG_INITRD2 0x54420005
struct tag_initrd {
u32 start; /* physical start address */
u32 size; /* size of compressed ramdisk image in bytes */
};
5) cmdline
/* command line: \0 terminated string */
#define ATAG_CMDLINE 0x54410009
struct tag_cmdline {
char cmdline[1]; /* this is the minimum size */
};</span>
arch/arm/lib/bootm.c
int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
{
bd_t *bd = gd->bd;
char *s;
int machid = bd->bi_arch_number;
void (*theKernel)(int zero, int arch, uint params);
#ifdef CONFIG_CMDLINE_TAG
char *commandline = getenv ("bootargs"); /*获取bootargs内容,后面会传递到cmdline中*/
#endif
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
theKernel = (void (*)(int, int, uint))images->ep;
s = getenv ("machid");
if (s) {
machid = simple_strtoul (s, NULL, 16);
printf ("Using machid 0x%x from environment\n", machid);
}
show_boot_progress (15);
debug ("## Transferring control to Linux (at address %08lx) ...\n",
(ulong) theKernel);
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
defined (CONFIG_CMDLINE_TAG) || \
defined (CONFIG_INITRD_TAG) || \
defined (CONFIG_SERIAL_TAG) || \
defined (CONFIG_REVISION_TAG)
<span style="font-family: Arial, Helvetica, sans-serif;">/*建立CORE TAG,TAG的起始位置为bd.bi_boot_params*/</span>
setup_start_tag (bd);
#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);
#endif
#ifdef CONFIG_CMDLINE_TAG
setup_commandline_tag (bd, commandline);
#endif
#ifdef CONFIG_INITRD_TAG
if (images->rd_start && images->rd_end)
setup_initrd_tag (bd, images->rd_start, images->rd_end);
#endif
setup_end_tag (bd);
#endif
/* we assume that the kernel is in place */
printf ("\nStarting kernel ...\n\n");
#ifdef CONFIG_USB_DEVICE
{
extern void udc_disconnect (void);
udc_disconnect ();
}
#endif
cleanup_before_linux ();
theKernel (0, machid, bd->bi_boot_params);
/* does not return */
return 1;
}
static void setup_start_tag (bd_t *bd)
{
params = (struct tag *) bd->bi_boot_params;
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);
}
</span>
static void setup_memory_tags (bd_t *bd)
{
int i;
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
params->hdr.tag = ATAG_MEM;
params->hdr.size = tag_size (tag_mem32);
params->u.mem.start = bd->bi_dram[i].start;
params->u.mem.size = bd->bi_dram[i].size;
params = tag_next (params);
}
}
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;
params->hdr.size =
(sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;
strcpy (params->u.cmdline.cmdline, p);
params = tag_next (params);
}
static void setup_initrd_tag (bd_t *bd, ulong initrd_start, ulong initrd_end)
{
/* an ATAG_INITRD node tells the kernel where the compressed
* ramdisk can be found. ATAG_RDIMG is a better name, actually.
*/
params->hdr.tag = ATAG_INITRD2;
params->hdr.size = tag_size (tag_initrd);
params->u.initrd.start = initrd_start;
params->u.initrd.size = initrd_end - initrd_start;
params = tag_next (params);
}
static void setup_end_tag (bd_t *bd)
{
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
}