ENABLING LOW LEVEL KERNEL DEBUGGING AND USING EARLY PRINTKs

In this post I am going to show how to enable low level kernel debugging option and how to enable 'printks' to get prints during boot up also.

There may be thousands of situations when an embedded engineer may face a problem of kernel failure before the serial console is enabled:



## Booting kernel from Legacy Image at 80000000 ...
   Image Name:   Linux-2.6.37
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    2327292 Bytes =  2.2 MB
   Load Address: 80008000
   Entry Point:  80008000
   Verifying Checksum ... OK
   Loading Kernel Image ... OK
OK

Starting kernel ...

Uncompressing Linux... done, booting the kernel.



There may be several reasons for this behaviour. But how to know what is the problem unless we get some prints.
For this you need low level kernel debugging and early printks. Follow the below steps:

A.  Enabling Kernel Low Level Debugging ( CONFIG_DEBUG_LL )

    1.  In menuconfig search for 'Kernel Low Level Debugging'. ( To search in menuconfig: after make ARCH=.. CROSS_COMPILE=... menuconfig, press '/' sign.
    A dialouge box will appear. Type the string to be searched and press enter.)

    2.  This will show where the low level debugging option is and by what name will it be represented. Note down the path and also check all the dependencies.

    3.  Press EXIT. Select all the dependencies and the low level debugging option.

    4.  Save the configuration and exit.

Do not build the kernel Image (uImage) yet.

B.  Using early printks:

    1.  In your kernel source open kernel/printk.c using vim editor ( or any editor you prefer ). Add 'printascii' to the function vprintk in the following manner:


    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;

        .
        .
        .
        .


    /* 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;
                }

         .
         .
         .


     2.  Save the file and exit. ( in vim press 'Esc' and the ':wq' and then 'Enter' to save and exit. )

     3.  Now build the kernel image. ( uImage )

     4.  On the u-boot prompt give the following command:

   
        $ setenv bootargs $(bootargs) earlyprintk=serial

         or simple add   'earlyprintk=serial'   to the bootargs.

C.  Save if desired and boot with the uImage formed above. You will get the prints even if the console is not initialized.
   

1 comment:

  1. Wonderful explanation!!!
    Thank you so much for sharing your knowledge!

    ReplyDelete