内核启动卡死在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

相关推荐
321.。2 小时前
深入理解 Linux 线程封装:从 pthread 到 C++ 面向对象实现
linux·开发语言·c++
EmbedLinX2 小时前
Linux内核之文件系统:从VFS到实际存储的运作机制
linux·服务器·c语言·c++
实心儿儿2 小时前
Linux —— 进程概念 - 初识进程
linux·运维·服务器
weixin_462446232 小时前
Linux/Mac 一键自动配置 JAVA_HOME 环境变量(含 JDK 完整性校验)
java·linux·macos
济6172 小时前
linux 系统移植(第十六期)---Linux 内核移植(5)-- 修改网络驱动(1)--- Ubuntu20.04
linux·嵌入式硬件
雾削木2 小时前
STM32 HAL库 BMP280气压计读取
linux·stm32·单片机·嵌入式硬件
峥嵘life2 小时前
Android16 EDLA【CTS】CtsNetTestCases存在fail项
android·java·linux·学习·elasticsearch
OopspoO2 小时前
lubancat-A1
嵌入式硬件
航Hang*2 小时前
计算机等级考试(三级Linux技术)--- 考纲与知识点
linux·运维·服务器·计算机三级·计算机等级考试