每个函数具体干了什么,还是得进去看代码,以下虽然只是很大概的一个总结,都花了十几个小时,所以,想真的弄明白一件事,就真得不怕花时间去做
asmlinkage __visible void __init start_kernel(void)
{
char *command_line;
char *after_dashes;
/*
* Need to run as early as possible, to initialize the
* lockdep hash:
*/
lockdep_init(); //初始化锁依赖检测机制,用于检测和调试多线程并发程序中潜在的死锁和锁竞争问题
set_task_stack_end_magic(&init_task); //设置魔数的目的是为了进行栈溢出检测,init_task是一个task_struct实例,后续创建0号idle进程会用到
smp_setup_processor_id(); //获取当前正在执行初始化的处理器ID
debug_objects_early_init(); //对调试对象进行早期的初始化,其实就是HASH锁和静态对象池进行初始化
/*
* Set up the the initial canary ASAP:
*/
boot_init_stack_canary(); //用于检测缓冲区溢出漏洞攻击,它通过在栈上插入一个随机值来保护函数返回地址的完整性,函数返回时会检测这个随机值有没被篡改
cgroup_init_early(); //初始化控制组,控制组是一种机制,用于对进程和资源进行分组和管理,以实现资源隔离、控制和限制。
local_irq_disable(); //禁用本地硬件中断
early_boot_irqs_disabled = true;
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
boot_cpu_init(); //初始化并激活当前cpu
page_address_init(); //初始化高端内存
pr_notice("%s", linux_banner);
setup_arch(&command_line); //负责初始化与特定体系结构相关的硬件和特性,为内核提供正确的运行环境,里面初始化了memblock来管理内存
mm_init_cpumask(&init_mm); //创建和初始化一个位图,记录可用的 CPU 的状态
setup_command_line(command_line); //将启动参数存储在特定的结构里,方便后续访问
setup_nr_cpu_ids(); //确定系统中可用 CPU 的数量,并设置相应的值
setup_per_cpu_areas(); //为每个 CPU 单独分配的内存区域,用于存放每个 CPU 特定的变量和数据结构
smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
build_all_zonelists(NULL, NULL); //构建和初始化所有的zone列表,为每个CPU构建合适的zone列表,以便在分配内存时能够快速地找到合适的内存区域
page_alloc_init(); //对页分配器进行初始化
pr_notice("Kernel command line: %s\n", boot_command_line);
parse_early_param(); //这个用的是bootloader传递过来的boot_command_line,通过这样来解析__setup( "foo=" , foo );
after_dashes = parse_args("Booting kernel", //这个是编译时定义的静态command
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);
jump_label_init(); //初始化跳转标签,这是一种编译时优化机制,不像goto等需要运行时控制
/*
* These use large bootmem allocations and must precede
* kmem_cache_init()
*/
setup_log_buf(0); //初始化日志缓冲区
pidhash_init(); //初始化进程pid的hash表
vfs_caches_init_early(); //早期初始化虚拟文件系统的缓存,在运行时更快地访问文件和目录
sort_main_extable(); //链接时lds会确定异常表(页面错误,除0错误等)的开始和结束地址,中断向量表的地址在链接的时候也会确定,并在__enable_mmu赋值给vbar_el1寄存器
trap_init(); //注册bug_break_hook处理trap
mm_init(); //初始化内存管理,后续就由伙伴系统来管理页分配了
/*
* 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(); //初始化调度器,0号idle进程通过fork就此诞生
/*
* 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 Allocator)缓存
rcu_init(); //初始化 RCU(Read-Copy-Update)子系统
/* trace_printk() and trace points may be used after this */
trace_init(); //traceponints初始化
context_tracking_init(); //初始化上下文跟踪子系统,用于跟踪和记录任务之间的上下文切换信息
radix_tree_init(); //初始化基数树,用于在内核中存储和检索key-value对
/* init some links before init_ISA_irqs() */
early_irq_init(); //通用逻辑,为irq_desc[]中各元素的某些成员填充默认值
init_IRQ(); //初始化中断控制器,将硬件中断号跟irq对应,irq再跟中断处理函数通过irq_desc关联
tick_init(); //设置定时器硬件以及与之相关的数据结构,以便在每个时钟中断时触发特定的操作
rcu_init_nohz(); //用于初始化无硬中断负载下的可读复制更新
init_timers(); //系统启动时负责初始化定时器机制,为操作系统提供时间轮询和在内核中使用定时器所需的基础设置
hrtimers_init(); //初始化高分辨率定时器
softirq_init(); //于在内核中通过软件方式处理延迟的任务和中断请求
timekeeping_init(); //确保系统能够准确追踪时间,并提供一致和可靠的时间接口
time_init(); //初始化系统的时钟源,并校准系统时间。
sched_clock_postinit(); //准备好调度时钟,以便在后续的任务调度和时间相关操作中使用
perf_event_init(); //它利用处理器的硬件性能计数器来收集各种硬件事件的计数信息,如指令执行、缓存命中、分支预测等等
profile_init(); //用于初始化系统性能分析工具。通过该函数,可以注册事件处理函数、分配数据结构并执行其他初始化操作,以准备好性能数据的采集和分析
call_function_init(); //初始化在多个CPU核心之间进行函数调用的机制
WARN(!irqs_disabled(), "Interrupts were enabled early\n");
early_boot_irqs_disabled = false;
local_irq_enable(); //开启本地硬件中断
kmem_cache_init_late(); //初始化内核中的内存缓存对象。这些内存缓存对象预先分配内存块,用于提高内核操作的效率并减少动态内存分配的开销
/*
* 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(); //打印锁的依赖信息
/*
* 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_ext_init(); //初始化与页面相关的扩展数据结构
debug_objects_mem_init(); //初始化调试对象内存分配器
kmemleak_init(); //初始化内核内存泄漏检测器
setup_per_cpu_pageset(); //遍历系统中所有的zone,对于每一个zone为所有的CPU分配pageset(冷热页缓存)并进行初始化
numa_policy_init(); //初始化 NUMA 策略,它会设置所需的数据结构和状态,并进行一些初始化操作
if (late_time_init)
late_time_init();
sched_clock_init(); //准备好调度时钟所需的资源,以便在后续的运行过程中能够准确地测量时间和进行任务调度
calibrate_delay(); //校准计算loops_per_jiffies值,用于mdelay和ndelay
pidmap_init(); //初始化进程标识符映射,为内核分配和设置必要的数据结构,以准备好处理进程标识符的分配和管理
anon_vma_init(); //初始化匿名虚拟内存区
acpi_early_init(); //初始化acpi,并填充acpi命名空间
#ifdef CONFIG_X86
if (efi_enabled(EFI_RUNTIME_SERVICES))
efi_enter_virtual_mode();
#endif
#ifdef CONFIG_X86_ESPFIX64
/* Should be run before the first non-init thread is created */
init_espfix_bsp();
#endif
thread_info_cache_init(); //使用线程信息缓存来提前分配和管理这些线程信息的存储空间,以避免频繁的内存分配和释放操作
cred_init(); //初始化进程凭据,凭据是与每个进程相关联的结构,用于表示进程的权限和身份信息
fork_init(); //创建task_struct的一个slab,后续通过struct task_struct *task = kmem_cache_alloc(task_struct_cachep, GFP_KERNEL);
proc_caches_init(); //创建和初始化这些与 /proc 文件系统相关的缓存。具体的初始化操作包括分配内存、初始化缓存数据结构等
buffer_init(); //初始化一个buffer_head的slab缓存,供后续使用
key_init(); //初始化密钥管理状态
security_init(); //初始化安全子系统,包括注册安全模块、创建安全上下文等。
dbg_late_init(); //初始化kdb_printf、断点表和kdb状态
vfs_caches_init(); //始化 VFS 的缓存,包括 inode 缓存、dentry 缓存和文件缓存。这些缓存用于提高文件系统的性能和效率
signals_init(); //初始化一个sigqueue的缓存
/* rootfs populating might need page-writeback */
page_writeback_init(); //初始化页面回写机制,包括创建回写线程、设置相关参数和数据结构等
proc_root_init(); //用于创建 Proc 文件系统的根节点。它会为根节点分配内存并初始化相关的数据结构
nsfs_init(); //初始化命名空间文件系统。它会创建命名空间文件系统的根目录,并注册相应的文件操作函数。通过访问命名空间文件系统,可以查看和设置命名空间的相关信息
cpuset_init(); //初始化cpuset控制器,对进程或任务进行CPU和内存资源的管理、限制和隔离
cgroup_init(); //用于初始化cgroup子系统,它通过将一组进程或任务进行组织和管理,提供了对系统资源的控制和限制,它会创建cgroupfs文件系统的根目录,注册相应的文件操作函数
taskstats_init_early(); //它提供了对进程和任务的统计信息的收集和查询,以获取进程的CPU使用情况、内存使用情况、执行状态、生命周期等信息,以及与进程相关的网络统计信息
delayacct_init(); //用于跟踪和统计进程或任务在延迟等待上所花费的时间,它可以统计进程等待磁盘 I/O、网络操作、锁等资源的时间,以及进程在等待中花费的总时间
check_bugs(); //各个平台自己会选择是否填充这个
acpi_subsystem_init(); //初始化 ACPI 子系统。它会完成与 ACPI 相关的数据结构和功能的初始化工作
sfi_init_late(); //初始化SFI子系统,它完成与 SFI 相关的数据结构的初始化,并注册 SFI 的回调函数,以便从SFI固件中获取硬件配置信
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
efi_late_init();
efi_free_boot_services();
}
ftrace_init(); //初始化Ftrac子系统,处理mcount段的函数,mcount是一种静态插桩技术,在代码编译阶段进行处理。它通过在每个函数的开头添加记录函数调用信息的代码
/* Do the rest non-__init'ed, we're now alive */
rest_init(); //1号进程kernel_init驱动初始化完,就直接启动用户空间的init进程;2号进程kthreadd就用来创建内核进程了,0号idle进入cpu_startup_entry以在空闲时loop
}