驱动程序里经常可以看到printk,那他和常见的printf有啥区别?使用起来没有区别!printk和printf的格式可以说一模一样,比如要打印变量a的值:
//printk
printk("a = %d\n", a);
//printf
printf("a = %d\n", a);
但不一样的是printk可以手动指定打印级别,指定级别时写法如下:
在字符串前面加上指定的宏,KERN_WARNING是其中的一个宏
//printk 带打印级别
printk(KERN_WARNING"a = %d\n", a);
图片上可以看到KERN_WARNING的打印级别为4,相关的宏总共有8个,也就是打印级别可以分为0-7,数字越小级别越高。那有两个问题,使用printk时不指定打印级别的话它的默认级别是多少,还是说没有级别?这些级别的用处体现在哪?
回答第一个问题:使用printk时若没有明确指定打印级别,内核会在语句处理前添加默认的打印级别:“4”;
回答第二个问题:现在我们知道了,每条printk语句都有自己的打印级别,要不就是手动指定的要不就是内核添加的,当该级别小于某个阈值时,内核才会打印该信息;若该级别大于该阈值时,则不打印该信息,注意,仅仅只是不打印而已。是可以执行dmesg命令查看以前被隐藏的打印信息的。
总结:每个printk都有自己的打印级别,打印级别用来控制该语句打不打印。
在include/linux/printk.h中有四个宏,其介绍如下:
//include/linux/printk.h
#define console_loglevel (console_printk[0])
#define default_message_loglevel (console_printk[1])
#define minimum_console_loglevel (console_printk[2])
#define default_console_loglevel (console_printk[3])
console_loglevel :当printk所指定的打印级别小于console_loglevel时,信息才会被打印;
default_message_loglevel :当使用printk时没有指定打印级别、内核为其使用的默认级别就是来自default_message_loglevel;
minimum_console_loglevel :是一个预设值,平时不起作用。通过其他工具来设置console_loglevel的值时,这个值不能小于minimum_console_logleve;(引用韦东山教程原话)
default_console_loglevel :也是一个预设值,平时不起作用。它表示设置console_loglevel时的默认值,通过其他工具来设置console_loglevel的值时,用到这个值;(引用韦东山教程原话)
console_printk[]数组:定义如下
//include/linux/printk.c
int console_printk[4] = {
CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel */
MESSAGE_LOGLEVEL_DEFAULT, /* default_message_loglevel */
CONSOLE_LOGLEVEL_MIN, /* minimum_console_loglevel */
CONSOLE_LOGLEVEL_DEFAULT, /* default_console_loglevel */
};
printk的打印级别我们已经知道如何指定了,就是printk语句里加入相关表示级别的宏即可,内核会判断其等级是否小于console_loglevel,小于则打印,大于等于则不打印;那又如何修改console_loglevel、default_message_loglevel、minimum_console_loglevel、default_console_loglevel呢?
回答:直接修改/proc/sys/kernel/printk文件来改变这4个值;
echo "1 4 1 7" > /proc/sys/kernel/printk
左边第一个 1 代表 console_loglevel;
左边第二个 4 代表 default_message_loglevel;
左边第三个 1 代表 minimum_console_loglevel;
左边第四个 7 代表 default_console_loglevel;
像上面这个例子,打印等级是1,默认等级是4,如果使用printk不指定打印等级的话,则使用默认等级4,4并不小于1,则该信息不会打印;
在设备树中的bootargs指定console即可,如下,也可指定多个console,
# 单个console
/ {
chosen {
bootargs = "console=ttymxc1,115200";
};
};
# 多个console
/ {
chosen {
bootargs = "console=ttymxc1,115200 console=ttymxc2";
};
};
无论是在uboot时填写的bootargs还是在哪,最后都会更新在设备树; (引用他人结论,未实验)
文章中出现的名词解释或个人理解若有误,恳请指出。