【问题标题】:Accessing 0xCxxxxxxx guest kernel pointers within qemu-system-mips在 qemu-system-mips 中访问 0xCxxxxxxx 来宾内核指针
【发布时间】:2016-06-03 06:32:14
【问题描述】:

在我基于 QEMU 的项目(系统仿真)中,我分析了客户 Linux 的各种内核结构。要读取来宾虚拟内存,我使用cpu_memory_rw_debug() 函数。

特别是,我使用某种启发式方法在内核内存中搜索struct module 链表。 以免假设此列表中元素的相关部分如下所示:

---------------------       ---------------------
| prev = 0xc1231234 |       | prev = 0xc5675678 |
---------------------       ---------------------
| next = 0xc1122334 |       | next = 0xc5566778 |
---------------------       ---------------------
| etc.              |       | etc.              |
---------------------       ---------------------

当 QEMU 模拟 x86 或 ARM 时,cpu_memory_rw_debug() 可以访问 prev/next 指针,它们实际上指向上一个/下一个列表元素。

但是,当 QEMU 模拟 MIPS 时,我观察到以下奇怪的行为:虽然 prev/next 指针看起来像列表中每个元素中的有效内核指针,但我无法通过 cpu_memory_rw_debug() 访问它们的指针,因为找到对应物理地址失败:访问权限正常,虚拟CPU处于内核态,但tlb->map_address()失败。

由于我无法遍历链表,因此我尝试逐个查找元素 - 只是为了看看它们的 prev/next 指针是什么样子 - 我实际上找到了所有元素,但它们都位于0xAxxxxxxx 地址,而不是 0xCxxxxxxx,正如 prev/next 所暗示的那样。

执行物理地址查找的函数r4k_map_address()如下所示(仅相关摘录):

#define KSEG0_BASE 0x80000000UL
#define KSEG1_BASE 0xA0000000UL
#define KSEG2_BASE 0xC0000000UL
#define KSEG3_BASE 0xE0000000UL
//..............
if (address < (int32_t)KSEG1_BASE) {
  /* kseg0 */
  if (kernel_mode) {
    *physical = address - (int32_t)KSEG0_BASE;
    *prot = PAGE_READ | PAGE_WRITE;
  } else {
    ret = TLBRET_BADADDR;
  }
} else if (address < (int32_t)KSEG2_BASE) {
  /* kseg1 */
  if (kernel_mode) {
    *physical = address - (int32_t)KSEG1_BASE;
    *prot = PAGE_READ | PAGE_WRITE;
  } else {
    ret = TLBRET_BADADDR;
  }
} else if (address < (int32_t)KSEG3_BASE) {
    /* sseg (kseg2) */
    if (supervisor_mode || kernel_mode) {
      ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
    } else {
      ret = TLBRET_BADADDR;
  }

也就是说,在 MIPS 上,0xC0000000...0xE0000000 范围的映射不同于较低的内核范围。 如果我将 TLB 访问替换为 *physical = address - (int32_t)KSEG1_BASE 直接映射,我就可以正常工作,但肯定不是解决方案。

它看起来像是与 QEMU 相关的问题还是与 MIPS 相关的问题?如果有任何想法或调试方向,我将不胜感激。

【问题讨论】:

    标签: linux-kernel mips qemu


    【解决方案1】:

    底线是cpu_memory_rw_debug() 在 qemu-system-mips 中不能可靠地工作。

    原因是 QEMU 模拟 MIPS 软件管理的 TLB。使用这种方法,只要 TLB 缓存中不存在虚拟->物理地址映射,QEMU 就会模拟“TLB-miss”异常,这应该由操作系统处理。遍历页面目录并填充 TLB 是操作系统的责任——QEMU(就像真正的 MIPS 一样)不会这样做。

    虽然这种方法适用于来宾代码,但它会导致无法 使用cpu_memory_rw_debug() 读取客户虚拟内存 - 它 对mapped segments 不可靠。

    至于为什么内核结构实际上驻留在 KSEG2 中而在 KSEG1 中观察到的问题 - 这只是因为 KSEG1 和 KSEG2 的某些虚拟范围对应于相同的物理页面。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-02-07
      • 2021-09-14
      • 2013-10-02
      • 1970-01-01
      • 2012-04-27
      • 2014-07-21
      • 2018-01-19
      相关资源
      最近更新 更多