当前位置: 首页 > news >正文

简单记录一下Debug的折磨历程

问题描述

书接上文,Linux内核ioremap函数问题小记,这篇里我们加载镜像文件成功并成功执行 ret 指令返回内核模块。

本文则是开始执行镜像入口函数之后,一直崩。一路 Debug 的过程记录。

先贴图:执行真正的镜像代码之后,内核直接无输出,崩掉了,没有任何打印,借助 QEMU 看到各寄存器状态如下:

在这里插入图片描述

问题很明确:有指令触发了 instruction page fault,代码进入 stvec 指向的地址执行,但该地址没有映射,不可执行。


小 插曲

原本镜像加载的虚拟地址固定为 IOREMAP 的区间中的:0xff20000000c00000。这个地址是 RISCV Ubuntu 系统在 SV57 分页模式下的高地址,读者可验证符号扩展的正确性。

但老遇到问题,时而加载不了,时而可以加载。也就是这段虚拟地址空间时而可用,时而不可用。

非常的烦人,不可用就要重启重新尝试。这个错误还是类似奇偶出现的形式,重启一次就好了,再来就不行,然后又可以这样。

遂,打印 [VMALLOC_START, VMALLOC_END] 这段区间的内容,具体如下:[VMALLOC_START = ff20000000000000, VMALLOC_END = ff60000000000000]

尝试探究偶发失败的原因,遂执行命令:cat /proc/vmallocinfo 部分截图如下所示:

在这里插入图片描述
说明从 0xff20000000c00000 开始的这段区间是内核常用分配 IOREMAP 的位置。

遂把映射地址改为:0xff30000000c00000。这个问题解决了。

原因分析:

回到原来的问题:既然镜像经常崩溃,在镜像中又无法打印,那么我们只能通过在镜像代码中加入死循环的方式来进行非常原始的单步行为。

中间繁杂的尝试、暂停、打印寄存器组的内容等等行为就不一一展示了。最终初步定位到问题如下。

在镜像入口的设置页表前的代码中加入死循环,如下:

temp_entry:j temp_entry/** 设置SATP寄存器启用页表* MODE=10 (Sv57), ASID=0, PPN=bootstrap_pt_l0的物理地址>>12*/la      x12, bootstrap_pt_l0virt2phys x12                   // 转换为物理地址srli    x12, x12, 12            // 右移12位得到PPNli      x10, 10                  // Sv57模式  slli    x10, x10, 60            // MODE字段位于[63:60]or      x12, x12, x10           // 组合MODE和PPNcsrw    satp, x12               // 写入SATP寄存器sfence.vma                      // 刷新TLBfence.i

重新加载镜像并执行,暂停 CPU 打印寄存器组的内容如下:
请添加图片描述
随后,利用 objdump 反汇编镜像文件的内容并对应,可以看到:

在这里插入图片描述
那么,在设置页表之前,是没有问题的。同样的,把死循环放在这段设置页表的代码之后,崩了。

更细致的来说,我们把死循环放在:

    csrw    satp, x12               // 写入SATP寄存器
temp_entry:j temp_entrysfence.vma                      // 刷新TLBfence.i

还是崩。

但我们把死循环换一个位置:

    or      x12, x12, x10           // 组合MODE和PPN
temp_entry:j temp_entrycsrw    satp, x12               // 写入SATP寄存器sfence.vma                      // 刷新TLBfence.i

这就不崩了。CPU info 如下所示,对应到反汇编的循环位置:

在这里插入图片描述

问题就出在页表设置的代码中,是页表内容错了


解决方案:

今天还没有解决方案,明天慢慢 Debug 补上。

昨天分析到,页表内容错了。具体 Debug 原因如下:

.macro set_block table, index, addr, lvl# RISC-V Sv57: 每级9位,第lvl级的页面大小为2^(12+(4-lvl)*9)# 地址对齐掩码计算li      t0, 9li      t1, 4addi     t1, t1, -\lvl      # t1 = 4 - lvlmul     t1, t1, t0        # t1 = (4 - lvl) * 9li      t0, 12add     t0, t0, t1        # t0 = 12 + (4 - lvl) * 9# 创建对齐掩码li      t1, 1sll     t1, t1, t0        # t1 = 1 << (12 + (4 - lvl) * 9)addi    t1, t1, -1        # t1 = (1 << (12 + (4 - lvl) * 9)) - 1not     t1, t1            # t1 = ~((1 << (12 + (4 - lvl) * 9)) - 1)and     t0, \addr, t1     # t0 = addr & 对齐掩码set_pte \table, \index, t0, PAGE_DEFAULT_FLAGS
.endm

这是原本设置大页映射的代码。这里错了,在调用 set_pte 宏的时候应当传入 PTE 的值,PTE中PPN需要左移 10bit,即便做了对齐但也不是物理地址 4k 一页的 12bit。故需要做移位。修改为如下内容:

.macro set_block table, index, addr, lvl/* -------- 1. 计算 shift = 12 + (4-lvl)*9 -------- */li      t0, 9li      t1, 4addi    t1, t1, -\lvl      /* t1 = 4-lvl              */mul     t1, t1, t0         /* t1 = (4-lvl)*9          */li      t0, 12add     t0, t0, t1         /* t0 = shift              *//* -------- 2. 用掩码把物理地址对齐到大页边界 -------- */li      t1, -1             /* 全 1                    */sll     t1, t1, t0         /* t1 = ~((1 << shift)-1)  */and     t1, \addr, t1      /* t1 = aligned phys base  *//* -------- 3. 把 PPN 移到 bit10,并加上叶子标志 -------- */srli    t1, t1, 12         /* strip page offset       */slli    t1, t1, 10         /* PPN ↦ bits 53:10        */ori     t1, t1, PAGE_DEFAULT_FLAGS/* -------- 4. 写入 table[index] -------- */la      t2, \tableslli    t0, \index, 3      /* t0 = index * 8          */add     t2, t2, t0sd      t1, 0(t2)
.endm

总结

没完结,不能撒花。

完结撒花!!!

http://www.dtcms.com/a/274893.html

相关文章:

  • 多项式环及Rq的含义
  • Solaris10 创建用户初始化家目录
  • 注意力机制十问
  • softmax回归的从零开始实现
  • Java 抽象类详解:从基础到实战,掌握面向对象设计的核心基石
  • 渗透测试之木马后门实验
  • 拥抱AI----AI时代下的SSM框架
  • 项目捷报 | 冠捷科技泰国工厂THA MES项目成功验收!TPV国际化布局再添里程碑!
  • 【中文核心期刊推荐】中国农业科技导报
  • php的原生类
  • 7.12 卷积 | 最小生成树 prim
  • 转转APP逆向
  • WIFI协议全解析06:Beacon帧、Probe帧你必须懂,搞WiFi通信绕不开它们
  • RAG知识库检索查询优化技术
  • 【实时Linux实战系列】 KVM-RT 与 Jailhouse 虚拟化
  • C++ 面向对象 - 默认值与常量成员
  • sensor_msgs中常用的传感器数据格式以及c++操作
  • 数字孪生技术引领UI前端设计新风尚:智能穿戴设备的界面优化
  • MongoDB(一)
  • 用Python和OpenCV从零搭建一个完整的双目视觉系统(六 最终篇)
  • 【9】PostgreSQL 之 vacuum 死元组清理
  • bash脚本-z检查参数是否为空
  • 雨污管网智慧监测系统网络建设方案:基于SD-WAN混合架构的最佳实践
  • 计算机组成原理:以ADD指令为例讲解微指令执行流程
  • SpringCloud之Eureka
  • 当贝桌面_九联UNT403HS_hi3798mv320处理器安卓9优盘刷机和线刷烧录包
  • 第Y7周:训练自己的数据
  • 洛谷P2042 [NOI2005] 维护数列
  • 可以自定义皮肤的桌面备忘便签软件-滴哦小精灵 v1.4.5
  • 深入理解JVM