14.7printk 和 early_printk console驱动
在 Linux 内核中,printk()是最常用的调试手段。printk()的打印消息会放入一个环形缓冲区(RingBuffer),而/proc/kmsg 文件用于描述这个环形缓冲区。通过 dmesg 命令或 klogd 可以读取该环形缓冲区。如果用户空间的 klogd 守护进程在运行,klogd将获取内核消息并分发给 syslogd,syslogd 接着检查/etc/syslog.conf 来找出如何处理它们。
内核 printk 信息支持 8 个级别,优先级从高到低(数值越高,级别越低,消息越不重要)分别是:KERN_EMERG(数值为0)、KERNEL_ALERT、KERN_CRIT、KERN_ERR、KERN_WARNING、KERN_NOTICE、KERN_INFO、KERN_DEBUG(数值为7)。当调用 printk()函数时指定的优先级小于指定的控制台优先级 console_loglevel 时,调试消息显示在控制台终端。默认的的 console_loglevel 值是 DEFAULT_CONSOLE_LOGLEVEL,用户可以使用系统调用 sys_syslog 或 klogd -c 来修改 console_loglevel 值,也可以直接 echo 值到/proc/sys/kernel/printk。/proc/sys/kernel/printk文件包含四个整数值,第一个表示系统当前的优先级,第二个表示系统默认的优先级。
在 Linux 中,用于 printk 输出的是内核 console,用 console 结构体来描述,如代码清单 14.19 所示。
代码清单 14.19 用于 printk 的 console 结构体
include/linux/console.h
struct console {
char name[16];
void (*write)(struct console *, const char *, unsigned);
int (*read)(struct console *, char *, unsigned);
struct tty_driver *(*device)(struct console *, int *);
void (*unblank)(void);
int (*setup)(struct console *, char *);
short flags;
short index;
int cflag;
void *data;
struct console *next;
};
分析:
其中,较关键的是 write()和 setup()成员函数,write()用于将打印消息写入 console,setup()用于设置 console 的特性,如波特率、停止位等。
printk()函数经过重重调用,经过_ _call_console_drivers()函数,最终调用 console 的 write()成员函数将控制台消息打印出去,如代码清单 14.20 所示。
代码清单 14.20 printk()最终调用到 console 的 write()成员函数
kernel/printk.c
/*
* Call the console drivers on a ran