[BPF] 第001篇 使用 eBPF 监控 Linux 内核内存分配 2月前 评论
[BPF] 第001篇 使用 eBPF 监控 Linux 内核内存分配

深入探索eBPF技术,该方案通过非侵入式方式在Linux内核中高效运行自定义字节码,实现对kmalloc内存分配的实时监控,兼具安全性和灵活性。文章详细展示了内核态插桩与用户态应用的协同原理与代码实践,支持多维过滤和实用输出,适合于系统性能分析及生产环境部署,为内核行为追踪和资源优化提供了极具价值的案例

[灵感风暴] Charger Property Engine 设计方案 2月前 评论
[灵感风暴] Charger Property Engine 设计方案

聚焦智能设备BMS中I2C通信瓶颈,提出结合属性缓存与自适应刷新机制的创新方案,通过缓存属性并动态调整TTL,有效减少I2C访问冲突和通信负担。自适应算法根据属性变化及噪声门限、窗口振幅智能控制刷新频率,提升系统实时性与稳定性,同时引入并发控制与总线熔断机制,确保关键数据高效、安全传输。

站在2025的尾巴上:回顾、感恩与前行 2月前 6 条
站在2025的尾巴上:回顾、感恩与前行

2025年,作者在人生与职业的双重转折中,聚焦于“尝试平衡”。工作上勇于转型,持续分享与协作,实现技术与心态的成长;生活中,婚姻和家庭成为新的关注重心。通过经验总结、系统学习和乐于成就他人,收获个人成长,体会到快速学习和适应变化是核心能力,并在自我反思中展望未来。

站在2025的尾巴上:回顾、感恩与前行
查看完整文章 评论
AI智能摘要
2025年,作者在人生与职业的双重转折中,聚焦于“尝试平衡”。工作上勇于转型,持续分享与协作,实现技术与心态的成长;生活中,婚姻和家庭成为新的关注重心。通过经验总结、系统学习和乐于成就他人,收获个人成长,体会到快速学习和适应变化是核心能力,并在自我反思中展望未来。
此摘要由AI分析文章内容生成,仅供参考。

前言

时间悄然行至2025的尾声,现在是12月的中旬,提笔写下这篇总结的时候,窗外的银杏叶已经落得差不多了。每当这个时候,我总习惯性地回望,试图从三百多个日夜的碎片中,拼凑出自己这一年的模样。

而今年的我,轮廓似乎有些改变。过往的岁月里,“工作”是当仁不让的主旋律,生活的其他部分则成了若有若无的和声。但这个节奏,在2024年我步入婚姻后,被悄然改写了。2025年,像是我和妻子为“家庭”这个新项目共同撰写的商业计划书的第一章。我们开始探讨资源(时间与精力)的分配,优化协作流程,并共同期待它的长期价值。2025年对我来说,关键词是“平衡”,更准确的说是“尝试平衡

站在年尾回望,是为了更好地出发。谨以此文,记录这一年的得失与感悟,也写下对未来的期待。

工作 | 岁月为证,山海同程

六年前初入公司时,我还是个对行业一无所知的新人。这一路上,是公司提供了成长的平台,是同事们不吝赐教、倾囊相授,让我在温暖包容的氛围里不断学习、持续成长。每段挑战都化作养分,每次困惑都有双手相助——这份知遇之恩,我始终铭记于心。

我也想郑重地感谢那个始终没有停下脚步的自己。感谢你在每个想要放弃的时刻选择坚持,在迷茫中依然保持学习的热情,在困难面前始终挺直脊梁。

今年,我职业发展的一个核心变化,是岗位从“短距离工程师”正式转型为“稳定性工程师”。虽然此前对新领域有所接触,但真正完成角色转变的这一年,无疑是我专业技能迭代最快、认知提升最显著的阶段。

既然选择了这条路,就应该风雨兼程

母亲从小教导我:“要么不做,要做就做到最好。”这句话,我一直奉为圭臬。

在公司负责稳定性模块以来,我成长迅速,如今已能独当一面,甚至被一些同事称为“大神”。起初,这个称呼让我开心,觉得是一种认可;但如今,我更愿意把它看作一种鞭策,一种持续前行的责任。

为什么?

因为既为“大神”,你就必须持续学习、不断精进,要能为大家提供真正有效的解决方案——说实话,这其实挺累的。但这份压力,也恰恰是推动我不断向前的动力。

2017年大学毕业,工作八年,我从职场小白一路走来,深知初入行时的困惑与渴望。也因此,我一直坚信:技术应当被分享。这正是我创建博客的初衷——把我掌握的知识点,分享给需要的人。很高兴看到很多人从中获益,我也期待这里能成为一个畅所欲言、互相启发、共同进步的平台。

当然,也有人问我:“你把东西都教给别人,不怕被同事超越、甚至抢了饭碗吗?”

对此,我的回答是:

我愿意给你成长的时间。若你能追上我,我欣然同行,前路正好缺一位道友;若你未能跟上,我也将继续前行,奔赴下一片开阔之地。

2025/12/halo_l9gxlbs.png

还有一个很重要的点就是,我是非常不喜欢做重复的工作的!一个难题在第一次解决是非常开心的,但是第二次第三次再遇到类似的问题就会很没有意思!如果我将这个教给我的同事,那这类问题后面就不再需要我来处理了!这样实在是太爽了!我就有更多的时间去研究我感兴趣的领域。


然后说说同事吧,在公司里,尤其像我们这个行业,离职率一直挺高的,我以为我已经看淡了,也不会有什么波动。但是吧,今年我有两个同事的离职了,我感觉挺难受的,分别是我的徒弟LSJ以及ZSL两人。

我的徒弟LSJ,为人谦和,工作努力,脸上总挂着笑容,脾气更是出了名的好。为什么我特别想提这一点?因为在教他短距离知识时,有些难点我需要反复讲解好几遍。说实话,这个过程偶尔也会让我失去耐心,语气不自觉重了些。但他从不生气,始终虚心接受,继续埋头学习。他的成长不算快,但每一步都走得扎实、稳健,很快就能独当一面。看着他逐渐成熟,我由衷地为他高兴。后来,他因家庭原因离开上海,回到了家乡。虽有不舍,但更愿祝他前路顺遂,一切都好。

回首这段师徒经历,他让我看到,何尝不是一场对我的修炼。教我收敛脾气,静心沉淀的,正是这个谦和的年轻人

说到另一位离职的同事 ZSL,他留给我最深的印象,是那种对知识深度近乎执着的追求,以及解决问题的雷厉风行。我们过去经常一起钻研问题,从具体难点延伸到系统原理,从偶然的灵感火花展开深度探究。我很清楚,那段与他并肩思考、相互激荡的时光,对我个人能力的成长起到了关键作用。

虽然他离职后,我们仍会偶尔联系,但已经很难再像从前那样,就一个问题进行长时间、无保留的深度探讨——毕竟不在同一环境,总会涉及一些信息边界。但无论如何,在我心里,他始终是我技术路上真正的同行者与道友

成长 | 步履不息,身如山海

2025年,我继续在个人成长的路径上深耕。为提升专业深度,我系统学习了Android稳定性模块,并将心得整理为【Android稳定性】系列文章持续更新。目前已经整理输出的这60篇笔记,既是我的学习足迹,也希望能为初涉此领域的同仁点亮一盏微光。

另一条学习主线是Linux内存管理。我研读了网络上众多技术大神的精华文章,但深感其内容分散,缺乏体系。因此,我萌生了一个想法:亲自整理一套系统化的学习路径,帮助新人更顺畅地入门。这个系列写得虽慢,但我会持之以恒,也期待能与大家在交流中碰撞出更多火花。

回望这一年,技术提升固然可喜,但更大的收获在于思维方式的转变:我开始系统性地思考“如何快速学习”

我愈发深刻地认识到:

快速学习的能力,是比掌握任何具体技术都更值得培养的元能力

“有没有能力快速理解它、上手它、找到它的边界”,我认为这是一种比掌握具体技术更本质的能力。

之所以需要这种能力,根源在于我们身处的环境。对我们大多数人而言,工作除了实现个人价值,更现实的是养家糊口。而在公司层面,一个能在不同岗位间灵活切换、哪里需要就能顶上的“多面手”,往往更具适应性。这并非否定深耕单一领域的价值——每个人都有权选择自己的职业路径——只是描述一种普遍存在的现实。

以我自身为例:我的职业生涯并非一条直线。我做过短距离通信工程师、SCM(软件配置管理)、自动化脚本开发,再到如今的稳定性模块,而老板下一步已计划让我切入Charger模块。每一次这样的转向,现实都不会给予你充足的学习时间,它要求你必须在短时间内快速适应并产出价值。

因此,“如何快速学习”不再是一个可选课题,而是我们在多变环境中立足、乃至脱颖而出的核心生存技能。

目前,我也已开始着手学习Charger模块,并同步整理其系统性的学习路线图。于我而言,绘制这样一张导航图的过程,本身就是“快速学习”核心思维的实践——它强迫你构建知识骨架、分清主次、预见瓶颈。这正是将陌生领域“快速理解、上手并摸清边界”的最佳演练。

我计划未来为此单独开设一个专题,将这份路线图与学习心得沉淀为系列文章。因为我知道,一份清晰的路径,对于每一位初涉此地的同行者而言,该是何等珍贵。

健康 | 山海行稳,身心为帆

从我去年结婚后,我和我的妻子的体重就开始持续飙升,才1年时间我竟然胖了30斤。而减肥的口号一直在我们的嘴里喊出,间歇性的健身也一直在欺骗自己,没有一直坚持下去!

坦白说,过去一年里,我绝大多数时间都与运动无缘,加之长期熬夜,身体已频频发出警示。正是这种真切的危机感,促使我在今年的公司体检中,自费做了一次全面的深度检查。

真的是一胖,什么病都来了,甘油三酯是正常值的四五倍!!!再加上谷氨酰转移酶也是正常值的三倍,我估计是我长期的熬夜(几乎大部分时间都在凌晨2点才入睡)导致的。

减肥/早点睡应该要提上日程了!!!

不过,今年在健康上并非没有建树——一个重要的转变是,我终于成功把烟戒了。至今已坚持两三个月,期间并无不适,我想,这次应该算是真正告别了它。

前路漫漫,健康的身体是唯一的舟楫。新的一年,我的重心必将切实地移至此间,为自己,也为所有牵挂。言出必行!

家庭 | 烟火岁月,长情相伴

说到我的妻子X,。

我的妻子X是个很务实的人,但是容易陷入焦虑。她常常为一些发生概率极低、甚至尚未发生的事反复担忧。尽管我多次从逻辑上分析,试图宽慰,但她内心的不安依然存在。坦白说,这一点我至今仍不完全理解。

去年十月,我们结婚了。今年是婚姻的第一年,也正如大多数新婚夫妻一样,我们在共同经营中不断磨合。很多观念与习惯,都需要慢慢协调。记得有一次,我们为了“要不要把热菜放凉再放进冰箱”争执不休。我认为无需多此一举,她却坚持热菜直接进冰箱会对菜和冰箱都不好。结果如今已不重要,但现在回想起来,只觉得挺好笑的。

诸如此类的小摩擦一直没断过,但我却觉得这样挺好——至少如今回忆时,我是嘴角含笑的

一个对的人是至关重要的,但同样重要的是,自己也要成为一个对的人。想找到自己要找的人,自己必然要先成为这种人

我们一路跌跌撞撞,却也一路向前。今年最值得欣慰的进步是,我们渐渐学会在争吵后冷静下来,尝试站在对方的立场去思考,而不是像从前那样陷入持久的冷战。

说到我的父亲母亲

我的母亲今年又胖了些。我知道,过去她一直为我的婚事悬着心,如今见我成家,心头大事落地,人也跟着松弛丰润起来。欣喜之余,我却有些隐隐的担忧——她常年患有高血压,需坚持服药,长胖恐怕会增加身体的负担。真愿她能一直健康安好。

每次打电话回家,她总说:“家里一切都好,别惦记。你在外面好好吃饭,和X好好过日子“。我母亲习惯了报喜不报忧,什么事都自己默默扛下。我和妻子长年在外工作,许多牵挂与照应,总是迟了一步。来年,我一定要多开车回去几趟,看看她,也再尝尝她亲手做的饭菜——那味道,是出门在外时,心头最深的念想。

不知道从什么时候起,我父亲头上的白发越来越多了,上一次微信视频时,我竟然发现头发已经近乎花白,那片刺眼的灰白让我怔住。当时挂断后,心绪仍久久难以平复。我高中时总是不听话,在学校里打架斗殴,桀骜不驯,在家里也总是和父亲对着干。而如今父亲早已经没有当初那个精力了,可是我却想起了小时候他之前打我的样子,我多想时光停留在那个节点,但是他好像老了,他也再打不动我了。。。唉

展望 | 奔赴新程,山海可期

再新的一年的目标:

  1. 健康:要坚持健身,要早点睡觉,这是未来一年的首要目标

  2. 个人成长:深入学习charger模块以及继续Android稳定性和Linux内存管理系列文章的更新

  3. 父母:能够多多回家陪陪父母,多尝尝父母做的饭,多陪父母说说话。

  4. 兴趣爱好:多出门走一走,看看这个世界,用相机记录一些世间的美好。

  5. 经济:努力挣钱,让妻子,让父母过的更好一点。

[linux内存管理] 第034篇 slab内存分配器之kmalloc全面详解 2月前 1 条
[linux内存管理] 第034篇 slab内存分配器之kmalloc全面详解

深入解析Linux内核中kmalloc的内存池体系,详解其在高效分配小至中等连续物理内存块中的核心作用。文章重点说明kmalloc通过预先创建多种尺寸的slab内存池,有效应对频繁的通用及专属内存分配需求,并结合源码分析创建流程、类型划分及对应场景,帮助开发者理解内核内存分配机制的高效性与灵活性。

[linux内存管理] 第031篇 内核启动早期的slab分配器的自举 2月前 5 条
[linux内存管理] 第031篇 内核启动早期的slab分配器的自举

梳理Linux内核启动早期内存管理的四个阶段,文章深入分析了slab分配器自举的“鸡生蛋”难题:分配器本身依赖尚未初始化的自身结构体。详细解读slab分配器如何通过静态变量及多层自举逻辑,巧妙解决这一循环依赖困境,进而实现对象级缓存的高效分配与初始化,为内核后续稳定运行打下坚实基础。

[Android稳定性] 第059篇 [问题篇] 内核内存区域重叠导致的页表映射错误 4月前 3 条
[Android稳定性] 第059篇 [问题篇] 内核内存区域重叠导致的页表映射错误

基线升级后引入高通baseline代码导致设备在重启时死机,问题定位至内核mtdoops_do_dump模块。通过dmesg日志和trace32调试发现,关键内存地址pte为空,导致系统在访问p_hdr结构时出现页表异常。分析详细还原故障场景,为后续修复提供技术依据,展示了系统性排查和调试过程的专业

[Android稳定性] 第059篇 [问题篇] 内核内存区域重叠导致的页表映射错误
查看完整文章 评论
AI智能摘要
基线升级后引入高通baseline代码导致设备在重启时死机,问题定位至内核mtdoops_do_dump模块。通过dmesg日志和trace32调试发现,关键内存地址pte为空,导致系统在访问p_hdr结构时出现页表异常。分析详细还原故障场景,为后续修复提供技术依据,展示了系统性排查和调试过程的专业
此摘要由AI分析文章内容生成,仅供参考。

问题背景

  1. 在一次基线升级后(引入高通baseline的代码),开机重启会进入死机模式

  2. 基线升级前的软件没有问题

问题分析

dmesg日志分析

[  397.719194][    T1] mtdoops: mtdoops_do_dump start , count = 279 , page = 6, reason = 5, dump_count = 1
[  397.733201][    T1] mtdoops: mtdoops_do_dump pmsg paddr = 0x000000000677a9c7 
[  397.733228][    T1] Unable to handle kernel paging request at virtual address ffffff8000e00000
[  397.733234][    T1] Mem abort info:
[  397.733240][    T1]   ESR = 0x0000000096000007
[  397.733246][    T1]   EC = 0x25: DABT (current EL), IL = 32 bits
[  397.733253][    T1]   SET = 0, FnV = 0
[  397.733260][    T1]   EA = 0, S1PTW = 0
[  397.733265][    T1]   FSC = 0x07: level 3 translation fault
[  397.733271][    T1] Data abort info:
[  397.733276][    T1]   ISV = 0, ISS = 0x00000007, ISS2 = 0x00000000
[  397.733283][    T1]   CM = 0, WnR = 0, TnD = 0, TagAccess = 0
[  397.733289][    T1]   GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[  397.733295][    T1] swapper pgtable: 4k pages, 39-bit VAs, pgdp=00000000a9c9f000
[  397.733302][    T1] [ffffff8000e00000] pgd=180000097ff78003, p4d=180000097ff78003, pud=180000097ff78003, pmd=180000097ff73003, pte=0000000000000000
[  397.733323][    T1] Internal error: Oops: 0000000096000007 [#1] PREEMPT SMP
[  397.734277][    T1] Hardware name: Qualcomm Technologies, Inc. Kunzite QRD (DT)
[  397.734283][    T1] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[  397.734291][    T1] pc : mtdoops_do_dump+0x1a0/0x2cc [mtdoops]
[  397.734323][    T1] lr : mtdoops_do_dump+0x1a0/0x2cc [mtdoops]
[  397.734351][    T1] sp : ffffffc0823abba0
[  397.734358][    T1] x29: ffffffc0823abbc0 x28: ffffff883b9c8000 x27: ffffff879a608c20
[  397.734370][    T1] x26: ffffffc082262000 x25: ffffff883b9c8000 x24: ffffffc0820bae18
[  397.734382][    T1] x23: ffffffc07c898000 x22: 0000000000000001 x21: ffffffc0823abcd8
[  397.734393][    T1] x20: ffffffc07c8981a8 x19: ffffff8000e00000 x18: ffffffc082389058
[  397.734404][    T1] x17: 0000000000000001 x16: ffffffffffffffff x15: 0000000000000004
[  397.734415][    T1] x14: ffffff88f5300000 x13: 0000000000000003 x12: 0000000000000003
[  397.734426][    T1] x11: 00000000fffeffff x10: c0000000fffeffff x9 : c92068df22ab7800
[  397.734438][    T1] x8 : c92068df22ab7800 x7 : 205b5d3130323333 x6 : 372e37393320205b
[  397.734449][    T1] x5 : ffffffc0822e579f x4 : ffffffc081580cfc x3 : 0000000000000000
[  397.734460][    T1] x2 : 0000000000000000 x1 : ffffffc0823ab950 x0 : 0000000000000039
[  397.734471][    T1] Call trace:
[  397.734478][    T1]  mtdoops_do_dump+0x1a0/0x2cc [mtdoops 0e68315fd17942ad7985f5125ce422a1f47288bf]
[  397.734517][    T1]  mtdoops_reboot_nb_handle+0x2c/0x40 [mtdoops 0e68315fd17942ad7985f5125ce422a1f47288bf]
[  397.734534][    T1]  notifier_call_chain+0x90/0x174
[  397.734549][    T1]  blocking_notifier_call_chain+0x48/0x78
[  397.734559][    T1]  kernel_restart+0x28/0x114
[  397.734570][    T1]  __arm64_sys_reboot+0x1b0/0x288
[  397.734580][    T1]  invoke_syscall+0x58/0x114
[  397.734593][    T1]  el0_svc_common+0xac/0xe0
[  397.734603][    T1]  do_el0_svc+0x1c/0x28
[  397.734613][    T1]  el0_svc+0x38/0x68
[  397.734625][    T1]  el0t_64_sync_handler+0x68/0xbc
[  397.734635][    T1]  el0t_64_sync+0x1a8/0x1ac
[  397.734645][    T1] Code: cb080128 b2596113 aa1303e1 951e72aa (b9400261) 
[  397.734652][    T1] ---[ end trace 0000000000000000 ]---

我们可以确定的是代码死在了mtdoops_do_dump+0x1a0

trace32恢复现场

PC位于B9400261处,这儿的ldr w1,[x19]

这里的x19也就是p_hdr的地址

而这个地址从dmesg中可以看到pte为空

[  397.733302][    T1] [ffffff8000e00000] pgd=180000097ff78003, p4d=180000097ff78003, pud=180000097ff78003, pmd=180000097ff73003, pte=0000000000000000

级别

状态

说明

PGD

180000097ff78003

✅ 有效

页全局目录项有效

P4D

180000097ff78003

✅ 有效

四级目录项有效

PUD

180000097ff78003

✅ 有效

页上层目录项有效

PMD

180000097ff73003

✅ 有效

页中间目录项有效

PTE

0000000000000000

无效

页表项为空

在ARM64页表机制中:

  • PTE为0表示该页表项为空

  • 没有建立虚拟地址到物理地址的映射

这点也可以用trace32查询该地址得到:

代码追踪

我们需要得到p_hdr的由来,查看他是否经过了映射!

static void mtdoops_do_dump(struct kmsg_dumper *dumper,
			    enum mtd_dump_reason reason)
{
//...
	pmsg_buffer_start = phys_to_virt(
		(cxt->pmsg_data.mem_address + cxt->pmsg_data.mem_size)-
		cxt->pmsg_data.pmsg_size);

	p_hdr = (struct pmsg_buffer_hdr *)pmsg_buffer_start;
	pr_err("mtdoops_do_dump pmsg paddr = 0x%p \n",
			pmsg_buffer_start);
//...

从代码里我们可以看到p_hdr结构体pmsg_buffer_hdr指针,指向pmsg_buffer_start

pmsg_buffer_start是通过phys_to_virtcxt->pmsg_data.mem_address转换成虚拟地址后,经过计算得来

static int mtdoops_pmsg_probe(struct platform_device *pdev)
{
	struct mtdoops_context *cxt = &oops_cxt;
	struct resource *res;
	u32 value;
	int ret;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		pr_err("failed to locate DT /reserved-memory resource\n");
		return -EINVAL;
	}
	cxt->pmsg_data.mem_size = resource_size(res);
	cxt->pmsg_data.mem_address = res->start;

	pr_err( "pares mtd_dt, mem_address =0x%llx, mem_size =0x%lx \n",
			cxt->pmsg_data.mem_address, cxt->pmsg_data.mem_size);
	pr_err( "pares mtd_dt, pmsg_size =0x%lx, console-size =0x%lx \n",
			cxt->pmsg_data.pmsg_size, cxt->pmsg_data.console_size);

cxt->pmsg_data.mem_address = res->start;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

从原理上来讲,驱动匹配后,获取到设备树里的内存资源,然后通过phys_to_virt转换成虚拟地址后,这个是没有问题的!

并且一个很关键的信息:

  1. 基线升级之前代码没有问题

  2. 基线升级的代码中mtdoops.c源码没有改动

所以现阶段只能怀疑是设备树的这段内存出现了问题!因为使用phys_to_virt转换虚拟地址,必须保证这段内存是线性内存区域!


mtdoops使用的内存区域,是reserved memory,也即是ramoops,这段地址是线性区域

&reserved_memory {	
    //...
    ramoops_mem: ramoops@80D00000 {
		compatible = "ramoops";
		reg = <0x0 0x80D00000 0x0 0x200000>;
        record-size = <0x40000>;
		pmsg-size = <0x100000>;
        console-size = <0x80000>;
	};
    //...
};

继续检查dmesg日志,因为开机时会打印所有的reserved_mem的region

[    0.000000][    T0] OF: reserved mem: OVERLAP DETECTED!
[    0.000000][    T0] pvm_fw_region@80c01000 (0x0000000080c01000--0x0000000080e01000) overlaps with ramoops@80D00000 (0x0000000080d00000--0x0000000080f00000)
[    0.000000][    T0] Reserved memory: created CMA memory pool at 0x00000000ff800000, size 4 MiB
[    0.000000][    T0] OF: reserved mem: initialized node vm_comm_mem_region, compatible id shared-dma-pool
[    0.000000][    T0] OF: reserved mem: 0x00000000ff800000..0x00000000ffbfffff (4096 KiB) map reusable vm_comm_mem_region
[    0.000000][    T0] OF: reserved mem: 0x00000000fec00000..0x00000000ff7fffff (12288 KiB) map non-reusable mem_dump_region
[    0.000000][    T0] Reserved memory: created CMA memory pool at 0x00000000fcc00000, size 32 MiB
[    0.000000][    T0] OF: reserved mem: initialized node linux,cma, compatible id shared-dma-pool
[    0.000000][    T0] OF: reserved mem: 0x00000000fcc00000..0x00000000febfffff (32768 KiB) map reusable linux,cma
[    0.000000][    T0] Reserved memory: created CMA memory pool at 0x00000000fc000000, size 12 MiB
[    0.000000][    T0] OF: reserved mem: initialized node adsp_heap_region, compatible id shared-dma-pool
[    0.000000][    T0] OF: reserved mem: 0x00000000fc000000..0x00000000fcbfffff (12288 KiB) map reusable adsp_heap_region
[    0.000000][    T0] Reserved memory: created CMA memory pool at 0x00000000fa400000, size 28 MiB
[    0.000000][    T0] OF: reserved mem: initialized node audio_cma_region, compatible id shared-dma-pool
[    0.000000][    T0] OF: reserved mem: 0x00000000fa400000..0x00000000fbffffff (28672 KiB) map reusable audio_cma_region
[    0.000000][    T0] Reserved memory: created CMA memory pool at 0x00000000fa000000, size 4 MiB
[    0.000000][    T0] OF: reserved mem: initialized node sdsp_region, compatible id shared-dma-pool
[    0.000000][    T0] OF: reserved mem: 0x00000000fa000000..0x00000000fa3fffff (4096 KiB) map reusable sdsp_region
[    0.000000][    T0] Reserved memory: created CMA memory pool at 0x00000000f7800000, size 40 MiB
[    0.000000][    T0] OF: reserved mem: initialized node secure_cdsp_region, compatible id shared-dma-pool
[    0.000000][    T0] OF: reserved mem: 0x00000000f7800000..0x00000000f9ffffff (40960 KiB) map reusable secure_cdsp_region
[    0.000000][    T0] OF: reserved mem: 0x000000097ffff000..0x000000097fffffff (4 KiB) nomap non-reusable debug_kinfo_region
[    0.000000][    T0] Reserved memory: created CMA memory pool at 0x000000097ec00000, size 16 MiB
[    0.000000][    T0] OF: reserved mem: initialized node va_md_mem_region, compatible id shared-dma-pool
[    0.000000][    T0] OF: reserved mem: 0x000000097ec00000..0x000000097fbfffff (16384 KiB) map reusable va_md_mem_region
[    0.000000][    T0] Reserved memory: created CMA memory pool at 0x00000000f1c00000, size 92 MiB
[    0.000000][    T0] OF: reserved mem: initialized node non_secure_display_region, compatible id shared-dma-pool
[    0.000000][    T0] OF: reserved mem: 0x00000000f1c00000..0x00000000f77fffff (94208 KiB) map reusable non_secure_display_region
[    0.000000][    T0] Reserved memory: created CMA memory pool at 0x00000000f0800000, size 20 MiB
[    0.000000][    T0] OF: reserved mem: initialized node qseecom_region, compatible id shared-dma-pool
[    0.000000][    T0] OF: reserved mem: 0x00000000f0800000..0x00000000f1bfffff (20480 KiB) map reusable qseecom_region
[    0.000000][    T0] Reserved memory: created CMA memory pool at 0x00000000e7800000, size 16 MiB
[    0.000000][    T0] OF: reserved mem: initialized node qseecom_ta_region, compatible id shared-dma-pool
[    0.000000][    T0] OF: reserved mem: 0x00000000e7800000..0x00000000e87fffff (16384 KiB) map reusable qseecom_ta_region
[    0.000000][    T0] OF: reserved mem: 0x0000000080600000..0x000000008063ffff (256 KiB) nomap non-reusable xbl_dtlog_region@80600000
[    0.000000][    T0] OF: reserved mem: 0x0000000080640000..0x00000000807fffff (1792 KiB) nomap non-reusable xbl_ramdump_region@80640000
[    0.000000][    T0] OF: reserved mem: 0x0000000080800000..0x000000008085ffff (384 KiB) nomap non-reusable aop_image_region@80800000
[    0.000000][    T0] OF: reserved mem: 0x0000000080860000..0x000000008087ffff (128 KiB) nomap non-reusable aop_cmd_db_region@80860000
[    0.000000][    T0] OF: reserved mem: 0x0000000080880000..0x000000008089ffff (128 KiB) nomap non-reusable aop_config_region@80880000
[    0.000000][    T0] OF: reserved mem: 0x00000000808a0000..0x00000000808dffff (256 KiB) nomap non-reusable tme_crash_dump_region@808a0000
[    0.000000][    T0] OF: reserved mem: 0x00000000808e0000..0x00000000808e3fff (16 KiB) nomap non-reusable tme_log_region@808e0000
[    0.000000][    T0] OF: reserved mem: 0x00000000808e4000..0x00000000808f3fff (64 KiB) nomap non-reusable uefi_log_region@808e4000
[    0.000000][    T0] OF: reserved mem: 0x0000000080900000..0x0000000080afffff (2048 KiB) nomap non-reusable smem_region@80900000
[    0.000000][    T0] OF: reserved mem: 0x0000000080b00000..0x0000000080bfffff (1024 KiB) nomap non-reusable cpucp_fw_region@80b00000
[    0.000000][    T0] OF: reserved mem: 0x0000000080c00000..0x0000000080c00fff (4 KiB) nomap non-reusable chipinfo_region@80c00000
[    0.000000][    T0] OF: reserved mem: 0x0000000080c01000..0x0000000080e00fff (2048 KiB) nomap non-reusable pvm_fw_region@80c01000
[    0.000000][    T0] OF: reserved mem: 0x0000000080d00000..0x0000000080efffff (2048 KiB) map non-reusable ramoops@80D00000
[    0.000000][    T0] OF: reserved mem: 0x0000000082a00000..0x0000000082cfffff (3072 KiB) nomap non-reusable wlan_fw_region@82a00000
[    0.000000][    T0] OF: reserved mem: 0x0000000083600000..0x00000000843fffff (14336 KiB) nomap non-reusable hyp_region@0x83600000
[    0.000000][    T0] OF: reserved mem: 0x0000000084b00000..0x00000000852fffff (8192 KiB) nomap non-reusable camera_region@84b00000
[    0.000000][    T0] OF: reserved mem: 0x0000000085300000..0x0000000086bfffff (25600 KiB) nomap non-reusable wpss_region@85300000
[    0.000000][    T0] OF: reserved mem: 0x0000000086c00000..0x00000000893fffff (40960 KiB) nomap non-reusable adsp_region@86c00000
[    0.000000][    T0] OF: reserved mem: 0x0000000089400000..0x0000000089dfffff (10240 KiB) nomap non-reusable cdsp_region@89400000
[    0.000000][    T0] OF: reserved mem: 0x0000000089e00000..0x0000000089e0ffff (64 KiB) nomap non-reusable ipa_fw_region@89e00000
[    0.000000][    T0] OF: reserved mem: 0x0000000089e10000..0x0000000089e19fff (40 KiB) nomap non-reusable ipa_gsi_region@89e10000
[    0.000000][    T0] OF: reserved mem: 0x0000000089e1a000..0x0000000089e1bfff (8 KiB) nomap non-reusable gpu_microcode_region@89e1a000
[    0.000000][    T0] OF: reserved mem: 0x000000008bc00000..0x000000009a1fffff (235520 KiB) nomap non-reusable mpss_region@8bc00000
[    0.000000][    T0] OF: reserved mem: 0x000000009a200000..0x000000009a8fffff (7168 KiB) nomap non-reusable video_region@9a200000
[    0.000000][    T0] OF: reserved mem: 0x00000000a6e00000..0x00000000a6e3ffff (256 KiB) nomap non-reusable xbl_sc_region@a6e00000
[    0.000000][    T0] OF: reserved mem: 0x00000000a6f00000..0x00000000a6ffffff (1024 KiB) nomap non-reusable global_sync_region@a6f00000
[    0.000000][    T0] OF: reserved mem: 0x00000000b8000000..0x00000000baafffff (44032 KiB) map non-reusable splash_region
[    0.000000][    T0] OF: reserved mem: 0x00000000e0600000..0x00000000e09fffff (4096 KiB) nomap non-reusable cpusys_vm_region@e0600000
[    0.000000][    T0] Reserved memory: created CMA memory pool at 0x00000000e0c00000, size 76 MiB
[    0.000000][    T0] OF: reserved mem: initialized node trust_ui_vm_region@e0c00000, compatible id shared-dma-pool
[    0.000000][    T0] OF: reserved mem: 0x00000000e0c00000..0x00000000e57fffff (77824 KiB) map reusable trust_ui_vm_region@e0c00000
[    0.000000][    T0] OF: reserved mem: 0x00000000e8800000..0x00000000e88fffff (1024 KiB) nomap non-reusable tz_stat_region@e8800000
[    0.000000][    T0] OF: reserved mem: 0x00000000e8900000..0x00000000e8f7ffff (6656 KiB) nomap non-reusable tags_region@e8900000
[    0.000000][    T0] OF: reserved mem: 0x00000000e8f80000..0x00000000e947ffff (5120 KiB) nomap non-reusable qtee_region@e8f80000
[    0.000000][    T0] OF: reserved mem: 0x00000000e9480000..0x00000000efc7ffff (106496 KiB) nomap non-reusable trusted_apps_region@e9480000

我们可以看到这段异常点:

[    0.000000][    T0] OF: reserved mem: OVERLAP DETECTED!
[    0.000000][    T0] pvm_fw_region@80c01000 (0x0000000080c01000--0x0000000080e01000) overlaps with ramoops@80D00000 (0x0000000080d00000--0x0000000080f00000)

这个pvm_rw_region的内存区域和ramoops的内存区域发生重叠!!

查询改动

而这段区域被设置为非映射区域

问题根因

直接原因

  • 三级页表转换错误(level 3 translation fault)

  • 页表项为空,没有建立虚拟地址到物理地址的映射

  • 任何访问该地址的操作都会触发页错误

根本原因

[    0.000000][    T0] OF: reserved mem: OVERLAP DETECTED!
[    0.000000][    T0] pvm_fw_region@80c01000 (0x0000000080c01000--0x0000000080e01000) overlaps with ramoops@80D00000 (0x0000000080d00000--0x0000000080f00000)
  • 两个驱动声明了重叠的物理内存区域

  • 内核无法为重叠区域建立一致的页表映射

解决方案

重新规划pvm_fw_region和ramoops的内存区域,避免重叠

关键技术知识点总结

物理地址与虚拟地址映射

直接映射 (线性映射)

c

// ARM64典型配置
#define PAGE_OFFSET     0xffff000000000000
虚拟地址 = PAGE_OFFSET + 物理地址

适用场景: 常规内核内存访问

动态映射

c

// 保留内存、设备内存等特殊区域
void *ioremap(phys_addr_t offset, size_t size);
void *memremap(phys_addr_t offset, size_t size, unsigned long flags);

适用场景:

  • 设备寄存器访问

  • 保留内存区域

  • 非连续物理内存

内存类型

推荐映射方法

注意事项

常规内核内存

phys_to_virt

仅限直接映射区域

设备寄存器

ioremap

设置正确的缓存属性

保留内存

ioremap/memremap

检查设备树配置

DMA缓冲区

dma_alloc_coherent

保证缓存一致性

设备树内存管理

reserved memory声明

reserved-memory {
    region@address {
        reg = <0x0 base_address 0x0 size>;
        no-map;          // 内核不创建映射
        reusable;        // 内核可临时使用
    };
};

内存属性

  • no-map: 内核不创建线性映射,必须手动ioremap

  • reusable: 内核可在驱动未加载时使用该内存

  • alignment: 内存对齐要求