rest_init 与 kernel_init 机制与实现详解
源码路径:
rk3588/kernel-6.1/init/main.c
内核版本:Linux 6.1(RK3588 / ARM64)
文档目录:linuxDoc/init/
目录
一、原理
1.1 为何需要 rest_init
start_kernel() 运行在 init_task 上且长期关抢占。再继续在同一上下文里挂根、exec init 会阻塞 boot CPU。rest_init() 的职责是:
- 创建 将变为 PID 1 的
kernel_init内核线程 - 创建
kthreadd(其它内核线程的父线程) - 让当前 boot 线程进入 idle
1.2 kernel_init 两阶段
| 阶段 | 函数 | 内容 |
|---|---|---|
| 可释放 init 内存前 | kernel_init_freeable |
SMP、initcall、initramfs、挂根 |
| 之后 | kernel_init 本体 |
free_initmem、SYSTEM_RUNNING、kernel_execve |
二、实现方式
2.1 rest_init()
1 | noinline void __ref rest_init(void) |
顺序约束:必须先有 kthreadd,否则 kernel_init 里创建 kthread 会 OOPS;因此 kernel_init 开头 wait_for_completion(&kthreadd_done)。
2.2 kernel_init_freeable()
典型顺序:
1 | gfp_allowed_mask = __GFP_BITS_MASK |
2.3 kernel_init() 收尾
1 | system_state = SYSTEM_FREEING_INITMEM; |
run_init_process() 内部 kernel_execve,使用 argv_init / envp_init(含 init= 与 -- 后参数)。
2.4 早期用户态 init(initramfs)
若 ramdisk_execute_command(默认常为 /init)存在且可访问,可能在 prepare_namespace 之前由 initramfs 脚本完成挂根;否则走 prepare_namespace()。逻辑在 kernel_init_freeable:
1 | if (init_eaccess(ramdisk_execute_command) != 0) { |
三、关键数据结构与接口
| 符号 | 含义 |
|---|---|
kthreadd_done |
completion,同步 kthreadd 就绪 |
execute_command |
init= 启动参数 |
ramdisk_execute_command |
initramfs 中 init 路径 |
system_state |
SYSTEM_SCHEDULING → FREEING_INITMEM → RUNNING |
cad_pid |
Ctrl-Alt-Del 处理用 pid(在 freeable 中设置) |
四、RK3588 平台说明
CONFIG_ROCKCHIP_THUNDER_BOOT_DEFER_FREE_MEMBLOCK 时,在 smp_init() / sched_init_smp() 之后启动 defer_mem 内核线程,将 memblock 延迟释放与 buddy 初始化并行。详见 07。
编解码板卡上 PID 1 多为 systemd 或 busybox;内核只负责 exec,服务编排不在 init/。
五、调试与观测
| 现象 | 排查 |
|---|---|
卡在 Freeing unused kernel memory 之前 |
initcall、wait_for_initramfs |
No working init found |
init= 路径、rootfs 是否含 /sbin/init |
| 重复挂根 | initramfs /init 是否已 pivot_root |
Failed to execute ... (error -2) |
ENOENT,检查 initramfs 或根分区 |
ps 不可用时,用 printk 中 Run ... as init process 确认 exec 目标。
附录:源码索引
| 符号 | 约行 main.c |
|---|---|
rest_init |
687 |
kernel_init |
1713 |
kernel_init_freeable |
1803 |
run_init_process |
1626 |
相关:03 initcall、04 挂根
正在加载留言…