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級
}