学习笔记:内核启动流程

⒈内核的配置:
Ⅰ、cp config_ok .config
Ⅱ、make uImage时:
.config生成include/linux/autoconf.h
.config生成include/config/auto.conf,被顶层Makefile包含,子目录下的Makefile用它。
⒉分析Makefile:
找到第一个文件:提纲挈领,顺藤摸瓜
链接脚本:内核放在那里,里面的东西是怎么排布的
Ⅰ、uImage: vmlinux

 zImage Image xipImage bootpImage uImage: vmlinux
 $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@   

Ⅱ、vmlinux: vmlinux-lds vmlinux-init vmlinux-main kallsyms.o

vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE

⑴、vmlinux-init

vmlinux-init := $(head-y) $(init-y)

①、head-y

head-y      := arch/arm/kernel/head$(MMUEXT).o                 arch/arm/kernel/init_task.o

②、init-y

init-y      := init/
init-y      := $(patsubst %/, %/built-in.o, $(init-y))

⑵、vmlinux-main

vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)

①、core-y

core-y      := usr/
core-y      += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
core-y      := $(patsubst %/, %/built-in.o, $(core-y))

②、libs-y

libs-y      := lib/
libs-y1     := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2     := $(patsubst %/, %/built-in.o, $(libs-y))
libs-y      := $(libs-y1) $(libs-y2)

③、drivers-y

drivers-y   := drivers/ sound/
drivers-y   := $(patsubst %/, %/built-in.o, $(drivers-y))

④、net-y

net-y       := net/
net-y       := $(patsubst %/, %/built-in.o, $(net-y))

Ⅲ、

vmlinux-all  := $(vmlinux-init) $(vmlinux-main)
vmlinux-lds  := arch/$(ARCH)/kernel/vmlinux.lds
export KBUILD_VMLINUX_OBJS := $(vmlinux-all)

Ⅳ、在编译uImage时原材料按以下方式组成内核

arm-linux-ld -EL  -p --no-undefined -X -o vmlinux 
-T arch/arm/kernel/vmlinux.lds 
arch/arm/kernel/head.o 
arch/arm/kernel/init_task.o  
init/built-in.o 
--start-group  
usr/built-in.o  arch/arm/kernel/built-in.o  arch/arm/mm/built-in.o  arch/arm/common/built-in.o  arch/arm/mach-s3c2410/built-in.o  arch/arm/mach-s3c2400/built-in.o  arch/arm/mach-s3c2412/built-in.o  arch/arm/mach-s3c2440/built-in.o  arch/arm/mach-s3c2442/built-in.o  arch/arm/mach-s3c2443/built-in.o  arch/arm/nwfpe/built-in.o  arch/arm/plat-s3c24xx/built-in.o  kernel/built-in.o  mm/built-in.o  fs/built-in.o  ipc/built-in.o  security/built-in.o  crypto/built-in.o  block/built-in.o  arch/arm/lib/lib.a  lib/lib.a  arch/arm/lib/built-in.o  lib/built-in.o  drivers/built-in.o  sound/built-in.o  net/built-in.o 
--end-group 
.tmp_kallsyms2.o

由此,我们找到了第一个文件:

arch/arm/kernel/head.S   

链接脚本:

arch/arm/kernel/vmlinux.lds                                 

3.分析head.S文件
Ⅰ、u-boot的传入参数有
⑴、机器ID
⑵、启动参数
Ⅱ、head.S主要功能:
⑴、判断是否支持这个CPU

bl  __lookup_processor_type

⑵、判断是否支持这个单板,机器ID在这步进行匹配

bl  __lookup_machine_type

⑶、建立页表

bl  __create_page_tables

⑷、使能MMU

adr lr, __enable_mmu

⑸、跳到linux-2.6.22.6\init\main.c:start_kernel函数,启动参数会在linux-2.6.22.6\init\main.c:start_kernel函数中处理
启动参数处理函数:

    setup_arch(&command_line);
    setup_command_line(command_line);

4、挂载根文件系统:(☞☞:调用)

linux-2.6.22.6\init\main.c:asmlinkage void __init start_kernel(void)

☞☞

linux-2.6.22.6\init\main.c:static void noinline __init_refok rest_init(void)
{
    ...
    kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
    ...
}

☞☞

linux-2.6.22.6\init\main.c:static int __init kernel_init(void * unused)

☞☞

linux-2.6.22.6\init\do_mounts.c:void __init prepare_namespace(void)

☞☞

linux-2.6.22.6\init\do_mounts.c:void __init mount_root(void)

5、通过以上步骤挂载好根文件系统后调用linux-2.6.22.6\init\main.c:init_post函数执行第一个应用程序

static int noinline init_post(void)
{
    ...
    if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
    ...
    if (execute_command) {
    run_init_process(execute_command);
    printk(KERN_WARNING "Failed to execute %s. Attempting "
                    "defaults...\n", execute_command);
    run_init_process("/sbin/init");
    run_init_process("/etc/init");
    run_init_process("/bin/init");
    run_init_process("/bin/sh");                    
    }
    ...
}

其中execute_command指针地址上得内容如下可得,是命令行参数init的值,宏__setup("init=", init_setup)会调用linux-2.6.22.6\init\main.c:init_setup函数将命令行参数传到execute_command保存的地址上去:

static char *execute_command;
static int __init init_setup(char *str)
{
    unsigned int i;

    execute_command = str;
    /*
     * In case LILO is going to boot us with default command line,
     * it prepends "auto" before the whole cmdline which makes
     * the shell think it should execute a script with such name.
     * So we ignore all arguments entered _before_ init=... [MJ]
     */
    for (i = 1; i < MAX_INIT_ARGS; i++)
        argv_init[i] = NULL;
    return 1;
}
__setup("init=", init_setup);

__setup("init=", init_setup)在如下定义
linux-2.6.22.6\linux-2.6.22.6\include\linux\init.h:

#define __setup(str, fn) \ __setup_param(str, fn, fn, 0)
#define __setup_param(str, unique_id, fn, early) \
    static char __setup_str_##unique_id[] __initdata = str; \
    static struct obs_kernel_param __setup_##unique_id \
        __attribute_used__              \
        __attribute__((__section__(".init.setup"))) \
        __attribute__((aligned((sizeof(long)))))    \
        = { __setup_str_##unique_id, fn, early }

学习笔记:内核启动流程_第1张图片

你可能感兴趣的:(内核,makefile)