Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15357893
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: LINUX

2008-10-17 14:36:49

浅析blob到kernel传递tags参数和cmdline处理流程
2.6.30.4内核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, &params[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, &param, &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
==========================

阅读(3919) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~