http://mcuos.com/thread-8169-1-1.html
(一)知識背景:
-
[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的串口寄存器物理和虛擬地址,從而進行真正的硬件底層操作。