kernel 启动流程----start_kernel

        start_kernel 位于Main.c (kernel4.14\init)中,如下,将对每个函数进行简单的介绍

  1. asmlinkage __visible void __init start_kernel(void)
  2. {
  3.     char *command_line;
  4.     char *after_dashes;
  5.     set_task_stack_end_magic(&init_task);//设置栈结束地址,用于判断栈溢出
  6.     smp_setup_processor_id();//设置处理器的id
  7.     debug_objects_early_init();//调试接口,没有实现
  8.     cgroup_init_early();//cgroup初始化,并按照是否需要early_init(Bool)配置,初始化相关的子系统
  9.     local_irq_disable();//关闭本地中断
  10.     early_boot_irqs_disabled = true;
  11.     /*
  12.      * Interrupts are still disabled. Do necessary setups, then
  13.      * enable them.
  14.      */
  15.     boot_cpu_init();//用于激活第一个处理器
  16.     page_address_init();//页地址初始化 初始化page_address_htable中的链表和锁
  17.     pr_notice("%s", linux_banner);
  18.     setup_arch(&command_line);//用于完成内存映像的初始化,其中command_line是从bootloader中传下来的 
  19.     /*
  20.      * Set up the the initial canary and entropy after arch
  21.      * and after adding latent and command line entropy.
  22.      */
  23.     add_latent_entropy();
  24.     add_device_randomness(command_line, strlen(command_line));
  25.     boot_init_stack_canary();//函数初始化堆栈保护的canary值,用来防止栈溢出攻击
  26. #ifdef CONFIG_PASR
  27.     early_pasr_setup();
  28. #endif
  29.     mm_init_cpumask(&init_mm);//初始化init_mm结构体,每一个任务都有一个mm_struct结构以管理内存空间,init_mm是内核的mm_struct。填充mm_struct结构体的相关变量。
  30.     setup_command_line(command_line);//保存command line以备将来使用。
  31.     setup_nr_cpu_ids();//设置nr_cpu_ids值
  32.     setup_per_cpu_areas();//该函数为每个cpu的per-cpu变量副本分配空间,设置SMP体系每个CPU使用的内存空间,同时拷贝初始化段里数据,
  33.     smp_prepare_boot_cpu();    /* arch-specific boot-cpu hooks */
  34.     boot_cpu_hotplug_init();//cpu热插拔初始化
  35.     build_all_zonelists(NULL);//初始化所有内存管理节点列表,以便后面进行内存管理初始化,建立系统内存页区链表
  36.     page_alloc_init();//内存页初始化,设置内存分页分配通知器
  37.     pr_notice("Kernel command line: %s\n", boot_command_line);
  38.     /* parameters may set static keys */
  39.     jump_label_init();//处理静态定义在跳转标号
  40.     parse_early_param();//解析需要更早处理的启动参数
  41.     after_dashes = parse_args("Booting kernel",
  42.                   static_command_line, __start___param,
  43.                   __stop___param - __start___param,
  44.                   -1, -1, NULL, &unknown_bootoption);//对传入内核参数进行解释,如果不能识别的命令就调用最后参数的函数
  45.     if (!IS_ERR_OR_NULL(after_dashes))
  46.         parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
  47.                NULL, set_init_arg);
  48.     /*
  49.      * These use large bootmem allocations and must precede
  50.      * kmem_cache_init()
  51.      */
  52.     setup_log_buf(0);//分配一个log buf
  53.     pidhash_init();//分配一个PID的hash
  54.     vfs_caches_init_early();//虚拟文件系统的早期初始化,包括dentry和inode的hash表初始化工作,在fs/dcache.c中实现
  55.     sort_main_extable();//对内核异常向量表进行排序,位于kernel/extable.c中实现
  56.     trap_init();//对内核陷阱异常进程初始化,位于arch\arm64\kernel\Traps.c实现
  57.     mm_init();//初始化内核内存分配器,过度到伙伴系统,启动slab机制,初始化非连续内存区,位于init/mian.c实现
  58.     ftrace_init();//功能跟踪调试机制初始化,初始化内核跟踪模块。ftrace的作用是帮助开发人员了解Linux内核的运行时行为,以便于进行故障调试或者性能分析。
  59.     /* trace_printk can be enabled here */
  60.     early_trace_init();//使能trace_printk
  61.     /*
  62.      * Set up the scheduler prior starting any interrupts (such as the
  63.      * timer interrupt). Full topology setup happens at smp_init()
  64.      * time - but meanwhile we still have a functioning scheduler.
  65.      */
  66.     sched_init();//系统进程调度初始化 位于kernel\sched\Core.c 
  67.      * Disable preemption - early bootup scheduling is extremely
  68.      * fragile until we cpu_idle() for the first time.
  69.      */
  70.     preempt_disable();//禁止进程内核抢占,早期启动时期,调度是极其脆弱的,
  71.     if (WARN(!irqs_disabled(),
  72.          "Interrupts were enabled *very* early, fixing it\n"))
  73.         local_irq_disable();
  74.     radix_tree_init();//初始化radix树算法初始化,在lib/radix_tree.c中实现
  75.     /*
  76.      * Allow workqueue creation and work item queueing/cancelling
  77.      * early.  Work item execution depends on kthreads and starts after
  78.      * workqueue_init().
  79.      */
  80.     workqueue_init_early();//工作队列早期初始化, kernel/workqueue.c文件
  81.     rcu_init();//初始化rcu机制
  82.     /* Trace events are available after this */
  83.     trace_init();//初始化trace机制
  84.     context_tracking_init();
  85.     /* init some links before init_ISA_irqs() */
  86.     early_irq_init();//早期外部中断描述初始化
  87.     init_IRQ();//架构相关中断初始化
  88.     tick_init();//初始化时钟滴答控制器
  89.     rcu_init_nohz();
  90.     init_timers();//初始化引导CPU的时钟相关的数据结构,在kernel/timer.c中实现
  91.     hrtimers_init();//初始化高精度定时器
  92.     softirq_init();//初始化软中断
  93.     timekeeping_init();//初始化系统时钟计时,在kernel/time/timekeeping.c中实现
  94.     time_init();//初始化系统时钟,在arch/arm64/kernel/time.c中实现
  95.     sched_clock_postinit();//对每个CPU进行系统进程调度时钟初始化
  96.     printk_safe_init();//为每个cpu建立work用于刷新消息
  97.     perf_event_init();//perf 事件初始化,位于kernel\events\Core.c中实现
  98.     profile_init();//profile初始化,profile是内核诊断工具,在kernel/profile.c中有实现
  99.     call_function_init();//为每个cpu call_single_queue出始化链表头, 在kernel\Smp.c中实现
  100.     WARN(!irqs_disabled(), "Interrupts were enabled early\n");
  101.     early_boot_irqs_disabled = false;
  102.     local_irq_enable();//使能本地中断
  103.     kmem_cache_init_late();//slab分配器后期初始化,在mm/slob.c、slub.c、slab.c中有实现,内核启动时使用临时内存分配器bootmem,之后由slab接管。kmem_cache_init_late()初始化了slab分配器(内核高速缓存分配器),这意味着bootmem的结束,同时内核的内存管理系统正式开始工作。bootmem的分配必须先于kmem_cache_init_late()
  104. #ifdef CONFIG_PASR
  105.     late_pasr_setup();
  106. #endif
  107.     /*
  108.      * HACK ALERT! This is early. We're enabling the console before
  109.      * we've done PCI setups etc, and console_init() must be aware of
  110.      * this. But we do want output early, in case something goes wrong.
  111.      */
  112.     console_init();//控制台初始化。从这个函数之后就可以输出内容到控制台了。在此之前的输出保存在输出缓冲区中,这个函数被调用之后就马上把之前的内容输出出来
  113.     if (panic_later)
  114.         panic("Too many boot %s vars at `%s'", panic_later,
  115.               panic_param);
  116.     lockdep_info();//如果定义了CONFIG_LOCKDEP宏,那么就打印锁依赖信息,进行自我检测,否则什么也不做 。在include/linux/lockdep.h中为空,在kernel/lockdep.c中有实现
  117.     /*
  118.      * Need to run this when irqs are enabled, because it wants
  119.      * to self-test [hard/soft]-irqs on/off lock inversion bugs
  120.      * too:
  121.      */
  122.     locking_selftest();//如果定义CONFIG_DEBUG_LOCKING_API_SELFTESTS宏   //则locking_selftest()是一个空函数,否则执行锁自测 
  123.     /*
  124.      * This needs to be called before any devices perform DMA
  125.      * operations that might use the SWIOTLB bounce buffers. It will
  126.      * mark the bounce buffers as decrypted so that their usage will
  127.      * not cause "plain-text" data to be decrypted when accessed.
  128.      */
  129.     mem_encrypt_init();//arm64为空
  130. #ifdef CONFIG_BLK_DEV_INITRD
  131.     if (initrd_start && !initrd_below_start_ok &&
  132.         page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
  133.         pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
  134.             page_to_pfn(virt_to_page((void *)initrd_start)),
  135.             min_low_pfn);
  136.         initrd_start = 0;
  137.     }
  138. #endif
  139.     kmemleak_init();//内存泄漏检测机制的初始化,在include/linux/kmemleak.h中为空,在mm/kmemleak.c中实现
  140.     debug_objects_mem_init();//创建调试对象内存缓存,空函数,在include/linux/debugobjects.h为空,在lib/debugobjects.c中实现
  141.     setup_per_cpu_pageset();//为每个CPU分配页集合,并初始化,位于文件mm/page_alloc.c中
  142.     numa_policy_init();//初始化NUMA的内存访问策略。提高多个CPU的内存访问速度。多个CPU访问同一个节点的内存速度比访问多个节点的内存速度大得多。
  143.     if (late_time_init)
  144.         late_time_init();//arm64中为空
  145.     calibrate_delay();//主要计算CPU需要校准的时间。
  146.     pidmap_init();//pid map 初始化,位于kernel\Pid.c中实现
  147.     anon_vma_init();//初始化EFI的接口,并进入虚拟模式
  148.     acpi_early_init();//acpi早期初始化
  149. #ifdef CONFIG_X86
  150.     if (efi_enabled(EFI_RUNTIME_SERVICES))
  151.         efi_enter_virtual_mode();
  152. #endif
  153.     thread_stack_cache_init();//进程栈缓存初始化
  154.     cred_init();//任务信用系统初始化,位于kernel/cred.c中实现
  155.     fork_init();//根据当前物理内存计算出来可以创建进程(线程)的最大数量,并进行进程环境初始化,为task_struct分配空间。进程创建机制初始化,在kernel/fork.c中实现
  156.     proc_caches_init();//进程缓存初始化,在kernel/fork.c中实现
  157.     buffer_init();//文件系统的缓存区初始化,在include/linux/buffer_head.h中为空,在fs/buffer.c中实现
  158.     key_init();//初始化内核安全键管理列表和结构,内核秘钥管理系统。
  159.     security_init();//初始化内核安全管理框架,以便提供文件\登陆等权限。
  160.     dbg_late_init();//内核调试系统后期初始化。
  161.     vfs_caches_init();//虚拟文件系统进行缓存初始化,提高虚拟文件系统的访问速度。
  162.     pagecache_init();//完成页缓存初始化,在mm/filemap.c文件中
  163.     signals_init();//完成信号初始化,位于文件kernel/signal.c中
  164.     proc_root_init();//初始化系统进程文件系统,主要提供内核与用户进行交互的平台,方便用户实时查看进程的信息。
  165.     nsfs_init();//初始化nsfs文件系统,位于文件fs/nsfs.c
  166.     cpuset_init();//初始化CPUSET。CPUSET主要为控制组提供CPU和内存节点的管理的结构。
  167.     cgroup_init();//进程控制组正式初始化,主要用来为进程和它的子进程提供性能控制。
  168.     taskstats_init_early();//任务状态早期初始化,为结构体获取高速缓存,并初始化互斥机制。
  169.     delayacct_init();//任务延迟机制初始化,初始化每个任务延时计数。当一个任务等待CPU或者IO同步的时候,都需要计算等待时间。
  170.     check_bugs();//检查CPU配置、FPU等是否非法使用不具备的功能,检查CPU BUG,软件规避BUG。
  171.     acpi_subsystem_init();// apci子系统初始化,arm64为空
  172.     arch_post_acpi_subsys_init();//arm64为空
  173.     sfi_init_late();//simple fireware interface 初始化,在include/linux/sfi.h中为空,在drivers/sfi/sfi_core.c中实现
  174.     if (efi_enabled(EFI_RUNTIME_SERVICES)) {
  175.         efi_free_boot_services();
  176.     }
  177.     /* Do the rest non-__init'ed, we're now alive */
  178.     rest_init();//kernel_init 和kthreadd线程的创建,完成内核的初始化
  179. }

以上start_kernel中各个函数都进行简单介绍,下一章将对start中部分函数详细介绍。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值