Having finished the HW environment initialization, the bootloader needs to pass some kernel-boot parameters to kernel when it tries to start Kernel. Indeed, In addition to the common Command Line parameter, there are other indispensable parameters, such as system memory layout profile as well as vendor specific parameters.
This article describes:
1. The way bootloader organizes such info.
2. The approach Kernel gets such info.
Part 1:Bootloader (Provider):
A. Bootloader defines the memory area used to keep parameters (Linux organizes such parameters as TAGs) in
lk/target/m805_893x_evm/rules.mk:
#define BASE_ADDR := 0x80000000
#define TAGS_ADDR := BASE_ADDR+0x00000100 //0x80000100
#define KERNEL_ADDR := BASE_ADDR+0x00008000 //0x80008000
B. Bootloader calls boot_linux() to start Kernel.
The routine boot_linux() is defined in lk/app/aboot.c. The 2nd parameter is exact TAGS_ADDR.
(BTW, the 1st parameter is exact KERNEL_ADDR, the start address of kernel image)
The routine first defines a pointer point to TAGS_ADDR, then put all parameters into subsequent memory address:
unsigned *ptr = tags; //TAGS_ADDR
/* CORE */
*ptr++ = 2;
*ptr++ = ATAG_CORE; //TAG type
if (ramdisk_size) {
*ptr++ = 4;
*ptr++ = ATAG_INITRD2; //TAG type
*ptr++ = (unsigned)ramdisk; //Parameter
*ptr++ = ramdisk_size; //Parameter
}
ptr = target_atag_mem(ptr); //TAG_MEM: The memory allocated to Kernel
//ATAG_TCC_PMAP. The memory allocated to specific HW. Vendor specific
if (cmdline) {
cmdline_len = strlen(cmdline);
*ptr++ = 2 + ((cmdline_len + 3) / 4);
*ptr++ = ATAG_CMDLINE; //ATAG_CMDLINE
strcpy(ptr, cmdline);
ptr += (cmdline_len + 3) / 4; //command line paramters
}
/* tag for the board revision */
ptr = target_atag_revision(ptr);
ptr = target_atag_is_camera_enable(ptr);
......
/* END */
*ptr++ = 0; //ATAG_NONE
*ptr++ = 0; //ATAG_NONE
Up to now, the bootloader has made the TAGs ready. The TAGs are organized this way:
-------------------------- TAGS_ADDR
2 (the size of tag TAG_CORE)
TAG_CORE
--------------------------TAG 1 SIZE
TAG 1 TYPE
TAG 1 para (if any)
--------------------------
TAG 2 SIZE
TAG 2 TYPE
TAG 2 para (if any)
--------------------------
...--------------------------
TAG n SIZE
TAG n TYPE
TAG n para (if any)
--------------------------
TAG_NONE TAG_NONE
--------------------------
Part 2:Kernel (Consumer):
A. The kernel gets TAGs address via below macro in arch/arm/mach-tcc893x/board-m805_893x.c
MACHINE_START(M805_893X, "m805_893x")
/* Maintainer: Telechips Android BSP Team <android_ce@telechipc.com> */
.boot_params = PHYS_OFFSET + 0x00000100, //0x80000100
.reserve = tcc8930_mem_reserve,
.map_io = m805_893x_map_io,
.init_early = m805_893x_init_early,
.init_irq = m805_893x_init_irq,
.init_machine = m805_893x_init_machine,
.timer = &tcc893x_timer,
MACHINE_END
B. In arch/arm/kernel/setup.c, the routine setup_arch calls setup_machine_tags() in the same file to parse TAGs:
static struct machine_desc * __init setup_machine_tags(unsigned int nr)
{
......
if (__atags_pointer)
tags = phys_to_virt(__atags_pointer);
else if (mdesc->boot_params) {
#ifdef CONFIG_MMU
/*
* We still are executing with a minimal MMU mapping created
* with the presumption that the machine default for this
* is located in the first MB of RAM. Anything else will
* fault and silently hang the kernel at this point.
*/
if (mdesc->boot_params < PHYS_OFFSET ||
mdesc->boot_params >= PHYS_OFFSET + SZ_1M) {
printk(KERN_WARNING
"Default boot params at physical 0x%08lx out of reach\n",
mdesc->boot_params);
} else
#endif
{
tags = phys_to_virt(mdesc->boot_params); //Get TAGs physical address then turns it into virtual address.
}
}
#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
/*
* If we have the old style parameters, convert them to
* a tag list.
*/
if (tags->hdr.tag != ATAG_CORE)
convert_to_tag_list(tags);
#endif
if (tags->hdr.tag != ATAG_CORE) {
#if defined(CONFIG_OF)
/*
* If CONFIG_OF is set, then assume this is a reasonably
* modern system that should pass boot parameters
*/
early_print("Warning: Neither atags nor dtb found\n");
#endif
tags = (struct tag *)&init_tags;
}
if (mdesc->fixup)
mdesc->fixup(mdesc, tags, &from, &meminfo);
if (tags->hdr.tag == ATAG_CORE) {
if (meminfo.nr_banks != 0)
squash_mem_tags(tags);
save_atags(tags);
parse_tags(tags); //Calls TAG handlers to parse TAG.
}
/* parse_early_param needs a boot_command_line */
strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
return mdesc;
}
PS: There is NO TAG packages in 8900 BSP!