linux内核 printk实现,Linux内核调试技术之printk

1、简介(基于s3c2440 linux)

在内核调试技术之中,最简单的就是printk的使用了,它的用法和C语言应用程序中的printf使用类似,在应用程序中依靠的是stdio.h中的库,而在linux内核中没有这个库,所以在linux内核中,使用这个printk就要对内核的实现有一定的了解。

printf和printk的区别:printk会在开头处加上""样式的字符,N的范围是0~7,表示这个信息的级别。

当printk(""......);中的n < console_loglevel 时候,这个信息才能被打印出来。

在内核文件中Printk.c (kernel) 中初始化这个console_loglevel 的级别为7.

/*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 */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*/};

2、通过命令cat /proc/sys/kernel/printk查看等级配置:

# cat /proc/sys/kernel/printk

7 4 1 7

其中的 7 4 1 7,分别对应与:console_loglevel、default_message_loglevel、minimum_console_loglevel、default_console_loglevel

3、修改等级配置:

#echo "1 4 1 7">/proc/sys/kernel/printk 改变这四个值,当被console_loglevel设置为1的时候,所有的调试信息都会被打印出来。

4、printk函数记录的名称及使用

在内核文件:Kernel.h (include\linux) 定义了0~7这8个级别的名称

#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 */

#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])

使用printk:

① printk(KERN_WARNING"there is a warning here!\n");//注意,中间没有逗号间隔。

② printk(KERN_DEBUG"%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

在①和②中,我们需要查看缓冲区log_buf中的数据,才能看到打印出来的信息。需要使用命令 #dmesg

还可以使用 cat /proc/kmsg& 后台运行,实时打印出调试信息。在②中,__FILE__, __FUNCTION__, __LINE__分别对应的是那个文件,那个函数,第几行。非常实用。

5、串口与printk函数的关系:

printk

vprintk

vscnprintf//先把输出信息放入临时BUFFER//Copy the output into log_buf.//把临时BUFFER里的数据稍作处理,再写入log_buf//比如printk("abc")会得到"<4>abc", 再写入log_buf//可以用dmesg命令把log_buf里的数据打印出来重现内核的输出信息//调用硬件的write函数输出

release_console_sem

call_console_drivers

//从log_buf得到数据,算出打印级别

_call_console_driversif ((msg_log_level < console_loglevel)//如果级别足够则打印

__call_console_drivers

con->write //con是console_drivers链表中的项,对用具体的输出函数 在drives/serial/s3c2410.c中查看

在该函数中注册一个console结构体

static void s3c24xx_serial_console_write(struct console *co, const char *s,

unsignedintcount)

{

uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);

}

串口输出函数,会调用s3c24xx_serial_console_putchar函数

static int s3c24xx_serial_initconsole(void)

{

...........................

register_console(&s3c24xx_serial_console);return 0;

}

static struct console s3c24xx_serial_console =

{

.name= S3C24XX_SERIAL_NAME,//这个宏被定义为:TTYSAC

.device= uart_console_device, //init进程,用户程序打开/dev/console的时候会调用

.flags= CON_PRINTBUFFER,//打印还没有初始化化console前保存在log_buf里面的数据

.index= -1,//选择那个串口,由uboot中的命令决定

.write= s3c24xx_serial_console_write,//控制台输出函数

.setup= s3c24xx_serial_console_setup //串口设置函数

};

这个函数和硬件相关,读取寄存器,看数据是否被发送完成,最后将数据一个字节一个字节的写入寄存器,s3c2440的串口控制器会自动把数据发送出去

static void s3c24xx_serial_console_putchar(struct uart_port *port, intch)

{

unsignedint ufcon =rd_regl(cons_uart, S3C2410_UFCON);while (!s3c24xx_serial_console_txrdy(port, ufcon))

barrier();

wr_regb(cons_uart, S3C2410_UTXH, ch);

}

uboot的console=ttySAC0如果在linux中被识别出来是串口0的,在/kernel/printk.c中有一下代码,

__setup("console=", console_setup);static int __init console_setup(char *str)

{

........

add_preferred_console(name, idx, options);

}

内核开始执行时,会发现“console=...”的命令行参数时候,就会调用console_setup函数进行数据解析,对于命令行参数"console=ttySAC0",会解析出:设备名(name)为ttySAC,索引index为0,这些信息被保存在类型为console_cmdline、名称为console_cmdline的全局数组中(注意:数组名和数组的类型相同)

在后面的register_console(&s3c24xx_serial_console);的时候,会将s3c24xx_serial_console结构和console_cmdline数组中的设备进行比较。

①解析出来的name为S3C24XX_SERIAL_NAME 既“ttySAC”,而console_cmdline中的命令中的name也为“ttySAC”

②s3c24xx_serial_console结构体中的索引index为-1,表示使用命令行参数“console=ttySAC0”中的索引,index =  0

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值