early_printk使用方法

本文详细介绍了Linux内核早期打印机制early_printk的使用场景,配置步骤以及其实现原理。通过在kernel hacking选项中启用early printk,并在boot参数中添加相关设置,可以在内核初始化阶段进行调试信息输出。关键在于early_printk函数的调用,它依赖于底层硬件操作,如S3C6410的串口寄存器。通过对arch/arm/kernel/early_printk.c及汇编代码的分析,揭示了early_printk如何通过底层硬件驱动将调试信息输出到串口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里写 (一)知识背景:

[color=Red]Uncompressing Linux... done, booting the kernel.
------------setup_arch------------
------------setup_machine_fdt return 0------------
Machine: MCUOS6410[/color]
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
bootconsole [earlycon0] enabled
S3C24XX Clocks, Copyright 2004 Simtec Electronics
camera: no parent clock specified
S3C64XX: PLL settings, A=532000000, M=532000000, E=24000000
S3C64XX: HCLK2=266000000, HCLK=133000000, PCLK=66500000
mout_apll: source is fout_apll (1), rate is 532000000
mout_epll: source is epll (1), rate is 24000000

复制代码

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

void __init setup_arch(char **cmdline_p)
{
        struct machine_desc *mdesc;

        unwind_init();

        setup_processor();
        early_printk("------------setup_arch------------\n");
        //return ;
        mdesc = setup_machine_fdt(__atags_pointer);
        early_printk("------------setup_machine_fdt return %d------------\n", mdesc);
        if (!mdesc)
                mdesc = setup_machine_tags(machine_arch_type);
        machine_desc = mdesc;
        machine_name = mdesc->name;
early_printk("Machine: %s\n", machine_name);
        if (mdesc->soft_reboot)
                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文件,上代码:

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 = {
        .name =                "earlycon",
        .write =        early_console_write,
        .flags =        CON_PRINTBUFFER | CON_BOOT,
        .index =        -1,
};

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

        va_start(ap, fmt);
        n = vscnprintf(buf, sizeof(buf), fmt, ap);
        early_write(buf, n);
        va_end(ap);
}

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

early_param("earlyprintk", setup_early_printk);

复制代码

其实这段code最终的实现都是靠:extern void printch(int);这个函数。这个函数实现是在:

arch/arm/kernel/debug.S中:

ENTRY(printch)
                addruart_current r3, r1, r2
                mov        r1, r0
                mov        r0, #0
                b        1b
ENDPROC(printch)

复制代码

                .macro        addruart_current, rx, tmp1, tmp2
                addruart        \tmp1, \tmp2
                mrc                p15, 0, \rx, c1, c0
                tst                \rx, #1
                moveq                \rx, \tmp1
                movne                \rx, \tmp2
                .endm

复制代码

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

        .macro addruart, rp, rv
                ldr        \rp, = S3C_PA_UART
                ldr        \rv, = (S3C_VA_UART + S3C_PA_UART & 0xfffff)
#if CONFIG_DEBUG_S3C_UART != 0
                add        \rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
                add        \rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
#endif
        .endm

复制代码

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值