使用printascii进行打印

make menuconfig里打开

Kernel debug中的 打开kernel low level debug functions 选项

kernel/printk.c中添加见using printascii to dump kernel message

 

 

 

using printascii to dump kernel message
When you port the linux kernel to your board, there will be some problem before you initial the console. So you should use the printascii to dump the debug message.

In this article, we use arm platform as example(intel xscale ixp425), the porting linux kernel is linux-2.6.28.

Firstly, we list the related files:
------------------------------------------------------------
[1]linux/arch/arm/kernel/debug.S
[2]linux/include/asm-arm/arch-xxxxx/debug-macro.S
[3]asm/hardware/debug-ixp425.S
[4]linux/arch/arm/kernel/head.S
[5]linux/arch/arm/mach-xxxxx/xxxxx.c


NOTE: "xxxxx" denotes name of certain platform
------------------------------------------------------------

It implements printascii function as follows:
ENTRY(printascii)
        addruart r3
        b    2f
1:      waituart r2, r3
        senduart r1, r3
        busyuart r2, r3
        teq    r1, #'/n'
        moveq  r1, #'/r'
        beq    1b
2:      teq    r0, #0
        ldrneb r1, [r0], #1
        teqne  r1, #0
        bne    1b
        mov    pc, lr
ENDPROC(printascii)


From the implementation of printascii function, we find out that four platform-specific functions are needed to be defined, which are "addruart", "waituart", "seduart", "busyuart".


The above four functions mentioned are carried out in debug-macro.S, the details you can find in that file.

 

You should define the linux kernel config variable CONFIG_DEBUG_LL, and use the function printascii both in asm code and c code. For example as below:

1. assemble language
emulate __error_p function implemented as following in "linux/arch/arm/kernel/head-common.S"
place  "bl __error_p"  where you want to inspect.


.type __error_p, %function
__error_p:
#ifdef CONFIG_DEBUG_LL
 adr r0, str_p1
 bl printascii
 b __error
str_p1: .asciz "/nError: unrecognized/unsupported processor variant./n"
 .align
#endif


2. C language
printascill function is nested in printk(kernel/printk.c), then use printk to trace. add the printascii to the funtion vprintk, as below:

extern void printascii(const char*);
asmlinkage int vprintk(const char *fmt, va_list args)
{
    int printed_len = 0;
    int current_log_level = default_message_loglevel;
    unsigned long flags;
    int this_cpu;
    char *p;

    boot_delay_msec();

    preempt_disable();
    /* This stops the holder of console_sem just where we want him */
    raw_local_irq_save(flags);
    this_cpu = smp_processor_id();

    /*
     * Ouch, printk recursed into itself!
     */
    if (unlikely(printk_cpu == this_cpu)) {
        /*
         * If a crash is occurring during printk() on this CPU,
         * then try to get the crash message out but make sure
         * we can't deadlock. Otherwise just return to avoid the
         * recursion and return - but flag the recursion so that
         * it can be printed at the next appropriate moment:
         */
        if (!oops_in_progress) {
            recursion_bug = 1;
            goto out_restore_irqs;
        }
        zap_locks();
    }

    lockdep_off();
    spin_lock(&logbuf_lock);
    printk_cpu = this_cpu;

    if (recursion_bug) {
        recursion_bug = 0;
        strcpy(printk_buf, recursion_bug_msg);
        printed_len = sizeof(recursion_bug_msg);
    }
    /* Emit the output into the temporary buffer */
    printed_len += vscnprintf(printk_buf + printed_len,
                  sizeof(printk_buf) - printed_len, fmt, args);

    printascii(printk_buf);
    /*
     * Copy the output into log_buf.  If the caller didn't provide
     * appropriate log level tags, we insert them here
     */
    for (p = printk_buf; *p; p++) {
        if (new_text_line) {
            /* If a token, set current_log_level and skip over */
            if (p[0] == '<' && p[1] >= '0' && p[1] <= '7' &&
                p[2] == '>') {
                current_log_level = p[1] - '0';
                p += 3;
                printed_len -= 3;
            }

            /* Always output the token */
            emit_log_char('<');
            emit_log_char(current_log_level + '0');
            emit_log_char('>');
            printed_len += 3;
            new_text_line = 0;

            if (printk_time) {
                /* Follow the token with the time */
                char tbuf[50], *tp;
                unsigned tlen;
                unsigned long long t;
                unsigned long nanosec_rem;

                t = cpu_clock(printk_cpu);
                nanosec_rem = do_div(t, 1000000000);
                tlen = sprintf(tbuf, "[%5lu.%06lu] ",
                        (unsigned long) t,
                        nanosec_rem / 1000);

                for (tp = tbuf; tp < tbuf + tlen; tp++)
                    emit_log_char(*tp);
                printed_len += tlen;
            }

            if (!*p)
                break;
        }

        emit_log_char(*p);
        if (*p == '/n')
            new_text_line = 1;
    }

    /*
     * Try to acquire and then immediately release the
     * console semaphore. The release will do all the
     * actual magic (print out buffers, wake up klogd,
     * etc).
     *
     * The acquire_console_semaphore_for_printk() function
     * will release 'logbuf_lock' regardless of whether it
     * actually gets the semaphore or not.
     */
    if (acquire_console_semaphore_for_printk(this_cpu))
        release_console_sem();

    lockdep_on();
out_restore_irqs:
    raw_local_irq_restore(flags);

    preempt_enable();
    return printed_len;
}

After that, you can use printk to dump message as usual.

文章出处:DIY部落(http://www.diybl.com/course/6_system/linux/Linuxjs/20090308/159734.html)

 

 

 

 

 

 

最后一个选项中的数字表示使用的 UART编号,相当于 /dev/ttyS0 中最后一位数字。
选中这些信息后,可以在 console_init 之前的任何位置显示信息,即使是在汇编部份也可以。
在C代码中可以用 printascii 和printhex(printhex2/printhex4/printhex8)来显示信息,这些函数都
是在汇编中实现的,对应C的原型为:

void printascii(const char *);
void printhex(unsigned long value, int nbytes);
void printhex2(unsigned char value);
void printhex4(unsigned short value);
void printhex8(unsigned long value);

这些“函数”直接从低层操作s3c2410的串口,并显示信息,因此不需要等到console_init后就可以显示信息。可以直接
将 printascii("Code goes here! "); 加到 init/main.c:start_kernel() 的代码中来初步确定代码运行到什么位置,从而确
认代码出错位置。因为通常不会遇到太大的问题,因此不用花太多的时间就可以解决问题了。

 

 

 

这个只是让printk可以在kernel启动阶段打印,其实不用这么麻烦,直接在要打印的文件声明extern void printascii(const char *ptr); 后直接使用即可。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值