Linux 内核启动过程中的日志输出阶段分析
Linux 内核启动过程中的日志输出阶段分析一、引言为什么要理解内核启动日志Linux 内核的启动过程是一个高度复杂且有序的初始化流程。在这个过程中内核会输出大量日志信息这些日志对于系统运维人员、驱动开发者以及内核开发者来说是诊断启动故障、理解硬件初始化顺序的重要依据。许多人只会在系统无法启动时才想起查看dmesg输出但实际上日志输出本身也遵循着严格的阶段性规律。本文将从基础概念出发带领你逐步理解内核在启动过程中日志输出是如何从无到有、从简单到丰富演进的。我们会涉及到 printk 机制、控制台初始化以及日志缓冲区的管理。## 二、基础概念printk 与日志级别### 2.1 什么是 printk在 Linux 内核中printk是内核态最常用的日志输出函数类似于用户态的printf。它允许内核在任意位置输出信息包括中断上下文、进程上下文等。c// 基础 printk 使用示例printk(Hello, Kernel World!\n);printk(KERN_INFO This is an informational message\n);printk(KERN_ERR This is an error message\n);### 2.2 日志级别Log Level每个 printk 消息都带有一个日志级别用于表示消息的严重程度。内核通过比较消息级别与当前控制台的日志级别console_loglevel来决定是否将消息输出到控制台。常见的日志级别从高到低| 宏定义 | 级别值 | 含义 ||--------|--------|------|| KERN_EMERG | 0 | 紧急情况系统不可用 || KERN_ALERT | 1 | 需要立即处理 || KERN_CRIT | 2 | 临界条件 || KERN_ERR | 3 | 错误条件 || KERN_WARNING | 4 | 警告条件 || KERN_NOTICE | 5 | 普通但重要的条件 || KERN_INFO | 6 | 信息性消息 || KERN_DEBUG | 7 | 调试级别的消息 |### 2.3 日志输出流程当 printk 被调用时内核会执行以下步骤1. 格式化消息字符串2. 将消息写入环形缓冲区ring buffer3. 检查消息级别是否 console_loglevel4. 如果是则立即输出到当前控制台5. 唤醒可能等待日志输出的进程如klogd## 三、启动阶段的日志输出演变### 3.1 早期启动阶段无控制台输出在 x86 架构下内核解压完成后会进入start_kernel()函数。在启动的最早期阶段大约是setup_arch()之前控制台硬件如串口、VGA 文本模式尚未初始化。此时所有 printk 输出都会被写入 __log_buf内核日志缓冲区但不会显示在任何物理设备上。c// 早期启动阶段的典型代码arch/x86/kernel/head_64.S 中// 此时只能使用早期的非常规输出方式例如通过 I/O 端口直接写串口mov $0x3f8, %dx // COM1 端口地址mov $K, %alout %al, %dx // 直接输出到串口不经过 printk 机制### 3.2 控制台初始化阶段日志开始可见当内核执行到console_init()函数时它会遍历所有注册的控制台驱动程序并激活第一个可用的控制台。这个阶段通常发生在start_kernel()的中期。控制台初始化的顺序决定了哪些日志会先出现在屏幕上。常见的控制台类型包括-VGA 文本控制台典型的 PC 显示器输出-串口控制台通过 RS-232 或 USB 串口输出-earlyprintk一种早期的调试输出机制c// 一个简化的控制台初始化流程伪代码void __init console_init(void){ // 1. 注册内置控制台 con_init(); // 初始化 VGA 控制台 // 2. 激活第一个控制台 // 之后所有 printk 输出都会同时写入缓冲区并显示到控制台 register_console(vt_console_driver); // 3. 打印初始化完成消息 printk(KERN_INFO Console: colour dummy device 80x25\n);}### 3.3 完整初始化阶段多控制台与日志管理在start_kernel()的最后阶段内核会启动init进程并切换到用户空间。此时日志系统已经完整运行包括- 环形缓冲区ring buffer已完全初始化-/proc/kmsg和/dev/kmsg设备文件可用- syslog 系统调用可用## 四、代码示例模拟日志输出阶段### 4.1 示例一使用 Python 模拟日志缓冲区的环形结构为了帮助你理解内核日志缓冲区的管理方式我们编写一个简单的 Python 程序来模拟环形缓冲区的工作原理。python#!/usr/bin/env python3模拟 Linux 内核日志缓冲区ring buffer的行为演示 printk 消息如何被存储和读取class KernelLogBuffer: 内核日志缓冲区模拟类 def __init__(self, size1024): self.buffer [None] * size # 固定大小的环形缓冲区 self.size size self.write_pos 0 # 当前写入位置 self.read_pos 0 # 当前读取位置 self.msg_count 0 # 消息计数 def printk(self, level, message): 模拟内核的 printk 函数 # 构造日志条目包含级别和内容 log_entry f[{level}] {message} # 写入环形缓冲区 self.buffer[self.write_pos] log_entry self.write_pos (self.write_pos 1) % self.size self.msg_count 1 # 如果缓冲区写满覆盖最旧的记录 if self.write_pos self.read_pos: self.read_pos (self.read_pos 1) % self.size # 返回消息是否应该输出到控制台 # 假设控制台日志级别为 6KERN_INFO console_loglevel 6 return level console_loglevel def read_logs(self, count10): 读取最近的日志条目 logs [] pos self.read_pos for _ in range(min(count, self.msg_count)): if self.buffer[pos] is not None: logs.append(self.buffer[pos]) pos (pos 1) % self.size return logs# 模拟内核启动过程if __name__ __main__: log_buf KernelLogBuffer(size32) # 阶段1: 早期启动控制台未初始化 print( 阶段1: 早期启动 - 日志只写入缓冲区 ) log_buf.printk(7, Early boot: CPU initialization) # KERN_DEBUG log_buf.printk(6, Early boot: Memory detection) # KERN_INFO # 阶段2: 控制台初始化 print(\n 阶段2: 控制台初始化 - 日志开始输出 ) log_buf.printk(5, Console: Initializing VGA console) # KERN_NOTICE log_buf.printk(4, Console: Registered device driver) # KERN_WARNING # 阶段3: 完整启动 print(\n 阶段3: 完整启动 - 正常日志输出 ) log_buf.printk(3, Mounting root filesystem) # KERN_ERR log_buf.printk(2, Starting init process) # KERN_CRIT # 读取并打印缓冲区状态 print(\n缓冲区中的日志:) for log in log_buf.read_logs(10): print(f {log}) print(f\n总共写入 {log_buf.msg_count} 条日志) print(f缓冲区已用空间: {len([x for x in log_buf.buffer if x is not None])}/{log_buf.size})### 4.2 示例二使用 Python 分析 dmesg 输出在实际的 Linux 系统中我们可以通过dmesg命令获取内核日志。下面的 Python 脚本演示了如何解析这些日志并分析启动阶段。python#!/usr/bin/env python3分析 dmesg 输出识别内核启动阶段需要 root 权限或 /var/log/dmesg 文件import refrom collections import defaultdictdef parse_dmesg_logs(log_file/var/log/dmesg): 解析 dmesg 日志文件识别不同启动阶段 参数: log_file: dmesg 日志文件路径 返回: 按阶段分组的日志字典 phases defaultdict(list) current_phase unknown # 定义阶段的识别模式 phase_patterns { early_boot: [ rLinux version, rCommand line, rBIOS-provided physical RAM map ], console_init: [ rConsole: colour, rconsole \[tty, rserial8250: ttyS ], device_init: [ rpci_bus, rata[0-9], rusb [0-9] ], filesystem: [ rVFS: Mounted root, rEXT4-fs, rkjournald ], init_done: [ rFreeing unused kernel memory, rinit started ] } try: with open(log_file, r, errorsignore) as f: for line in f: # 检测阶段切换 for phase, patterns in phase_patterns.items(): for pattern in patterns: if re.search(pattern, line, re.IGNORECASE): current_phase phase break # 提取时间戳如果有 timestamp_match re.match(r\[\s*(\d\.\d)\], line) timestamp timestamp_match.group(1) if timestamp_match else N/A # 存储日志 phases[current_phase].append({ timestamp: timestamp, message: line.strip() }) except FileNotFoundError: print(f错误: 找不到日志文件 {log_file}) print(请尝试运行: dmesg /tmp/dmesg.txt 并修改脚本路径) return None return phasesdef print_phase_analysis(phases): 打印各阶段的分析报告 if not phases: return total_lines sum(len(lines) for lines in phases.values()) print(f总日志条数: {total_lines}) print(- * 60) for phase, logs in phases.items(): print(f\n阶段: {phase} ({len(logs)} 条日志)) print(- * 40) # 显示前3条和后2条日志作为示例 if len(logs) 5: for log in logs[:3]: print(f [{log[timestamp]}] {log[message][:80]}) print(f ... (中间 {len(logs)-5} 条省略) ...) for log in logs[-2:]: print(f [{log[timestamp]}] {log[message][:80]}) else: for log in logs: print(f [{log[timestamp]}] {log[message][:80]})if __name__ __main__: # 分析当前系统的 dmesg 日志 phases parse_dmesg_logs() if phases: print_phase_analysis(phases)## 五、高级话题自定义日志输出与调试技巧### 5.1 动态调整控制台日志级别在内核运行时可以通过/proc/sys/kernel/printk文件动态调整日志级别。文件中包含四个数字$ cat /proc/sys/kernel/printk7 4 1 7分别代表1. 控制台日志级别console_loglevel2. 默认消息日志级别default_message_loglevel3. 最低控制台日志级别minimum_console_loglevel4. 默认控制台日志级别default_console_loglevel修改方法bash# 只显示 KERN_WARNING (4) 及以上级别的消息echo 4 4 1 7 /proc/sys/kernel/printk### 5.2 使用 earlyprintk 进行早期调试当系统在启动早期崩溃时常规控制台可能尚未工作。此时可以使用earlyprintk内核参数bash# 在 GRUB 启动参数中添加earlyprintkserial,ttyS0,115200这样可以在控制台初始化之前将日志直接输出到串口。## 六、总结通过本文的学习我们深入理解了 Linux 内核启动过程中日志输出的演变规律1.早期阶段日志仅写入内核缓冲区不显示到物理设备2.控制台初始化第一个控制台被激活日志开始可见3.完整阶段多控制台支持用户空间工具可读取日志掌握这些知识有助于我们在系统启动失败时通过分析dmesg输出来定位问题。无论是硬件初始化失败、驱动加载异常还是文件系统挂载错误启动日志都能提供关键的线索。最后建议读者在实验环境中多观察不同内核版本的启动日志尝试调整printk级别这样能够获得更深刻的理解。记住每一次内核启动都是一次精彩的初始化交响乐而日志就是这场交响乐的乐谱。

相关新闻

openclaw自动写代码由于脱敏机制误判导致代码不可用

openclaw自动写代码由于脱敏机制误判导致代码不可用

问题描述:借助openclaw辅助编写脚本或工程代码时,偶尔遇到敏感信息脱敏为***的场景,且反复沟通后,无法完成修正。代码如下:api_key os.getenv("OPENAI_API_KEY") base_url os.getenv("OPENAI_BASE_UR…

2026/7/31 12:06:06 阅读更多 →
基于MCU微控制器的冰箱压缩机系统解决方案

基于MCU微控制器的冰箱压缩机系统解决方案

在智能冰箱的整体架构中,压缩机是决定设备制冷性能、能耗水平与运行稳定性的核心机械电控部件,它的控制精度直接影响冰箱的能效等级、静音效果与使用寿命。随着家电变频智能化升级,传统控制方案已难以适配高端冰箱的节能、低噪、稳定运行需求…

2026/7/31 12:06:06 阅读更多 →
【人大金仓KingbaseES安装教程】最新图文详解(附安装包)

【人大金仓KingbaseES安装教程】最新图文详解(附安装包)

前言 在国产数据库浪潮席卷各行各业的今天,人大金仓KingbaseES安装教程已成为众多DBA和运维人员最常搜索的技术文档之一。作为中国较早具备完整自主知识产权的关系型数据库,KingbaseES凭借其出色的Oracle兼容性和企业级稳定性,正在党政、金融…

2026/7/31 12:06:06 阅读更多 →

最新新闻

CentOS 7 磁盘配额实验:EXT4 用户/组限额与 XFS Project Quota

CentOS 7 磁盘配额实验:EXT4 用户/组限额与 XFS Project Quota

CentOS 7 磁盘配额实验:EXT4 用户/组限额与 XFS Project Quota1. 服务介绍Linux 磁盘配额(Quota)用于限制普通用户、用户组或指定目录可以占用的磁盘容量和文件数量。它常用于教学服务器、共享文件服务器、邮件服务器和虚拟主机,避…

2026/7/31 13:29:34 阅读更多 →
BepInEx插件框架:3步解锁Unity游戏无限潜力

BepInEx插件框架:3步解锁Unity游戏无限潜力

BepInEx插件框架:3步解锁Unity游戏无限潜力 【免费下载链接】BepInEx Unity / XNA game patcher and plugin framework 项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx 你是否梦想过为心爱的游戏添加新功能、优化体验或创造全新玩法?…

2026/7/31 13:29:34 阅读更多 →
终极指南:5分钟学会用pkNX定制你的Switch宝可梦游戏体验

终极指南:5分钟学会用pkNX定制你的Switch宝可梦游戏体验

终极指南:5分钟学会用pkNX定制你的Switch宝可梦游戏体验 【免费下载链接】pkNX Pokmon (Nintendo Switch) ROM Editor & Randomizer 项目地址: https://gitcode.com/gh_mirrors/pk/pkNX 你是否想过完全掌控自己的宝可梦游戏世界?想要调整游戏…

2026/7/31 13:29:34 阅读更多 →
原神自动化助手:如何用脚本提升游戏效率的3个关键模块

原神自动化助手:如何用脚本提升游戏效率的3个关键模块

原神自动化助手:如何用脚本提升游戏效率的3个关键模块 【免费下载链接】genshin-impact-script 原神脚本,包含自动钓鱼、自动拾取、自动跳过对话等多项实用功能。A Genshin Impact script includes many useful features such as automatic fishing, aut…

2026/7/31 13:29:34 阅读更多 →
Java面试宝典:微服务、分布式、高并发场景题实战解析

Java面试宝典:微服务、分布式、高并发场景题实战解析

这次我们来看一个专门针对Java面试的项目场景题解析宝典。这个资源最大的特点是直接从项目实战角度出发,把常见的面试场景题进行了系统化整理,相比单纯啃书或者背八股文,效率能提升十倍以上。 对于正在准备Java面试的开发者来说,…

2026/7/31 13:29:34 阅读更多 →
SysML v2 2025-02版本发布:新一代系统建模语言的深度解析与实战指南

SysML v2 2025-02版本发布:新一代系统建模语言的深度解析与实战指南

SysML v2 2025-02版本发布:新一代系统建模语言的深度解析与实战指南 【免费下载链接】SysML-v2-Release The latest incremental release of SysML v2. Start here. 项目地址: https://gitcode.com/gh_mirrors/sy/SysML-v2-Release SysML v2 2025-02版本作为…

2026/7/31 13:28:34 阅读更多 →

日新闻

物理复制比逻辑复制好在哪?数据库复制原理详解

物理复制比逻辑复制好在哪?数据库复制原理详解

数据库复制是把主库数据同步到备库的机制,分为逻辑复制和物理复制两种。逻辑复制传输的是 SQL 语句或行变更事件,物理复制传输的是存储引擎底层的物理日志。阿里云 PolarDB(云原生数据库)采用物理复制,在同步延迟、数据…

2026/7/31 0:00:34 阅读更多 →
BilibiliDown:3分钟学会B站视频下载的终极指南

BilibiliDown:3分钟学会B站视频下载的终极指南

BilibiliDown:3分钟学会B站视频下载的终极指南 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/bi/Bilib…

2026/7/31 0:00:34 阅读更多 →
有哪些游戏数据AI平台?游戏行业Data+AI融合方案盘点

有哪些游戏数据AI平台?游戏行业Data+AI融合方案盘点

当前,游戏行业的“DataAI融合”已从概念验证进入价值落地阶段。根据IDC 2025年数据,中国AI游戏云市场规模已达18.6亿元;同时,游戏研发环节AI渗透率高达86%,生成式AI内容普及率超过50%。面对庞大的市场,游戏…

2026/7/31 0:00:34 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/31 1:03:03 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/29 14:34:28 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/31 4:19:39 阅读更多 →

月新闻