kernel启动过程中的调试打印

内核启动过程中涉及到多个地方,启动过程的代码由汇编代码和C代码组成。其中的打印函数也有多个。
1. 汇编阶段
打印函数包括如下几种:
printascii
printch
printhex8
printhex4
printhex2

这些函数定义在kernel/arch/arm/kernel/debug.S中,需要在make menuconfig中使能Kernel low-level debugging functions 才会这些内容编译进内核。

2. C语言阶段启动初期
在linux系统启动的初级阶段,”真正的”console驱动还没有加载进kernel,但是此时需要打印信息来调试内核,那么就需要使用early printk来调试,它的实现包括两部分,一个是early_printk的api,另一个对应的bootconsole驱动。
(1)early_printk函数是在kernel/kernel/printk.c文件中实现的
(2)bootconsole驱动一般属于平台相关,是在kernel/arch/arm/kernel/early_printk.c文件中实现

想要使用early_printk模块,还需要在make menuconfig中使能Early printk才会编译进内核。实际上在early_printk.c中对于bootconsole驱动的实现,也是调用到了前面汇编阶段所实现的代码printch的,也就是说最终打印所调用的底层函数都是汇编中的实现。那么就有一种依赖关系,具体的Makefile和Kconfig如下所示:

kernel/arch/arm/kernel/Makefile
obj-$(CONFIG_DEBUG_LL)  += debug.o
obj-$(CONFIG_EARLY_PRINTK)  += early_printk.o



Kernel/arch/arm/Kconfig.debug

config DEBUG_LL
      bool "Kernel low-level debugging functions "
      depends on DEBUG_KERNEL

config EARLY_PRINTK
     bool "Early printk"
     depends on DEBUG_LL

可以看出EARLY_PRINTK是依赖于DEBUG_LL的,也就是说要使能early_printk,必须也要使能DEBUG_LL才行。
在early_printk.c中:

static int __init setup_early_printk(char *buf)
{
    printk("%s enter\n", __func__);
    register_console(&early_console);
    return 0;
}
early_param("earlyprintk", setup_early_printk);

虽然内核配置了,但是要让内核调用setup_early_printk还必须在u-boot给内核传参的时候给bootargs在加上一个参数”earlyprintk”,比如:

set bootargs ‘console=ttyS5,115200,115200n8 androidboot.console=ttySAC0 uhost0=n ctp=2 skipcali=y vmalloc=384m lcd=S70 **earlyprintk**’

3. C语言启动后期
这是在真正的consolo驱动加载以后,此时就不再使用debug.S中的打印实现了,而是另外实现了一个linux标准tty驱动来作为printk的输出,这个也就是我们常用的pirntk了。

所以说当kernel启动不了,但又没有什么提示消息时,可以打开early printk查看。

因为在内核刚启动时,有些打印语句可能在串口还没有注册之前就调用了,那就不能显示了,early printk就是实现这个功能。
选上以下内核配置就可以了:
Kernel hacking —> Kernel low-level debugging functions –> Early printk
比如内核打印如下:
Starting kernel …

Uncompressing Linux… done, booting the kernel.
接着就什么都没了,这时候把early printk选上,果然看到kernel刚启动的信息了。

你可能感兴趣的:(内核笔记)