printk: legacy bootconsole [sbi0] disabled是 console_init()→ register_console()里反注册 early console 时打的,它发生在 start_kernel()中 console_init()返回之后、调用 calibrate_delay()(即 "Calibrating delay loop...")之前。这段区间是内核完成大量内存/调度/时间子系统初始化的关键阶段。
以 Linux 5.x/6.x init/main.c::start_kernel()为主,流程如下:
console_init()之后 → calibrate_delay()之前的调用链
start_kernel()
{
...
console_init(); // ← 这里 sbi0 bootconsole 被 disable,正式 console 注册
// 打印: "console [ttyS0] enabled"
// "legacy bootconsole [sbi0] disabled"
if (panic_later) panic(...);
lockdep_info(); // 打印 lockdep 信息(若 CONFIG_LOCKDEP=y)
locking_selftest(); // 锁依赖自测(rwlock/mutex/ww_mutex 等)
page_ext_init(); // 页扩展调试初始化(DEBUG_PAGEALLOC/KASAN 场景)
debug_objects_mem_init(); // debugobjects 内存池
kmemleak_init(); // 内存泄漏检测初始化
setup_per_cpu_pageset(); // 每个 CPU 的页集(pcp)初始化
numa_policy_init(); // NUMA 内存策略(UP 上基本空操作)
if (late_time_init) // RISC-V 通常在这里调 riscv_time_init()
late_time_init();
sched_clock_init(); // 调度器时钟源初始化(sched_clock 可用)
calibrate_delay(); // ← 打印 "Calibrating delay loop..."
...
}
各步骤简要说明
| 函数 | 作用 |
|---|---|
console_init()返回 |
bootconsolesbi0 已 unregister,正式串口 console 接管 printk 输出 |
**lockdep_info()/ locking_selftest()** |
若开启 LOCKDEP,做锁反转检测自测并打印结果 |
**debug_objects_mem_init()/ kmemleak_init()** |
初始化对象生命周期追踪和内存泄漏检测(调试内核可见) |
**setup_per_cpu_pageset()** |
为每个 CPU 建立 struct per_cpu_pageset,zone->pageset 指向它 |
**numa_policy_init()** |
初始化 NUMA 默认内存分配策略(非 NUMA 基本是空) |
**late_time_init()** |
RISC-V 平台在此完成 clint/clocksource 时间源注册(早于 calibrate_delay 用 timer) |
**sched_clock_init()** |
使能 sched_clock(),部分架构此前不可用 |
**calibrate_delay()** |
跑 delay loop 测定 lpj(loops_per_jiffy),打印 **Calibrating delay loop...** |
特别说明(RISC-V SBI 场景)
-
[sbi0] disabled说明 earlycon=sbi的 early console 已被unregister_console()摘除,正式 8250/SIFIVE/NS16550 串口 console 已接管 -
RISC-V 的
late_time_init = riscv_time_init(在setup_arch()中赋值),在calibrate_delay()之前被调用,确保 timer 已就绪------否则calibrate_delay()可能用 jiffy 方式校准而非高精度 timer -
如果
keep_bootcon在 cmdline,bootconsole 不注销,这行日志不会出现
一句话总结: bootconsole [sbi0] disabled是 console_init()退出的标志,之后内核依次做完 lockdep 自检 → debug/kmemleak → per-cpu pageset → NUMA policy → late_time_init(RISC-V timer) → sched_clock_init,然后立刻进 calibrate_delay()打出 "Calibrating delay loop"。