美文网首页
[Boot]Kernel启动

[Boot]Kernel启动

作者: Letcos | 来源:发表于2020-02-25 14:32 被阅读0次
    platform:RK3399
    OS:Android 7.1
    Kernel:4.4
    参考:
    1.Younix 《Android启动流程分析》
    

    概述

    Uboot最后阶段通过do_bootm_linux跳转到内核,此时内核开始运行,uboot任务完成。之后内核会完成一系列的初始化和注册,最终启动init进程(pid=1)和kthreadd(pid=2),并进入idle.

    整体介绍

    在这里插入图片描述

    start_kernel

    函数名 定义目录 简介
    lockdep_init() kernel/locking/lockdep.c 初始化运行时锁校验器
    set_task_stack_end_magic kernel/fork.c
    smp_setup_processor_id() arch/arm64/kernel/setup.c
    debug_objects_early_init() lib/debugobjects.c 初始化哈希桶并将静态对象池对象链接到轮询列表中
    boot_init_stack_canary() arch/arm64/include/asm/stackprotector.h
    cgroup_init_early() kernel/cgroup.c
    local_irq_disable() include/linux/irqflags.h
    boot_cpu_init() init/main.c
    page_address_init() mm/highmem.c 初始化页地址hash链表
    setup_arch(&command_line) arch/arm64/kernel/setup.c
    mm_init_cpumask(&init_mm) include/linux/mm_types.h
    setup_command_line init/main.c 保存command line
    setup_nr_cpu_ids() kernel/smp.c
    setup_per_cpu_areas() mm/percpu.c
    smp_prepare_boot_cpu() arch/arm64/kernel/smp.c
    build_all_zonelists mm/page_alloc.c 初始化所有build_zonelists
    page_alloc_init() mm/page_alloc.c 注册page_alloc_cpu_notify
    parse_early_param() init/main.c
    jump_label_init() kernel/jump_label.c
    setup_log_buf(0) kernel/printk/printk.c
    pidhash_init() kernel/pid.c 初始化pid hash表(16~4096)
    vfs_caches_init_early() fs/dcache.c dchche/inode init
    sort_main_extable() kernel/extable.c exception table
    trap_init() arch/arm64/kernel/traps.c register_break_hook
    mm_init() init/main.c 内核内存分配器
    sched_init() kernel/sched/core.c 初始化任务调度器
    preempt_disable() include/linux/preempt.h barrier()
    idr_init_cache() lib/idr.c
    rcu_init() kernel/rcu/tree.c
    trace_init() kernel/trace/trace.c
    context_tracking_init() kernel/context_tracking.c
    radix_tree_init() lib/radix-tree.c
    early_irq_init() kernel/irq/irqdesc.c
    init_IRQ() arch/arm64/kernel/irq.c irqchip_init()
    tick_init() kernel/time/tick-common.c
    rcu_init_nohz() kernel/rcu/tree_plugin.h
    init_timers() kernel/time/timer.c
    hrtimers_init() kernel/time/hrtimer.c 初始化高精度定时器
    softirq_init() kernel/softirq.c
    timekeeping_init() kernel/time/timekeeping.c 初始化时钟源和公共时效值
    time_init() arch/arm64/kernel/time.c
    sched_clock_postinit() kernel/time/sched_clock.c
    perf_event_init() kernel/events/core.c
    profile_init() kernel/profile.c
    call_function_init() kernel/smp.c 初始化call_single_queue队列;注册hotplug_cfd_notifier
    local_irq_enable() include/linux/irqflags.h
    kmem_cache_init_late() mm/slob.c slab.c slub.c
    console_init() drivers/tty/tty_io.c 注册控制台设备
    lockdep_info() kernel/locking/lockdep.c 打印信息
    locking_selftest() lib/locking-selftest.c
    page_ext_init() mm/page_ext.c
    debug_objects_mem_init() lib/debugobjects.c 初始化专用缓冲池
    kmemleak_init() mm/kmemleak.c
    setup_per_cpu_pageset() mm/page_alloc.c 为每个cpu分配pagesets
    numa_policy_init() mm/mempolicy.c
    late_time_init() init_main.c
    sched_clock_init() kernel/sched/clock.c
    calibrate_delay() init/calibrate.c 默认延时校准
    pidmap_init() kernel/pid.c
    anon_vma_init() mm/rmap.c
    acpi_early_init() drivers/acpi/bus.c
    thread_stack_cache_init() kernel/fork.c
    cred_init() kernel/cred.c 分配一个cred_jar cache
    fork_init() kernel/fork.c
    proc_caches_init() kernel/fork.c
    buffer_init() fs/buffer.c
    key_init() security/keys/key.c 初始化秘钥管理状态
    security_init() security/security.c 初始化安全框架
    dbg_late_init() kernel/debug/debug_core.c
    vfs_caches_init() fs/dcache.c
    signals_init() kernel/signal.c
    page_writeback_init() mm/page-writeback.c
    proc_root_init() fs/proc/root.c 初始化proc文件系统
    nsfs_init() fs/nsfs.c
    cpuset_init() kernel/cpuset.c
    cgroup_init() kernel/cgroup.c
    taskstats_init_early() kernel/taskstats.c
    delayacct_init() kernel/delayacct.c
    check_bugs() arch/arm/mm/fault-armv.c
    acpi_subsystem_init() drivers/acpi/bus.c 初始化acpi子系统
    sfi_init_late() drivers/sfi/sfi_core.c
    ftrace_init() kernel/trace/ftrace.c
    rest_init() init/main.c 执行非__init结尾的初始化

    执行了非常多的初始化_init函数,为整个系统运行做好准备,最后调用rest_init。

    rest_init

    初始化项

    函数名 定义目录 简介
    rcu_scheduler_starting() kernel/rcu/tree.c rcu_scheduler_active = 1
    smpboot_thread_init() kernel/cpu.c 注册smpboot_thread_notifier
    kernel_thread(kernel_init) init/main.c 在Kernel_init线程中创建init进程并执行init中的命令
    numa_default_policy() mm/mempolicy.c
    pid = kernel_thread(kthreadd) kernel/kthread.c 创建2号进程Kthreadd
    init_idle_bootup_task(current) kernel/sched/core.c
    schedule_preempt_disabled() kernel/sched/core.c
    cpu_startup_entry(CPUHP_ONLINE) kernel/sched/idle.c 执行idle_loop,空闲循环等待

    kernel_init

    static int __ref kernel_init(void *unused)
    {
        int ret;
    
        kernel_init_freeable();
        /* need to finish all async __init code before freeing the memory */
        async_synchronize_full();
        free_initmem();
        mark_readonly();
        system_state = SYSTEM_RUNNING;
        numa_default_policy();
    
        flush_delayed_fput();
    
        if (ramdisk_execute_command) {
            ret = run_init_process(ramdisk_execute_command);
            if (!ret)
                return 0;
            pr_err("Failed to execute %s (error %d)\n",
                   ramdisk_execute_command, ret);
        }
    
        /*
         * We try each of these until one succeeds.
         *
         * The Bourne shell can be used instead of init if we are
         * trying to recover a really broken machine.
         */
        /*执行init*/
        if (execute_command) {
            ret = run_init_process(execute_command);
            if (!ret)
                return 0;
            panic("Requested init %s failed (error %d).",
                  execute_command, ret);
        }
        if (!try_to_run_init_process("/sbin/init") ||
            !try_to_run_init_process("/etc/init") ||
            !try_to_run_init_process("/bin/init") ||
            !try_to_run_init_process("/bin/sh"))
            return 0;
    }
    

    kernel_init_freeable()

    static noinline void __init kernel_init_freeable(void)
    {
        ....
        //真正开始初始化
        do_basic_setup();
    
        /* Open the /dev/console on the rootfs, this should never fail */
        if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
            pr_err("Warning: unable to open an initial console.\n");
    
        (void) sys_dup(0);
        (void) sys_dup(0);
        /*
         * check if there is an early userspace init.  If yes, let it do all
         * the work
         */
    
        if (!ramdisk_execute_command)
            ramdisk_execute_command = "/init";
    
        if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
            ramdisk_execute_command = NULL;
            prepare_namespace();
        }
       ...
    }
    
    

    do_basic_setup()

    static void __init do_basic_setup(void)
    {
        cpuset_init_smp();
        shmem_init();
        driver_init();
        init_irq_proc();
        do_ctors();
        usermodehelper_enable();
        //加载并注册所有的module
        do_initcalls();
        random_int_secret_init();
    }
    

    总结:在rest_init中真正让整个内核跑了起来,并创建了两个非常重要的进程:Kthreadd(pid=2)负责内核空间线程的创建。init(pid=1),该进程是所有用户空间进程的鼻祖。另外一边完成了初始化的内核进入idle_loop状态。

    个人博客:https://www.letcos.top/

    相关文章

      网友评论

          本文标题:[Boot]Kernel启动

          本文链接:https://www.haomeiwen.com/subject/rxktchtx.html