start_kernel 早期初始化机制与实现详解
源码路径:
rk3588/kernel-6.1/init/main.c(start_kernel)
内核版本:Linux 6.1(RK3588 / ARM64)
文档目录:linuxDoc/init/
目录
一、原理
1.1 角色
start_kernel() 是 架构无关 的内核主初始化函数:在 boot CPU、中断关闭 的早期环境中,依次建立内存管理、调度器、中断与时间子系统的基础,再打开中断并完成进程/VFS/cgroup 等“晚期”初始化,最后交给 rest_init() 进入多任务世界。
1.2 与 arch 的分工
| 层次 | 典型工作 |
|---|---|
arch/arm64 |
页表、异常向量、setup_arch、DT、SMP 表 |
start_kernel |
通用子系统顺序、命令行解析、调用 mm_init 等 |
二、实现方式
2.1 入口与早期安全
1 | asmlinkage __visible void __init __no_sanitize_address start_kernel(void) |
set_task_stack_end_magic(&init_task):栈溢出检测魔数cgroup_init_early():最早 cgroup 钩子setup_boot_config():可选 bootconfig blob
2.2 命令行与早期参数
setup_command_line合并 DT / 内置 / 用户 cmdline →saved_command_line- RK:分段
pr_cont打印(见第四节) parse_early_param():__setup中early标记的选项parse_args:内核模块参数表__param;--之后交给 init 的argv
2.3 内存与陷阱
| 调用 | 作用 |
|---|---|
mm_init() |
slab、vmalloc、buddy 相关晚期 mm 初始化 |
trap_init() |
陷阱/异常表(架构相关实现) |
sort_main_extable() |
内核异常表排序 |
须在 kmem_cache_init() 之前完成大块 bootmem 分配(如 setup_log_buf)。
2.4 调度、RCU、中断、时间
1 | sched_init(); |
注意:完整 CPU 拓扑与 SMP 负载均衡在 kernel_init_freeable 的 smp_init() / sched_init_smp(),此处仅为 单 CPU 可调度 的最小环境。
2.5 开中断后的“晚期”初始化
1 | local_irq_enable(); |
calibrate_delay():BogoMIPS(见 06)arch_call_rest_init():通常直接调用rest_init(),且 不再返回
三、关键接口与顺序
| 全局状态 | 设置时机 |
|---|---|
system_state |
rest_init 中设为 SYSTEM_SCHEDULING |
gfp_allowed_mask |
kernel_init_freeable 开头放开 |
四、RK3588 平台说明
CONFIG_ARCH_ROCKCHIP 时,首次 pr_notice 打印 cmdline 后,用循环 pr_cont 输出剩余字符,避免 单条日志长度限制 导致启动参数截断(排查 root=、console= 时很重要)。
五、调试与观测
| 手段 | 说明 |
|---|---|
earlyprintk / console= |
在 console_init 前后观察 |
initcall_debug |
对 initcall 更有效,但 start_kernel 末尾可开 trace |
ignore_loglevel |
强制打印级别 |
| 启动 stall | 对比 printk 时间戳,定位卡在 calibrate_delay、console_init 等 |
附录:源码索引
| 符号 | 文件 | 约行 |
|---|---|---|
start_kernel |
init/main.c |
939 |
parse_early_options |
init/main.c |
755 |
arch_call_rest_init |
arch 或 weak 默认 | — |
正在加载留言…