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内核的设计哲学和实现细节。