解决linux内核配置成runtime后,无法启动的问题(自己添加的lcd代码的问题导致)

本文详细描述了如何通过逐步定位和调试方法解决Linux内核启动时出现的UncompressingLinux...done,bootingthekernel.后停止的问题。包括检查启动过程中的关键步骤,如确认start_kernel()函数是否执行,以及通过打印printk()缓存信息来定位串口配置和系统时钟源初始化错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内核版本:linux-3.4.99

bootloader:u-boot-2012-04-01

开发板:mini2440

参考视频:韦东山第三期视频


在韦东山第三期视频中电源管理项目的runtime一节中,有讲到在lcd_init()函数开头注册lcd_device,lcd_driver后,linux内核启动会出现:

## Booting kernel from Legacy Image at 30000000 ...
   Image Name:   Linux-3.4.99
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    2862672 Bytes = 2.7 MiB
   Load Address: 30008000
   Entry Point:  30008000
   Verifying Checksum ... OK
   Loading Kernel Image ... OK
OK
Using machid 0x16a from environment


Starting kernel ...


Uncompressing Linux... done, booting the kernel.


之后内核就停在这里,当时韦老师直接就把错误告诉了我们(lcd_device,lcd_driver应该在lcd的寄存器初始后再调用),实际如果在调试过程中,如果出现这种问题,应该怎么办呢?

此时串口已经没有打印信息,上网百度,谷歌后,关于“Uncompressing Linux... done, booting the kernel.”的问题,网上基本归结为两类:

1.uboot传入给linux的参数不对(机器码等等)。

2.串口配置不对。

照着这个思路,网上溜一圈,出现了各种解决方法,盲目的去找哪种方法显然是不科学的。


那我就慢慢的从linux内核开始,一步步去定位出错的地方:

1.首先确定linux_kernel有没有启动:在booting the kernel 之后Kernel 最先执行的是start_kernel() 函数,确认start_kernel() 有否执行就是在其开始代码段添加printascii(“start_kernel …”) ,如果串口没有打印出start_kernel …,说明start_kernel() 没有运行。测试代码如下(init/main.c):


extern void printascii(const char*); // Modify

asmlinkage void __init start_kernel(void)

{

char * command_line;

extern struct kernel_param __start___param[], __stop___param[];

printascii("[tony]:start linux_kernel …"); // Modify

smp_setup_processor_id();

…

编译内核,下载,发现:

## Booting kernel from Legacy Image at 30000000 ...
   Image Name:   Linux-3.4.99
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    2862672 Bytes = 2.7 MiB
   Load Address: 30008000
   Entry Point:  30008000
   Verifying Checksum ... OK
   Loading Kernel Image ... OK
OK
Using machid 0x16a from environment


Starting kernel ...


Uncompressing Linux... done, booting the kernel.
[tony]:start linux_kernel


好了,可以确定启动了start_kernel() 

2.接下来,使用printascii() 函数打印printk() 缓存信息 :

 如果Kernel已进入到start_kernel() 执行,仍然没有启动信息打印出来,说明串口波特率出问题的可能性比较大,启动信息是暂时缓存到临时buffer–printk_buf 中的,进入start_kernel() 中会对串口波特率重新初始化,当初始化完成后,缓存的系统启动信息便打印出来,不能打印说明用于串口波特率初始化的系统时钟源没有初始化正确,通常是系统时钟源和实际的晶振频率不一致导致的,通常排查和解决这个问题后,系统启动信息是能正确打印的。为了帮助解决问题,可以使用 printascii() 打印printk_buf 内容。这样就能把printascii()打印的系统信息和预想的系统信息进行比较,从而加快解决问题的进度。 

测试代码如下(kernel/printk.c):
extern void printascii(const char*); // Modify

static char printk_buf[1024]; // Modify

asmlinkage int printk(const char *fmt, ...)

{

va_list args;

int r;

va_start(args, fmt);

r = vprintk(fmt, args);

va_end(args);

printascii(printk_buf); // Modify

return r;

}

…

static int recursion_bug;

static int new_text_line = 1;

//static char printk_buf[1024]; // Modify

编译内核,下载,重启:

## Booting kernel from Legacy Image at 30000000 ...
   Image Name:   Linux-3.4.99
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    2862272 Bytes = 2.7 MiB
   Load Address: 30008000
   Entry Point:  30008000
   Verifying Checksum ... OK
   Loading Kernel Image ... OK
OK
Using machid 0x16a from environment


Starting kernel ...


Uncompressing Linux... done, booting the kernel.
[tony]:start linux_kernel<6>Booting Linux on physical CPU 0
<5>Linux version 3.4.99 (root@tony-virtual-machine) (gcc version 4.3.2 (Sourcery G++ Lite 2008q3-72) ) #49 Mon Nov 24 19:08:40 CST 2014
CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177
CPU: VIVT data cache, VIVT instruction cache
Machine: SMDK2440
Memory policy: ECC disabled, Data cache writeback
CPU S3C2440A (id 0x32440001)
<6>S3C24XX Clocks, Copyright 2004 Simtec Electronics
S3C244X: core 405.600 MHz, memory 101.400 MHz, peripheral 50.700 MHz
CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
<7>On node 0 totalpages: 16384
<7>free_area_init_node: node 0, pgdat c0592f80, node_mem_map c05bb000
<7>  Normal zone: 128 pages used for memmap
<7>  Normal zone: 0 pages reserved
<7>  Normal zone: 16256 pages, LIFO batch:3
<7>pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768<c>
<7>pcpu-alloc: <c>[0] <c>0 <c>
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 16256
<5>Kernel command line: noinitrd root=/dev/nfs nfsroot=192.168.10.219:/work/tony_fs ip=192.168.10.244:192.168.10.219:192.168.10.1:255.255.255.0::eth0:off console=ttySAC0,115200
<6>PID hash table entries: 256 (order: -2, 1024 bytes)
<6>Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
<6>Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
<6>Memory: 64MB = 64MB total
<5>Memory: 59040k/59040k available, 6496k reserved, 0K highmem
<5>Virtual kernel memory layout:
    vector  : 0xffff0000 - 0xffff1000   (   4 kB)
    fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
    vmalloc : 0xc4800000 - 0xff000000   ( 936 MB)
    lowmem  : 0xc0000000 - 0xc4000000   (  64 MB)
    modules : 0xbf000000 - 0xc0000000   (  16 MB)
      .text : 0xc0008000 - 0xc0527d40   (5248 kB)
      .init : 0xc0528000 - 0xc0551000   ( 164 kB)
      .data : 0xc0552000 - 0xc0593860   ( 263 kB)
       .bss : 0xc0593884 - 0xc05badfc   ( 158 kB)
<6>NR_IRQS:85
irq: clearing subpending status 00000002
<7>timer tcon=00500000, tcnt a509, tcfg 00000200,00000000, usec 00001e4c
<6>sched_clock: 32 bits at 200 Hz, resolution 5000000ns, wraps every 4294967291ms
<6>Console: colour dummy device 80x30
<6>Calibrating delay loop... <c>201.52 BogoMIPS (lpj=503808)
<6>pid_max: default: 32768 minimum: 301
<6>Mount-cache hash table entries: 512
<6>CPU: Testing write buffer coherency: ok
<6>Setting up static identity map for 0x303cfc78 - 0x303cfcd0
<6>gpiochip_add: registered GPIOs 0 to 23 on device: GPIOA
<6>gpiochip_add: registered GPIOs 32 to 47 on device: GPIOB
<6>gpiochip_add: registered GPIOs 64 to 79 on device: GPIOC
<6>gpiochip_add: registered GPIOs 96 to 111 on device: GPIOD
<6>gpiochip_add: registered GPIOs 128 to 143 on device: GPIOE
<6>gpiochip_add: registered GPIOs 160 to 167 on device: GPIOF
<6>gpiochip_add: registered GPIOs 192 to 207 on device: GPIOG
<6>gpiochip_add: registered GPIOs 224 to 234 on device: GPIOH
<6>gpiochip_add: registered GPIOs 256 to 271 on device: GPIOJ
<6>NET: Registered protocol family 16
S3C Power Management, Copyright 2004 Simtec Electronics
S3C2440: Initialising architecture
S3C2440: IRQ Support
S3C244X: Clock Support, DVS off
S3C24XX DMA Driver, Copyright 2003-2006 Simtec Electronics
DMA channel 0 at c4804000, irq 33
DMA channel 1 at c4804040, irq 34
DMA channel 2 at c4804080, irq 35
DMA channel 3 at c48040c0, irq 36
<6>bio: create slab <bio-0> at 0
<5>SCSI subsystem initialized
<6>usbcore: registered new interface driver usbfs
<6>usbcore: registered new interface driver hub
<6>usbcore: registered new device driver usb
<6>s3c-i2c s3c2440-i2c: slave address 0x10
<6>s3c-i2c s3c2440-i2c: bus frequency set to 99 KHz
<6>s3c-i2c s3c2440-i2c: i2c-0: S3C I2C adapter
<6>Linux video capture interface: v2.00
<6>Advanced Linux Sound Architecture Driver Version 1.0.25.
<6>cfg80211: Calling CRDA to update world regulatory domain
<6>NET: Registered protocol family 2
<6>IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
<6>TCP established hash table entries: 2048 (order: 2, 16384 bytes)
<6>TCP bind hash table entries: 2048 (order: 1, 8192 bytes)
<6>TCP: Hash tables configured (established 2048 bind 2048)
<6>TCP: reno registered
<6>UDP hash table entries: 256 (order: 0, 4096 bytes)
<6>UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
<6>NET: Registered protocol family 1
<6>RPC: Registered named UNIX socket transport module.
<6>RPC: Registered udp transport module.
<6>RPC: Registered tcp transport module.
<6>RPC: Registered tcp NFSv4.1 backchannel transport module.
<4>NetWinder Floating Point Emulator V0.97 (extended precision)
<6>jffs2: version 2.2. (NAND) (SUMMARY)  漏 2001-2006 Red Hat, Inc.
<6>ROMFS MTD (C) 2007 Red Hat, Inc.
<7>yaffs: yaffs built Nov 24 2014 17:02:32 Installing.
<6>msgmni has been set to 115
<6>io scheduler noop registered
<6>io scheduler deadline registered
<6>io scheduler cfq registered (default)
drivers/video/mini2440_t35.c lcd_suspend 130
<1>Unable to handle kernel NULL pointer dereference at virtual address 00000000
<1>pgd = c0004000
<1>[00000000] *pgd=00000000
<0>Internal error: Oops: 5 [#1] ARM
<d>Modules linked in:
CPU: 0    Not tainted  (3.4.99 #49)
PC is at lcd_enable+0x18/0x94
LR is at lcd_suspend+0x28/0x3c
pc : [<c01842cc>]    lr : [<c01843b0>]    psr: 40000093
sp : c381fe40  ip : 00001342  fp : 00000000
r10: c056d2c4  r9 : c05649d8  r8 : 00000000
r7 : 00000000  r6 : 00000000  r5 : 40000013  r4 : 00000000
r3 : 00000000  r2 : 00000008  r1 : 00000000  r0 : c05b1ed8
Flags: nZcv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
Control: c000717f  Table: 30004000  DAC: 00000017
<0>Process swapper (pid: 1, stack limit = 0xc381e270)
<0>Stack: (0xc381fe40 to 0xc3820000)
<0>fe40: c056d218 c056d218 00000000 c01b77e8 00000000 c01bb890 c0594a94 00000000
<0>fe60: c056d294 c381e000 24af4412 00000000 c381feb0 c00e0a70 c381feb0 c381feb0
<0>fe80: c0571700 60000013 24af4412 00000000 00000000 00000000 22222222 60000013
<0>fea0: 00000004 00000000 c056d38c c05b3bf4 c05938a0 00000000 00000000 c01bcc64
<0>fec0: c056d218 c01b7d2c c056d218 c01bbe74 60000013 c056d218 00000000 c01bc008
<0>fee0: 00000001 c01b39d4 c056d218 c056d24c c056d38c c01b3ac4 c38e9ba0 c05938a0
<0>ff00: 00000000 c01b3b50 00000000 c381ff18 c056d38c c01b2360 c38047b8 c38e9c30
<0>ff20: c05500c4 c05500c4 c056d38c c056d38c c05718c8 c01b2aa4 c04ab1b4 00000000
<0>ff40: c056d218 c05500c4 c056d38c 00000007 c381e000 000000bb c01843c4 c01b4134
<0>ff60: c05500c4 c0547d5c 00000007 c381e000 000000bb c01843d8 c05500c4 c0547d5c
<0>ff80: 00000007 c381e000 000000bb c0008560 00000006 00000006 c0504d2c c0490fa8
<0>ffa0: 00000000 c05500c4 c0547d5c 00000007 c05938a0 000000bb c05281ac c0547d68
<0>ffc0: 00000000 c052830c 00000006 00000006 c05281ac 00000000 00000000 c0528218
<0>ffe0: c00162e8 00000013 00000000 00000000 00000000 c00162e8 00000100 00000000
[<c01842cc>] (lcd_enable+0x18/0x94) from [<00000000>] (  (null))
<0>Code: e3853080 e121f003 e5904004 e5903070 (e594c000) 
<4>---[ end trace 2d1ab6a7025a992b ]---
<0>Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b

好了,之前没打印出来的出错信息都出来。

drivers/video/mini2440_t35.c lcd_suspend 130
<1>Unable to handle kernel NULL pointer dereference at virtual address 00000000

很快就定位到lcd代码的错误。


<think>我们正在讨论DRM(DirectRenderingManager)架构下LCD屏幕的灭屏流程。根据用户的问题,我们需要关注DRM框架中如何控制LCD屏幕熄灭的机制。DRM是Linux内核中用于管理图形硬件的子系统,负责显示输出、渲染和GPU管理。在DRM架构中,屏幕的亮灭状态主要由显示管线(displaypipeline)控制,涉及多个组件:DRMcore、KMS(KernelModeSetting)模块、显示驱动(displaydriver)和可能的背光控制。###DRM架构中LCD灭屏的核心流程1.**用户空间触发灭屏请求**:-当系统需要熄灭屏幕时(如用户按下电源键或系统进入休眠),用户空间的显示管理服务(如X11/Waylandcompositor或AndroidSurfaceFlinger)会通过DRM的libdrm库向内核发送`DRM_IOCTL_MODE_SETPLANE`或`DRM_IOCTL_MODE_SETCRTC`等ioctl请求,将CRTC(显示控制器)的状态设置为关闭[^2]。2.**KMS模块处理显示状态变更**:-KMS是DRM的核心功能之一,负责配置显示控制器(CRTC)、编码器(Encoder)、连接器(Connector)和显示面板(Panel)。灭屏时,KMS会执行以下关键操作:-停止CRTC的扫描输出(disableCRTC)。-通过连接器(Connector)通知显示面板进入休眠状态(如发送MIPIDCS命令进入睡眠模式)。-若面板支持,会先关闭背光(Backlight)再关闭面板电源[^1]。3.**面板驱动执行具体灭屏序列**:-显示面板驱动(如MIPIDSI面板驱动)会按照面板规格书的要求,发送特定的MIPIDCS命令序列。常见的灭屏命令包括:-`DCS_SET_DISPLAY_OFF`(0x28):通知面板停止显示。-`DCS_ENTER_SLEEP_MODE`(0x10):使面板进入低功耗睡眠状态。-这些命令通过DSI主机控制器(如SynopsysDWDSI)发送到LCD屏幕[^1][^2]。4.**电源管理协同**:-灭屏流程通常与电源管理子系统(如LinuxruntimePM)联动。当屏幕熄灭后,DRM驱动可能会降低GPU或显示控制器的时钟频率,甚至关闭其电源域以节省功耗[^1]。###关键代码流程(简化版)以下是一个典型的灭屏调用栈(以LinuxDRM驱动为例):```c用户空间compositor→drmModeSetCrtc(crtc_id,0,0,0,0,NULL,0,NULL)→ioctl(DRM_IOCTL_MODE_SETCRTC)内核DRMcore:drm_mode_setcrtc()→drm_atomic_helper_disable_plane()→drm_atomic_commit()→显示驱动中的atomic_disable回调函数→面板驱动的disable函数→发送MIPIDCS睡眠命令[^1][^2]```###灭屏时序要求面板的灭屏通常需要严格遵循时序(参考面板规格书):1.先关闭背光(避免残留影像)。2.等待一帧时间(frametime)。3.发送`DISPLAY_OFF`命令。4.等待`t_off`时间(通常5ms)。5.发送`SLEEP_IN`命令。6.最后关闭IO电源(VCC)或进入深度睡眠[^1]。###注意事项-**原子提交(AtomicCommit)**:现代DRM驱动使用原子提交确保状态变更的同步性,避免闪烁[^2]。-**错误处理**:若灭屏过程中硬件无响应(如I2C通信失败),DRM驱动会记录错误并尝试恢复,严重时可能触发内核oops[^1]。§§相关问题§§1.DRM架构中如何实现屏幕亮屏流程?2.MIPIDCS命令在面板驱动中如何被发送和处理?3.DRMatomiccommit机制如何保证显示状态切换的稳定性?4.LCD屏幕灭屏过程中可能遇到哪些硬件故障?如何诊断?</think>在 DRM(Direct Rendering Manager)架构下,LCD 屏幕的灭屏流程是一个涉及多个软硬件层级的协同过程。以下是完整的灭屏机制和流程: ### 核心灭屏流程 1. **用户空间触发灭屏请求** - 用户操作(如按电源键)或系统策略(如超时休眠)触发显示管理服务(如 Weston/Wayland compositor)调用 DRM API - 通过 libdrm 库向内核发送 `DRM_IOCTL_MODE_SETCRTC` ioctl 请求,携带 `DRM_MODE_DPMS_OFF` 标志[^2] - 数学表达:设显示状态 $S$,当 $S = \text{DPMS\_OFF}$ 时触发灭屏序列 2. **DRM/KMS 子系统处理** ```mermaid graph TD A[DRM Core] --> B[KMS 模块] B --> C[CRTC 停用] B --> D[Encoder 停用] B --> E[Connector 停用] E --> F[Panel 驱动] ``` - **CRTC(显示控制器)**:停止扫描输出和时序生 - **Encoder**:关闭视频信号编码 - **Connector**:通知面板进入休眠状态[^1] 3. **面板驱动执行硬件操作** - 通过 MIPI DSI 发送标准 DCS 命令序列: ``` DISPLAY_OFF (0x28) → SLEEP_IN (0x10) → WAIT(>5ms) → 硬件复位/断电 ``` - 背光控制: ```c // 典型背光关闭代码 struct backlight_device *bl_dev = panel->backlight; bl_dev->props.brightness = 0; backlight_update_status(bl_dev); // 触发PWM调光 ``` 4. **帧缓冲区管理** - DRM 驱动停止向显示引擎提交新的帧数据 - 释放 GPU 渲染资源(如停止 shader 计算) - FrameBuffer 进入冻结状态,保留最后一帧数据[^1] 5. **电源管理协同** - 触发 runtime PM:`pm_runtime_put_sync(dev)` - 显示控制器时钟门控(clock gating) - 电源域下电序列:$$ P_{\text{core}} \rightarrow P_{\text{phy}} \rightarrow P_{\text{io}} $$ ### 关键技术细节 1. **原子提交(Atomic Commit)** 现代 DRM 使用原子更新确保状态同步: ```c drm_atomic_state *state = drm_atomic_state_alloc(dev); drm_atomic_set_crtc_for_connector(connector_state, NULL); // 解绑连接 drm_atomic_commit(state); // 原子提交变更 ``` 2. **时序要求** 根据 MIPI DSI 规范: | 操作 | 最小延时 | 最大延时 | |------|----------|----------| | DISPLAY_OFF → SLEEP_IN | 0 | 5ms | | SLEEP_IN → 断电 | 5ms | 120ms | 3. **错误恢复机制** - 超时检测:若面板无 ACK 响应,触发硬件复位 - 状态回滚:通过 `drm_atomic_state_clear` 恢复先前状态 - 内核日志记录:`drm_err()` 输出错误码 ### 常见问题定位 当灭屏失败时,可检查: 1. DRM 状态:`cat /sys/kernel/debug/dri/0/state` 2. DSI 命令跟踪:启用 `CONFIG_DRM_DSI_TRACE` 3. 电源状态:`pm_runtime_status(dev)` ### 总结流程 $$ \text{用户请求} \xrightarrow{\text{libdrm}} \text{KMS原子提交} \xrightarrow{\text{硬件控制}} \text{DSI命令} \xrightarrow{\text{PM}} \text{电源下电} $$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值