浅析blob到kernel传递tags参数和cmdline处理流程
2009-12-10 23:17
330 查看
浅析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 early_params *p; for (p = &__early_begin; p < &__early_end; p++) { int len = strlen(p->arg); if (memcmp(from, p->arg, len) == 0) { if (to != command_line) to -= 1; from += len; p->fn(&from); while (*from != ' ' && *from != '/0') from++; break; } } } c = *from++; if (!c) break; if (COMMAND_LINE_SIZE <= ++len) break; *to++ = c; } *to = '/0'; *cmdline_p = command_line; } arch/arm/kernel/vmlinux.lds __early_begin = .; *(.early_param.init) __early_end = .; #define __early_param(name,fn) / static struct early_params __early_##fn __used / __attribute__((__section__(".early_param.init"))) = { name, fn } 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); ========================== static void __init setup_command_line(char *command_line) { saved_command_line = alloc_bootmem(strlen (boot_command_line)+1);//申请内存 static_command_line = alloc_bootmem(strlen (command_line)+1); strcpy (saved_command_line, boot_command_line); strcpy (static_command_line, command_line); //拷贝命令行参数字符串,因为setup_arch中,已经将default_command_line拷贝到了boot_command_line, //所以该操作之后,saved_command_line和static_command_line中的cmdline字符串就是default_command_line中的字符串了, //而default_command_line在setup_arch中经过了parse_tags(tags);操作, //所以default_command_line中的内容可能是1.CONFIG_CMDLINE或者2.blob传递进来的cmdline. } ========================== static int parse_one(char *param, char *val, struct kernel_param *params, unsigned num_params, int (*handle_unknown)(char *param, char *val)) { unsigned int i; /* Find parameter */ for (i = 0; i < num_params; i++) {//没有调用 if (parameq(param, params[i].name)) { DEBUGP("They are equal! Calling %p/n", params[i].set); return params[i].set(val, ¶ms[i]); } } if (handle_unknown) {//调用该方法处理该param,如:do_early_param DEBUGP("Unknown argument: calling %p/n", handle_unknown); return handle_unknown(param, val); } DEBUGP("Unknown argument `%s'/n", param); return -ENOENT; } int parse_args(const char *name, char *args, struct kernel_param *params, unsigned num, int (*unknown)(char *param, char *val)) { char *param, *val; DEBUGP("Parsing ARGS: %s/n", args); /* Chew leading spaces */ while (*args == ' ') args++; while (*args) { int ret; int irq_was_disabled; args = next_arg(args, ¶m, &val);//获得参数字符串直到下一个空格或NULL irq_was_disabled = irqs_disabled(); ret = parse_one(param, val, params, num, unknown); if (irq_was_disabled && !irqs_disabled()) { printk(KERN_WARNING "parse_args(): option '%s' enabled " "irq's!/n", param); } switch (ret) { case -ENOENT: printk(KERN_ERR "%s: Unknown parameter `%s'/n", name, param); return ret; case -ENOSPC: printk(KERN_ERR "%s: `%s' too large for parameter `%s'/n", name, val ?: "", param); return ret; case 0: break; default: printk(KERN_ERR "%s: `%s' invalid for parameter `%s'/n", name, val ?: "", param); return ret; } } /* All parsed OK. */ return 0; } static int __init do_early_param(char *param, char *val) { struct obs_kernel_param *p; for (p = __setup_start; p < __setup_end; p++) { if ((p->early && strcmp(param, p->str) == 0) || (strcmp(param, "console") == 0 && strcmp(p->str, "earlycon") == 0) ) { if (p->setup_func(val) != 0) printk(KERN_WARNING "Malformed early option '%s'/n", param); } } /* We accept everything at this stage. */ return 0; } /* Arch code calls this early on, or if not, just before other parsing. */ void __init parse_early_param(void) { static __initdata int done = 0; static __initdata char tmp_cmdline[COMMAND_LINE_SIZE]; if (done) return; //解析cmdline命令行,可能是1.CONFIG_CMDLINE或者2.blob传递进来的cmdline. /* All fall through to do_early_param. */ strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE); parse_args("early options", tmp_cmdline, NULL, 0, do_early_param); done = 1; } arch/arm/kernel/vmlinux.lds __setup_start = .; *(.init.setup) __setup_end = .; #define __setup_param(str, unique_id, fn, early) / static char __setup_str_##unique_id[] __initdata __aligned(1) = str; / static struct obs_kernel_param __setup_##unique_id / __used __section(.init.setup) / __attribute__((aligned((sizeof(long))))) / = { __setup_str_##unique_id, fn, early } #define __setup_null_param(str, unique_id) / __setup_param(str, unique_id, NULL, 0) #define __setup(str, fn) / __setup_param(str, fn, fn, 0) /* NOTE: fn is as per module_param, not __setup! Emits warning if fn * returns non-zero. */ #define early_param(str, fn) / __setup_param(str, fn, fn, 1) 所以__setup_param,__setup_null_param,__setup,early_param都是定义存储到该区间的宏. 最后只有: __setup和early_param被driver们所使用. 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); 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); ========================== parse_args("Booting kernel", static_command_line, __start___param, __stop___param - __start___param, &unknown_bootoption); arch/arm/kernel/vmlinux.lds __start___param = .; *(__param) //为kernel buit in的内容,我的kernel没有定义该存储区段 __stop___param = .; =>parse_args("Booting kernel", static_command_line, __start___param, __stop___param - __start___param,//所以__stop___param - __start___param等于0 &unknown_bootoption) static int __init unknown_bootoption(char *param, char *val) { /* Change NUL term back to "=", to make "param" the whole string. */ if (val) { /* param=val or param="val"? */ if (val == param+strlen(param)+1) val[-1] = '='; else if (val == param+strlen(param)+2) { val[-2] = '='; memmove(val-1, val, strlen(val)+1); val--; } else BUG(); } /* Handle obsolete-style parameters */ if (obsolete_checksetup(param))//尝试处理 return 0;//成功找到built in的param处理函数,并已处理之[luther.gliethttp] /* * Preemptive maintenance for "why didn't my misspelled command * line work?" */ if (strchr(param, '.') && (!val || strchr(param, '.') < val)) { printk(KERN_ERR "Unknown boot option `%s': ignoring/n", param); return 0; } if (panic_later) return 0; //如果cmdline的参数在built in的param中没有找到对应的处理函数,那么将作为init进程的参数或者环境变量 //传递给init进程[luther.gliethttp] if (val) { /* Environment option */ unsigned int i; for (i = 0; envp_init[i]; i++) { if (i == MAX_INIT_ENVS) { panic_later = "Too many boot env vars at `%s'"; panic_param = param; } if (!strncmp(param, envp_init[i], val - param)) break; } envp_init[i] = param;//添加到init环境变量中 } else { /* Command line option */ unsigned int i; for (i = 0; argv_init[i]; i++) { if (i == MAX_INIT_ARGS) { panic_later = "Too many boot init vars at `%s'"; panic_param = param;//添加到init程序参数中 } } argv_init[i] = param; } /* 以上参数在init进程执行时,传递个init程序的环境变量和程序参数[luther.gliethttp] start_kernel =>rest_init =>kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); =>kernel_init =>init_post =>run_init_process static void run_init_process(char *init_filename) { argv_init[0] = init_filename; kernel_execve(init_filename, argv_init, envp_init); } */ return 0; } static int __init obsolete_checksetup(char *line) { struct obs_kernel_param *p; int had_early_param = 0; p = __setup_start; do { int n = strlen(p->str); if (!strncmp(line, p->str, n)) {//比较所有param存储区中的数据项 if (p->early) {//对于early属性的param,我们已经在上面的parse_early_param()中搞定了[luther.gliethttp] /* Already done in parse_early_param? * (Needs exact match on param part). * Keep iterating, as we can have early * params and __setups of same names 8( */ if (line[n] == '/0' || line[n] == '=') had_early_param = 1; } else if (!p->setup_func) { printk(KERN_WARNING "Parameter %s is obsolete," " ignored/n", p->str); return 1; } else if (p->setup_func(line + n))//执行之 return 1; } p++; } while (p < __setup_end); return had_early_param; } ========================== Kernel command line: ip=192.168.100.2:192.168.100.1::255.255.255.0::usb0:on console=ttyS0,115200 mem=112M init=/init android comm_v75 i2c_fastmode initcall_debug uart_dma ip_auto_config_setup ip=192.168.100.2:192.168.100.1::255.255.255.0::usb0:on console_setup console=ttyS0,115200 early_mem mem=112M init_setup init=/init android_setup android comm_v75_setup comm_v75 i2c_fastmode_setup i2c_fastmode initcall_debug_setup initcall_debug uart_dma_setup uart_dma ==========================
浅析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 early_params *p; for (p = &__early_begin; p < &__early_end; p++) { int len = strlen(p->arg); if (memcmp(from, p->arg, len) == 0) { if (to != command_line) to -= 1; from += len; p->fn(&from); while (*from != ' ' && *from != '/0') from++; break; } } } c = *from++; if (!c) break; if (COMMAND_LINE_SIZE <= ++len) break; *to++ = c; } *to = '/0'; *cmdline_p = command_line; } arch/arm/kernel/vmlinux.lds __early_begin = .; *(.early_param.init) __early_end = .; #define __early_param(name,fn) / static struct early_params __early_##fn __used / __attribute__((__section__(".early_param.init"))) = { name, fn } 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); ========================== static void __init setup_command_line(char *command_line) { saved_command_line = alloc_bootmem(strlen (boot_command_line)+1);//申请内存 static_command_line = alloc_bootmem(strlen (command_line)+1); strcpy (saved_command_line, boot_command_line); strcpy (static_command_line, command_line); //拷贝命令行参数字符串,因为setup_arch中,已经将default_command_line拷贝到了boot_command_line, //所以该操作之后,saved_command_line和static_command_line中的cmdline字符串就是default_command_line中的字符串了, //而default_command_line在setup_arch中经过了parse_tags(tags);操作, //所以default_command_line中的内容可能是1.CONFIG_CMDLINE或者2.blob传递进来的cmdline. } ========================== static int parse_one(char *param, char *val, struct kernel_param *params, unsigned num_params, int (*handle_unknown)(char *param, char *val)) { unsigned int i; /* Find parameter */ for (i = 0; i < num_params; i++) {//没有调用 if (parameq(param, params[i].name)) { DEBUGP("They are equal! Calling %p/n", params[i].set); return params[i].set(val, ¶ms[i]); } } if (handle_unknown) {//调用该方法处理该param,如:do_early_param DEBUGP("Unknown argument: calling %p/n", handle_unknown); return handle_unknown(param, val); } DEBUGP("Unknown argument `%s'/n", param); return -ENOENT; } int parse_args(const char *name, char *args, struct kernel_param *params, unsigned num, int (*unknown)(char *param, char *val)) { char *param, *val; DEBUGP("Parsing ARGS: %s/n", args); /* Chew leading spaces */ while (*args == ' ') args++; while (*args) { int ret; int irq_was_disabled; args = next_arg(args, ¶m, &val);//获得参数字符串直到下一个空格或NULL irq_was_disabled = irqs_disabled(); ret = parse_one(param, val, params, num, unknown); if (irq_was_disabled && !irqs_disabled()) { printk(KERN_WARNING "parse_args(): option '%s' enabled " "irq's!/n", param); } switch (ret) { case -ENOENT: printk(KERN_ERR "%s: Unknown parameter `%s'/n", name, param); return ret; case -ENOSPC: printk(KERN_ERR "%s: `%s' too large for parameter `%s'/n", name, val ?: "", param); return ret; case 0: break; default: printk(KERN_ERR "%s: `%s' invalid for parameter `%s'/n", name, val ?: "", param); return ret; } } /* All parsed OK. */ return 0; } static int __init do_early_param(char *param, char *val) { struct obs_kernel_param *p; for (p = __setup_start; p < __setup_end; p++) { if ((p->early && strcmp(param, p->str) == 0) || (strcmp(param, "console") == 0 && strcmp(p->str, "earlycon") == 0) ) { if (p->setup_func(val) != 0) printk(KERN_WARNING "Malformed early option '%s'/n", param); } } /* We accept everything at this stage. */ return 0; } /* Arch code calls this early on, or if not, just before other parsing. */ void __init parse_early_param(void) { static __initdata int done = 0; static __initdata char tmp_cmdline[COMMAND_LINE_SIZE]; if (done) return; //解析cmdline命令行,可能是1.CONFIG_CMDLINE或者2.blob传递进来的cmdline. /* All fall through to do_early_param. */ strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE); parse_args("early options", tmp_cmdline, NULL, 0, do_early_param); done = 1; } arch/arm/kernel/vmlinux.lds __setup_start = .; *(.init.setup) __setup_end = .; #define __setup_param(str, unique_id, fn, early) / static char __setup_str_##unique_id[] __initdata __aligned(1) = str; / static struct obs_kernel_param __setup_##unique_id / __used __section(.init.setup) / __attribute__((aligned((sizeof(long))))) / = { __setup_str_##unique_id, fn, early } #define __setup_null_param(str, unique_id) / __setup_param(str, unique_id, NULL, 0) #define __setup(str, fn) / __setup_param(str, fn, fn, 0) /* NOTE: fn is as per module_param, not __setup! Emits warning if fn * returns non-zero. */ #define early_param(str, fn) / __setup_param(str, fn, fn, 1) 所以__setup_param,__setup_null_param,__setup,early_param都是定义存储到该区间的宏. 最后只有: __setup和early_param被driver们所使用. 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); 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); ========================== parse_args("Booting kernel", static_command_line, __start___param, __stop___param - __start___param, &unknown_bootoption); arch/arm/kernel/vmlinux.lds __start___param = .; *(__param) //为kernel buit in的内容,我的kernel没有定义该存储区段 __stop___param = .; =>parse_args("Booting kernel", static_command_line, __start___param, __stop___param - __start___param,//所以__stop___param - __start___param等于0 &unknown_bootoption) static int __init unknown_bootoption(char *param, char *val) { /* Change NUL term back to "=", to make "param" the whole string. */ if (val) { /* param=val or param="val"? */ if (val == param+strlen(param)+1) val[-1] = '='; else if (val == param+strlen(param)+2) { val[-2] = '='; memmove(val-1, val, strlen(val)+1); val--; } else BUG(); } /* Handle obsolete-style parameters */ if (obsolete_checksetup(param))//尝试处理 return 0;//成功找到built in的param处理函数,并已处理之[luther.gliethttp] /* * Preemptive maintenance for "why didn't my misspelled command * line work?" */ if (strchr(param, '.') && (!val || strchr(param, '.') < val)) { printk(KERN_ERR "Unknown boot option `%s': ignoring/n", param); return 0; } if (panic_later) return 0; //如果cmdline的参数在built in的param中没有找到对应的处理函数,那么将作为init进程的参数或者环境变量 //传递给init进程[luther.gliethttp] if (val) { /* Environment option */ unsigned int i; for (i = 0; envp_init[i]; i++) { if (i == MAX_INIT_ENVS) { panic_later = "Too many boot env vars at `%s'"; panic_param = param; } if (!strncmp(param, envp_init[i], val - param)) break; } envp_init[i] = param;//添加到init环境变量中 } else { /* Command line option */ unsigned int i; for (i = 0; argv_init[i]; i++) { if (i == MAX_INIT_ARGS) { panic_later = "Too many boot init vars at `%s'"; panic_param = param;//添加到init程序参数中 } } argv_init[i] = param; } /* 以上参数在init进程执行时,传递个init程序的环境变量和程序参数[luther.gliethttp] start_kernel =>rest_init =>kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); =>kernel_init =>init_post =>run_init_process static void run_init_process(char *init_filename) { argv_init[0] = init_filename; kernel_execve(init_filename, argv_init, envp_init); } */ return 0; } static int __init obsolete_checksetup(char *line) { struct obs_kernel_param *p; int had_early_param = 0; p = __setup_start; do { int n = strlen(p->str); if (!strncmp(line, p->str, n)) {//比较所有param存储区中的数据项 if (p->early) {//对于early属性的param,我们已经在上面的parse_early_param()中搞定了[luther.gliethttp] /* Already done in parse_early_param? * (Needs exact match on param part). * Keep iterating, as we can have early * params and __setups of same names 8( */ if (line[n] == '/0' || line[n] == '=') had_early_param = 1; } else if (!p->setup_func) { printk(KERN_WARNING "Parameter %s is obsolete," " ignored/n", p->str); return 1; } else if (p->setup_func(line + n))//执行之 return 1; } p++; } while (p < __setup_end); return had_early_param; } ========================== Kernel command line: ip=192.168.100.2:192.168.100.1::255.255.255.0::usb0:on console=ttyS0,115200 mem=112M init=/init android comm_v75 i2c_fastmode initcall_debug uart_dma ip_auto_config_setup ip=192.168.100.2:192.168.100.1::255.255.255.0::usb0:on console_setup console=ttyS0,115200 early_mem mem=112M init_setup init=/init android_setup android comm_v75_setup comm_v75 i2c_fastmode_setup i2c_fastmode initcall_debug_setup initcall_debug uart_dma_setup uart_dma ==========================
相关文章推荐
- 浅析blob到kernel传递tags参数和cmdline处理流程
- u-boot 到 kernel 传递参数的流程
- [Misc]利用cmdline,将参数从preloader传递到kernel
- android 利用cmdline,将参数从preloader传递到kernel [MTK通用]
- android 利用cmdline,将参数从preloader传递到kernel
- android 利用cmdline,将参数从preloader传递到kernel
- Universal-ImageLoader源码流程浅析之(一)--参数配置及主要参数说明
- Storm处理流程, 基本参数配置
- 浅析frmware的加载和init通过netlink处理uevent事件的一般流程(转)
- 在js传递参数中含加号(+)的处理方式
- 浅谈在js传递参数中含加号(+)的处理方式
- window.showModalDialog参数传递中含有特殊字符的处理方法
- Spring(四):spring mvc模型数据传递、请求参数处理
- vuex actions传递多参数的处理方法
- Linux Kernel Module 中传递参数
- jsp中URL传递中文参数的处理方法
- 细说webpack源码之compile流程-rules参数处理技巧(2)
- 第6章创建函数-----------(在函数中使用变量、向函数传递参数、在函数中处理变量、关键字local)
- Bootloader与Kernel间参数传递机制 taglist【转】