您的位置:首页 > 其它

浅析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
==========================
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: