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的驱动输出后续日志。完成了整个内核初始化及后续过程中的日志输出不同阶段的衔接。

相关推荐
mounter6257 小时前
深入理解 Linux 网络新特性:netkit 中的 RX/TX Queue Leasing 与 TCP Devmem
linux·服务器·网络·tcp/ip·kernel
mounter6253 天前
Linux Kernel Design Patterns (Part 2):从经典链表到现代 XArray,拆解内核复杂数据结构的设计哲学
linux·数据结构·链表·设计模式·内存管理·kernel
mounter62510 天前
【内核新动向】告别物理槽位束缚:深度解析 Linux Virtual Swap Space 机制
linux·内存管理·kernel·swap·virtual swap
Railshiqian11 天前
安卓源码编译ko文件到设备img,并在开机阶段自动加载
android·kernel
Railshiqian11 天前
common-android15-6.6 kernel环境下,编写并编译一个helloworld驱动模块
android·kernel
mounter62512 天前
【内核前沿】Linux IPC 迎来大变局?POSIX 消息队列增强、io_uring IPC 与 Bus1 十年回归
linux·运维·服务器·kernel·ipc·io_uring
mounter62516 天前
深度拦截:Linux 内核引入 Firmware LSM 挂钩,eBPF 再下一城!
linux·服务器·ebpf·kernel·firmware
吴烦恼的博客18 天前
RK3588-kernel BringUp记录(二)
linux·kernel
mounter62518 天前
【深度解析】Device Memory TCP:开启高性能网络传输的“零拷贝”新时代
linux·服务器·网络·网络协议·tcp/ip·kernel·devmem
mounter62522 天前
【硬核前沿】CXL 深度解析:重塑数据中心架构的“高速公路”,Linux 内核如何应对挑战?-- CXL 协议详解与 LSF/MM 最新动态
linux·服务器·网络·架构·kernel