for_each_shadow_entry宏分析

来源:互联网 发布:java 处理大批量数据 编辑:程序博客网 时间:2024/06/09 20:01

for_each_shadow_entr三个参数的含义

_vcpu:对应kvm_vcpu结构体的指针。

_addr:如果是ETP的话,是GuestOS的物理地址

_walker:游标

 

 

#define for_each_shadow_entry(_vcpu, _addr, _walker)    /
 for (shadow_walk_init(&(_walker), _vcpu, _addr); /
      shadow_walk_okay(&(_walker));   /
      shadow_walk_next(&(_walker)))

可以看出for_each_shadow_entry通过宏来实现.

 

首先介绍iterator参数的含义

struct kvm_shadow_walk_iterator {
 u64 addr;   //寻找的GuestOS物理地址
 hpa_t shadow_addr; //指向对应下一个要找的EPT页表的指针
 int level; //当前查找所处的页表级别
 u64 *sptep; //执行对应页表项的指针
 unsigned index; //对应所在页表的页表项的索引
};

static void shadow_walk_init(struct kvm_shadow_walk_iterator *iterator,
        struct kvm_vcpu *vcpu, u64 addr)
{
 iterator->addr = addr;  //把要找的地址赋给addr
 iterator->shadow_addr = vcpu->arch.mmu.root_hpa; //初始化时,下一个要找的页表就是当前VCPU的根页表目录。
 iterator->level = vcpu->arch.mmu.shadow_root_level; //guestos对应的页表是几级页表。

 

 if (iterator->level == PT64_ROOT_LEVEL &&
     vcpu->arch.mmu.root_level < PT64_ROOT_LEVEL &&
     !vcpu->arch.mmu.direct_map)
  --iterator->level;

 

 if (iterator->level == PT32E_ROOT_LEVEL) {
  iterator->shadow_addr
   = vcpu->arch.mmu.pae_root[(addr >> 30) & 3];
  iterator->shadow_addr &= PT64_BASE_ADDR_MASK;
  --iterator->level;
  if (!iterator->shadow_addr)
   iterator->level = 0;
 }

这部分代码要看懂还需要了解64位和PAE的页表结构。


}

 

 

 

static bool shadow_walk_okay(struct kvm_shadow_walk_iterator *iterator)
{
 if (iterator->level < PT_PAGE_TABLE_LEVEL)
  return false;

 if (iterator->level == PT_PAGE_TABLE_LEVEL)
  if (is_large_pte(*iterator->sptep))
   return false;

 iterator->index = SHADOW_PT_INDEX(iterator->addr, iterator->level);
 iterator->sptep = ((u64 *)__va(iterator->shadow_addr)) + iterator->index;  //获取GuestOS物理地址在EPT页表对应级别的页表项地址。
 return true;
}

 

static void shadow_walk_next(struct kvm_shadow_walk_iterator *iterator)
{
 iterator->shadow_addr = *iterator->sptep & PT64_BASE_ADDR_MASK;  //这个是下一级页表的物理地址。
 --iterator->level; 级别减少1级
}