ARM64,在kernel未建立console之前,使用earlycon,实现打印。在bootargs中,要加入如下选项:
pl011表示针对pl011这个串口设备,0x70000000是串口的起始地址。
使用 amba-pl011串口,在 amba-pl011.c中,
有如下宏定义:
展开之后,
定义了一个earlycon_id结构的变量_earlycon_pl011。该变量中, setup函数指针指向pl011_early_console_setup函数。
在 earlycon.c(drivers/tty/serial)中,有如下宏定义:
展开如下,定义一个变量,和一个结构体变量。结构体变量,放在了.init.setup段中。
s
obs_kernel_param原型:
在 init/main.c中, start_kernel->setup_arch->parse_early_param,通过cmdline传递的参数,进行early初始化。
通过parse_early_op
tions函数,分析cmdline,也就是bootargs。
调用parse_args,从cmdline中,分析early options。关键是do_early_param函数。参数param是cmdline中的参数变量以及参数值。
这里的__setup_start,是链接脚本中的变量,定义如下,该变量是段.init.setup的起始地址,__setup_end是.init.setup段的结束地址。
do_early_param函数的for循环中,从.init.setup段中,依次将obs_kernel_param结构体变量取出来,如果变量中的early为1,并且变量中的str,和函数的参数一致,那么调用结构体中的setup_func函数。
在之前,__setup_param_setup_earlycon变量,是定义在.init.setup段。如下图所示。
因为cmdline中,传递了earlycon参数,匹配__setup_param_setup_earlycon中的earlycon,因此执行param_setup_earlycon函数。
在earlycon.c(drivers/tty/serial),有该函数,该函数调用setup_earlycon函数。
对于setup_earlycon函数,参数buf是cmdline的参数值。在这里是earlycon=pl011,0x70000000。
遍历__earlycon_table开始的earlycon_id类型的变量。
对于_earlycon_table,是定义在链接脚本中,保存__early_table段的起始地址。
__early_table = .; (__early_table) (__earlycon_table_end) . = ALIGN(8)
在之前,有定义_earlycon_pl011变量,并且,放在了__early_table段中。
cmdline传的参数是 earlycon=pl011,0x70000000,
参数值为pl011,0x70000000,逗号之前的pl011和_earlycon_pl011变量中的pl011匹配,因此执行register_earlycon函数。
该函数的2个参数,buf,是0x70000000,match是_earlycon_pl011变量的指针。
最终,调用match->setup函数,建立earlycon,其实就是调用pl011_early_console_setup。
其实就是将设置write函数指针为pl011_early_write。这样,在kernel未建立console之前,使用printk打印的信息,最终是调用pl011_early_write函数输出了。
过程中遇到的问题:
在kernel未建立console之前,printk打印的信息是怎么输出?
对于ARM64,通过earlycon机制输出。
在kernel未初始化earlycon之前,printk打印的信息是怎么输出?
在未初始化earlycon之前,printk打印的信息,其实是没有打印出来的,打印信息保存在内部的缓冲区,等待earlycon建立好后,缓冲区的信息才被打印出来。