linux驱动调试之printk的原理

来源:互联网 发布:淘宝主页全屏轮播 编辑:程序博客网 时间:2024/06/06 00:58

转自


1、启动开发板进入uboot

输入print命令打印环境变量


2、启动参数(上面bootargs部分)

uboot的目的是启动内核,启动内核前要设置一些参数,修改启动参数不添加console=ttySAC0(内核打印信息显示的地方)



没有内核的任何打印信息出来


uboot设置参数,console=ttySAC0,这里0表示第1个串口,用tty1打印到LCD上面去。

内核里面用printk打印,这些信息肯定要发送到具体的硬件,因而肯定会调用硬件函数,函数里面会调用串口的操作函数和LCD的操作函数,打印到串口还是LCD是由bootargs的console=决定的,从而肯定会调用console=参数来找到硬件处理函数

也就是说,内核会根据命令行参数中console=来找到对应的硬件操作函数。


3、内核分析

(1)在内核中搜索console=

在sourceinsight的内核源码中随意地方写入console=


然后选中点击右键,进行查找引用(查找引用比常规查找更快)


(2)在printk.c文件中


猜测,当发现bootargs传入的参数里面有console=这个前缀时,就会调用sonsole_setup这个函数来处理这个字符串


现在分析_setup,这是1个宏,定义某1个结构体,这个结构体有一个name=(console=xxx),函数等于console_setup.会把同类型的结构体放在一块,以后发现这些字符串的时候就去那一块里面众多的结构体里面把函数给抽取出来并调用执行

(3)console_setup分析

static int __init console_setup(char *str)//这个str是console=ttySAC0中的ttySAC0

//第1个参数是传进来的参数,// 我想用名为"ttySAC0"的控制台,先记录下来

传入1个名字,console_cmdline是1个数组,如果数组里面的某一项跟我们想要用的控制台一样(已经被注册),设置标志,否则存在数组里面。



(4)根据ttySAC0找到对应的硬件操作函数

硬件操作函数有串口,LCD打印等。猜测结构体里面有name和write函数,当打印内核信息是,根据结构体里面的name确定是哪一个终端,然后调用write函数写到对应的终端。


刚才吧名为"ttySAC0"的控制台存在console_cmdline这个数组,在内核中搜索这个数组的调用情况,由于这个数组是静态变量,智能在本文件中使用

register_console函数可能用于注册上面包含name和write函数的结构体,然后跟console_setup比较(用name 和console_setup里面想用的名字是否一样,如果一样调用相应的write函数

函数硬件驱动的入口函数里:

drivers/serial/s3c2410.c
register_console(&s3c24xx_serial_console)//注册s3c24xx_serial_console这个结构体

这个结构体

里面S3C24xx_SERIL_NAME对应的是ttySAC,0表示第0个


4、printk分析

vprintk
/* Emit the output into the temporary buffer */
// 先把输出信息放入临时BUFFER

vscnprintf

// Copy the output into log_buf.
// 把临时BUFFER里的数据稍作处理(没有打印级别自动加上默认打印级别),再写入log_buf
// 比如printk("abc")会得到"
<4>abc", 再写入log_buf(是1个字符串数组),<4>表示打印级别,默认打印级别是4
// 可以用dmesg命令把log_buf里的数据打印出来重现内核的输出信息


// 调用硬件的write函数输出
release_console_sem();
call_console_drivers(_con_start, _log_end);
// 从log_buf得到数据,算出打印级别(小于设定级别才打印)
_call_console_drivers(start_print, cur_index, msg_level);
// 如果可以级别够格打印
if ((msg_log_level < console_loglevel
__call_console_drivers
con->write(con, &LOG_BUF(start), end - start);

原创粉丝点击