原作者链接: http://mcuos.com/thread-8169-1-1.html
(一)知识背景:
Uncompressing Linux... done, booting the kernel.
------------setup_arch------------
------------setup_machine_fdt return 0------------
Machine: MCUOS6410
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的串口寄存器物理和虚拟地址,从而进行真正的硬件底层操作。
离线