linux cmdline学习笔记

来源:互联网 发布:it基础知识 编辑:程序博客网 时间:2024/06/06 07:17

内核启动的时候有这样一条打印信息:

[    0.000000]Kernel command line: mem=524256K@0x20000000 console=ttyGS0…………

这条打印信息的源代码在init/main.c中的start_kernel()函数中:

printk(KERN_NOTICE"Kernel command line: %s\n", boot_command_line);

可见,cmdline字符串是保存在boot_command_line中的。

boot_command_line是在init/main.c中定义的一个字符数组:

char __initdata boot_command_line[COMMAND_LINE_SIZE];

并且在init.h中有对这个boot_command_line的声明:

extern char __initdataboot_command_line[];

解析cmdline的操作是由parse_early_param()函数执行的。

然而,setup_arch()在调用parse_early_param()前会调用setup_machine_tags()

setup_machine_tags()中有如下代码:

static struct machine_desc * __init setup_machine_tags(unsigned int nr){…………char *from = default_command_line;…………if (__atags_pointer)tags = phys_to_virt(__atags_pointer);else if (mdesc->boot_params) {…………}…………if (tags->hdr.tag == ATAG_CORE) {if (meminfo.nr_banks != 0)squash_mem_tags(tags);save_atags(tags);parse_tags(tags);}/* parse_early_param needs a boot_command_line */strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);return mdesc;}

在setup.c中有如下定义:

static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
CONFIG_CMDLINE应该是在Makefile中定义的或在编译过程中生成的一个字符串。


但是,在setup_machine_tags中,复制cmdline字符串到boot_command_line中之前,会调用parse_tags函数,这个函数会解析所有的tag并对cmdline的tag调用下面这个函数。

static int __init parse_tag_cmdline(const struct tag *tag){#if defined(CONFIG_CMDLINE_EXTEND)strlcat(default_command_line, " ", COMMAND_LINE_SIZE);strlcat(default_command_line, tag->u.cmdline.cmdline,COMMAND_LINE_SIZE);#elif defined(CONFIG_CMDLINE_FORCE)pr_warning("Ignoring tag cmdline (using the default kernel command line)\n");#elsestrlcpy(default_command_line, tag->u.cmdline.cmdline,COMMAND_LINE_SIZE);#endifreturn 0;}__tagtable(ATAG_CMDLINE, parse_tag_cmdline);

其中CONFIG_CMDLINE_EXTEND和CONFIG_CMDLINE_FORCE都没有定义,那么default_command_line的初始值在这里被tag->u.cmdline.cmdline覆盖。

那么parse_tag_cmdline是怎么被调用的呢,这个就是一个叫做“自动数组”的机制的功劳了。其实就是利用__tagtable把这个函数信息放到了自动数组里面了。

__tagtable的定义在setup.h中:

#define __tag __used __attribute__((__section__(".taglist.init")))#define __tagtable(tag, fn) \static struct tagtable __tagtable_##fn __tag = { tag, fn }

可见这种静态定义的结构体被放到了一个特定的段中。


现在再来看一看tags是怎么来的。

setup_machine_tags()中有如下一段代码:

if (__atags_pointer)tags = phys_to_virt(__atags_pointer);

__atags_pointer是什么?它实际就是bootloader中存储tags的地址,把这个地址转换为虚拟地址,内核就得到了bootloader创建的tags。

 

有网上资料说:内核(arch/arm/kernel/head-common.S中的__mmap_switched)将这个地址存入__atags_pointer(定义于arch/arm/kernel/setup.c)。下面分析一下这段代码:

__INIT__mmap_switched:adrr3, __mmap_switched_dataldmiar3!, {r4, r5, r6, r7}cmpr4, r5@ Copy data segment if needed1:cmpner5, r6ldrnefp, [r4], #4strnefp, [r5], #4bne1bmovfp, #0@ Clear BSS (and zero fp)1:cmpr6, r7strccfp, [r6],#4bcc1b ARM(ldmiar3, {r4, r5, r6, r7, sp}) /* 这样__atags_pointer的地址就保存在R6中了 */ THUMB(ldmiar3, {r4, r5, r6, r7}) THUMB(ldrsp, [r3, #16])strr9, [r4]@ Save processor IDstrr1, [r5]@ Save machine typestrr2, [r6]@ Save atags pointer /* 保存atags地址 */bicr4, r0, #CR_A@ Clear 'A' bitstmiar7, {r0, r4}@ Save control register valuesbstart_kernelENDPROC(__mmap_switched)//----------------------------------------.align2.type__mmap_switched_data, %object__mmap_switched_data:.long__data_loc@ r4.long_sdata@ r5.long__bss_start@ r6.long_end@ r7.longprocessor_id@ r4.long__machine_arch_type@ r5.long__atags_pointer@ r6 /* 声明一个long型数据,数据的内容是__atags_pointer的地址 */.longcr_alignment@ r7.longinit_thread_union + THREAD_START_SP @ sp.size__mmap_switched_data, . - __mmap_switched_data

bootloader中,通常是这样跳转到linux的:

static void boot_linux(unsigned kaddr){    void (*entry)(unsigned,unsigned,unsigned) = (void*) kaddr;    entry(0, board_machtype(), linux_tags);}

可以看出tags的地址是放在r2寄存器中的。



0 0
原创粉丝点击