Skip to the content.

pl011

AMBA 是片上总线架构,PL011 是具体的 UART 控制器。

为什么 arm 虚拟机不需要配置console=ttyAMA0 默认就有输出

固件提供的 ACPI SPCR 表指定了串口 console,因此不需要显式配置 console=ttyAMA0。

guest 内核是 6.14.0-63.fc42.aarch64,启动日志明确记录:

ACPI: SPCR: console: pl011,mmio32,0x9000000,9600
ACPI: Use ACPI SPCR as default console: Yes
ARMH0011:00: ttyAMA0 at MMIO 0x9000000 ...
printk: legacy console [ttyAMA0] enabled

/proc/consoles 和 /sys/class/tty/console/active 也确认当前 console 是 ttyAMA0。对应源码路径是:

  1. arch/arm64/kernel/acpi.c 中的 acpi_boot_table_init() 默认启用 SPCR console。源码 (https://github.com/torvalds/linux/blob/v6.14/arch/arm64/kernel/acpi.c)

  2. drivers/acpi/spcr.c 中的 acpi_parse_spcr() 读取串口类型、地址和波特率,通过 add_preferred_console() 添加 console。源码 (https://github.com/torvalds/linux/blob/v6.14/drivers/acpi/spcr.c)

  3. PL011 驱动的 pl011_console_match() 按地址 0x9000000 匹配到 ttyAMA0。源码 (https://github.com/torvalds/linux/blob/v6.14/drivers/tty/serial/amba-pl011.c)

PL011 注册时匹配不上这个名字,register_console() 会继续尝试平台默认配置,于是匹配到了 SPCR 指定的串口。源码中的 register_console() (https://github.com/torvalds/linux/blob/v6.14/kernel/printk/printk.c)

基本初始化的过程

drivers/tty/serial/amba-pl010.c

static struct console amba_console = {
	.name		= "ttyAMA",
	.device		= uart_console_device,
	.setup		= pl011_console_setup,
	.match		= pl011_console_match,
	.write_atomic	= pl011_console_write_atomic,
	.write_thread	= pl011_console_write_thread,
	.device_lock	= pl011_console_device_lock,
	.device_unlock	= pl011_console_device_unlock,
	.flags		= CON_PRINTBUFFER | CON_ANYTIME | CON_NBCON,
	.index		= -1,
	.data		= &amba_reg,
};

sbsa_uart_probe() → pl011_register_port() → uart_add_one_port() → serial_ctrl_register_port() → serial_core_register_port() → serial_core_add_one_port() → uart_configure_port() → register_console(port->cons)

drivers/tty/serial/8250/8250_core.c

static struct console univ8250_console = {
	.name		= "ttyS",
	.write		= univ8250_console_write,
	.device		= uart_console_device,
	.setup		= univ8250_console_setup,
	.exit		= univ8250_console_exit,
	.match		= univ8250_console_match,
	.flags		= CON_PRINTBUFFER | CON_ANYTIME,
	.index		= -1,
	.data		= &serial8250_reg,
};
static int __init univ8250_console_init(void)
{
	if (nr_uarts == 0)
		return -ENODEV;

	serial8250_isa_init_ports();
	register_console(&univ8250_console);
	return 0;
}
console_initcall(univ8250_console_init);

本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。