现在的位置: 首页 > 综合 > 正文

浅析blob到kernel传递tags参数和cmdline处理流程

2013年10月19日 ⁄ 综合 ⁄ 共 14184字 ⁄ 字号 评论关闭

浅析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

抱歉!评论已关闭.