• 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 == '
    ')
                printch('
    ');
            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没有

  • 相关阅读:
    为什么少有人在Windows电脑上安OS X?
    Xamarin.iOS开发初体验
    MySQL MyISAM/InnoDB高并发优化经验
    windows系统上安装与使用Android NDK r8d(二)
    windows系统上安装与使用Android NDK r8d(一)
    Windows平台下如何使用Android NDK
    Xamarin 手动安装步骤+破解(最新版Xamarin V3)
    MONO,原来你是水中月
    剑客vs刀客 Java vs .NET
    终于理解了什么是LGPL
  • 原文地址:https://www.cnblogs.com/vedic/p/10749745.html
Copyright © 2020-2023  润新知