在qemu-system-mips中访问0xCxxxxxxx来宾内核指针

时间:2016-02-21 23:13:06

标签: linux-kernel mips qemu

在我基于QENU的项目(系统仿真)中,我分析了来宾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()失败。

由于我无法浏览链表,我试图逐个找到这些元素 - 只是为了看看它们的上一个/下一个指针是什么样的 - 我实际上找到了所有元素,但它们都位于0xAxxxxxxx地址,而不是0xCxxxxxxx,正如上一个/下一个暗示的那样。

执行物理地址查找的函数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范围的映射与较低的内核范围不同。 如果我用*physical = address - (int32_t)KSEG1_BASE直接映射替换TLB访问,我会把事情搞定,但肯定不是解决方案。

是否与QEMU相关的问题或与MIPS相关的问题?我很欣赏任何想法或调试方向。

1 个答案:

答案 0 :(得分:0)

底线是cpu_memory_rw_debug()在qemu-system-mips中无法正常工作。

原因是QEMU模拟MIPS软件管理的TLB。通过这种方法,每当TLB高速缓存中不存在虚拟 - >物理地址映射时,QEMU就模拟&#34; TLB-miss&#34;异常,应由操作系统处理。操作页面目录并填写TLB-QEMU(就像真正的MIPS一样)是操作系统的责任。

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

至于为什么实际存在于KSEG2中的内核结构的问题,这是因为KSEG1和KSEG2的某些虚拟范围对应于相同的物理页面。