start_kernel 位于Main.c (kernel4.14\init)中,如下,将对每个函数进行简单的介绍
- asmlinkage __visible void __init start_kernel(void)
- {
- char *command_line;
- char *after_dashes;
- set_task_stack_end_magic(&init_task);//设置栈结束地址,用于判断栈溢出
- smp_setup_processor_id();//设置处理器的id
- debug_objects_early_init();//调试接口,没有实现
- cgroup_init_early();//cgroup初始化,并按照是否需要early_init(Bool)配置,初始化相关的子系统
- local_irq_disable();//关闭本地中断
- early_boot_irqs_disabled = true;
- /*
- * Interrupts are still disabled. Do necessary setups, then
- * enable them.
- */
- boot_cpu_init();//用于激活第一个处理器
- page_address_init();//页地址初始化 初始化page_address_htable中的链表和锁
- pr_notice("%s", linux_banner);
- setup_arch(&command_line);//用于完成内存映像的初始化,其中command_line是从bootloader中传下来的
- /*
- * Set up the the initial canary and entropy after arch
- * and after adding latent and command line entropy.
- */
- add_latent_entropy();
- add_device_randomness(command_line, strlen(command_line));
- boot_init_stack_canary();//函数初始化堆栈保护的canary值,用来防止栈溢出攻击
- #ifdef CONFIG_PASR
- early_pasr_setup();
- #endif
- mm_init_cpumask(&init_mm);//初始化init_mm结构体,每一个任务都有一个mm_struct结构以管理内存空间,init_mm是内核的mm_struct。填充mm_struct结构体的相关变量。
- setup_command_line(command_line);//保存command line以备将来使用。
- setup_nr_cpu_ids();//设置nr_cpu_ids值
- setup_per_cpu_areas();//该函数为每个cpu的per-cpu变量副本分配空间,设置SMP体系每个CPU使用的内存空间,同时拷贝初始化段里数据,
- smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
- boot_cpu_hotplug_init();//cpu热插拔初始化
- build_all_zonelists(NULL);//初始化所有内存管理节点列表,以便后面进行内存管理初始化,建立系统内存页区链表
- page_alloc_init();//内存页初始化,设置内存分页分配通知器
- pr_notice("Kernel command line: %s\n", boot_command_line);
- /* parameters may set static keys */
- jump_label_init();//处理静态定义在跳转标号
- parse_early_param();//解析需要更早处理的启动参数
- after_dashes = parse_args("Booting kernel",
- static_command_line, __start___param,
- __stop___param - __start___param,
- -1, -1, NULL, &unknown_bootoption);//对传入内核参数进行解释,如果不能识别的命令就调用最后参数的函数
- if (!IS_ERR_OR_NULL(after_dashes))
- parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
- NULL, set_init_arg);
- /*
- * These use large bootmem allocations and must precede
- * kmem_cache_init()
- */
- setup_log_buf(0);//分配一个log buf
- pidhash_init();//分配一个PID的hash
- vfs_caches_init_early();//虚拟文件系统的早期初始化,包括dentry和inode的hash表初始化工作,在fs/dcache.c中实现
- sort_main_extable();//对内核异常向量表进行排序,位于kernel/extable.c中实现
- trap_init();//对内核陷阱异常进程初始化,位于arch\arm64\kernel\Traps.c实现
- mm_init();//初始化内核内存分配器,过度到伙伴系统,启动slab机制,初始化非连续内存区,位于init/mian.c实现
- ftrace_init();//功能跟踪调试机制初始化,初始化内核跟踪模块。ftrace的作用是帮助开发人员了解Linux内核的运行时行为,以便于进行故障调试或者性能分析。
- /* trace_printk can be enabled here */
- early_trace_init();//使能trace_printk
- /*
- * 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();//系统进程调度初始化 位于kernel\sched\Core.c
- * 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();
- radix_tree_init();//初始化radix树算法初始化,在lib/radix_tree.c中实现
- /*
- * Allow workqueue creation and work item queueing/cancelling
- * early. Work item execution depends on kthreads and starts after
- * workqueue_init().
- */
- workqueue_init_early();//工作队列早期初始化, kernel/workqueue.c文件
- rcu_init();//初始化rcu机制
- /* Trace events are available after this */
- trace_init();//初始化trace机制
- context_tracking_init();
- /* init some links before init_ISA_irqs() */
- early_irq_init();//早期外部中断描述初始化
- init_IRQ();//架构相关中断初始化
- tick_init();//初始化时钟滴答控制器
- rcu_init_nohz();
- init_timers();//初始化引导CPU的时钟相关的数据结构,在kernel/timer.c中实现
- hrtimers_init();//初始化高精度定时器
- softirq_init();//初始化软中断
- timekeeping_init();//初始化系统时钟计时,在kernel/time/timekeeping.c中实现
- time_init();//初始化系统时钟,在arch/arm64/kernel/time.c中实现
- sched_clock_postinit();//对每个CPU进行系统进程调度时钟初始化。
- printk_safe_init();//为每个cpu建立work用于刷新消息
- perf_event_init();//perf 事件初始化,位于kernel\events\Core.c中实现
- profile_init();//profile初始化,profile是内核诊断工具,在kernel/profile.c中有实现
- call_function_init();//为每个cpu call_single_queue出始化链表头, 在kernel\Smp.c中实现
- WARN(!irqs_disabled(), "Interrupts were enabled early\n");
- early_boot_irqs_disabled = false;
- local_irq_enable();//使能本地中断
- 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()
- #ifdef CONFIG_PASR
- late_pasr_setup();
- #endif
- /*
- * 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("Too many boot %s vars at `%s'", panic_later,
- panic_param);
- lockdep_info();//如果定义了CONFIG_LOCKDEP宏,那么就打印锁依赖信息,进行自我检测,否则什么也不做 。在include/linux/lockdep.h中为空,在kernel/lockdep.c中有实现
- /*
- * 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();//如果定义CONFIG_DEBUG_LOCKING_API_SELFTESTS宏 //则locking_selftest()是一个空函数,否则执行锁自测
- /*
- * This needs to be called before any devices perform DMA
- * operations that might use the SWIOTLB bounce buffers. It will
- * mark the bounce buffers as decrypted so that their usage will
- * not cause "plain-text" data to be decrypted when accessed.
- */
- mem_encrypt_init();//arm64为空
- #ifdef CONFIG_BLK_DEV_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
- kmemleak_init();//内存泄漏检测机制的初始化,在include/linux/kmemleak.h中为空,在mm/kmemleak.c中实现
- debug_objects_mem_init();//创建调试对象内存缓存,空函数,在include/linux/debugobjects.h为空,在lib/debugobjects.c中实现
- setup_per_cpu_pageset();//为每个CPU分配页集合,并初始化,位于文件mm/page_alloc.c中
- numa_policy_init();//初始化NUMA的内存访问策略。提高多个CPU的内存访问速度。多个CPU访问同一个节点的内存速度比访问多个节点的内存速度大得多。
- if (late_time_init)
- late_time_init();//arm64中为空
- calibrate_delay();//主要计算CPU需要校准的时间。
- pidmap_init();//pid map 初始化,位于kernel\Pid.c中实现
- anon_vma_init();//初始化EFI的接口,并进入虚拟模式
- acpi_early_init();//acpi早期初始化
- #ifdef CONFIG_X86
- if (efi_enabled(EFI_RUNTIME_SERVICES))
- efi_enter_virtual_mode();
- #endif
- thread_stack_cache_init();//进程栈缓存初始化
- cred_init();//任务信用系统初始化,位于kernel/cred.c中实现
- fork_init();//根据当前物理内存计算出来可以创建进程(线程)的最大数量,并进行进程环境初始化,为task_struct分配空间。进程创建机制初始化,在kernel/fork.c中实现
- proc_caches_init();//进程缓存初始化,在kernel/fork.c中实现
- buffer_init();//文件系统的缓存区初始化,在include/linux/buffer_head.h中为空,在fs/buffer.c中实现
- key_init();//初始化内核安全键管理列表和结构,内核秘钥管理系统。
- security_init();//初始化内核安全管理框架,以便提供文件\登陆等权限。
- dbg_late_init();//内核调试系统后期初始化。
- vfs_caches_init();//虚拟文件系统进行缓存初始化,提高虚拟文件系统的访问速度。
- pagecache_init();//完成页缓存初始化,在mm/filemap.c文件中
- signals_init();//完成信号初始化,位于文件kernel/signal.c中
- proc_root_init();//初始化系统进程文件系统,主要提供内核与用户进行交互的平台,方便用户实时查看进程的信息。
- nsfs_init();//初始化nsfs文件系统,位于文件fs/nsfs.c
- cpuset_init();//初始化CPUSET。CPUSET主要为控制组提供CPU和内存节点的管理的结构。
- cgroup_init();//进程控制组正式初始化,主要用来为进程和它的子进程提供性能控制。
- taskstats_init_early();//任务状态早期初始化,为结构体获取高速缓存,并初始化互斥机制。
- delayacct_init();//任务延迟机制初始化,初始化每个任务延时计数。当一个任务等待CPU或者IO同步的时候,都需要计算等待时间。
- check_bugs();//检查CPU配置、FPU等是否非法使用不具备的功能,检查CPU BUG,软件规避BUG。
- acpi_subsystem_init();// apci子系统初始化,arm64为空
- arch_post_acpi_subsys_init();//arm64为空
- sfi_init_late();//simple fireware interface 初始化,在include/linux/sfi.h中为空,在drivers/sfi/sfi_core.c中实现
- if (efi_enabled(EFI_RUNTIME_SERVICES)) {
- efi_free_boot_services();
- }
- /* Do the rest non-__init'ed, we're now alive */
- rest_init();//kernel_init 和kthreadd线程的创建,完成内核的初始化
- }
以上start_kernel中各个函数都进行简单介绍,下一章将对start中部分函数详细介绍。