linux的early printk的探討

http://mcuos.com/thread-8169-1-1.html

(一)知識背景:

  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的串口寄存器物理和虛擬地址,從而進行真正的硬件底層操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章