1、简介(基于s3c2440 linux)
在内核调试技术之中,最简单的就是printk的使用了,它的用法和c语言应用程序中的printf使用类似,在应用程序中依靠的是stdio.h中的库,而在linux内核中没有这个库,所以在linux内核中,使用这个printk就要对内核的实现有一定的了解。
printf和printk的区别:printk会在开头处加上样式的字符,n的范围是0~7,表示这个信息的级别。
当printk(......);中的n /proc/sys/kernel/printk 改变这四个值,当被console_loglevel设置为1的时候,所有的调试信息都会被打印出来。
4、printk函数记录的名称及使用
在内核文件:kernel.h (include\linux) 定义了0~7这8个级别的名称
#define kern_emerg /* system is unusable */#define kern_alert /* action must be taken immediately */#define kern_crit /* critical conditions */#define kern_err /* error conditions */#define kern_warning /* warning conditions */#define kern_notice /* normal but significant condition*/#define kern_info /* informational*/#define kern_debug /* 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_warningthere is a warning here!\n);//注意,中间没有逗号间隔。② printk(kern_debug%s %s %d\n, __file__, __function__, __line__);
在①和②中,我们需要查看缓冲区log_buf中的数据,才能看到打印出来的信息。需要使用命令 #dmesg
1
2
3
4
5
6
7
8
9
10
11
12
#
# dmesg
linux version 2.6.22.6 (book@book-desktop) (gcc version 3.4.5) #19 thu dec 8 14:06:03 cst 2016
cpu: arm920t [41129200] revision 0 (armv4t), cr=c0007177
machine: smdk2440
memory policy: ecc disabled, data cache writeback
on node 0 totalpages: 16384
dma zone: 128 pages usedformemmap
dma zone: 0 pages reserved
dma zone: 16256 pages, lifo batch:3
normal zone: 0 pages usedformemmap
cpu s3c2440a (id 0x32440001)
................................
还可以使用cat /proc/kmsg& 后台运行,实时打印出调试信息。在②中,__file__, __function__, __line__分别对应的是那个文件,那个函数,第几行。非常实用。
1
2
3
4
5
6
7
8
9
# cat /proc/kmsg&
# ./firstdrvtest on
/work/linuxdrives/20.printk_debug/first_drv.c first_drv_open 23
/work/linuxdrives/20.printk_debug/first_drv.c first_drv_open 25
/work/linuxdrives/20.printk_debug/first_drv.c first_drv_open 27
# ./firstdrvtest off
/work/linuxdrives/20.printk_debug/first_drv.c first_drv_open 23
/work/linuxdrives/20.printk_debug/first_drv.c first_drv_open 25
/work/linuxdrives/20.printk_debug/first_drv.c first_drv_open 27
5、串口与printk函数的关系:
printk vprintk vscnprintf //先把输出信息放入临时buffer // copy the output into log_buf. // 把临时buffer里的数据稍作处理,再写入log_buf // 比如printk(abc)会得到abc, 再写入log_buf // 可以用dmesg命令把log_buf里的数据打印出来重现内核的输出信息 // 调用硬件的write函数输出 release_console_sem call_console_drivers//从log_buf得到数据,算出打印级别 _call_console_drivers if ((msg_log_level write //con是console_drivers链表中的项,对用具体的输出函数 在drives/serial/s3c2410.c中查看在该函数中注册一个console结构体
static void s3c24xx_serial_console_write(struct console *co, const char *s,unsigned int count){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, int ch){unsigned int 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
正弦交流电的“三要素”
无线充电市场迅速发展与普及
锐龙52600和酷睿i5-8400哪个性价比最高
解析STM32的库函数-1
高通是否要重回数据中心市场?
你知道Linux内核调试关键技术之一的printk?
以80C196MC单片机为控制核心的步进电机恒转矩斩设计
基于Arduino自制儿童小电脑
美国高调表态重回新能源汽车战场
独角兽企业是什么意思_中国的独角兽公司都分布在哪些行业呢?
蓝白可调电阻焊接方法_蓝白可调电阻焊接注意事项
Xilinx FPGA重构技术介绍
iPhone8什么时候上市?iPhone8最新消息:外观创新无边框设计,内置指纹识别与无线充电!iPhone8有这4大黑科技?
气体检测仪的使用寿命是多久
禾多科技参加MEET2024智能未来大会
多功能充电器的设计与制作,Multi-function battery charger
不同Pi-pad衰减器的电路方程案例
中国移动正式公布了2019-2020年基站天线集中采购项目中标候选人结果
5G时代即将来临 但仍面临多项挑战
最常见的7805集成稳压电路介绍