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

相关推荐
leoufung3 个月前
ECPF 简介
linux·网络·kernel
leoufung3 个月前
内核内存锁定机制与用户空间内存锁定的交互分析
linux·kernel
奔跑吧 android4 个月前
《Linux内存管理:实验驱动的深度探索》【附录】【实验环境搭建 4】【Qemu 如何模拟numa架构】
linux·qemu·内存管理·kernel
leoufung6 个月前
调度算法 HTB 或 CBQ 简介
linux·网络·kernel·driver·qos
hello_yj6 个月前
Linux Mem -- ARM8.5-A Memory Tagging Extension
linux·kernel
Once_day6 个月前
Linux之kernel(1)系统基础理论(2)
linux·操作系统·kernel
Once_day6 个月前
Linux之kernel(4)netlink通信
linux·kernel·netlink
Once_day6 个月前
Linux之kernel(1)系统基础理论(1)
linux·操作系统·kernel
plmm烟酒僧7 个月前
香橙派5Plus启动报错bug: spinlock bad magic on cpu#6, systemd-udevd/443
linux·bug·rk3588·kernel·香橙派·orangepi5plus