內核啟動早期的打印
在移植4.16內核到tiny4412的過程中遇到一個問題,官方的uboot2012引導內核成功卡在staring the kernel沒有了下文,看來內核還沒有到註冊uart驅動就已經掛掉了,嘗試打開 early printk ,讓內核自解壓之後能夠及時的打印信息。
說句題外話,內核啟動卡在staring the kernel,在2440的時代,未使用設備樹,這種情況往往是機器ID設置錯誤,或者是串口波特率等方面的原因導致,在設備樹的時代,機器ID已經被廢除,最有可能的問題可能就是出在設備樹的身上。
early printk的使用
- 配置內核
make menuconfig Kernel hacking ---> [*] Kernel low-level debugging functions (read help!) Kernel low-level debugging port (Use Samsung S3C UART 0 for low-level debug) [*] Early printk
- 設置環境變量
Add earlyprintk to your kernel parameters to enable this console
在 bootargs 中添加 earlyprintk
bootargs earlyprintk的解析
arch/arm/kernel/early_printk.c
extern void printascii(const char *); static void early_write(const char *s, unsigned n) { char buf[128]; while (n) { unsigned l = min(n, sizeof(buf)-1); memcpy(buf, s, l); buf[l] = 0; s += l; n -= l; printascii(buf); } } 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);
在內核啟動進入C語言階段,start_kernel->parse_early_param 就會第一時間解析early_param("earlyprintk", setup_early_printk);
然後調用 register_console(&early_console_dev);
可以看到 early_console 的 write 函數最終靠 printascii 來實現,同樣,直接調用 earlyprintk 也會調用 printascii
void __init early_print(const char *str, ...) { extern void printascii(const char *); char buf[256]; va_list ap; va_start(ap, str); vsnprintf(buf, sizeof(buf), str, ap); va_end(ap); #ifdef CONFIG_DEBUG_LL printascii(buf); #endif printk("%s", buf); }
printascii:arch/arm/kernel/debug.S
ENTRY(printascii)
addruart_current r3, r1, r2
1: teq r0, #0
ldrneb r1, [r0], #1
teqne r1, #0
reteq lr
2: teq r1, #‘\n‘
bne 3f
mov r1, #‘\r‘
waituart r2, r3
senduart r1, r3
busyuart r2, r3
mov r1, #‘\n‘
3: waituart r2, r3
senduart r1, r3
busyuart r2, r3
b 1b
ENDPROC(printascii)
.macro addruart_current, rx, tmp1, tmp2
addruart \tmp1, \tmp2, \rx
mrc p15, 0, \rx, c1, c0
tst \rx, #1
moveq \rx, \tmp1
movne \rx, \tmp2
.endm
addruart_current 和 addruart 都是宏定義
各個平臺實現自己的 addruart 宏:4412的位於:arch/arm/include/debug/exynos.S
.macro addruart, rp, rv, tmp
mrc p15, 0, \tmp, c0, c0, 0
and \tmp, \tmp, #0xf0
teq \tmp, #0xf0 @@ A15
beq 100f
mrc p15, 0, \tmp, c0, c0, 5
and \tmp, \tmp, #0xf00
teq \tmp, #0x100 @@ A15 + A7 but boot to A7
100: ldreq \rp, =EXYNOS5_PA_UART
movne \rp, #EXYNOS4_PA_UART @@ EXYNOS4
ldr \rv, =S3C_VA_UART
#if CONFIG_DEBUG_S3C_UART != 0
add \rp, \rp, #(0x10000 * CONFIG_DEBUG_S3C_UART)
add \rv, \rv, #(0x10000 * CONFIG_DEBUG_S3C_UART)
#endif
.endm
這裏返回的是 uart0 的基地址,虛擬地址和物理地址,EXYNOS4_PA_UART=0x13800000
有了基地址還不夠,能需要UTXHn的偏移地址才行
arch/arm/include/debug/samsung.S
.macro senduart,rd,rx
strb \rd, [\rx, # S3C2410_UTXH]
.endm
include/linux/serial_s3c.h
#define S3C2410_UTXH (0x20)
因此,可以得知,內核earlyprintk不會去初始化串口,直接使用Uboot初始化ok的,這是個好消息~
C語言階段,可以調用early_printk,那麽在自解壓之後,C語言之前的匯編階段,如何打印呢?
參考:
__error_p:
#ifdef CONFIG_DEBUG_LL
adr r0, str_p1
bl printascii
mov r0, r9
bl printhex8
adr r0, str_p2
bl printascii
b __error
str_p1: .asciz "\nError: unrecognized/unsupported processor variant (0x"
str_p2: .asciz ").\n"
.align
#endif
ENDPROC(__error_p)
註意:匯編階段調用函數,一定記得保護現場,否則會破壞原有寄存器,引入不必要的麻煩
自解壓階段的打印
內核自解壓階段也可以調用早期的打印函數,需要針對自己的平臺稍加修改(addruart 宏定義),這個階段可能出現的問題,內核自解壓把設備樹覆蓋了,導致卡在 staring the kernel 我這裏就是如此~~,修改Uboot設備樹的重定位地址即可。
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -24,6 +24,7 @@
* 100% relocatable. Any attempt to do so will result in a crash.
* Please select one of the following when turning on debugging.
*/
+#define DEBUG
#ifdef DEBUG
#if defined(CONFIG_DEBUG_ICEDCC)
@@ -67,7 +68,7 @@
.endm
#else
.macro loadsp, rb, tmp
- addruart \rb, \tmp
+ addruart \rb, \tmp, \tmp
.endm
#endif
#endif
@@ -554,6 +555,12 @@ not_relocated: mov r0, #0
* r7 = architecture ID
* r8 = atags pointer
*/
+ stmfd sp!, {r0-r3, r10-r12, lr}
+ mov r0, r8
+ bl memdump
+ kputc #‘\n‘
+ ldmfd sp!, {r0-r3, r10-r12, lr}
+
mov r0, r4
mov r1, sp @ malloc space above stack
add r2, sp, #0x10000 @ 64k max
@@ -563,6 +570,12 @@ not_relocated: mov r0, #0
bl cache_off
mov r1, r7 @ restore architecture number
mov r2, r8 @ restore atags pointer
+
+ stmfd sp!, {r0-r3, r10-r12, lr}
+ mov r0, r8
+ bl memdump
+ kputc #‘\n‘
+ ldmfd sp!, {r0-r3, r10-r12, lr}
#ifdef CONFIG_ARM_VIRT_EXT
參考:https://www.cnblogs.com/pengdonglin137/p/5146791.html
參考:http://www.wowotech.net/x_project/kernel_earlycon_porting.html
來自為知筆記(Wiz)
內核啟動早期的打印