内核启动卡死在Starting kernel ...,没有任何打印如何定位

目录

一,跟踪手段

二,stext入口测试

三,使用debug/8250.S实现

1,修改configs

2,修改debug/8250.S

store函数修改:

busyuart函数修改:

四,测试uart

[1,在arm/kernel/head.S 的ENTRY(stext)下面写入测试代码](#1,在arm/kernel/head.S 的ENTRY(stext)下面写入测试代码)

2,测试效果


魔改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

相关推荐
深紫色的三北六号1 天前
Linux 服务器磁盘扩容与目录迁移:rsync + bind mount 实现服务无感迁移(无需修改配置)
linux·扩容·服务迁移
SudosuBash1 天前
[CS:APP 3e] 关于对 第 12 章 读/写者的一点思考和题解 (作业 12.19,12.20,12.21)
linux·并发·操作系统(os)
哈基咪怎么可能是AI1 天前
为什么我就想要「线性历史 + Signed Commits」GitHub 却把我当猴耍 🤬🎙️
linux·github
十日十行2 天前
Linux和window共享文件夹
linux
木心月转码ing2 天前
WSL+Cpp开发环境配置
linux
崔小汤呀4 天前
最全的docker安装笔记,包含CentOS和Ubuntu
linux·后端
何中应4 天前
vi编辑器使用
linux·后端·操作系统
何中应4 天前
Linux进程无法被kill
linux·后端·操作系统
何中应4 天前
rm-rf /命令操作介绍
linux·后端·操作系统
何中应4 天前
Linux常用命令
linux·操作系统