Linux内核启动过程中主函数的执行流程是一个复杂但精妙的过程,下面我将详细解析这一流程。
Linux内核的入口点通常是start_kernel()
函数,位于init/main.c
文件中。这是内核解压后执行的第一个C语言函数。
asmlinkage __visible void __init start_kernel(void)
{
// 内核初始化主流程
}
设置处理器和体系结构相关参数
set_task_stack_end_magic(&init_task);
smp_setup_processor_id();
debug_objects_early_init();
初始化引导参数
boot_init_stack_canary();
cgroup_init_early();
内存子系统早期初始化
setup_arch(&command_line);
mm_init_cpumask(&init_mm);
setup_command_line(command_line);
调度器初始化
sched_init();
中断系统初始化
early_irq_init();
init_IRQ();
tick_init();
定时器子系统初始化
init_timers();
hrtimers_init();
time_init();
内存管理初始化
mem_init();
kmem_cache_init();
vmstat_init();
早期控制台初始化
console_init();
安全子系统初始化
security_init();
虚拟文件系统(VFS)初始化
vfs_caches_init(totalram_pages);
设备模型初始化
rest_init();
start_kernel()
最后会调用rest_init()
完成剩余初始化:
static noinline void __init_refok rest_init(void)
{
// 创建内核线程
kernel_thread(kernel_init, NULL, CLONE_FS);
// 创建kthreadd线程
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
// 调度器开始运行
cpu_startup_entry(CPUHP_ONLINE);
}
kernel_init
线程负责完成最后的初始化工作:
等待kthreadd线程就绪
wait_for_completion(&kthreadd_done);
初始化设备驱动
do_basic_setup();
挂载根文件系统
prepare_namespace();
执行用户空间init程序
if (execute_command) {
run_init_process(execute_command);
}
在内核主函数执行过程中,几个关键数据结构被初始化:
现代Linux内核在主函数执行过程中还会进行多项性能优化相关的初始化:
CPU频率调节
cpufreq_init();
电源管理
early_pm_init();
性能监控单元(PMU)
perf_event_init();
内核主流程还包含调试基础设施的初始化:
ftrace初始化
ftrace_init();
动态调试
dynamic_debug_init();
Kprobes
kprobe_init();
Linux内核主函数的执行流程是一个精心设计的层次化过程,从底层硬件初始化逐步过渡到高层子系统,最终启动用户空间。理解这一流程对于内核开发、性能调优和问题诊断至关重要。