Kernel启动流程源码解析 5 start_kernel 下


一 start_kernel

start_kernel函数是kernel启动过程执行的第一个c语言函数,其通过调用一系列初始化函数完成的内核的初始化工作,下篇分析 local_irq_enable之后的代码。

1.0 start_kernel

定义在init/main.c中

asmlinkage void __init start_kernel(void)
{
    char * command_line;
    extern const struct kernel_param __start___param[], __stop___param[];

    /*
     * Need to run as early as possible, to initialize the
     * lockdep hash:
     */
    lockdep_init(); // 初始化内核死锁检测机制的哈希表
    smp_setup_processor_id(); // 返回cpu号,单核cpu返回0
    debug_objects_early_init(); // 对调试对象进行早期的初始化

    cgroup_init_early(); // 对Control Groups进行早期的初始化

    local_irq_disable(); // 关闭当前cpu的中断
    early_boot_irqs_disabled = true;

/*
 * Interrupts are still disabled. Do necessary setups, then
 * enable them
 */
    boot_cpu_init(); // 设置当前cpu位激活状态
    page_address_init();  // 初始化高端内存的,arm没有用到
    pr_notice("%s", linux_banner);
    setup_arch(&command_line); // 内核架构相关初始化函数
    /*
     * Set up the the initial canary ASAP:
     */
    boot_init_stack_canary(); // 初始化栈canary值,canary值用于防止栈溢出攻击的堆栈的保护字
    mm_init_owner(&init_mm, &init_task); // mm.owner = &init_task
    mm_init_cpumask(&init_mm);
    setup_command_line(command_line); // 对cmdline进行备份
    setup_nr_cpu_ids(); // nr_cpu_ids
    setup_per_cpu_areas(); // 每个cpu的per-cpu变量副本分配空间
    smp_prepare_boot_cpu();    /* arch-specific boot-cpu hooks */

    build_all_zonelists(NULL, NULL); // 建立系统内存页区(zone)链表
    page_alloc_init(); // 内存页初始化

    pr_notice("Kernel command line: %s\n", boot_command_line);
    parse_early_param(); // 解析需要'早期'处理的启动参数用?setup_arch已经调用了一次
    parse_args("Booting kernel", static_command_line, __start___param,
           __stop___param - __start___param,
           -1, -1, &unknown_bootoption); // 解析cmdline中的启动参数

    jump_label_init(); // 处理静态定义在跳转标号

    /*
     * These use large bootmem allocations and must precede
     * kmem_cache_init()
     */
    setup_log_buf(0); // 使用memblock_alloc分配一个启动时log缓冲区
    pidhash_init(); // 初始化pid散列表
    vfs_caches_init_early(); // 初始化dentry和inode的hashtable
    sort_main_extable(); // 对内核异常向量表进行排序
    trap_init(); // 对内核陷阱异常进行初始化,arm没有用到
    mm_init(); // 初始化内核内存分配器,过度到伙伴系统,启动slab机制,初始化非连续内存区

    /*
     * Set up the scheduler prior starting any interrupts (such as the
     * timer interrupt). Full topology setup happens at smp_init()
     * time - but meanwhile we still have a functioning scheduler.
     */
    sched_init(); // 初始化进程调度器
    /*
     * Disable preemption - early bootup scheduling is extremely
     * fragile until we cpu_idle() for the first time.
     */
    preempt_disable(); // 进制内核抢占
    if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n"))
        local_irq_disable(); // 关闭本地中断
    idr_init_cache(); // 创建idr(整数id管理机制)高速缓存
    perf_event_init(); // 初始化性能诊断工具
    rcu_init(); // 初始化rcu机制(读-写-拷贝)
    tick_nohz_init(); // 初始化动态时钟框架
    radix_tree_init(); // 初始化内核基数树
    /* init some links before init_ISA_irqs() */
    early_irq_init(); // arm64没有用到
    init_IRQ(); // 初始化中断
    tick_init(); // 初始化时钟滴答控制器
    init_timers(); // 初始化内核定时器
    hrtimers_init(); // 初始化高精度时钟
    softirq_init(); // 初始化软中断
    timekeeping_init();  // 初始化了大量的时钟相关全局变量
    time_init(); // 时钟初始化
    profile_init(); //  对内核的一个性能测试工具profile进行初始化
    call_function_init(); // smp下跨cpu的函数传递初始化
    WARN(!irqs_disabled(), "Interrupts were enabled early\n");
    early_boot_irqs_disabled = false;
    local_irq_enable(); // 使能当前cpu中断
// -----------------------------------------------------------
    kmem_cache_init_late(); // 初始化slab分配器的缓存机制

    /*
     * HACK ALERT! This is early. We're enabling the console before
     * we've done PCI setups etc, and console_init() must be aware of
     * this. But we do want output early, in case something goes wrong.
     */
    console_init(); // 初始化控制台
    if (panic_later)
        panic(panic_later, panic_param);

    lockdep_info(); // 打印锁的依赖信息

    /*
     * Need to run this when irqs are enabled, because it wants
     * to self-test [hard/soft]-irqs on/off lock inversion bugs
     * too:
     */
    locking_selftest(); // 死锁检测

#ifdef CONFIG_BLK_DEV_INITRD // 检查initrd的位置是否符合要求
    if (initrd_start && !initrd_below_start_ok &&
        page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
        pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
            page_to_pfn(virt_to_page((void *)initrd_start)),
            min_low_pfn);
        initrd_start = 0;
    }
#endif
    page_cgroup_init(); // 为page_cgroup相关结构分配存储空间
    debug_objects_mem_init(); // 创建debug_obj的slab高速缓存
    kmemleak_init(); // 初始化内存泄漏检测机制
    setup_per_cpu_pageset(); // 设置并初始化每个cpu的页组
    numa_policy_init(); // 初始化NUMA的内存访问策略
    if (late_time_init) // arm64为空
        late_time_init();
    sched_clock_init(); // 初始化调度器时钟
    calibrate_delay(); // 延时校准
    pidmap_init(); // 初始化进程pid位图
    anon_vma_init(); // 创建anon_vma的slab缓存
#ifdef CONFIG_X86
    if (efi_enabled(EFI_RUNTIME_SERVICES))
        efi_enter_virtual_mode();
#endif
    thread_info_cache_init(); // 创建进程thread_info的slab高速缓存
    cred_init(); // 创建任务信用系统的slab高速缓存
    fork_init(totalram_pages); // 初始化进程创建机制
    proc_caches_init(); // 创建进程所需的各结构体slab高速缓存
    buffer_init(); // 为buffer_head结构体创建slab高速缓存
    key_init(); // 初始化内核密钥管理系统
    security_init(); // 初始化内核安全框架
    dbg_late_init(); // 初始化内核调试模块kdb
    vfs_caches_init(totalram_pages); // 初始化虚拟文件系统
    signals_init(); // 创建信号队列slab高速缓存
    /* rootfs populating might need page-writeback */
    page_writeback_init(); // 初始化页回写机制
#ifdef CONFIG_PROC_FS
    proc_root_init(); // 初始化proc文件系统
#endif
    cgroup_init(); // control group正式初始化
    cpuset_init(); // 初始化cpuset
    taskstats_init_early(); // 任务状态早期初始化函数,创建高速缓存并初始化互斥机制
    delayacct_init(); // 初始化任务延时机制

    check_bugs(); // arm64为空

    acpi_early_init(); /* before LAPIC and SMP init */ // 初始化acpi电源管理
    sfi_init_late(); // simple fireware interface
    if (efi_enabled(EFI_RUNTIME_SERVICES)) { // arm暂时没有用到
        efi_late_init();
        efi_free_boot_services();
    }

    ftrace_init(); // 初始化ftrace

    /* Do the rest non-__init'ed, we're now alive */
    rest_init(); // 后续初始化,单独分析
}

1.1 kmem_cache_init_late

定义在mm/slab.c中
void __init kmem_cache_init_late(void)
{
    struct kmem_cache *cachep;

    slab_state = UP;

    /* 6) resize the head arrays to their final sizes */
    mutex_lock(&slab_mutex);
    list_for_each_entry(cachep, &slab_caches, list)
        if (enable_cpucache(cachep, GFP_NOWAIT))
            BUG();
    mutex_unlock(&slab_mutex);

    /* Annotate slab for lockdep -- annotate the malloc caches */
    init_lock_keys();

    /* Done! */
    slab_state = FULL;

    /*
     * Register a cpu startup notifier callback that initializes
     * cpu_cache_get for all new cpus
     */
    register_cpu_notifier(&cpucache_notifier);

#ifdef CONFIG_NUMA
    /*
     * Register a memory hotplug callback that initializes and frees
     *
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值