GNU ARM汇编--(十五)linux下的printascii

在前面对很多s3c2440的功能模块进行学习后,已经具备了将这些模块综合起来的条件,基于此,将前面的代码综合成一个简单的bootloader.自己写的bootloader在引导kernel的时候,串口输出只有Uncompressing Linux...和done, booting the kernel。串口有这个输出,说明kernel被正确引导了,但是串口有问题。

        这篇blog只是分析解决这个问题的第一步:

        既然"Uncompressing Linux..."这句打印是kernel代码中的,那kernel的其他打印怎么没有?

        在arch\arm\boot\compressed目录下的misc.c中,上面的打印是在decompress_kernel函数中,而该函数是在kernel的初始汇编中调用的,也就是说这个时候kernel的串口驱动肯定是没有工作的,那这里的串口输出只能是用bootloader初始化好的串口,

        putstr("Uncompressing Linux...");

        putstr(" done, booting the kernel.\n");

 

  1. <span style="font-size:18px;">static void putstr(const char *ptr)  
  2. {  
  3.     char c;  
  4.   
  5.     while ((c = *ptr++) != '\0') {  
  6.         if (c == '\n')  
  7.             putc('\r');  
  8.         putc(c);  
  9.     }  
  10.   
  11.     flush();  
  12. }  
  13. </span>  


        在include\asm-arm\plat-s3\uncompress.h中,有putc函数的定义:

 

 

  1. <span style="font-size:18px;">static void putc(int ch)  
  2. {  
  3.     if (uart_rd(S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE) {  
  4.         int level;  
  5.   
  6.         while (1) {  
  7.             level = uart_rd(S3C2410_UFSTAT);  
  8.             level &= fifo_mask;  
  9.   
  10.             if (level < fifo_max)  
  11.                 break;  
  12.         }  
  13.   
  14.     } else {  
  15.         /* not using fifos */  
  16.   
  17.         while ((uart_rd(S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE) != S3C2410_UTRSTAT_TXE)  
  18.             barrier();  
  19.     }  
  20.   
  21.     /* write byte to transmission register */  
  22.     uart_wr(S3C2410_UTXH, ch);  
  23. }</span>  

        从这里可以看到,这里的输出的确是利用了bootloader中对串口的初始化,但是这部分代码还是通用的:不管在bootloader中将串口初始化为用fifo还是非fifo的,这一小块代码都是可以正常串口输出的。

 

        既然明白了这两句打印为什么可以输出后,就要排查后续没有打印的原因了,这里我们就利用printascii函数来debug,我们知道kernel的printf函数是printk,在printk函数内部添加printascii函数,make menuconfig中选中:

        Kernel hacking下的 [*] Kernel low-level debugging functions下的 [*]   Kernel low-level debugging messages via S3C UART,并选择 (0) S3C UART to use for low-level debug

         Device Drivers -->Character devices--> Serial drivers--> <*> Samsung S3C2410/S3C2440/S3C2442/S3C2412 Serial port support和[*]   Support for console on S3C2410 serial port 

         printk函数修改如下:

 

  1. asmlinkage int printk(const char *fmt, ...)  
  2. {  
  3.     va_list args;  
  4.     int r;  
  5.       
  6. #ifdef CONFIG_DEBUG_LL  
  7.         extern void printascii(const char *);  
  8.         char buff[256];  
  9. #endif  
  10.   
  11.     va_start(args, fmt);  
  12.     r = vprintk(fmt, args);  
  13.       
  14. #ifdef CONFIG_DEBUG_LL  
  15.         vsprintf(buff, fmt, args);  
  16. #endif  
  17.     va_end(args);  
  18. #ifdef CONFIG_DEBUG_LL  
  19.         printascii(buff);  
  20. #endif  
  21.   
  22.     return r;  
  23. }  



 

        重新编译内核烧写后,发现kernel的输出都有了,这说明kernel的串口驱动有问题,或者说要去研究要bootloader如何向kernel传递参数的。另外一个疑惑就是printk没有输出,为什么printascii有输出呢?

        查看源码才知道,printascii是针对arm平台的debug函数:

        在arch\arm\kernel\debug.S中

  1. <span style="font-size:18px;">ENTRY(printascii)  
  2.         addruart r3  
  3.         b   2f  
  4. 1:      waituart r2, r3  
  5.         senduart r1, r3  
  6.         busyuart r2, r3  
  7.         teq r1, #'\n'  
  8.         moveq   r1, #'\r'  
  9.         beq 1b  
  10. 2:      teq r0, #0  
  11.         ldrneb  r1, [r0], #1  
  12.         teqne   r1, #0  
  13.         bne 1b  
  14.         mov pc, lr  
  15. </span>  


        在include\asm-arm\arch-s3c241\debug-macro.S中,addruart宏定义如下:

 

 

  1. <span style="font-size:18px;">  .macro addruart, rx  
  2.         mrc p15, 0, \rx, c1, c0  
  3.         tst \rx, #1  
  4.         ldreq   \rx, = S3C24XX_PA_UART  
  5.         ldrne   \rx, = S3C24XX_VA_UART  
  6. #if CONFIG_DEBUG_S3C_UART != 0  
  7.         add \rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)  
  8. #endif  
  9.     .endm  
  10. </span>  

        从p15协处理器来查看MMU是否打开了,从而用PA或者VA,这说明MMU打开前或者后都可以用printascii进行debug。

 

        在include\asm-arm\plat-s3c\debug-macro.S中,有senduart、busyuart和waituart的定义,具体代码就不贴出来了,这三个代码实现了串口的输出,这三个宏定义针对fifo和非fifo的情况都做了处理,保证代码的健壮。

        到这里,可以看出来printascii基于bootloader或者kernel对串口的初始化后才能起作用,但一般用printascii辅助debug主要用于kernel的最开始部分,这时候的串口初始化用的还是bootloader的。当然,在kernel的串口驱动正常工作后,printascii同样是起作用的。最后,printascii代码还是很健壮的,而且printascii的生命周期也是相当长的,从kernel启动开始到kernle关闭之时,printascii都是能向串口输出信息的。

        在用printascii函数debug和分析printascii是如何实现之后,对于开头的问题,进一步缩小了分析目标,后面的分析将围绕bootloader与kernel之间的参数传递问题,以及linux的串口驱动。

 

                                                                                                                         转载于:blog.csdn.net/dndxhej

posted on 2012-10-15 22:28  Daniel.G  阅读(682)  评论(0编辑  收藏  举报