Linux内核的主函数是start_kernel()
,它位于init/main.c
文件中。这个函数是内核初始化过程的核心,负责初始化内核的所有主要子系统,并最终启动用户空间的第一个进程(通常是init进程)。
以下是start_kernel()
函数的主要执行流程:
asmlinkage __visible void __init start_kernel(void)
{
char *command_line;
char *after_dashes;
// 设置当前任务(0号进程)的CPU掩码
set_task_stack_end_magic(&init_task);
// 初始化调试系统
boot_init_stack_canary();
// 初始化cgroup的早期子系统
cgroup_init_early();
// 关闭本地中断
local_irq_disable();
// 早期控制台初始化
early_boot_irqs_disabled = true;
boot_cpu_init();
page_address_init();
pr_notice("%s", linux_banner);
setup_arch(&command_line);
// 初始化内存管理
mm_init_cpumask(&init_mm);
setup_command_line(command_line);
setup_nr_cpu_ids();
setup_per_cpu_areas();
smp_prepare_boot_cpu();
// 构建所有CPU的调度域
build_all_zonelists(NULL);
page_alloc_init();
}
// 打印命令行参数
pr_notice("Kernel command line: %s\n", boot_command_line);
// 解析命令行参数
parse_early_param();
after_dashes = parse_args("Booting kernel",
static_command_line, __start___param,
__stop___param - __start___param,
-1, -1, &unknown_bootoption);
// 初始化跳转标签
jump_label_init();
// 设置日志缓冲区
setup_log_buf(0);
// 初始化PID哈希表
pidhash_init();
// 初始化虚拟文件系统(VFS)缓存
vfs_caches_init_early();
// 初始化排序机制
sort_main_extable();
// 初始化中断和陷阱
trap_init();
// 初始化内存管理
mm_init();
// 初始化调度器
sched_init();
// 初始化RCU机制
rcu_init();
// 初始化定时器
tick_init();
init_timers();
hrtimers_init();
softirq_init();
timekeeping_init();
time_init();
// 初始化性能事件
perf_event_init();
// 初始化分析器
profile_init();
// 初始化控制台
console_init();
// 初始化锁调试
lockdep_info();
// 初始化内存保护键
pkeys_init();
// 初始化页表
page_ext_init();
// 初始化kmemleak
kmemleak_init();
// 初始化调试对象
debug_objects_mem_init();
// 初始化内核内存分配器
setup_per_cpu_pageset();
numa_policy_init();
if (late_time_init)
late_time_init();
sched_clock_init();
calibrate_delay();
pidmap_init();
anon_vma_init();
acpi_early_init();
thread_stack_cache_init();
cred_init();
fork_init();
proc_caches_init();
buffer_init();
key_init();
security_init();
dbg_late_init();
vfs_caches_init();
pagecache_init();
signals_init();
proc_root_init();
nsfs_init();
cpuset_init();
cgroup_init();
taskstats_init_early();
delayacct_init();
check_bugs();
acpi_subsystem_init();
sfi_init_late();
efi_enable_reset_attack_mitigation();
ftrace_init();
// 初始化设备驱动
rest_init();
}
在start_kernel()
的最后,会调用rest_init()
函数,这是内核初始化的最后阶段:
static noinline void __init_refok rest_init(void)
{
int pid;
// 创建内核线程kernel_init(即init进程)
kernel_thread(kernel_init, NULL, CLONE_FS);
// 创建kthreadd内核线程
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
// 设置kthreadd线程的CPU亲和性
rcu_read_lock();
kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
rcu_read_unlock();
// 完成系统启动
complete(&kthreadd_done);
// 初始化调度器空闲循环
init_idle_bootup_task(current);
// 调度器开始运行
schedule_preempt_disabled();
// CPU进入空闲状态
cpu_startup_entry(CPUHP_ONLINE);
}
mm_init()
函数负责初始化内存管理系统:
- 初始化页表
- 建立内存区域(zone)
- 初始化slab分配器
- 设置虚拟内存管理
sched_init()
函数初始化进程调度系统:
- 初始化运行队列
- 设置调度类
- 建立调度域
- 初始化负载均衡机制
设备驱动初始化分为多个阶段:
1. 早期控制台初始化(console_init()
)
2. 核心驱动框架初始化
3. 平台特定驱动初始化
4. 设备树解析和驱动匹配
vfs_caches_init()
初始化虚拟文件系统:
- 初始化inode缓存
- 初始化dentry缓存
- 注册默认文件系统
- 挂载根文件系统
kernel_init()
函数负责从内核空间过渡到用户空间:
1. 完成剩余的初始化工作
2. 尝试执行用户指定的init程序
3. 如果失败,尝试默认的init程序(/sbin/init, /etc/init等)
4. 如果所有init程序都失败,执行/bin/sh作为最后手段
Linux内核的启动过程是一个复杂而有序的过程,start_kernel()
作为主函数协调了所有子系统的初始化。理解这个过程对于深入掌握Linux内核工作原理、进行内核调试和性能优化都非常重要。每个子系统的初始化顺序都经过精心设计,确保依赖关系得到正确处理,最终为用户空间提供一个稳定可靠的运行环境。