如果正常配置了输入输出终端,则内核启动过程中会将很多信息输出到控制台上。这些信息中有些表示严重错误,有些只是一般的提示信息。
在平台成熟后,继续保留这些信息既不美观,也会影响启动速度(串口的波特率很低)。因此要尽量屏蔽不重要的信息。这需要对内核进行一些改造。
内核打印分析
内核启动过程中的打印都是通过printk()输出的,按照重要程度,内核把这些打印分类为8个级别:
============== include/linux/printk.h 7 14 ===================#define KERN_EMERG "<0>" /* system is unusable */#define KERN_ALERT "<1>" /* action must be taken immediately */#define KERN_CRIT "<2>" /* critical conditions */#define KERN_ERR "<3>" /* error conditions */#define KERN_WARNING "<4>" /* warning conditions */#define KERN_NOTICE "<5>" /* normal but significant condition */#define KERN_INFO "<6>" /* informational */#define KERN_DEBUG "<7>" /* debug-level messages */ 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
此外,内核还定义了一些宏来表示要输出到控制台上的级别、printk函数的默认级别等,在一个数组中描述:
=============== kernel/printk.c 60 74 =====================/* printk's without a loglevel use this.. */#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING *//* We show everything that is MORE important than this.. */#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */DECLARE_WAIT_QUEUE_HEAD(log_wait);int console_printk[4] = { DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */ DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */ MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */ DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */}; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
浏览内核代码可以看到,基本上启动过程中的打印都是以默认级别KERN_WARNING及以下级别输出,因此要控制这些信息,只需要修改上面几个宏即可,尤其是将DEFAULT_CONSOLE_LOGLEVEL修改为4即可屏蔽大部分信息。
重新编译内核后尝试启动,可见大部分输出都被屏蔽了。
恢复打印
启动完成后恢复打印
改造后大部分的打印信息消失,但是启动后一些模块的正常printk也会被屏蔽,这会漏失掉很多重要信息,为此在启动完成后要恢复打印,方法是在启动脚本中执行一句:
echo 7 4 1 7 > /proc/sys/kernel/printk
就能恢复默认打印级别。
找回启动过程中的打印
如果启动过程异常,是不是打印就找不回来呢?当然不是,内核的printk除了向控制台输出外,还将一些信息输出到了/proc/kmsg中,可以在启动后通过dmsg命令全部找回。
恢复启动时打印
如果需要临时恢复打印,并不需要重新编译内核。在启动参数中配置一项ignore_loglevel即可:
=============== kernel/printk.c 471 479 ==================static int __init ignore_loglevel_setup(char *str){ ignore_loglevel = 1; printk(KERN_INFO "debug: ignoring loglevel setting.\n"); return 0;}early_param("ignore_loglevel", ignore_loglevel_setup); 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10
在输出时会判断ignore_loglevel变量,如果为真则无论如何都会将信息输出到控制台上。