diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2010-09-10 11:30:52 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-10-24 04:52:38 -0400 |
commit | 2329d46d213d0721dafae18db29f54b196f11468 (patch) | |
tree | d417b780c53b11c00e927e31bde995e26bfcb51f /arch/x86/kvm/paging_tmpl.h | |
parent | ec92fe44e7ff94d04d8305e49efcffd8773e1cf6 (diff) |
KVM: MMU: Make walk_addr_generic capable for two-level walking
This patch uses kvm_read_guest_page_tdp to make the
walk_addr_generic functions suitable for two-level page
table walking.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/paging_tmpl.h')
-rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index eefe363156b9..f4e09d341e28 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h | |||
@@ -124,6 +124,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, | |||
124 | unsigned index, pt_access, uninitialized_var(pte_access); | 124 | unsigned index, pt_access, uninitialized_var(pte_access); |
125 | gpa_t pte_gpa; | 125 | gpa_t pte_gpa; |
126 | bool eperm, present, rsvd_fault; | 126 | bool eperm, present, rsvd_fault; |
127 | int offset; | ||
128 | u32 access = 0; | ||
127 | 129 | ||
128 | trace_kvm_mmu_pagetable_walk(addr, write_fault, user_fault, | 130 | trace_kvm_mmu_pagetable_walk(addr, write_fault, user_fault, |
129 | fetch_fault); | 131 | fetch_fault); |
@@ -153,12 +155,14 @@ walk: | |||
153 | index = PT_INDEX(addr, walker->level); | 155 | index = PT_INDEX(addr, walker->level); |
154 | 156 | ||
155 | table_gfn = gpte_to_gfn(pte); | 157 | table_gfn = gpte_to_gfn(pte); |
156 | pte_gpa = gfn_to_gpa(table_gfn); | 158 | offset = index * sizeof(pt_element_t); |
157 | pte_gpa += index * sizeof(pt_element_t); | 159 | pte_gpa = gfn_to_gpa(table_gfn) + offset; |
158 | walker->table_gfn[walker->level - 1] = table_gfn; | 160 | walker->table_gfn[walker->level - 1] = table_gfn; |
159 | walker->pte_gpa[walker->level - 1] = pte_gpa; | 161 | walker->pte_gpa[walker->level - 1] = pte_gpa; |
160 | 162 | ||
161 | if (kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte))) { | 163 | if (kvm_read_guest_page_mmu(vcpu, mmu, table_gfn, &pte, |
164 | offset, sizeof(pte), | ||
165 | PFERR_USER_MASK|PFERR_WRITE_MASK)) { | ||
162 | present = false; | 166 | present = false; |
163 | break; | 167 | break; |
164 | } | 168 | } |
@@ -209,15 +213,27 @@ walk: | |||
209 | is_large_pte(pte) && | 213 | is_large_pte(pte) && |
210 | mmu->root_level == PT64_ROOT_LEVEL)) { | 214 | mmu->root_level == PT64_ROOT_LEVEL)) { |
211 | int lvl = walker->level; | 215 | int lvl = walker->level; |
216 | gpa_t real_gpa; | ||
217 | gfn_t gfn; | ||
212 | 218 | ||
213 | walker->gfn = gpte_to_gfn_lvl(pte, lvl); | 219 | gfn = gpte_to_gfn_lvl(pte, lvl); |
214 | walker->gfn += (addr & PT_LVL_OFFSET_MASK(lvl)) | 220 | gfn += (addr & PT_LVL_OFFSET_MASK(lvl)) >> PAGE_SHIFT; |
215 | >> PAGE_SHIFT; | ||
216 | 221 | ||
217 | if (PTTYPE == 32 && | 222 | if (PTTYPE == 32 && |
218 | walker->level == PT_DIRECTORY_LEVEL && | 223 | walker->level == PT_DIRECTORY_LEVEL && |
219 | is_cpuid_PSE36()) | 224 | is_cpuid_PSE36()) |
220 | walker->gfn += pse36_gfn_delta(pte); | 225 | gfn += pse36_gfn_delta(pte); |
226 | |||
227 | access |= write_fault ? PFERR_WRITE_MASK : 0; | ||
228 | access |= fetch_fault ? PFERR_FETCH_MASK : 0; | ||
229 | access |= user_fault ? PFERR_USER_MASK : 0; | ||
230 | |||
231 | real_gpa = mmu->translate_gpa(vcpu, gfn_to_gpa(gfn), | ||
232 | access); | ||
233 | if (real_gpa == UNMAPPED_GVA) | ||
234 | return 0; | ||
235 | |||
236 | walker->gfn = real_gpa >> PAGE_SHIFT; | ||
221 | 237 | ||
222 | break; | 238 | break; |
223 | } | 239 | } |