浅析blob到kernel传递tags参数和cmdline处理流程 浅析blob到kernel传递tags参数和cmdline处理流程
浅析blob到kernel传递tags参数和cmdline处理流程
================================================================
1.blob
blob主程序main.c
int main(void)
{
...
/* initialise status */
blob_status.paramType = fromFlash;
blob_status.kernelType = fromFlash;
blob_status.ramdiskType = fromFlash;
blob_status.downloadSpeed = baud_115200;
blob_status.terminalSpeed = TERMINAL_SPEED;
blob_status.load_ramdisk = LOAD_RAMDISK;
blob_status.cmdline[0] = '/0';
blob_status.boot_delay = BLOB_BOOT_DELAY_TIME;
...
}
static void setup_commandline_tag(int argc, char *argv[])
{
...
/* initialise commandline */
params->u.cmdline.cmdline[0] = '/0';
/* copy default commandline from parameter block */
if(blob_status.cmdline[0] != '/0')
strlcpy(params->u.cmdline.cmdline, blob_status.cmdline,
COMMAND_LINE_SIZE);
/* copy commandline */
if(argc >= 2) {
p = params->u.cmdline.cmdline;
for(i = 1; i < argc; i++) {
strlcpy(p, argv[i], COMMAND_LINE_SIZE);
p += strlen(p);
*p++ = ' ';
}
...
}
...
if(strlen(params->u.cmdline.cmdline) > 0) {
params->hdr.tag = ATAG_CMDLINE;//tag传递cmdline
params->hdr.size = (sizeof(struct tag_header) +
strlen(params->u.cmdline.cmdline) + 1 + 4) >> 2;
params = tag_next(params);
}
}
static int boot_linux(int argc, char *argv[])
{
...
setup_start_tag();
setup_memory_tags();
setup_commandline_tag(argc, argv);
...
ramKernel(0, mach_type, BOOT_PARAMS);
...
}
static int boot_linux(int argc, char *argv[])
{
...
ramKernel(0, mach_type, BOOT_PARAMS);
...
}
static void (*ramKernel)(int zero, int arch, u32 params) =
(void (*)(int, int, u32)) KERNEL_RAM_BASE;
include/blob/arch/pxa_luther.h
#define KERNEL_RAM_BASE (0x80800000)//因为blob没有打开MMU,所以这里地址为DDR对应的物理地址
#define BOOT_PARAMS (0x80000100)//blob传递给kernel的tags物理存储地址,kenel会调用
所以ramKernel(0, mach_type, BOOT_PARAMS);将跳转到
pc=0x80800000处执行程序,
r0=0
r1=mach_type
r2=BOOT_PARAMS
================================================================
2.kernel
arch/arm/kernel/head.S
r0 = 0,
r1 = machine nr,
r2 = atags pointer.
.section ".text.head", "ax"
.type stext, %function
ENTRY(stext)//(0xc0000000) + 0x00008000 kernel入口
msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
@ and irqs disabled
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid
movs r10, r5 @ invalid processor (r5=0)?
beq __error_p @ yes, error 'p'
bl __lookup_machine_type @ r5=machinfo
movs r8, r5 @ invalid machine (r5=0)?
beq __error_a @ yes, error 'a'
bl __vet_atags
bl __create_page_tables
ldr r13, __switch_data @ address to jump to after
@ the initialization is done
adr lr, __after_proc_init @ return (PIC) address
add pc, r10, #PROCINFO_INITFUNC//调用b __arm920_setup
.type __after_proc_init, %function
__after_proc_init:
...
mov pc, r13 @ clear the BSS and jump//跳转到__switch_data执行程序,即执行:__mmap_switched函数
arch/arm/mm/proc-arm920.S
.type __arm920_setup, #function
__arm920_setup:
mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
#endif
adr r5, arm920_crval
ldmia r5, {r5, r6}
mrc p15, 0, r0, c1, c0 @ get control register v4
bic r0, r0, r5
orr r0, r0, r6
mov pc, lr//返回到__after_proc_init执行
arch/arm/kernel/head-common.S
ENTRY(lookup_processor_type)
stmfd {r4 - r7, r9, lr}
mov r9, r0
bl __lookup_processor_type//读取__proc_info_begin存储区的信息
mov r0, r5
ldmfd {r4 - r7, r9, pc}
.long __proc_info_begin
.long __proc_info_end
arch/arm/kernel/vmlinux.lds
__proc_info_begin = .;
*(.proc.info.init)
__proc_info_end = .;
比如:
arch/arm/mm/proc-arm920.S
.align
.section ".proc.info.init", #alloc, #execinstr
.type __arm920_proc_info,#object
__arm920_proc_info:
.long 0x41009200
.long 0xff00fff0
.long PMD_TYPE_SECT | /
PMD_SECT_BUFFERABLE | /
PMD_SECT_CACHEABLE | /
PMD_BIT4 | /
PMD_SECT_AP_WRITE | /
PMD_SECT_AP_READ
.long PMD_TYPE_SECT | /
PMD_BIT4 | /
PMD_SECT_AP_WRITE | /
PMD_SECT_AP_READ
b __arm920_setup
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
.long cpu_arm920_name
.long arm920_processor_functions
.long v4wbi_tlb_fns
.long v4wb_user_fns
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
.long arm920_cache_fns
#else
.long v4wt_cache_fns
#endif
.size __arm920_proc_info, . - __arm920_proc_info
arch/arm/kernel/head-common.S
.type __switch_data, %object
__switch_data:
.long __mmap_switched
.long __data_loc @ r4
.long __data_start @ r5
.long __bss_start @ r6
.long _end @ r7
.long processor_id @ r4
.long __machine_arch_type @ r5
.long __atags_pointer @ r6
.long cr_alignment @ r7
.long init_thread_union + THREAD_START_SP @ sp
...
.type __mmap_switched, %function
__mmap_switched:
adr r3, __switch_data + 4
ldmia {r4, r5, r6, r7}
cmp r4, r5 @ Copy data segment if needed
1: cmpne r5, r6
ldrne fp, [r4], #4
strne fp, [r5], #4
bne 1b
mov fp, #0 @ Clear BSS (and zero fp)
1: cmp r6, r7
strcc fp, [r6],#4
bcc 1b
ldmia r3, {r4, r5, r6, r7, sp}
str r9, [r4] @ Save processor ID
str r1, [r5] @ Save machine type
str r2, [r6] @ Save atags pointer//将blob传递进来的tags物理地址数值存入__atags_pointer指针中
bic r4, r0, #CR_A @ Clear 'A' bit
stmia r7, {r0, r4} @ Save control register values
b start_kernel //执行c函数
start_kernel
=>setup_arch(&command_line)//读出blob传进来的tags字符串参数,如果blob没有指定cmdline,那么使用make menuconfig指定的cmdline.
/*
setup_arch中首先对blob传递进来的tags们执行parse_tags解析,可能blob也传递cmdline命令行tag,所以这样blob传递的cmdline将去掉
make menuconfig内核自定义的cmdline.
arch/arm/kernel/setup.c|633| __tagtable(ATAG_CORE, parse_tag_core);
arch/arm/kernel/setup.c|649| __tagtable(ATAG_MEM, parse_tag_mem32);
arch/arm/kernel/setup.c|675| __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
arch/arm/kernel/setup.c|688| __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
arch/arm/kernel/setup.c|699| __tagtable(ATAG_INITRD, parse_tag_initrd);
arch/arm/kernel/setup.c|708| __tagtable(ATAG_INITRD2, parse_tag_initrd2);
arch/arm/kernel/setup.c|717| __tagtable(ATAG_SERIAL, parse_tag_serialnr);
arch/arm/kernel/setup.c|725| __tagtable(ATAG_REVISION, parse_tag_revision);
arch/arm/kernel/setup.c|733| __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
arch/arm/kernel/setup.c|751| __tagtable(ATAG_POWERUP_REASON, parse_tag_powerup_reason);
然后对cmdline命令行参数执行parse_cmdline
arch/arm/kernel/setup.c|458| __early_param("initrd=", early_initrd);
arch/arm/kernel/setup.c|503| __early_param("mem=", early_mem);
arch/arm/mm/mmu.c|124| __early_param("cachepolicy=", early_cachepolicy);
arch/arm/mm/mmu.c|132| __early_param("nocache", early_nocache);
arch/arm/mm/mmu.c|140| __early_param("nowb", early_nowrite);
arch/arm/mm/mmu.c|152| __early_param("ecc=", early_ecc);
*/
=>setup_command_line//设置cmdline
=>parse_early_param()//提前执行如下方法
/*
drivers/pci/pci.c|1667| early_param("pci", pci_setup);
init/main.c|154| early_param("nosmp", nosmp);
init/main.c|165| early_param("maxcpus", maxcpus);
init/main.c|245| early_param("debug", debug_kernel);
init/main.c|246| early_param("quiet", quiet_kernel);
init/main.c|254| early_param("loglevel", loglevel);
kernel/printk.c|488| early_param("ignore_loglevel", ignore_loglevel_setup);
mm/page_alloc.c|1976| early_param("numa_zonelist_order", setup_numa_zonelist_order);
mm/page_alloc.c|3941| early_param("kernelcore", cmdline_parse_kernelcore);
mm/page_alloc.c|3942| early_param("movablecore", cmdline_parse_movablecore);
*/
=>parse_args("Booting kernel", static_command_line, __start___param,
__stop___param - __start___param,
&unknown_bootoption);//所以__stop___param - __start___param等于0
/*
因为上面已经尝试执行early_param()等了,
现在尝试执行__setup()的命令.
arch/arm/kernel/process.c|82| __setup("nohlt", nohlt_setup);
arch/arm/kernel/process.c|83| __setup("hlt", hlt_setup);
arch/arm/kernel/process.c|186| __setup("reboot=", reboot_setup);
arch/arm/mach-pxa/pxa3xx.c|61| __setup("android", android_setup);
arch/arm/mach-pxa/pxa3xx.c|75| __setup("i2c_fastmode", i2c_fastmode_setup);
arch/arm/mach-pxa/pxa930.c|40| __setup("comm_v75", comm_v75_setup);
drivers/block/brd.c|407| __setup("ramdisk=", ramdisk_size);
drivers/block/brd.c|408| __setup("ramdisk_size=", ramdisk_size2);
drivers/video/fbmem.c|1654| __setup("video=", video_setup);
drivers/video/console/fbcon.c|548| __setup("fbcon=", fb_console_setup);
drivers/net/netconsole.c|64| __setup("netconsole=", option_setup);
drivers/serial/pxa.c|123| __setup("uart_dma", uart_dma_setup);
fs/nfs/nfsroot.c|400| __setup("nfsroot=", nfs_root_setup);
init/do_mounts.c|36| __setup("load_ramdisk=", load_ramdisk);
init/do_mounts.c|54| __setup("ro", readonly);
init/do_mounts.c|55| __setup("rw", readwrite);
init/do_mounts.c|125| __setup("root=", root_dev_setup);
init/do_mounts.c|135| __setup("rootwait", rootwait_setup);
init/do_mounts.c|158| __setup("rootflags=", root_data_setup);
init/do_mounts.c|159| __setup("rootfstype=", fs_names_setup);
init/do_mounts.c|160| __setup("rootdelay=", root_delay_setup);
init/main.c|188| __setup("reset_devices", set_reset_devices);
init/main.c|336| __setup("init=", init_setup);
init/main.c|348| __setup("rdinit=", rdinit_setup);
init/main.c|660| __setup("initcall_debug", initcall_debug_setup);
init/main.c|761| __setup("nosoftlockup", nosoftlockup_setup);
kernel/printk.c|185| __setup("log_buf_len=", log_buf_len_setup);
kernel/printk.c|199| __setup("console_loglevel=", console_loglevel_setup);
kernel/printk.c|224| __setup("boot_delay=", boot_delay_setup);
kernel/printk.c|881| __setup("console=", console_setup);
kernel/printk.c|949| __setup("no_console_suspend", console_suspend_disable);
net/ethernet/eth.c|63| __setup("ether=", netdev_boot_setup);
net/core/dev.c|551| __setup("netdev=", netdev_boot_setup);
net/ipv4/ipconfig.c|1541| __setup("ip=", ip_auto_config_setup);
net/ipv4/ipconfig.c|1542| __setup("nfsaddrs=", nfsaddrs_config_setup);
net/ipv4/ipconfig.c|1543| __setup("dhcpclass=", vendor_class_identifier_setup);
net/ipv4/tcp.c|2611| __setup("thash_entries=", set_thash_entries);
net/ipv4/route.c|2991| __setup("rhash_entries=", set_rhash_entries);
*/
==========================
void __init setup_arch(char **cmdline_p)
{
struct tag *tags = (struct tag *)&init_tags;
char *from = default_command_line;//从default_command_line读取cmdline命令行参数
...
if (__atags_pointer)//__atags_pointer为blob传进来的参数,优先考虑,对于我的就是上面blob定义的:
//#define BOOT_PARAMS (0x80000100)//blob传递给kernel的tags物理存储地址,kenel会调用
tags = phys_to_virt(__atags_pointer);
else if (mdesc->boot_params)//如果blob没有传递参数进来,那么查看默认的地址处,是否有合法的tags
tags = phys_to_virt(mdesc->boot_params);
...
if (tags->hdr.tag != ATAG_CORE)
convert_to_tag_list(tags);
if (tags->hdr.tag != ATAG_CORE)
tags = (struct tag *)&init_tags;//如果没有有效的tags,那么使用默认的init_tags
if (tags->hdr.tag == ATAG_CORE) {
if (meminfo.nr_banks != 0)
squash_mem_tags(tags);
save_atags(tags);
parse_tags(tags);//ok,调用tags解析处理函数
}
...
memcpy(boot_command_line, from, COMMAND_LINE_SIZE);//将default_command_line中的内容拷贝到boot_command_line中,
//因为之前经过了parse_tags(tags);操作,所以这时default_command_line中的内容可能是1.CONFIG_CMDLINE或者2.blob传递进来的cmdline.
boot_command_line[COMMAND_LINE_SIZE-1] = '/0';
parse_cmdline(cmdline_p, from);
//尝试解析cmdline中的early_params部分,这些设置需要提前被解析出来,比如"mem=",因为紧接着就要buddy内存.
//比如:"initrd=","mem=","cachepolicy=","nocache","nowb","ecc="等cmdline命令行.
paging_init(&meminfo, mdesc);
...
}
mdesc->boot_params位于
arch/arm/mach-pxa/luther.c
MACHINE_START(LUTHER, "luther")
.phys_io = 0x40000000,
.boot_params = 0xa0000100,
.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
.map_io = pxa_map_io,
.init_irq = pxa3xx_init_irq,
.timer = &pxa_timer,
.init_machine = luther_init,
MACHINE_END
=>setup_arch
==>parse_tags
==>parse_tag
static void __init parse_tags(const struct tag *t)
{
for (; t->hdr.size; t = tag_next(t))
if (!parse_tag(t))
printk(KERN_WARNING
"Ignoring unrecognised tag 0x%08x/n",
t->hdr.tag);
}
static int __init parse_tag(const struct tag *tag)
{
extern struct tagtable __tagtable_begin, __tagtable_end;
struct tagtable *t;
for (t = &__tagtable_begin; t < &__tagtable_end; t++)
if (tag->hdr.tag == t->tag) {
t->parse(tag);
break;
}
return t < &__tagtable_end;
}
#define __tag __used __attribute__((__section__(".taglist.init")))
#define __tagtable(tag, fn) /
static struct tagtable __tagtable_##fn __tag = { tag, fn }
arch/arm/kernel/vmlinux.lds
__tagtable_begin = .;
*(.taglist.init)
__tagtable_end = .;
arch/arm/kernel/setup.c
#ifdef CONFIG_CMDLINE_BOOL
static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
#endif
这里default_command_line的CONFIG_CMDLINE由make menuconfig生成,最后保存在include/linux/autoconf.h文件中[luther.gliethttp].
static int __init parse_tag_cmdline(const struct tag *tag)
{
strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
return 0;
}
#define ATAG_CMDLINE 0x54410009//如果blob传递了cmdline对应的tag进入kernel,那么覆盖CONFIG_CMDLINE编译时定义的参数字符串.
__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
arch/arm/kernel/setup.c|633| __tagtable(ATAG_CORE, parse_tag_core);
arch/arm/kernel/setup.c|649| __tagtable(ATAG_MEM, parse_tag_mem32);
arch/arm/kernel/setup.c|675| __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
arch/arm/kernel/setup.c|688| __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
arch/arm/kernel/setup.c|699| __tagtable(ATAG_INITRD, parse_tag_initrd);
arch/arm/kernel/setup.c|708| __tagtable(ATAG_INITRD2, parse_tag_initrd2);
arch/arm/kernel/setup.c|717| __tagtable(ATAG_SERIAL, parse_tag_serialnr);
arch/arm/kernel/setup.c|725| __tagtable(ATAG_REVISION, parse_tag_revision);
arch/arm/kernel/setup.c|733| __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
arch/arm/kernel/setup.c|751| __tagtable(ATAG_POWERUP_REASON, parse_tag_powerup_reason);
static void __init parse_cmdline(char **cmdline_p, char *from)
{
char c = ' ', *to = command_line;
int len = 0;
for (;;) {
if (c == ' ') {
extern struct early_params __early_begin, __early_end;
struct