快乐虾
http://blog.csdn.net/lights_joy/
lights@hb165.com
本文适用于
ADI bf561 DSP
uclinux-2008r1.5-rc3 (smp patch)
Visual DSP++ 5.0 (update 5)
欢迎转载,但请保留作者信息
细看printk.c文件,可以发现几个与printk函数相关的参数:
1.1 log_buf_len
__setup("log_buf_len=", log_buf_len_setup);
即这个内核参数由log_buf_len_setup函数进行处理:
static char __log_buf[__LOG_BUF_LEN];
static char *log_buf = __log_buf;
static int log_buf_len = __LOG_BUF_LEN;
static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */
static int __init log_buf_len_setup(char *str)
{
unsigned long size = memparse(str, &str);
unsigned long flags;
if (size)
size = roundup_pow_of_two(size);
if (size > log_buf_len) {
unsigned long start, dest_idx, offset;
char *new_log_buf;
new_log_buf = alloc_bootmem(size);
if (!new_log_buf) {
printk(KERN_WARNING "log_buf_len: allocation failed\n");
goto out;
}
spin_lock_irqsave(&logbuf_lock, flags);
log_buf_len = size;
log_buf = new_log_buf;
offset = start = min(con_start, log_start);
dest_idx = 0;
while (start != log_end) {
log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)];
start++;
dest_idx++;
}
log_start -= offset;
con_start -= offset;
log_end -= offset;
spin_unlock_irqrestore(&logbuf_lock, flags);
printk(KERN_NOTICE "log_buf_len: %d\n", log_buf_len);
}
out:
return 1;
}
在默认情况下,printk缓冲区的大小由__LOG_BUF_LEN指定
#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
#define CONFIG_LOG_BUF_SHIFT 14
即2的14次方。输入的值必须比这个值大才有效果。而且由于使用了memparse进行数值的分析,因此它可以K, M, G这三个值。如:
log_buf_len=64k
1.2 ignore_loglevel
static int __read_mostly ignore_loglevel;
static int __init ignore_loglevel_setup(char *str)
{
ignore_loglevel = 1;
printk(KERN_INFO "debug: ignoring loglevel setting.\n");
return 1;
}
__setup("ignore_loglevel", ignore_loglevel_setup);
这个内核参数不需要设置值。这个参数仅用在_call_console_drivers函数中
static void _call_console_drivers(unsigned long start,
unsigned long end, int msg_log_level)
{
if ((msg_log_level < console_loglevel || ignore_loglevel) &&
console_drivers && start != end) {
if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
/* wrapped write */
__call_console_drivers(start & LOG_BUF_MASK,
log_buf_len);
__call_console_drivers(0, end & LOG_BUF_MASK);
} else {
__call_console_drivers(start, end);
}
}
}
在使用了这个内核参数后,printk将忽略输出的级别,直接将传递进来的所有信息输出。
1.3 KERN_*
在使用printk输出的时候,可以使用KERN_*宏来指定输出级别。
#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 */
在_call_console_drivers函数中可以看到,当指定的输出级别大于等于console_loglevel时,信息将不会输出。console_loglevel的定义为:
#define console_loglevel (console_printk[0])
当使用printk而不指定输出级别时,printk取默认级别default_message_loglevel,其定义为:
#define default_message_loglevel (console_printk[1])
这里涉及的console_printk是一个全局变量:
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 */
};
#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
因此,只要不是在输出时指定KERN_DEBUG,其信息都将被printk输出。
1.4 printk_time
这个参数定义为:
#if defined(CONFIG_PRINTK_TIME)
static int printk_time = 1;
#else
static int printk_time = 0;
#endif
module_param(printk_time, int, S_IRUGO | S_IWUSR);
static int __init printk_time_setup(char *str)
{
if (*str)
return 0;
printk_time = 1;
return 1;
}
__setup("time", printk_time_setup);
在指定这个参数之后,printk将在每条信息之前加上时间。
asmlinkage int vprintk(const char *fmt, va_list args)
{
…………………………….
for (p = printk_buf; *p; p++) {
if (log_level_unknown) {
/* log_level_unknown signals the start of a new line */
if (printk_time) {
int loglev_char;
char tbuf[50], *tp;
unsigned tlen;
unsigned long long t;
unsigned long nanosec_rem;
/*
* force the log level token to be
* before the time output.
*/
if (p[0] == '<' && p[1] >='0' &&
p[1] <= '7' && p[2] == '>') {
loglev_char = p[1];
p += 3;
printed_len -= 3;
} else {
loglev_char = default_message_loglevel
+ '0';
}
t = printk_clock();
nanosec_rem = do_div(t, 1000000000);
tlen = sprintf(tbuf,
"<%c>[%5lu.%06lu] ",
loglev_char,
(unsigned long)t,
nanosec_rem/1000);
for (tp = tbuf; tp < tbuf + tlen; tp++)
emit_log_char(*tp);
printed_len += tlen;
} else {
if (p[0] != '<' || p[1] < '0' ||
p[1] > '7' || p[2] != '>') {
emit_log_char('<');
emit_log_char(default_message_loglevel
+ '0');
emit_log_char('>');
printed_len += 3;
}
}
log_level_unknown = 0;
if (!*p)
break;
}
emit_log_char(*p);
if (*p == '\n')
log_level_unknown = 1;
}
………………………
}
1 参考资料
uclinux内核的console(1):数据结构(2009-1-31)
uclinux内核的console(2):early console(2009-1-31)
uclinux内核的console(3):console驱动初始化(2009-1-31)
uclinux内核的console(4):通过console输出信息(2009-1-31)