全志A33-linux内核early_printk分析及使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012247418/article/details/82314023

      分析Linux内核启动流程时可以知道,在调用setup_arch函数之前就已经调用过printk函数了,但是这个时候的printk函数只是将打印信息放在缓存区中,并没有打印到控制台上,因为这个时候控制台还没有被初始化。

      只有在start_kernel函数中的console_init函数被调用后,控制台才会被注册、初始化,printk函数打印的内容才会被真正地输出到屏幕上。如果想在console_init函数之前打印信息,需要调用early_printk函数。

1. 内核配置

(1)Kernel hacking  ---> Kernel low-level debugging functions -->   Early printk 

(2)boot option中需要添加 earlyprintk项。

类似于:earlyprintk=ttyS0,115200 loglevel=9 initcall_debug=1 console=ttyS0,115200 ramfs

2. 使用

在需要打印调试信息的地方调用此函数

early_printk("------------xxx------------\n");

3. A33开发板

如在./arch/arm/mach-sunxi/sun8i.c 中有如下语句:

early_printk("[%s]: From boot, get meminfo:\n", __func__);

启动开发板时串口控制台信息如下:

在没有启用early_printk之前,串口控制台信息如下:

4. 对early printk的驱动实现的分析

arch/arm/kernel/early_printk.c文件,上代码:

  1. extern void printch(int);
  2.  
  3. static void early_write(const char *s, unsigned n)
  4. {
  5.         while (n-- > 0) {
  6.                 if (*s == '\n')
  7.                         printch('\r');
  8.                 printch(*s);
  9.                 s++;
  10.         }
  11. }
  12.  
  13. static void early_console_write(struct console *con, const char *s, unsigned n)
  14. {
  15.         early_write(s, n);
  16. }
  17.  
  18. static struct console early_console = {
  19.         .name =                "earlycon",
  20.         .write =        early_console_write,
  21.         .flags =        CON_PRINTBUFFER | CON_BOOT,
  22.         .index =        -1,
  23. };
  24.  
  25. asmlinkage void early_printk(const char *fmt, ...)
  26. {
  27.         char buf[512];
  28.         int n;
  29.         va_list ap;
  30.  
  31.         va_start(ap, fmt);
  32.         n = vscnprintf(buf, sizeof(buf), fmt, ap);
  33.         early_write(buf, n);
  34.         va_end(ap);
  35. }
  36.  
  37. static int __init setup_early_printk(char *buf)
  38. {
  39.         register_console(&early_console);
  40.         return 0;
  41. }
  42.  
  43. early_param("earlyprintk", setup_early_printk);

其实这段code最终的实现都是靠:extern void printch(int);这个函数。这个函数实现是在:arch/arm/kernel/debug.S中:

  1. ENTRY(printch)
  2.                 addruart_current r3, r1, r2
  3.                 mov        r1, r0
  4.                 mov        r0, #0
  5.                 b        1b
  6.  
  7. ENDPROC(printch)
  8.                 .macro        addruart_current, rx, tmp1, tmp2
  9.                 addruart        \tmp1, \tmp2
  10.                 mrc                p15, 0, \rx, c1, c0
  11.                 tst                \rx, #1
  12.                 moveq                \rx, \tmp1
  13.                 movne                \rx, \tmp2
  14.                 .endm

printch会调用到 addruart_current函数,而addruart_current函数用调用到:addruart函数,该函数实现是在:arch\arm\mach-s3c64xx\include\mach中的debug-macro.S汇编文件中:

  1.         .macro addruart, rp, rv
  2.                 ldr        \rp, = S3C_PA_UART
  3.                 ldr        \rv, = (S3C_VA_UART + S3C_PA_UART & 0xfffff)
  4. #if CONFIG_DEBUG_S3C_UART != 0
  5.                 add        \rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
  6.                 add        \rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
  7. #endif
  8.         .endm

我们从上面的代码可以看到S3C_PA_UART, S3C_PA_UART都是实际的6410的串口寄存器物理和虚拟地址,从而进行真正的硬件底层操作。

猜你喜欢

转载自blog.csdn.net/u012247418/article/details/82314023