<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>首页 on Yun 的个人博客</title><link>https://yun7211.github.io/</link><description>Recent content in 首页 on Yun 的个人博客</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Mon, 18 May 2026 12:20:00 +0800</lastBuildDate><atom:link href="https://yun7211.github.io/index.xml" rel="self" type="application/rss+xml"/><item><title>AI 功能上线前检查清单</title><link>https://yun7211.github.io/ai/ai-engineering/ai-feature-checklist/</link><pubDate>Mon, 18 May 2026 12:20:00 +0800</pubDate><guid>https://yun7211.github.io/ai/ai-engineering/ai-feature-checklist/</guid><description>&lt;h2 id="为什么需要检查清单"&gt;为什么需要检查清单
&lt;/h2&gt;&lt;p&gt;AI 功能很容易在演示阶段看起来不错，但上线后遇到长尾输入、成本波动、上下文缺失和不可复现问题。上线前需要把这些风险尽量显性化。&lt;/p&gt;
&lt;h2 id="数据和上下文"&gt;数据和上下文
&lt;/h2&gt;&lt;p&gt;先确认模型能看到完成任务所需的信息：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据来源是否可靠&lt;/li&gt;
&lt;li&gt;上下文是否过长或过少&lt;/li&gt;
&lt;li&gt;用户隐私和敏感信息是否被保护&lt;/li&gt;
&lt;li&gt;引用或检索结果是否可追溯&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="评测和日志"&gt;评测和日志
&lt;/h2&gt;&lt;p&gt;至少准备一组代表性样例，覆盖正常输入、边界输入和失败输入。日志要能回答：用了什么提示词、传了什么上下文、模型返回了什么、最终是否被用户接受。&lt;/p&gt;
&lt;h2 id="失败兜底"&gt;失败兜底
&lt;/h2&gt;&lt;p&gt;AI 功能必须允许失败。失败时应该给出可理解的提示，必要时回退到人工处理、传统规则或安全默认值。&lt;/p&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;AI 工程化的重点不是让模型永远正确，而是让系统在模型不稳定时仍然可诊断、可回退、可持续改进。&lt;/p&gt;</description></item><item><title>提示词结构的最小模板</title><link>https://yun7211.github.io/ai/prompt-agents/prompt-structure/</link><pubDate>Mon, 18 May 2026 12:10:00 +0800</pubDate><guid>https://yun7211.github.io/ai/prompt-agents/prompt-structure/</guid><description>&lt;h2 id="为什么需要结构"&gt;为什么需要结构
&lt;/h2&gt;&lt;p&gt;提示词不是越长越好，而是越清楚越好。一个稳定的提示词应该让模型知道要完成什么、依据什么、不能做什么，以及结果如何判断。&lt;/p&gt;
&lt;h2 id="最小模板"&gt;最小模板
&lt;/h2&gt;&lt;p&gt;可以从这个结构开始：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;目标：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;上下文：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;输入：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;约束：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;输出格式：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;验收标准：
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果任务需要多轮完成，还可以补充“先做什么、后做什么、什么时候停下来问问题”。&lt;/p&gt;
&lt;h2 id="约束比鼓励更重要"&gt;约束比鼓励更重要
&lt;/h2&gt;&lt;p&gt;“请认真一点”这类表达很难约束行为。更有效的是明确边界，例如不要修改无关文件、必须引用来源、先运行测试、输出必须包含失败原因。&lt;/p&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;好的提示词像一份小型任务说明。它不替代判断，但能显著减少误解和返工。&lt;/p&gt;</description></item><item><title>AI 模型选择笔记</title><link>https://yun7211.github.io/ai/model-basics/model-selection-notes/</link><pubDate>Mon, 18 May 2026 12:00:00 +0800</pubDate><guid>https://yun7211.github.io/ai/model-basics/model-selection-notes/</guid><description>&lt;h2 id="不同任务需要不同模型"&gt;不同任务需要不同模型
&lt;/h2&gt;&lt;p&gt;选择 AI 模型时，不要只看模型名字或排行榜。真正重要的是任务需要什么能力：理解长上下文、写代码、总结资料、调用工具、推理规划，还是快速生成草稿。&lt;/p&gt;
&lt;p&gt;一个简单的判断方式是先区分任务类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;简单改写和摘要：优先速度和成本&lt;/li&gt;
&lt;li&gt;代码修改和调试：优先上下文理解和可靠性&lt;/li&gt;
&lt;li&gt;多步骤研究：优先推理能力和工具使用能力&lt;/li&gt;
&lt;li&gt;大量批处理：优先稳定性、成本和吞吐&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="看上下文而不是只看输入长度"&gt;看上下文而不是只看输入长度
&lt;/h2&gt;&lt;p&gt;上下文窗口越大，不代表效果一定越好。长上下文任务要关注模型能否抓住关键约束，以及是否会忽略早期信息。&lt;/p&gt;
&lt;p&gt;对于长文档或代码库，最好先组织结构化上下文，再让模型执行具体任务。&lt;/p&gt;
&lt;h2 id="评估要贴近真实任务"&gt;评估要贴近真实任务
&lt;/h2&gt;&lt;p&gt;模型选择应该用自己的任务做小型评估。比如博客写作可以比较标题、结构、事实准确性和可读性；代码任务可以比较测试通过率、改动范围和解释质量。&lt;/p&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;模型选择不是一次性决定。随着任务、成本和工具链变化，模型策略也应该定期复盘。&lt;/p&gt;</description></item><item><title>研究课题周复盘模板</title><link>https://yun7211.github.io/research/writing-review/research-weekly-review/</link><pubDate>Mon, 18 May 2026 11:50:00 +0800</pubDate><guid>https://yun7211.github.io/research/writing-review/research-weekly-review/</guid><description>&lt;h2 id="为什么做周复盘"&gt;为什么做周复盘
&lt;/h2&gt;&lt;p&gt;研究任务经常是开放问题，如果只记录最终结果，中间的判断依据很容易丢失。周复盘的目标是留下阶段证据，让下一周知道该继续、收缩还是换方向。&lt;/p&gt;
&lt;h2 id="推荐结构"&gt;推荐结构
&lt;/h2&gt;&lt;p&gt;可以固定写这几项：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;本周目标：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;完成进展：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;关键证据：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;遇到的问题：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;判断变化：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;下周计划：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;需要求助：
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个结构不复杂，但能覆盖研究推进最重要的信息。&lt;/p&gt;
&lt;h2 id="关键证据"&gt;关键证据
&lt;/h2&gt;&lt;p&gt;复盘里最值得保留的是证据，而不是情绪化结论。证据可以是实验结果、日志、图表、论文结论、对比数据或失败复现记录。&lt;/p&gt;
&lt;p&gt;如果某个判断改变了，要写清楚是哪个证据让判断改变。&lt;/p&gt;
&lt;h2 id="下周计划"&gt;下周计划
&lt;/h2&gt;&lt;p&gt;下周计划最好具体到可以执行：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;复现某篇论文的一个实验&lt;/li&gt;
&lt;li&gt;补齐一个数据处理脚本&lt;/li&gt;
&lt;li&gt;比较两个基线方法&lt;/li&gt;
&lt;li&gt;写完相关工作的一小节&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;周复盘不是额外负担，而是研究过程的导航。它能帮助我们避免在模糊问题里原地打转。&lt;/p&gt;</description></item><item><title>C 代码审查清单</title><link>https://yun7211.github.io/c-language/debug-quality/code-review-checklist/</link><pubDate>Mon, 18 May 2026 11:40:00 +0800</pubDate><guid>https://yun7211.github.io/c-language/debug-quality/code-review-checklist/</guid><description>&lt;h2 id="审查目标"&gt;审查目标
&lt;/h2&gt;&lt;p&gt;C 代码审查不是挑风格问题，而是提前发现运行时成本最高的问题：内存错误、资源泄漏、接口歧义、错误路径遗漏和不可测试的全局状态。&lt;/p&gt;
&lt;h2 id="接口语义"&gt;接口语义
&lt;/h2&gt;&lt;p&gt;先看函数接口是否清楚：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;参数能否为 &lt;code&gt;NULL&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;返回值如何表达错误&lt;/li&gt;
&lt;li&gt;调用方是否负责释放资源&lt;/li&gt;
&lt;li&gt;输出参数失败时是否有效&lt;/li&gt;
&lt;li&gt;函数是否修改传入缓冲区&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接口语义不清楚时，后续实现再漂亮也容易出问题。&lt;/p&gt;
&lt;h2 id="内存和边界"&gt;内存和边界
&lt;/h2&gt;&lt;p&gt;重点检查长度、容量和生命周期：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;字符串空间是否包含 &lt;code&gt;\0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;memcpy&lt;/code&gt;、&lt;code&gt;snprintf&lt;/code&gt;、数组下标是否有边界&lt;/li&gt;
&lt;li&gt;释放路径是否覆盖所有失败分支&lt;/li&gt;
&lt;li&gt;指针释放后是否还会被访问&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="错误路径"&gt;错误路径
&lt;/h2&gt;&lt;p&gt;C 项目里很多 bug 只在异常路径出现。审查时要刻意走失败分支：申请失败、文件打开失败、设备不存在、协议字段不合法、部分初始化后返回错误。&lt;/p&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;好的代码审查清单能把经验固化下来。每次发现新问题，都应该把它变成下一次能提前检查的条目。&lt;/p&gt;</description></item><item><title>Kernel panic 排查记录模板</title><link>https://yun7211.github.io/embedded-linux/debug-performance/kernel-panic-debugging/</link><pubDate>Mon, 18 May 2026 11:30:00 +0800</pubDate><guid>https://yun7211.github.io/embedded-linux/debug-performance/kernel-panic-debugging/</guid><description>&lt;h2 id="先保留现场"&gt;先保留现场
&lt;/h2&gt;&lt;p&gt;Kernel panic 出现时，第一件事不是立刻改代码，而是把现场保存下来。串口完整日志、内核版本、设备树版本、启动参数、复现步骤和最近改动都应该保留。&lt;/p&gt;
&lt;p&gt;最小记录清单：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;panic 完整日志&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bootargs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Kernel commit 或版本号&lt;/li&gt;
&lt;li&gt;DTB 来源&lt;/li&gt;
&lt;li&gt;根文件系统版本&lt;/li&gt;
&lt;li&gt;外设连接状态&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="看最后一个有效栈"&gt;看最后一个有效栈
&lt;/h2&gt;&lt;p&gt;panic 日志里最有价值的是调用栈和触发点。先找到 &lt;code&gt;Call trace&lt;/code&gt;，再判断是空指针、非法地址、BUG_ON、oops 还是 watchdog。&lt;/p&gt;
&lt;p&gt;如果地址已经符号化，可以直接看函数名；如果没有符号，需要保留未裁剪的 &lt;code&gt;vmlinux&lt;/code&gt;，配合 &lt;code&gt;addr2line&lt;/code&gt; 定位源码行。&lt;/p&gt;
&lt;h2 id="区分必现和偶现"&gt;区分必现和偶现
&lt;/h2&gt;&lt;p&gt;必现问题优先缩小配置和输入。偶现问题要关注并发、时序、内存越界、栈溢出和硬件状态。&lt;/p&gt;
&lt;p&gt;对于偶现问题，日志要尽量包含时间戳，并在关键路径加轻量日志，避免日志本身改变时序太多。&lt;/p&gt;
&lt;h2 id="复盘问题来源"&gt;复盘问题来源
&lt;/h2&gt;&lt;p&gt;定位后还要记录根因类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;设备树配置错误&lt;/li&gt;
&lt;li&gt;驱动资源申请失败后清理不完整&lt;/li&gt;
&lt;li&gt;中断上下文误用阻塞接口&lt;/li&gt;
&lt;li&gt;DMA buffer 或 cache 同步问题&lt;/li&gt;
&lt;li&gt;用户态输入触发内核边界缺陷&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;Kernel panic 排查的关键是保留证据、定位栈、区分复现类型，再把根因沉淀成可检查的清单。&lt;/p&gt;</description></item><item><title>实验记录应该写什么</title><link>https://yun7211.github.io/research/experiment-reproduction/experiment-log-template/</link><pubDate>Mon, 18 May 2026 11:20:00 +0800</pubDate><guid>https://yun7211.github.io/research/experiment-reproduction/experiment-log-template/</guid><description>&lt;h2 id="实验记录的价值"&gt;实验记录的价值
&lt;/h2&gt;&lt;p&gt;实验记录不是流水账，而是为了让未来的自己能够复现当时的判断。好的实验记录应该能回答：为什么做这个实验，怎么做的，结果是什么，是否支持原假设。&lt;/p&gt;
&lt;h2 id="推荐字段"&gt;推荐字段
&lt;/h2&gt;&lt;p&gt;可以固定记录这些字段：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;实验日期：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;实验目标：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;假设：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;环境：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;输入数据：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;操作步骤：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;关键参数：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;结果：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;异常：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;结论：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;下一步：
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;字段不一定每次都写满，但假设、环境、结果和结论最好保留。&lt;/p&gt;
&lt;h2 id="环境记录"&gt;环境记录
&lt;/h2&gt;&lt;p&gt;环境包括硬件、系统版本、依赖版本、编译参数和数据版本。很多复现失败不是方法错了，而是环境差异没有记录。&lt;/p&gt;
&lt;p&gt;嵌入式相关实验还要记录板卡型号、内核版本、设备树版本、启动参数和外设连接状态。&lt;/p&gt;
&lt;h2 id="异常也要记录"&gt;异常也要记录
&lt;/h2&gt;&lt;p&gt;失败实验同样有价值。异常日志、错误输入和失败条件能帮助排除路径，也能避免之后重复踩同一个问题。&lt;/p&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;实验记录的目标是支持复盘和复现。只要能让结论有证据、有上下文、有下一步，它就是有效记录。&lt;/p&gt;</description></item><item><title>论文阅读笔记模板</title><link>https://yun7211.github.io/research/topic-literature/literature-reading-notes/</link><pubDate>Mon, 18 May 2026 11:10:00 +0800</pubDate><guid>https://yun7211.github.io/research/topic-literature/literature-reading-notes/</guid><description>&lt;h2 id="为什么要固定模板"&gt;为什么要固定模板
&lt;/h2&gt;&lt;p&gt;论文读多以后，如果每篇只留下零散划线，很难回头比较。固定模板能帮助我们把论文放到同一张表里看：它解决什么问题，用什么方法，证据是否充分，能否复现。&lt;/p&gt;
&lt;h2 id="基本信息"&gt;基本信息
&lt;/h2&gt;&lt;p&gt;先记录最基础的信息：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;标题：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;作者：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;年份：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;会议/期刊：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;代码/数据：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;关键词：
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这些信息方便之后检索和引用。&lt;/p&gt;
&lt;h2 id="核心问题"&gt;核心问题
&lt;/h2&gt;&lt;p&gt;用自己的话写出论文试图解决的问题。不要直接复制摘要，而是回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;以前的方法哪里不够&lt;/li&gt;
&lt;li&gt;作者具体改进了什么&lt;/li&gt;
&lt;li&gt;这个问题为什么重要&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="方法和实验"&gt;方法和实验
&lt;/h2&gt;&lt;p&gt;方法部分记录主要流程、关键假设和实现细节。实验部分记录数据集、基线、指标和消融实验。&lt;/p&gt;
&lt;p&gt;如果论文有代码，最好记录运行环境、依赖版本和复现步骤。&lt;/p&gt;
&lt;h2 id="读后判断"&gt;读后判断
&lt;/h2&gt;&lt;p&gt;最后写一段自己的判断：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这篇论文最有价值的点是什么&lt;/li&gt;
&lt;li&gt;哪些结论还需要进一步验证&lt;/li&gt;
&lt;li&gt;对当前课题有什么启发&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;论文阅读不是把内容搬进笔记，而是把论文转化为自己的问题地图。模板的作用，是让每次阅读都有可比较的结构。&lt;/p&gt;</description></item><item><title>研究课题选题框架</title><link>https://yun7211.github.io/research/topic-literature/topic-selection-framework/</link><pubDate>Mon, 18 May 2026 11:00:00 +0800</pubDate><guid>https://yun7211.github.io/research/topic-literature/topic-selection-framework/</guid><description>&lt;h2 id="好课题的几个特征"&gt;好课题的几个特征
&lt;/h2&gt;&lt;p&gt;一个合适的研究课题不只是“有意思”，还需要能被验证、能在资源约束内推进，并且有清晰产出。&lt;/p&gt;
&lt;p&gt;可以从四个维度初筛：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;问题是否真实存在&lt;/li&gt;
&lt;li&gt;是否有明确评价指标&lt;/li&gt;
&lt;li&gt;当前资源能否支撑实验&lt;/li&gt;
&lt;li&gt;最终能形成什么产出&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="问题价值"&gt;问题价值
&lt;/h2&gt;&lt;p&gt;问题价值来自实际需求、理论缺口或工程瓶颈。选题时要能说清楚：如果这个问题被解决，会带来什么变化。&lt;/p&gt;
&lt;p&gt;如果只能说“这个方向很热门”，还不够。&lt;/p&gt;
&lt;h2 id="可验证性"&gt;可验证性
&lt;/h2&gt;&lt;p&gt;研究问题要能转化为可验证假设。例如“优化系统性能”太宽，可以进一步拆成“在给定负载下，降低任务切换带来的平均延迟”。&lt;/p&gt;
&lt;p&gt;可验证性越强，实验设计越容易落地。&lt;/p&gt;
&lt;h2 id="资源约束"&gt;资源约束
&lt;/h2&gt;&lt;p&gt;资源包括时间、设备、数据、算力、工具链和已有知识。一个好课题不是越大越好，而是能在当前条件下持续推进。&lt;/p&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;选题不是一次性决定，而是不断收缩问题边界。先找到真实问题，再把它改写成可验证、可推进、可复盘的计划。&lt;/p&gt;</description></item><item><title>C 内存问题排查清单</title><link>https://yun7211.github.io/c-language/debug-quality/debugging-memory-bugs/</link><pubDate>Mon, 18 May 2026 10:50:00 +0800</pubDate><guid>https://yun7211.github.io/c-language/debug-quality/debugging-memory-bugs/</guid><description>&lt;h2 id="常见现象"&gt;常见现象
&lt;/h2&gt;&lt;p&gt;C 内存问题经常表现得很绕：崩溃点不一定是出错点，今天能复现的问题明天可能消失，打开日志后问题也可能变化。&lt;/p&gt;
&lt;p&gt;常见类型包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数组或缓冲区越界&lt;/li&gt;
&lt;li&gt;使用已经释放的指针&lt;/li&gt;
&lt;li&gt;重复释放&lt;/li&gt;
&lt;li&gt;未初始化读取&lt;/li&gt;
&lt;li&gt;资源泄漏&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="先缩小范围"&gt;先缩小范围
&lt;/h2&gt;&lt;p&gt;不要一开始就盯着崩溃现场。先确认最近改动、输入数据规模、线程数量、编译优化级别和是否只在特定平台出现。&lt;/p&gt;
&lt;p&gt;如果问题能稳定复现，优先构造最小复现用例。&lt;/p&gt;
&lt;h2 id="检查边界"&gt;检查边界
&lt;/h2&gt;&lt;p&gt;内存越界通常和长度计算有关。重点检查：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缓冲区大小是否包含结尾 &lt;code&gt;\0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;memcpy&lt;/code&gt; 长度是否来自可信来源&lt;/li&gt;
&lt;li&gt;循环边界是否使用 &lt;code&gt;&amp;lt;&lt;/code&gt; 而不是误用 &lt;code&gt;&amp;lt;=&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;结构体长度和协议字段是否一致&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="检查生命周期"&gt;检查生命周期
&lt;/h2&gt;&lt;p&gt;悬空指针来自对象生命周期结束后继续访问。释放后可以把指针置为 &lt;code&gt;NULL&lt;/code&gt;，但这只能减少部分误用，不能替代清晰的所有权设计。&lt;/p&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;排查内存问题要有耐心，也要有方法。先稳定复现，再缩小范围，最后回到边界、生命周期和错误路径。&lt;/p&gt;</description></item><item><title>C 模块接口设计的几个原则</title><link>https://yun7211.github.io/c-language/module-interface/module-interface-design/</link><pubDate>Mon, 18 May 2026 10:40:00 +0800</pubDate><guid>https://yun7211.github.io/c-language/module-interface/module-interface-design/</guid><description>&lt;h2 id="模块边界"&gt;模块边界
&lt;/h2&gt;&lt;p&gt;C 项目变大以后，真正难维护的往往不是语法，而是模块边界。好的模块接口应该让调用方知道能做什么，不需要知道内部怎么做。&lt;/p&gt;
&lt;p&gt;常见做法是把结构体定义隐藏在 &lt;code&gt;.c&lt;/code&gt; 文件里，只在头文件暴露不透明类型。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;logger_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;logger_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;logger_write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;调用方不能直接访问内部字段，模块就有空间调整实现。&lt;/p&gt;
&lt;h2 id="资源成对管理"&gt;资源成对管理
&lt;/h2&gt;&lt;p&gt;创建和销毁函数要成对出现，命名保持一致。这样调用方一眼能看出资源生命周期。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;init/deinit
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;create/destroy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;open/close
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;alloc/free
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不要让调用方猜一个对象应该用 &lt;code&gt;free&lt;/code&gt;、&lt;code&gt;close&lt;/code&gt; 还是自定义函数释放。&lt;/p&gt;
&lt;h2 id="错误处理"&gt;错误处理
&lt;/h2&gt;&lt;p&gt;C 语言没有异常，接口必须明确错误返回。常见方式是返回 &lt;code&gt;0&lt;/code&gt; 表示成功，负数或非零表示错误。&lt;/p&gt;
&lt;p&gt;更重要的是：失败时资源状态要可预测。函数要么完全成功，要么保持原状态，不能留下半初始化对象。&lt;/p&gt;
&lt;h2 id="减少全局状态"&gt;减少全局状态
&lt;/h2&gt;&lt;p&gt;全局变量会让测试、并发和复用都变困难。能通过上下文对象传递的状态，就尽量放进上下文对象。&lt;/p&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;C 模块接口的目标是降低调用方心智负担。接口越稳定、语义越明确，后续维护成本越低。&lt;/p&gt;</description></item><item><title>C 语言指针与所有权笔记</title><link>https://yun7211.github.io/c-language/pointer-memory/pointer-and-ownership/</link><pubDate>Mon, 18 May 2026 10:30:00 +0800</pubDate><guid>https://yun7211.github.io/c-language/pointer-memory/pointer-and-ownership/</guid><description>&lt;h2 id="指针问题的本质"&gt;指针问题的本质
&lt;/h2&gt;&lt;p&gt;C 语言不会替我们记录对象归谁所有、什么时候释放、还能不能访问。很多指针 bug 表面是野指针、重复释放或内存泄漏，背后都是所有权边界不清楚。&lt;/p&gt;
&lt;p&gt;写 C 代码时，可以主动给指针加上三类语义：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;拥有：负责释放资源&lt;/li&gt;
&lt;li&gt;借用：只临时使用，不释放&lt;/li&gt;
&lt;li&gt;输出：函数负责写入结果&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="拥有型指针"&gt;拥有型指针
&lt;/h2&gt;&lt;p&gt;拥有型指针通常来自 &lt;code&gt;malloc&lt;/code&gt;、资源打开函数或创建函数。谁拥有它，谁就负责释放。&lt;/p&gt;
&lt;p&gt;命名上可以用 &lt;code&gt;create/free&lt;/code&gt;、&lt;code&gt;open/close&lt;/code&gt; 成对出现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;buffer_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;buffer_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种接口比让调用者猜释放方式更稳。&lt;/p&gt;
&lt;h2 id="借用型指针"&gt;借用型指针
&lt;/h2&gt;&lt;p&gt;借用型指针不应该被释放，也不应该长期保存到超过对象生命周期的地方。&lt;/p&gt;
&lt;p&gt;函数参数里常见的 &lt;code&gt;const char *name&lt;/code&gt; 多数是借用。加上 &lt;code&gt;const&lt;/code&gt; 能明确函数不会修改传入内容。&lt;/p&gt;
&lt;h2 id="输出参数"&gt;输出参数
&lt;/h2&gt;&lt;p&gt;C 语言里常用输出参数返回多个结果。输出参数要说明是否允许为 &lt;code&gt;NULL&lt;/code&gt;，以及失败时是否会被修改。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;sensor_read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sensor&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个接口至少需要约定：&lt;code&gt;dev&lt;/code&gt; 和 &lt;code&gt;value&lt;/code&gt; 是否能为空，返回非零时 &lt;code&gt;value&lt;/code&gt; 是否有效。&lt;/p&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;指针本身只是地址。真正决定代码可靠性的，是所有权、生命周期和错误路径是否写清楚。&lt;/p&gt;</description></item><item><title>根文件系统构建笔记</title><link>https://yun7211.github.io/embedded-linux/boot-system/rootfs-build-notes/</link><pubDate>Mon, 18 May 2026 10:20:00 +0800</pubDate><guid>https://yun7211.github.io/embedded-linux/boot-system/rootfs-build-notes/</guid><description>&lt;h2 id="根文件系统承担什么"&gt;根文件系统承担什么
&lt;/h2&gt;&lt;p&gt;Kernel 启动后需要挂载根文件系统，并运行第一个用户态进程。根文件系统里至少要有基础目录、初始化程序、命令工具、动态库、配置文件和设备节点。&lt;/p&gt;
&lt;p&gt;最小系统常见目录包括：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/bin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/sbin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/etc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/lib
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/dev
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/proc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/sys
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/tmp
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/var
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="init"&gt;init
&lt;/h2&gt;&lt;p&gt;Kernel 默认会尝试运行 &lt;code&gt;/sbin/init&lt;/code&gt;、&lt;code&gt;/etc/init&lt;/code&gt;、&lt;code&gt;/bin/init&lt;/code&gt; 或 &lt;code&gt;/bin/sh&lt;/code&gt;。如果这些路径都不存在，系统会 panic。&lt;/p&gt;
&lt;p&gt;调试时可以临时在 &lt;code&gt;bootargs&lt;/code&gt; 里指定：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;init=/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样能绕过复杂启动脚本，先确认根文件系统能否进入用户态。&lt;/p&gt;
&lt;h2 id="动态库"&gt;动态库
&lt;/h2&gt;&lt;p&gt;如果应用或 BusyBox 是动态链接，需要把对应 C 运行库和动态加载器放进根文件系统。缺库时，常见现象是文件明明存在，却提示 &lt;code&gt;not found&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;可以用交叉工具链的 &lt;code&gt;readelf&lt;/code&gt; 或 &lt;code&gt;ldd&lt;/code&gt; 替代方案检查依赖。&lt;/p&gt;
&lt;h2 id="虚拟文件系统"&gt;虚拟文件系统
&lt;/h2&gt;&lt;p&gt;启动脚本通常需要挂载：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mount -t proc proc /proc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mount -t sysfs sysfs /sys
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mount -t devtmpfs devtmpfs /dev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;缺少这些挂载会影响进程信息、设备节点和驱动状态查看。&lt;/p&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;根文件系统问题要从两个角度看：Kernel 是否成功挂载它，用户态程序是否能在里面正常运行。先确认最小 shell 可用，再逐步恢复完整启动脚本。&lt;/p&gt;</description></item><item><title>设备树调试的几个检查点</title><link>https://yun7211.github.io/embedded-linux/drivers-dts/device-tree-debugging/</link><pubDate>Mon, 18 May 2026 10:10:00 +0800</pubDate><guid>https://yun7211.github.io/embedded-linux/drivers-dts/device-tree-debugging/</guid><description>&lt;h2 id="为什么设备树容易出问题"&gt;为什么设备树容易出问题
&lt;/h2&gt;&lt;p&gt;设备树描述硬件，但它本身不会证明硬件真的可用。一个节点看起来完整，也可能因为地址、时钟、中断、复位或引脚复用配置错误而导致驱动 probe 失败。&lt;/p&gt;
&lt;p&gt;调试设备树时，可以先围绕几个高频字段检查。&lt;/p&gt;
&lt;h2 id="compatible"&gt;compatible
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;compatible&lt;/code&gt; 决定设备节点能否匹配到驱动。驱动侧通常通过 &lt;code&gt;of_device_id&lt;/code&gt; 表匹配字符串。&lt;/p&gt;
&lt;p&gt;如果驱动没有 probe，先检查：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;字符串是否拼写一致&lt;/li&gt;
&lt;li&gt;驱动是否编进内核或模块已加载&lt;/li&gt;
&lt;li&gt;节点 &lt;code&gt;status&lt;/code&gt; 是否为 &lt;code&gt;okay&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="reg-和-ranges"&gt;reg 和 ranges
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;reg&lt;/code&gt; 描述寄存器地址和长度。地址单元数量受父节点的 &lt;code&gt;#address-cells&lt;/code&gt; 和 &lt;code&gt;#size-cells&lt;/code&gt; 影响。&lt;/p&gt;
&lt;p&gt;如果寄存器读写异常，要确认物理地址、长度和父总线地址映射是否正确。&lt;/p&gt;
&lt;h2 id="pinctrlclock-和-reset"&gt;pinctrl、clock 和 reset
&lt;/h2&gt;&lt;p&gt;很多外设 probe 成功但不能工作，问题往往在 pinctrl、clock 或 reset。&lt;/p&gt;
&lt;p&gt;常见检查项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;引脚复用是否切到外设功能&lt;/li&gt;
&lt;li&gt;上拉、下拉、驱动能力是否符合硬件&lt;/li&gt;
&lt;li&gt;时钟是否被正确打开&lt;/li&gt;
&lt;li&gt;reset 是否释放&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="interrupt"&gt;interrupt
&lt;/h2&gt;&lt;p&gt;中断问题通常表现为驱动正常加载，但事件没有响应。需要确认中断号、触发方式和中断控制器引用是否正确。&lt;/p&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;设备树调试要同时看 DTS、驱动匹配表、内核日志和硬件原理图。只看一个文件很容易误判。&lt;/p&gt;</description></item><item><title>嵌入式 Linux 启动流程速记</title><link>https://yun7211.github.io/embedded-linux/boot-system/linux-boot-flow/</link><pubDate>Mon, 18 May 2026 10:00:00 +0800</pubDate><guid>https://yun7211.github.io/embedded-linux/boot-system/linux-boot-flow/</guid><description>&lt;h2 id="启动主线"&gt;启动主线
&lt;/h2&gt;&lt;p&gt;嵌入式 Linux 的启动过程可以先抓住一条主线：硬件上电后，Boot ROM 找到第一阶段启动程序，随后加载 U-Boot，再由 U-Boot 加载 Linux Kernel、设备树和根文件系统。&lt;/p&gt;
&lt;p&gt;完整路径通常是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Power On -&amp;gt; Boot ROM -&amp;gt; SPL/TPL -&amp;gt; U-Boot -&amp;gt; Kernel -&amp;gt; init -&amp;gt; user space
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不同芯片的细节会变化，但定位问题时先把当前卡在哪一段确认清楚，排查效率会高很多。&lt;/p&gt;
&lt;h2 id="boot-rom"&gt;Boot ROM
&lt;/h2&gt;&lt;p&gt;Boot ROM 是芯片内部固化代码，负责根据启动引脚或熔丝配置选择启动介质，例如 eMMC、SD 卡、SPI NOR、NAND 或 USB 下载模式。&lt;/p&gt;
&lt;p&gt;这一阶段常见问题包括启动介质不可读、镜像偏移不对、签名校验失败、供电和时钟没有满足芯片要求。&lt;/p&gt;
&lt;h2 id="u-boot"&gt;U-Boot
&lt;/h2&gt;&lt;p&gt;U-Boot 负责初始化更多硬件，并准备 Kernel 运行环境。常见动作包括初始化 DRAM、加载镜像、传递启动参数、加载设备树和设置 &lt;code&gt;bootargs&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;调试时优先确认：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;串口是否有输出&lt;/li&gt;
&lt;li&gt;DRAM 大小是否识别正确&lt;/li&gt;
&lt;li&gt;Kernel、DTB、rootfs 地址是否正确&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bootcmd&lt;/code&gt; 和 &lt;code&gt;bootargs&lt;/code&gt; 是否符合当前启动介质&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="kernel"&gt;Kernel
&lt;/h2&gt;&lt;p&gt;Kernel 接管后会解压、初始化内核子系统、解析设备树、挂载根文件系统并启动第一个用户态进程。&lt;/p&gt;
&lt;p&gt;如果 Kernel 已经打印日志但最终 panic，重点看 panic 前的最后几行。根文件系统挂载失败时，常见原因是驱动缺失、设备节点不匹配、文件系统类型不支持或 &lt;code&gt;root=&lt;/code&gt; 参数错误。&lt;/p&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;启动问题不要一开始就陷入全部日志。先判断卡在 Boot ROM、U-Boot、Kernel 还是用户态，再按阶段收集证据，问题会清楚很多。&lt;/p&gt;</description></item><item><title>GitHub Pages 部署前检查清单</title><link>https://yun7211.github.io/posts/github-pages-deploy-checklist/</link><pubDate>Mon, 18 May 2026 09:20:00 +0800</pubDate><guid>https://yun7211.github.io/posts/github-pages-deploy-checklist/</guid><description>&lt;h2 id="配置检查"&gt;配置检查
&lt;/h2&gt;&lt;p&gt;部署前先确认 &lt;code&gt;hugo.toml&lt;/code&gt; 中的站点地址、语言、标题和分页配置。&lt;code&gt;baseURL&lt;/code&gt; 会影响线上资源路径，尤其是样式和图片。&lt;/p&gt;
&lt;p&gt;如果使用 GitHub Pages 的用户站点，常见地址是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;baseURL&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://username.github.io/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果使用项目站点，则通常需要带上仓库名。&lt;/p&gt;
&lt;h2 id="内容检查"&gt;内容检查
&lt;/h2&gt;&lt;p&gt;发布前至少检查这些内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首页能说明博客主题&lt;/li&gt;
&lt;li&gt;About 页面不是空白&lt;/li&gt;
&lt;li&gt;至少有几篇正式文章&lt;/li&gt;
&lt;li&gt;文章 &lt;code&gt;draft = false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;日期不是未来时间&lt;/li&gt;
&lt;li&gt;图片路径大小写一致&lt;/li&gt;
&lt;li&gt;没有提交私钥、邮箱明文或私人照片&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="actions-检查"&gt;Actions 检查
&lt;/h2&gt;&lt;p&gt;GitHub 仓库的 Pages Source 需要选择 GitHub Actions。工作流构建时要安装 Hugo Extended，并上传 &lt;code&gt;public&lt;/code&gt; 目录作为 Pages artifact。&lt;/p&gt;
&lt;p&gt;常用构建命令是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo --gc --minify
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;部署问题通常不是 Hugo 本身复杂，而是路径、草稿状态、Actions 权限和 Pages 设置容易漏。上线前做一次清单检查，可以省掉很多排查时间。&lt;/p&gt;</description></item><item><title>一套简单的 Markdown 写作流程</title><link>https://yun7211.github.io/posts/markdown-writing-workflow/</link><pubDate>Mon, 18 May 2026 09:10:00 +0800</pubDate><guid>https://yun7211.github.io/posts/markdown-writing-workflow/</guid><description>&lt;h2 id="为什么需要流程"&gt;为什么需要流程
&lt;/h2&gt;&lt;p&gt;技术文章很容易变成命令堆砌。写之前先想清楚读者、问题和结果，文章会更容易读，也更方便未来的自己回看。&lt;/p&gt;
&lt;h2 id="五步写作法"&gt;五步写作法
&lt;/h2&gt;&lt;p&gt;第一步是选题。选题可以来自今天解决的问题、刚学会的工具、项目里的坑，或者一段值得保留的思考。&lt;/p&gt;
&lt;p&gt;第二步是列提纲。提纲不需要复杂，只要回答三个问题：背景是什么，问题是什么，最后得到什么结果。&lt;/p&gt;
&lt;p&gt;第三步是写初稿。初稿阶段先追求完整，不急着打磨句子。&lt;/p&gt;
&lt;p&gt;第四步是本地预览。Hugo 的本地预览可以及时发现标题层级、代码块、图片路径和链接问题。&lt;/p&gt;
&lt;p&gt;第五步是校对和发布。发布前检查草稿状态、日期、标签、图片、链接和隐私信息。&lt;/p&gt;
&lt;h2 id="文章模板"&gt;文章模板
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-md" data-lang="md"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## 背景
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## 问题
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## 过程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## 结果
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## 总结
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个模板很朴素，但足够覆盖大多数学习笔记和项目复盘。&lt;/p&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;写作流程的价值不是限制表达，而是减少启动成本。每次都从同一套结构开始，长期会更容易坚持。&lt;/p&gt;</description></item><item><title>用 Hugo 搭建个人博客的第一步</title><link>https://yun7211.github.io/posts/hugo-blog-setup/</link><pubDate>Mon, 18 May 2026 09:00:00 +0800</pubDate><guid>https://yun7211.github.io/posts/hugo-blog-setup/</guid><description>&lt;h2 id="背景"&gt;背景
&lt;/h2&gt;&lt;p&gt;我希望博客能长期维护，文章源文件可以直接用 Git 管理，部署流程尽量简单，所以选择了 Hugo、Markdown 和 GitHub Pages。&lt;/p&gt;
&lt;p&gt;这一套方案的核心好处是：文章就是普通 Markdown 文件，构建结果是静态页面，不依赖数据库，也方便以后迁移。&lt;/p&gt;
&lt;h2 id="第一版目标"&gt;第一版目标
&lt;/h2&gt;&lt;p&gt;第一版不追求复杂功能，先完成几个基础能力：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可以本地预览文章&lt;/li&gt;
&lt;li&gt;可以用 Markdown 写作&lt;/li&gt;
&lt;li&gt;有首页、文章列表、关于页和项目页&lt;/li&gt;
&lt;li&gt;推送到 GitHub 后能自动部署&lt;/li&gt;
&lt;li&gt;站点结构清晰，后续容易扩展&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="项目结构"&gt;项目结构
&lt;/h2&gt;&lt;p&gt;当前项目采用 Hugo 标准结构：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;content/ # 页面和文章
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;layouts/ # 自定义模板
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;assets/ # Hugo 处理的 CSS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;static/ # 原样复制的图片和图标
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;没有引入外部主题，主要是为了减少初始依赖。等站点稳定后，再决定是否接入主题或继续维护自定义模板。&lt;/p&gt;
&lt;h2 id="发布流程"&gt;发布流程
&lt;/h2&gt;&lt;p&gt;写文章时先使用草稿状态：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo new content posts/my-new-post.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo server -D
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;确认内容、图片、链接和排版都没问题后，再把 &lt;code&gt;draft&lt;/code&gt; 改为 &lt;code&gt;false&lt;/code&gt;，提交并推送到 GitHub。&lt;/p&gt;
&lt;h2 id="小结"&gt;小结
&lt;/h2&gt;&lt;p&gt;个人博客最重要的不是功能复杂，而是能稳定写、稳定发布、稳定维护。先让系统跑起来，再逐步加入搜索、评论、统计和自定义域名。&lt;/p&gt;</description></item></channel></rss>