您的位置:首页 > 其它

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

2012-02-15 18:24 537 查看
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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: