Linux内核启动流程从start_kernel()函数开始,这是内核初始化过程的起点。在x86架构中,启动流程大致如下:
arch/x86/boot/header.S中的汇编代码arch/x86/kernel/head_64.S(64位系统)start_kernel()start_kernel()函数位于init/main.c中,是内核初始化的核心函数。其主要职责包括:
asmlinkage __visible void __init start_kernel(void)
{
// 初始化关键子系统
set_task_stack_end_magic(&init_task);
smp_setup_processor_id();
debug_objects_early_init();
// 早期初始化
boot_cpu_init();
page_address_init();
pr_notice("%s", linux_banner);
setup_arch(&command_line);
// 内存管理初始化
mm_init();
// 调度器初始化
sched_init();
// 中断和定时器初始化
init_IRQ();
tick_init();
init_timers();
// 进程管理初始化
fork_init();
// 文件系统初始化
vfs_caches_init();
// 设备驱动初始化
rest_init();
}
处理器和体系结构相关初始化
smp_setup_processor_id(): 设置处理器IDsetup_arch(): 架构相关初始化内存管理初始化
mm_init(): 初始化内存管理子系统mem_init(): 释放不再需要的内存给伙伴系统调度系统初始化
sched_init(): 初始化调度器中断和定时器
init_IRQ(): 中断子系统初始化tick_init(): 时钟中断初始化进程管理
fork_init(): 初始化进程创建机制文件系统
vfs_caches_init(): 虚拟文件系统缓存初始化start_kernel()最后调用rest_init()完成剩余初始化工作:
static noinline void __init_refok rest_init(void)
{
// 创建内核线程
pid = kernel_thread(kernel_init, NULL, CLONE_FS);
// 创建kthreadd线程
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
// 启动调度系统
cpu_startup_entry(CPUHP_ONLINE);
}
kernel_init线程
kernel_init() → kernel_init_freeable() → do_basic_setup()kthreadd线程
设备驱动初始化
do_basic_setup()调用do_initcalls()执行所有注册的初始化函数挂载根文件系统
prepare_namespace()准备命名空间mount_root()挂载根文件系统启动用户空间init进程
/sbin/init或内核参数指定的init程序init_task
内存管理结构
调度器结构
启动卡住
initcall_debug内核参数查看初始化调用顺序内存问题
dmesg输出中的内存初始化信息mem=nn[KMG]参数限制内存大小进行测试文件系统问题
printk调试
/proc/sys/kernel/printk控制日志级别KGDB调试
动态追踪
减少初始化时间
async机制)内存优化
调度优化
Linux内核的启动过程是一个复杂而精密的初始化序列,从底层硬件初始化到高级子系统建立,最终过渡到用户空间。理解start_kernel()及其相关函数的执行流程对于内核开发、驱动开发和系统调优都至关重要。通过分析这些核心函数,可以深入理解Linux内核的设计哲学和实现细节。