天天看點

驅動調試之printk原理

1、核心對uboot傳進來的console=ttyAMA0處理

核心檔案搜尋"console="

在kernel/printk/printk.c找到

__setup(“console=”, console_setup);

__setup 為宏,将字元串console=,用console_setup函數處理

注意:此處記錄了裝置想用哪個控制台作為列印輸出

2、硬體注冊控制台

對于hi3519v101在下面路徑注冊,核心檔案搜尋"ttyAMA"

drivers/tty/serial/amba-pl011.c

static struct console amba_console = {
	.name		= "ttyAMA",
	.write		= pl011_console_write,
	.device		= uart_console_device,
	.setup		= pl011_console_setup,
	.flags		= CON_PRINTBUFFER,
	.index		= -1,
	.data		= &amba_reg,
};

#define AMBA_CONSOLE	(&amba_console)
           

3、printk

kernel/printk/printk.c

asmlinkage __visible int printk(const char *fmt, ...)
	vprintk_emit(0, -1, NULL, 0, fmt, args);
		vprintk_emit
			//這裡會對printk的列印級别做處理
			//預設列印級别 4,把臨時BUFFER裡的資料稍作處理,再寫入log_buf
			// 比如printk("abc")會得到"<4>abc", 再寫入log_buf
			// 可以用dmesg指令把log_buf裡的資料列印出來重制核心的輸出資訊
			default_message_loglevel
			// 如果可以級别夠格列印
			if ((msg_log_level < console_loglevel
				__call_console_drivers
					con->write(con, &LOG_BUF(start), end - start);
           

4、修改列印級别console_loglevel

4.1系統啟動之後修改

cat proc/sys/kernel/printk
7       4       1       7    //第一個7為預設控制台級别
echo "8 4 1 7" > proc/sys/kernel/printk 
cat proc/sys/kernel/printk   //修改為8,printk級别小于控制台級别才會列印
8       4       1       7
           

4.2修改預設的

如下文檔有說明

Documentation/kernel-parameters.txt

loglevel= All Kernel Messages with a loglevel smaller than the

console loglevel will be printed to the console. It can

also be changed with klogd or other programs. The

loglevels are defined as follows:

0 (KERN_EMERG)		system is unusable
		1 (KERN_ALERT)		action must be taken immediately
		2 (KERN_CRIT)		critical conditions
		3 (KERN_ERR)		error conditions
		4 (KERN_WARNING)	warning conditions
		5 (KERN_NOTICE)		normal but significant condition
		6 (KERN_INFO)		informational
		7 (KERN_DEBUG)		debug-level messages
           

loglevel在init/main.c有使用到

uboot傳進來的loglevel值最終會賦給console_loglevel

static int __init loglevel(char *str)
{
	int newlevel;

	/*
	 * Only update loglevel value when a correct setting was passed,
	 * to prevent blind crashes (when loglevel being set to 0) that
	 * are quite hard to debug
	 */
	if (get_option(&str, &newlevel)) {
		console_loglevel = newlevel;
		return 0;
	}

	return -EINVAL;
}

early_param("loglevel", loglevel);
           

隻要在uboot設定bootargs加上loglevel=某個值即可,如

set bootargs loglevel = 8 ...(其他内容不變)
save
reset
           

除了loglevel,還有其他的列印級别

static int __init debug_kernel(char *str)
{
	console_loglevel = CONSOLE_LOGLEVEL_DEBUG;
	return 0;
}

static int __init quiet_kernel(char *str)
{
	console_loglevel = CONSOLE_LOGLEVEL_QUIET;
	return 0;
}

early_param("debug", debug_kernel);
early_param("quiet", quiet_kernel);
           

繼續閱讀