diff options
author | Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp> | 2011-04-21 11:34:44 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-05-22 08:39:38 -0400 |
commit | 6e2ca7d1802bf8ed9908435e34daa116662e7790 (patch) | |
tree | 802f56f655246d21cf722e06353bd2d30011252a | |
parent | 40e19b519caeb93def89c45082d776fccfb96dbb (diff) |
KVM: MMU: Optimize guest page table walk
This patch optimizes the guest page table walk by using get_user()
instead of copy_from_user().
With this patch applied, paging64_walk_addr_generic() has become
about 0.5us to 1.0us faster on my Phenom II machine with NPT on.
Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 1b6899088f97..a32a1c809149 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h | |||
@@ -123,6 +123,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, | |||
123 | gva_t addr, u32 access) | 123 | gva_t addr, u32 access) |
124 | { | 124 | { |
125 | pt_element_t pte; | 125 | pt_element_t pte; |
126 | pt_element_t __user *ptep_user; | ||
126 | gfn_t table_gfn; | 127 | gfn_t table_gfn; |
127 | unsigned index, pt_access, uninitialized_var(pte_access); | 128 | unsigned index, pt_access, uninitialized_var(pte_access); |
128 | gpa_t pte_gpa; | 129 | gpa_t pte_gpa; |
@@ -158,6 +159,9 @@ walk: | |||
158 | pt_access = ACC_ALL; | 159 | pt_access = ACC_ALL; |
159 | 160 | ||
160 | for (;;) { | 161 | for (;;) { |
162 | gfn_t real_gfn; | ||
163 | unsigned long host_addr; | ||
164 | |||
161 | index = PT_INDEX(addr, walker->level); | 165 | index = PT_INDEX(addr, walker->level); |
162 | 166 | ||
163 | table_gfn = gpte_to_gfn(pte); | 167 | table_gfn = gpte_to_gfn(pte); |
@@ -166,9 +170,22 @@ walk: | |||
166 | walker->table_gfn[walker->level - 1] = table_gfn; | 170 | walker->table_gfn[walker->level - 1] = table_gfn; |
167 | walker->pte_gpa[walker->level - 1] = pte_gpa; | 171 | walker->pte_gpa[walker->level - 1] = pte_gpa; |
168 | 172 | ||
169 | if (kvm_read_guest_page_mmu(vcpu, mmu, table_gfn, &pte, | 173 | real_gfn = mmu->translate_gpa(vcpu, gfn_to_gpa(table_gfn), |
170 | offset, sizeof(pte), | 174 | PFERR_USER_MASK|PFERR_WRITE_MASK); |
171 | PFERR_USER_MASK|PFERR_WRITE_MASK)) { | 175 | if (real_gfn == UNMAPPED_GVA) { |
176 | present = false; | ||
177 | break; | ||
178 | } | ||
179 | real_gfn = gpa_to_gfn(real_gfn); | ||
180 | |||
181 | host_addr = gfn_to_hva(vcpu->kvm, real_gfn); | ||
182 | if (kvm_is_error_hva(host_addr)) { | ||
183 | present = false; | ||
184 | break; | ||
185 | } | ||
186 | |||
187 | ptep_user = (pt_element_t __user *)((void *)host_addr + offset); | ||
188 | if (get_user(pte, ptep_user)) { | ||
172 | present = false; | 189 | present = false; |
173 | break; | 190 | break; |
174 | } | 191 | } |