目录
[1,在arm/kernel/head.S 的ENTRY(stext)下面写入测试代码](#1,在arm/kernel/head.S 的ENTRY(stext)下面写入测试代码)
魔改uboot和kernel后,内核启动卡死在Starting kernel...这个打印,没有任何其他输出,开始怀疑很多地方
(1)是不是解压失败了
(2)是不是config把镜像偏移搞错了
(3)是不是uboot环境出问题了
等等,反正出了问题后想法很多。
一,跟踪手段
(1)jtag单步调试,这个最快,但我这个板子没开放jtag管脚
(2)点灯或示波器测试gpio管教,这个效率太低了,但是有帮助
(3)earlycon或early_printk,这个有空窗期,就是比如之前这个阶段

(4)打开CONFIG_DEBUG_LL=y和CONFIG_DEBUG_UNCOMPRESS=y观察有没有uncompress打印,事实证明这个没有用,因为解压在earlycon之前的空窗期
(5)使用uboot的uart寄存器配置配合改造后的debug/8250.S实现stext入口就能使用uart,本章主要研究这种方法
二,stext入口测试
在arm/kernel/head.S 的ENTRY(stext)下面写入
mov r4, #'1' @ 测试字符
ldr r5, =0xff690000 @ UART2 地址
str r4, [r5] @ 尝试写入
mov r4, #'X'
str r4, [r5]
mov r4, #'\n'
str r4, [r5]
可以看到这样的效果

这种是最简单加日志的方法,不依赖dts,不依赖earlycon,不依赖early_printk,纯粹使用uboot配置好的uart环境,但是只能单个单个的ascii添加 ,很不方便
三,使用debug/8250.S实现
1,修改configs
CONFIG_EARLY_PRINTK=y
CONFIG_DEBUG_LL=y
CONFIG_DEBUG_UNCOMPRESS=y
CONFIG_DEBUG_LL_INCLUDE="debug/8250.S"
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_PHYS=0xff690000
CONFIG_DEBUG_UART_VIRT=0xff690000
CONFIG_DEBUG_UART_8250=y
CONFIG_DEBUG_UART_BAUDRATE=115200
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_KERNEL=y
CONFIG_GDB_SCRIPTS=y
CONFIG_PRINTK=y
CONFIG_SERIAL_EARLYCON=y
CONFIG_DEBUG_LL_UART_8250=y
解析:
CONFIG_DEBUG_UART_VIRT为啥要设置成物理地址

看这三个函数不管物理地址或虚拟地址都要作为基地址,而且虚拟地址我测试一直没有映射过,所以改成跟物理地址相同的地址。
2,修改debug/8250.S
store函数修改:
看trm手册3288的uart位宽支持8/16/32bit,但我实测strb指令无效,而且head.S采用了EP8字节序,大小端不受干扰,我看uboot采用的write32函数,所以这个地方要开启CONFIG_DEBUG_UART_8250_WORD或直接把strb改成str,我才用的第二种


busyuart函数修改:
原函数采用load \rd, [\rx, #UART_LSR << UART_SHIFT]获取UART_LSR寄存器状态,跟踪发现改函数卡死,1002死循环了。查看linux/serial_reg.h头文件发现UART_LSR的地址跟手册不符,所以直接写成固定值0x14

这样uart环境就搭好了
四,测试uart
1,在arm/kernel/head.S 的ENTRY(stext)下面写入测试代码
ENTRY(stext)
ARM_BE8(setend be ) @ ensure we are in BE8 mode
THUMB( badr r9, 1f ) @ Kernel is always entered in ARM.
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
THUMB( .thumb ) @ switch to Thumb now.
THUMB(1: )
mov r10, r0 @ 保存机器ID
mov r11, r1 @ 保存ATAGS/DTB指针
mov r12, r2 @ 保存其他参数
mrc p15, 0, r4, c1, c0, 0 /* 读取CP15的C1寄存器到R0中 */
bic r4, r4, #0x1 /* 清除C1寄存器的bit0(M位),关闭MMU */
mcr p15, 0, r4, c1, c0, 0 /* 将r0寄存器中的值写入到CP15的C1寄存器中 */
mov r0, r10
bl printhex8
mov r0, #'\n'
bl printascii
ldr r0, =0xff00ff00
bl printhex8
mov r0, #'\n'
bl printascii
mov r0, r12
bl printhex8
mov r0, #'\n'
bl printascii
@mov r4, #'2' @ 测试字符
@ldr r5, =0xff690000 @ UART2 地址
@str r4, [r5] @ 尝试写入
@mov r4, #'\r'
@str r4, [r5]
/* 打印提示信息 */
adr r0, msg_start
bl printascii
mov r0, #'\n'
bl printascii
/* 打印机器ID (r4) */
adr r0, msg_machine_id
bl printascii
mov r0, r10
bl printhex8 @ 假设有打印16进制的函数
mov r0, #'\n'
bl printascii
/* 打印ATAGS/DTB地址 (r5) */
adr r0, msg_atags_addr
bl printascii
mov r0, r12
bl printhex8
mov r0, #'\n'
bl printascii
/* 继续正常启动流程 */
mov r0, r10 @ 机器ID
mov r1, r11 @ ATAGS/DTB指针
mov r2, r12 @ 其他参数
@后面就是原有的代码了,非测试代码
#ifdef CONFIG_ARM_VIRT_EXT
bl __hyp_stub_install
#endif
在stext结束位置加上这个

2,测试效果

这样在stext可以打印文字,地址以及组合体,整合这些代码就能实现类似uboot的md或kernel的devmem命令的打印功能了。使用这个方法继续跟踪就可以继续沿袭程序员的必修课"有bug加打印"。
比如:重复增加计数确认走到哪一步了,多埋几个点
mov r6, r0
mov r0, #3 @这个是计数
bl printhex8
mov r0, #'\n'
bl printascii
mov r0, r6