关于 earlycon 的实现机制,已经有很多文章提及,这里就不赘述了。
主要就是记录在某高通平台打开 earlycon 的一个过程记录。
使用 earlycon 最好的方式,其参数是从 dtb 取得,也就是我们要在 dts 里配置 chosen 节点
chosen {
bootargs = "sched_enable_hmp=1 sched_enable_power_aware=1 app_setting.use_32bit_app_setting=1";
stdout-path = &uart0;
};
关于 stdout-path ,在这个平台上并没有 uart0 这个节点,其 /proc/cmdline 里控制台参数是
console=ttyHSL0,115200,n8
查看下它的设备号
# ls -l /dev/ttyHSL0
crw------- 1 root root 240, 0 1970-01-01 06:27 /dev/ttyHSL0
查看下其他相关信息
# cd /sys/dev/char/240:0
/sys/dev/char/240:0 # cat iomem_base
0x75B0000
/sys/dev/char/240:0 # cat uevent
MAJOR=240
MINOR=0
DEVNAME=ttyHSL0
/sys/dev/char/240:0 # cd device/
/sys/dev/char/240:0/device # cat uevent e
DRIVER=msm_serial_hsl
OF_NAME=serial
OF_FULLNAME=/soc/serial@075b0000
OF_COMPATIBLE_0=qcom,msm-lsuart-v14
OF_COMPATIBLE_N=1
MODALIAS=of:NserialT<NULL>Cqcom,msm-lsuart-v14
根据 compatible 和 iomem_base 从相关的dtsi 里确认,其 stdout-path 应该为
chosen {
bootargs = "sched_enable_hmp=1 sched_enable_power_aware=1 app_setting.use_32bit_app_setting=1";
stdout-path = &uartblsp2dm1;
};
找到平台对应的mk 文件(这里是BoardConfig.mk)添加
ifneq ($(TARGET_BUILD_VARIANT),user)
BOARD_KERNEL_CMDLINE += earlycon
endif
结果发现并没有生效,而是出现这样的 Kernel log
[ 0.000000] Malformed early option 'earlycon'
由网上的文章,我们可以知道,在一个特定系统里对于 earlycon 支持,关键的几个配置开关
CONFIG_DEBUG_KERNEL=y
CONFIG_SERIAL_EARLYCON=y
CONFIG_OF_EARLY_FLATTREE=Y
几个定义
EARLYCON_DECLARE
OF_EARLYCON_DECLARE
在代码里查找,发现使用的是
EARLYCON_DECLARE(msm_hsl_uart, msm_hsl_earlycon_setup);
OF_EARLYCON_DECLARE(msm_hsl_uart, "qcom,msm_hsl_uart", msm_hsl_earlycon_setup);
由 fdt.c 里的相关源码
#ifdef CONFIG_SERIAL_EARLYCON
extern struct of_device_id __earlycon_of_table[];
static int __init early_init_dt_scan_chosen_serial(void)
{
int offset;
const char *p;
int l;
const struct of_device_id *match = __earlycon_of_table;
const void *fdt = initial_boot_params;
offset = fdt_path_offset(fdt, "/chosen");
if (offset < 0)
offset = fdt_path_offset(fdt, "/chosen@0");
if (offset < 0)
return -ENOENT;
p = fdt_getprop(fdt, offset, "stdout-path", &l);
if (!p)
p = fdt_getprop(fdt, offset, "linux,stdout-path", &l);
if (!p || !l)
return -ENOENT;
/* Get the node specified by stdout-path */
offset = fdt_path_offset(fdt, p);
if (offset < 0)
return -ENODEV;
while (match->compatible[0]) {
unsigned long addr;
if (fdt_node_check_compatible(fdt, offset, match->compatible)) {
match++;
continue;
}
addr = fdt_translate_address(fdt, offset);
if (!addr){
return -ENXIO;
}
of_setup_earlycon(addr, match->data);
return 0;
}
return -ENODEV;
}
static int __init setup_of_earlycon(char *buf)
{
if (buf)
return 0;
return early_init_dt_scan_chosen_serial();
}
early_param("earlycon", setup_of_earlycon);
#endif
在进行 of 扫描时,会检查 compatible,因此换里这里的
OF_EARLYCON_DECLARE(msm_hsl_uart, "qcom,msm_hsl_uart", msm_hsl_earlycon_setup);
应当改为
OF_EARLYCON_DECLARE(msm_hsl_uart, "qcom,msm-lsuart-v14", msm_hsl_earlycon_setup);
重新编译下载 boot.img,果然 OK 。
后续阅读 Documentation/kernel-parameters.txt,关于 earlycon 还有与msm_hsl_uart 相关的一段说明
earlycon= [KNL] Output early console device and options.
.
.
.
msm_hsl_uart,<addr>
Start an early, polled-mode console on an msm serial
port at the specified address. The serial port
must already be setup and configured. Options are not
yet supported.
.
.
.
我们如果只修改 kernel 的命令行
BOARD_KERNEL_CMDLINE += earlycon=msm_hsl_uart,0x075b0000
也是可以的,但是这样,参数就不是从 dtb 读取。