Linux kernel 在qemu系统mips中访问0xCxxxxxxx来宾内核指针

Linux kernel 在qemu系统mips中访问0xCxxxxxxx来宾内核指针,linux-kernel,mips,qemu,Linux Kernel,Mips,Qemu,在我基于QEMU的项目(系统仿真)中,我分析了来宾Linux的各种内核结构。要读取来宾虚拟内存,我使用cpu\u memory\u rw\u debug()函数 特别是,我使用某种启发式方法在内核内存中搜索struct module链表。 假设此列表中元素的相关部分如下所示: --------------------- --------------------- | prev = 0xc1231234 | | prev = 0xc5675678 | -----------

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

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

---------------------       ---------------------
| prev = 0xc1231234 |       | prev = 0xc5675678 |
---------------------       ---------------------
| next = 0xc1122334 |       | next = 0xc5566778 |
---------------------       ---------------------
| etc.              |       | etc.              |
---------------------       ---------------------
当QEMU模拟x86或ARM时,
cpu\u memory\u rw\u debug()
可以访问上一个/下一个指针,它们实际上指向上一个/下一个列表元素

然而,当QEMU模拟MIPS时,我观察到以下奇怪的行为:虽然列表中的每个元素中的prev/next指针看起来都是有效的内核指针,但我无法通过
cpu\u memory\u rw\u debug()
访问它们的指针对象,因为查找相应的物理地址失败:访问权限正常,虚拟CPU处于内核模式,但
tlb->map\u address()
失败

由于我无法遍历链表,我试图一个接一个地查找元素——只是想看看它们的上一个/下一个指针是什么样子——实际上我找到了所有元素,但它们都位于
0xAxxxxxxx
地址,而不是
0xcxxxxxx
,正如上一个/next所暗示的那样

执行物理地址查找的函数
r4k\u map\u address()
如下所示(仅相关摘录):

#定义KSEG0_基准0x80000000UL
#定义KSEG1_基0xA0000000UL
#定义KSEG2_基0xC0000000UL
#定义KSEG3_基0xE0000000UL
//..............
if(地址<(int32_t)KSEG1_基){
/*kseg0*/
if(内核模式){
*物理=地址-(int32_t)KSEG0_基;
*prot=页面读取|页面写入;
}否则{
ret=TLBRET_BADADDR;
}
}else if(地址<(int32_t)KSEG2_基){
/*kseg1*/
if(内核模式){
*物理=地址-(int32_t)KSEG1_基;
*prot=页面读取|页面写入;
}否则{
ret=TLBRET_BADADDR;
}
}else if(地址<(int32_t)KSEG3_BASE){
/*sseg(kseg2)*/
if(主管模式| |内核模式){
ret=env->tlb->映射地址(环境、物理、保护、真实地址、rw、访问类型);
}否则{
ret=TLBRET_BADADDR;
}
也就是说,在MIPS上,0xC0000000…0xE0000000范围的映射不同于较低的内核范围。 如果我将TLB访问替换为
*physical=address-(int32_t)KSEG1_BASE
直接映射,我就可以实现这些功能,但这肯定不是解决方案


它看起来像是QEMU相关的问题还是MIPS相关的问题?我希望有任何想法或调试方向。

底线是
cpu\u内存\u rw\u调试()
在QEMU系统MIPS中无法可靠工作

原因是QEMU模拟MIPS软件管理的TLB。通过这种方法,每当TLB缓存中不存在虚拟->物理地址映射时,QEMU模拟“TLB未命中”异常,该异常应由操作系统处理。操作系统负责遍历页面目录并填充TLB--QEMU(就像真正的MIPS一样)我不会那么做的

虽然这种方法适用于来宾代码,但它会导致无法使用 要使用
cpu\u memory\u rw\u debug()读取来宾虚拟内存
-it 对你来说不可靠


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

底线是,
cpu\u memory\u rw\u debug()
在qemu系统mips中无法可靠工作

原因是QEMU模拟MIPS软件管理的TLB。通过这种方法,每当TLB缓存中不存在虚拟->物理地址映射时,QEMU模拟“TLB未命中”异常,该异常应由操作系统处理。操作系统负责遍历页面目录并填充TLB--QEMU(就像真正的MIPS一样)我不会那么做的

虽然这种方法适用于来宾代码,但它会导致无法使用 要使用
cpu\u memory\u rw\u debug()读取来宾虚拟内存
-it 对你来说不可靠

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

#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;
  }