在移植4.16内核到tiny4412的过程中遇到一个问题,官方的uboot2012引导内核成功卡在staring the kernel没有了下文,看来内核还没有到注册uart驱动就已经挂掉了,尝试打开 early printk ,让内核自解压之后能够及时的打印信息。
说句题外话,内核启动卡在staring the kernel,在2440的时代,未使用设备树,这种情况往往是机器ID设置错误,或者是串口波特率等方面的原因导致,在设备树的时代,机器ID已经被废除,最有可能的问题可能就是出在设备树的身上。
early printk的使用:
1、配置内核
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
2、设置环境变量
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);
35
1
extern void printascii(const char *);
2
3
static void early_write(const char *s, unsigned n)
4
{
5
char buf[128];
6
while (n) {
7
unsigned l = min(n, sizeof(buf)-1);
8
memcpy(buf, s, l);
9
buf[l] = 0;
10
s += l;
11
n -= l;
12
printascii(buf);
13
}
14
}
15
16
static void early_console_write(struct console *con, const char *s, unsigned n)
17
{
18
early_write(s, n);
19
}
20
21
static struct console early_console_dev = {
22
.name = "earlycon",
23
.write = early_console_write,
24
.flags = CON_PRINTBUFFER | CON_BOOT,
25
.index = -1,
26
};
27
28
static int __init setup_early_printk(char *buf)
29
{
30
early_console = &early_console_dev;
31
register_console(&early_console_dev);
32
return 0;
33
}
34
35
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);
}
15
1
void __init early_print(const char *str, ...)
2
{
3
extern void printascii(const char *);
4
char buf[256];
5
va_list ap;
6
7
va_start(ap, str);
8
vsnprintf(buf, sizeof(buf), str, ap);
9
va_end(ap);
10
11
#ifdef CONFIG_DEBUG_LL
12
printascii(buf);
13
#endif
14
printk("%s", buf);
15
}
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)
18
1
ENTRY(printascii)
2
addruart_current r3, r1, r2
3
1: teq r0, #0
4
ldrneb r1, [r0], #1
5
teqne r1, #0
6
reteq lr
7
2: teq r1, #‘\n‘
8
bne 3f
9
mov r1, #‘\r‘
10
waituart r2, r3
11
senduart r1, r3
12
busyuart r2, r3
13
mov r1, #‘\n‘
14
3: waituart r2, r3
15
senduart r1, r3
16
busyuart r2, r3
17
b 1b
18
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
7
1
.macro addruart_current, rx, tmp1, tmp2
2
addruart \tmp1, \tmp2, \rx
3
mrc p15, 0, \rx, c1, c0
4
tst \rx, #1
5
moveq \rx, \tmp1
6
movne \rx, \tmp2
7
.endm
addruart_current 和 addruart 都是宏定义
各个平台实现自己的 addruart 宏:4412的位于:arch/arm/include/debug/exynos.S
23 .macro addruart, rp, rv, tmp
24 mrc p15, 0, \tmp, c0, c0, 0
25 and \tmp, \tmp, #0xf0
26 teq \tmp, #0xf0 @@ A15
27 beq 100f
28 mrc p15, 0, \tmp, c0, c0, 5
29 and \tmp, \tmp, #0xf00
30 teq \tmp, #0x100 @@ A15 + A7 but boot to A7
31 100: ldreq \rp, =EXYNOS5_PA_UART
32 movne \rp, #EXYNOS4_PA_UART @@ EXYNOS4
33 ldr \rv, =S3C_VA_UART
34 #if CONFIG_DEBUG_S3C_UART != 0
35 add \rp, \rp, #(0x10000 * CONFIG_DEBUG_S3C_UART)
36 add \rv, \rv, #(0x10000 * CONFIG_DEBUG_S3C_UART)
37 #endif
38 .endm
17
1
23 .macro addruart, rp, rv, tmp
2
24 mrc p15, 0, \tmp, c0, c0, 0
3
25 and \tmp, \tmp, #0xf0
4
26 teq \tmp, #0xf0 @@ A15
5
27 beq 100f
6
28 mrc p15, 0, \tmp, c0, c0, 5
7
29 and \tmp, \tmp, #0xf00
8
30 teq \tmp, #0x100 @@ A15 + A7 but boot to A7
9
31 100: ldreq \rp, =EXYNOS5_PA_UART
10
32 movne \rp, #EXYNOS4_PA_UART @@ EXYNOS4
11
33 ldr \rv, =S3C_VA_UART
12
34 #if CONFIG_DEBUG_S3C_UART != 0
13
35 add \rp, \rp, #(0x10000 * CONFIG_DEBUG_S3C_UART)
14
36 add \rv, \rv, #(0x10000 * CONFIG_DEBUG_S3C_UART)
15
37 #endif
16
38 .endm
17
这里返回的是 uart0 的基地址,虚拟地址和物理地址,EXYNOS4_PA_UART=0x13800000
有了基地址还不够,能需要UTXHn的偏移地址才行
arch/arm/include/debug/samsung.S
51 .macro senduart,rd,rx
52 strb \rd, [\rx, # S3C2410_UTXH]
53 .endm
3
1
51 .macro senduart,rd,rx
2
52 strb \rd, [\rx, # S3C2410_UTXH]
3
53 .endm
include/linux/serial_s3c.h:33:#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)
14
1
__error_p:
2
#ifdef CONFIG_DEBUG_LL
3
adr r0, str_p1
4
bl printascii
5
mov r0, r9
6
bl printhex8
7
adr r0, str_p2
8
bl printascii
9
b __error
10
str_p1: .asciz "\nError: unrecognized/unsupported processor variant (0x"
11
str_p2: .asciz ").\n"
12
.align
13
#endif
14
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
45
1
--- a/arch/arm/boot/compressed/head.S
2
+++ b/arch/arm/boot/compressed/head.S
3
@@ -24,6 +24,7 @@
4
* 100% relocatable. Any attempt to do so will result in a crash.
5
* Please select one of the following when turning on debugging.
6
*/
7
+#define DEBUG
8
#ifdef DEBUG
9
10
#if defined(CONFIG_DEBUG_ICEDCC)
11
@@ -67,7 +68,7 @@
12
.endm
13
#else
14
.macro loadsp, rb, tmp
15
- addruart \rb, \tmp
16
+ addruart \rb, \tmp, \tmp
17
.endm
18
#endif
19
#endif
20
@@ -554,6 +555,12 @@ not_relocated: mov r0, #0
21
* r7 = architecture ID
22
* r8 = atags pointer
23
*/
24
+ stmfd sp!, {r0-r3, r10-r12, lr}
25
+ mov r0, r8
26
+ bl memdump
27
+ kputc #‘\n‘
28
+ ldmfd sp!, {r0-r3, r10-r12, lr}
29
+
30
mov r0, r4
31
mov r1, sp @ malloc space above stack
32
add r2, sp, #0x10000 @ 64k max
33
@@ -563,6 +570,12 @@ not_relocated: mov r0, #0
34
bl cache_off
35
mov r1, r7 @ restore architecture number
36
mov r2, r8 @ restore atags pointer
37
+
38
+ stmfd sp!, {r0-r3, r10-r12, lr}
39
+ mov r0, r8
40
+ bl memdump
41
+ kputc #‘\n‘
42
+ ldmfd sp!, {r0-r3, r10-r12, lr}
43
44
#ifdef CONFIG_ARM_VIRT_EXT
45
参考:https://www.cnblogs.com/pengdonglin137/p/5146791.html
参考:http://www.wowotech.net/x_project/kernel_earlycon_porting.html
原文地址:https://www.cnblogs.com/bringup/p/9316103.html