返回列表 发帖

[站长原创] 跟我学系列-移植内核必备知识-对linux的early printk的探讨

[站长原创] 跟我学系列-移植内核必备知识-对linux的early printk的探讨

跟我学系列-移植内核必备知识-对linux的early printk的探讨

嵌入式开发联盟

www.mcuos.com

Osboy 站长原创

QQ:82475491

Mcuos.com@gmail.com

(一)知识背景:
  1. [color=Red]Uncompressing Linux... done, booting the kernel.
  2. ------------setup_arch------------
  3. ------------setup_machine_fdt return 0------------
  4. Machine: MCUOS6410[/color]
  5. Linux version 3.0.30-g4e794c6-dirty (zswan@zswan-laptop-ubuntu) (gcc version 4.2.1) #17 Sun May 6 00:55:44 CST 2012
  6. bootconsole [earlycon0] enabled
  7. S3C24XX Clocks, Copyright 2004 Simtec Electronics
  8. camera: no parent clock specified
  9. S3C64XX: PLL settings, A=532000000, M=532000000, E=24000000
  10. S3C64XX: HCLK2=266000000, HCLK=133000000, PCLK=66500000
  11. mout_apll: source is fout_apll (1), rate is 532000000
  12. mout_epll: source is epll (1), rate is 24000000
复制代码


我们知道line 5-12行代码部分,是printk打印出来的。而如果你想要在打印linux的版本之前的函数line1-4行中也加打印信息,那么printk这个时候其实串口,console什么的还没注册呢,所以肯定没有信息的。比如说,我想打印setup函数中的部分调试信息:
  1. void __init setup_arch(char **cmdline_p)
  2. {
  3.         struct machine_desc *mdesc;

  4.         unwind_init();

  5.         setup_processor();
  6.         early_printk("------------setup_arch------------\n");
  7.         //return ;
  8.         mdesc = setup_machine_fdt(__atags_pointer);
  9.         early_printk("------------setup_machine_fdt return %d------------\n", mdesc);
  10.         if (!mdesc)
  11.                 mdesc = setup_machine_tags(machine_arch_type);
  12.         machine_desc = mdesc;
  13.         machine_name = mdesc->name;
  14. early_printk("Machine: %s\n", machine_name);
  15.         if (mdesc->soft_reboot)
  16.                 reboot_setup("s");
复制代码
就可以使用early printk的功能啦,那么如何打开这个功能呢,下面我做个介绍:
(二)支持early printk对内核需要做的配置
(1)Kernel hacking  ---> Kernel low-level debugging functions -->   Early printk
(2)boot option中你需要添加 earlyprintk项。类似于:
root=/dev/ram0 console=ttySAC0,115200n8 rdinit=/sbin/init earlyprintk

(三)在需要加打印信息的地方使用early_printk函数代替printk函数。
(四)对early printk的驱动实现的分析

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

  1. extern void printch(int);

  2. static void early_write(const char *s, unsigned n)
  3. {
  4.         while (n-- > 0) {
  5.                 if (*s == '\n')
  6.                         printch('\r');
  7.                 printch(*s);
  8.                 s++;
  9.         }
  10. }

  11. static void early_console_write(struct console *con, const char *s, unsigned n)
  12. {
  13.         early_write(s, n);
  14. }

  15. static struct console early_console = {
  16.         .name =                "earlycon",
  17.         .write =        early_console_write,
  18.         .flags =        CON_PRINTBUFFER | CON_BOOT,
  19.         .index =        -1,
  20. };

  21. asmlinkage void early_printk(const char *fmt, ...)
  22. {
  23.         char buf[512];
  24.         int n;
  25.         va_list ap;

  26.         va_start(ap, fmt);
  27.         n = vscnprintf(buf, sizeof(buf), fmt, ap);
  28.         early_write(buf, n);
  29.         va_end(ap);
  30. }

  31. static int __init setup_early_printk(char *buf)
  32. {
  33.         register_console(&early_console);
  34.         return 0;
  35. }

  36. 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. ENDPROC(printch)
复制代码



  1.                 .macro        addruart_current, rx, tmp1, tmp2
  2.                 addruart        \tmp1, \tmp2
  3.                 mrc                p15, 0, \rx, c1, c0
  4.                 tst                \rx, #1
  5.                 moveq                \rx, \tmp1
  6.                 movne                \rx, \tmp2
  7.                 .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的串口寄存器物理和虚拟地址,从而进行真正的硬件底层操作。
分享到: QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友

底层知识搞不懂

TOP

early printk 实际上是直接调用底层汇编与s3c6410串口寄存器物理和虚拟地址控制的输出?

TOP

2410的
  1. .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_S3C2410_UART != 0
  7.                 add        \rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C2410_UART)
  8. #endif
  9.                 .endm
复制代码

TOP

返回列表
网页右侧QQ悬浮滚动在线客服
网页右侧QQ悬浮滚动在线客服