diff options
Diffstat (limited to 'arch/x86/kvm/paging_tmpl.h')
| -rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 20 |
1 files changed, 19 insertions, 1 deletions
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 043330159179..ad75d77999d0 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h | |||
| @@ -99,6 +99,7 @@ struct guest_walker { | |||
| 99 | pt_element_t prefetch_ptes[PTE_PREFETCH_NUM]; | 99 | pt_element_t prefetch_ptes[PTE_PREFETCH_NUM]; |
| 100 | gpa_t pte_gpa[PT_MAX_FULL_LEVELS]; | 100 | gpa_t pte_gpa[PT_MAX_FULL_LEVELS]; |
| 101 | pt_element_t __user *ptep_user[PT_MAX_FULL_LEVELS]; | 101 | pt_element_t __user *ptep_user[PT_MAX_FULL_LEVELS]; |
| 102 | bool pte_writable[PT_MAX_FULL_LEVELS]; | ||
| 102 | unsigned pt_access; | 103 | unsigned pt_access; |
| 103 | unsigned pte_access; | 104 | unsigned pte_access; |
| 104 | gfn_t gfn; | 105 | gfn_t gfn; |
| @@ -235,6 +236,22 @@ static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu, | |||
| 235 | if (pte == orig_pte) | 236 | if (pte == orig_pte) |
| 236 | continue; | 237 | continue; |
| 237 | 238 | ||
| 239 | /* | ||
| 240 | * If the slot is read-only, simply do not process the accessed | ||
| 241 | * and dirty bits. This is the correct thing to do if the slot | ||
| 242 | * is ROM, and page tables in read-as-ROM/write-as-MMIO slots | ||
| 243 | * are only supported if the accessed and dirty bits are already | ||
| 244 | * set in the ROM (so that MMIO writes are never needed). | ||
| 245 | * | ||
| 246 | * Note that NPT does not allow this at all and faults, since | ||
| 247 | * it always wants nested page table entries for the guest | ||
| 248 | * page tables to be writable. And EPT works but will simply | ||
| 249 | * overwrite the read-only memory to set the accessed and dirty | ||
| 250 | * bits. | ||
| 251 | */ | ||
| 252 | if (unlikely(!walker->pte_writable[level - 1])) | ||
| 253 | continue; | ||
| 254 | |||
| 238 | ret = FNAME(cmpxchg_gpte)(vcpu, mmu, ptep_user, index, orig_pte, pte); | 255 | ret = FNAME(cmpxchg_gpte)(vcpu, mmu, ptep_user, index, orig_pte, pte); |
| 239 | if (ret) | 256 | if (ret) |
| 240 | return ret; | 257 | return ret; |
| @@ -309,7 +326,8 @@ retry_walk: | |||
| 309 | goto error; | 326 | goto error; |
| 310 | real_gfn = gpa_to_gfn(real_gfn); | 327 | real_gfn = gpa_to_gfn(real_gfn); |
| 311 | 328 | ||
| 312 | host_addr = gfn_to_hva(vcpu->kvm, real_gfn); | 329 | host_addr = gfn_to_hva_prot(vcpu->kvm, real_gfn, |
| 330 | &walker->pte_writable[walker->level - 1]); | ||
| 313 | if (unlikely(kvm_is_error_hva(host_addr))) | 331 | if (unlikely(kvm_is_error_hva(host_addr))) |
| 314 | goto error; | 332 | goto error; |
| 315 | 333 | ||
