现在的位置: 首页 > 综合 > 正文

using printascii to dump kernel message

2013年09月15日 ⁄ 综合 ⁄ 共 4925字 ⁄ 字号 评论关闭

This article references to Edwin.Rong's blog(http://blog.chinaunix.net/u1/43047/showart_1183494.html).

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)

抱歉!评论已关闭.