Linux 内核启动过程中的日志输出阶段分析

问题描述

在对比原理图后,发现打印日志的串口是UART2(GPIO3_A2 & GPIO3_A3),但设备树中只开启了UART0(GPIO1_C2&GPIO1_C3)

/* 以下设备树内容来自多个设备树描述文件*/

dts 复制代码
&uart0 {
	pinctrl-names = "default";
	pinctrl-0 = <&uart0_xfer &uart0_ctsn>;
	status = "okay";
};
uart0: serial@ff560000 {
	compatible = "rockchip,rv1126-uart", "snps,dw-apb-uart";
	reg = <0xff560000 0x100>;
	interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
	reg-shift = <2>;
	reg-io-width = <4>;
	dmas = <&dmac 5>, <&dmac 4>;
	clock-frequency = <24000000>;
	clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>;
	clock-names = "baudclk", "apb_pclk";
	pinctrl-names = "default";
	pinctrl-0 = <&uart0_xfer &uart0_ctsn &uart0_rtsn>;
	status = "disabled";
};
uart0_xfer: uart0-xfer {
	rockchip,pins =
		/* uart0_rx */
		<1 RK_PC2 1 &pcfg_pull_up>,
		/* uart0_tx */
		<1 RK_PC3 1 &pcfg_pull_up>;
};
uart2: serial@ff570000 {
	compatible = "rockchip,rv1126-uart", "snps,dw-apb-uart";
	reg = <0xff570000 0x100>;
	interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
	reg-shift = <2>;
	reg-io-width = <4>;
	dmas = <&dmac 9>, <&dmac 8>;
	clock-frequency = <24000000>;
	clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>;
	clock-names = "baudclk", "apb_pclk";
	pinctrl-names = "default";
	pinctrl-0 = <&uart2m1_xfer>;
	status = "disabled";
};
uart2m1_xfer: uart2m1-xfer {
	rockchip,pins =
		/* uart2_rx_m1 */
		<3 RK_PA3 1 &pcfg_pull_up>,
		/* uart2_tx_m1 */
		<3 RK_PA2 1 &pcfg_pull_up>;
};

问题分析

无论是硬件原理图还是实际结果都表示启动日志是从UART2打印出来的,所以我们就要尽量往UART2去拓展。

由设备树可以得到内核启动参数 bootargs

dts 复制代码
chosen {
  bootargs = "earlycon=uart8250,mmio32,0xff570000 console=ttyFIQ0 root=PARTUUID=614e0000-0000 rootfstype=ext4 rootwait snd_aloop.index=7";
};

earlycon阶段(内核初始化早期)

首先可以看到earlycon=uart8250,mmio32,0xff570000earlycon直接在设备树解析前初始化硬件,不依赖设备树中的status属性。在内核初始化早期,直接向地址0xff570000 输出日志,对比之前提到的设备树配置,我们可以看到这个地址就是UART2串口。

标准console阶段(内核初始化后期)

bootargs中设置了console=ttyFIQ0

  • 由于UART2在设备树中被标记为disabled,内核不会注册标准UART驱动(如ttyS2)
  • 后续日志会通过ttyFIQ0输出(通常是 Rockchip 的 FIQ 调试串口)
    就像一个知道结果的解谜游戏,我们现在大可以猜测是不是ttyFIQ0配置了UART2,接过了日志输出的任务并继续向UART2输出(通过FIQ驱动,绕过标准UART状态),接下来我们继续分析设备树:
dts 复制代码
&fiq_debugger {
	status = "okay";
};

fiq_debugger是启用的,我们继续向上层设备树文件找,目前来到了rv1126.dtsi

dts 复制代码
fiq_debugger: fiq-debugger {
	compatible = "rockchip,fiq-debugger";
	rockchip,serial-id = <2>;  // 绑定到 UART2
	rockchip,wake-irq = <0>;
	rockchip,irq-mode-enable = <0>;
	rockchip,baudrate = <1500000>;  /* Only 115200 and 1500000 */
	interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
	status = "disabled";
};

出现了!rockchip,serial-id = <2>,我们可以看到fiq_debugger节点绑定到了UART2,由此完成了内核启动早期与后期的日志输出的衔接。

总结

本篇文章是由一个statusdisable但却被作为日志输出的UART2引出,核心是围绕着bootargs中的earlyconconsole参数展开。earlycon直接通过UART2的地址,在设备树解析前输出早期日志;console通过FIQ调试串口,复用了UART2的端口,实际上是使用了FIQ的驱动输出后续日志。完成了整个内核初始化及后续过程中的日志输出不同阶段的衔接。

相关推荐
mounter6254 天前
跨越鸿沟:从内核驱动开发到超大规模云端生产环境的思考
linux·驱动开发·linux kernel·kernel
mounter6254 天前
探索未来 AI 算力网络的基石:从传统 RoCE 走向 SRv6 驱动的弹性弹性网络(解析 Netdev 0x1A 创新实践)
linux·网络·人工智能·linux kernel·kernel·rdma·rocev2
mounter6254 天前
从内存隔离到运行时防线:透视 Linux 内核安全强化的博弈与演进
linux·网络·安全·linux kernel·kernel
mounter6255 天前
现代 Linux 内核中的数据持久化艺术:从回写(Writeback)到多样化写策略
linux·linux kernel·kernel·writeback·writethrough
mounter6256 天前
质检员与超能引擎的碰撞:KASAN 护航 eBPF JIT 的技术演进与安全抉择
linux·ebpf·linux kernel·kernel·kasan
mounter6256 天前
走向长时运行:引入协程(Coroutines),打破 BPF 程序的“一堂到底”限制
linux·ebpf·kernel
mounter6258 天前
Linux 7.2 内核技术前瞻:核心 subsystems 合并与重构深度解析
linux·kernel
mounter62510 天前
BPF 的进化史:从网络过滤器到 AI 时代的 Linux 核心引擎
linux·网络·人工智能·ebpf·linux kernel·kernel
胖大和尚11 天前
Linux 内核工程师、HPC工程师、C++工程师
c++·kernel·hpc
mounter62514 天前
深入解析 RDMA 中的 Address Handler (AH) 缓存:AWS EFA 驱动的硬件演进与软件复用艺术
linux·kernel·rdma·hashtable·hash table·address handle