Linux最小系統移植之早期打印CONFIG_EARLY_PRINTK


 

  請先參考先前博文:  Linux最小系統移植之早期打印CONFIG_DEBUG_LL  , 因為eraly_printk其實就是對printch()封裝的

一、 必要選項(在上面鏈接選中的前提下再新增CONFIG_EARLY_PRINTK):

/* linux-3.10.65/arch/arm/kernel/Makefile */
obj-$(CONFIG_DEBUG_LL)    += debug.o
obj-$(CONFIG_EARLY_PRINTK)    += early_printk.o

 

 二、源碼分析

  先貼出early_printk.c源碼:

/*
 *  linux/arch/arm/kernel/early_printk.c
 *
 *  Copyright (C) 2009 Sascha Hauer <s.hauer@pengutronix.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/init.h>

extern void printch(int);

static void early_write(const char *s, unsigned n)
{
    while (n-- > 0) {
        if (*s == '\n')
            printch('\r');
        printch(*s);
        s++;
    }
}

static void early_console_write(struct console *con, const char *s, unsigned n)
{
    early_write(s, n);
}

static struct console early_console_dev = {
    .name =        "earlycon",
    .write =    early_console_write,
    .flags =    CON_PRINTBUFFER | CON_BOOT,
    .index =    -1,
};

static int __init setup_early_printk(char *buf)
{
    early_console = &early_console_dev;
    register_console(&early_console_dev);
    return 0;
}

early_param("earlyprintk", setup_early_printk);

  以及調用的地方:

/* linux-3.10.65/kernel/printk.c */
void early_vprintk(const char *fmt, va_list ap)
{
    if (early_console) {
        char buf[512];
        int n = vscnprintf(buf, sizeof(buf), fmt, ap);

        early_console->write(early_console, buf, n);
    }
}

asmlinkage void early_printk(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    early_vprintk(fmt, ap);
    va_end(ap);
}
#endif

 

1. 調用者使用early_printk()可變參數打印函數
2. 函數的參數是存放在棧中的,由於是可變參數, 請問怎么知道棧存放多少參數? --> 使用va_start()解析
 其原理根據第一個參數fmt的地址,以及最后一個參數ap地址知道這塊棧區域都是形參, 記得變量ap要放在函數
 第一行表示形參結束。同時,為確保所有參數都是放置棧(GCC編譯器默認把前四個形參放置R0/1/2/3,后面才放入棧中)
 定義了asmlinkage, 告知編譯器全部形參放置棧中
3. vscnprintf()作用就是解析%d,%x, int a等格式, 最終全部轉為字符放置buf中, 再調用early_console->write()輸出
4. CON_PRINTBUFFER 打印緩沖所有數據, 如果后續串口驅動也設置這個標志, printk會重復打印eraly_printk 打的,CON_BOOT表示在啟動期間有效
5. early_param("earlyprintk", setup_early_printk); 說明uboot或者DTB傳給kernle 的 cmdline要有這個字段才能生效
6. 由於early_param是在start_kernel() -> parse_args() 的unknown_bootoption()處理的, 所以必須放置這個函數之后才能使用, 否則early_printk()就是空函數

7. 與printascii() printch()最大不同在於eraly_printk()可以打印格式參數%d, %p等, 方便調試

 

三、測試驗證

  

  

  

  

  測試發現確實只有2打印出來, 1沒有

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM