aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorXiao Guangrong <xiaoguangrong@linux.vnet.ibm.com>2012-06-20 03:58:58 -0400
committerAvi Kivity <avi@redhat.com>2012-07-11 09:51:19 -0400
commit49fde3406f3266c5af9430467672c20b63a31e83 (patch)
tree74da453686c6c7a1ca81c5d95d6fcaa882dc2217 /arch/x86/kvm
parent6e7d035407dc402a313e466c4f7ccb21aaed0da2 (diff)
KVM: MMU: introduce SPTE_MMU_WRITEABLE bit
This bit indicates whether the spte can be writable on MMU, that means the corresponding gpte is writable and the corresponding gfn is not protected by shadow page protection In the later path, SPTE_MMU_WRITEABLE will indicates whether the spte can be locklessly updated Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/mmu.c57
1 files changed, 38 insertions, 19 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index a2fc65ba76a..b160652f7ee 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -145,7 +145,8 @@ module_param(dbg, bool, 0644);
145#define CREATE_TRACE_POINTS 145#define CREATE_TRACE_POINTS
146#include "mmutrace.h" 146#include "mmutrace.h"
147 147
148#define SPTE_HOST_WRITEABLE (1ULL << PT_FIRST_AVAIL_BITS_SHIFT) 148#define SPTE_HOST_WRITEABLE (1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
149#define SPTE_MMU_WRITEABLE (1ULL << (PT_FIRST_AVAIL_BITS_SHIFT + 1))
149 150
150#define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) 151#define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level)
151 152
@@ -1084,34 +1085,51 @@ static void drop_large_spte(struct kvm_vcpu *vcpu, u64 *sptep)
1084 kvm_flush_remote_tlbs(vcpu->kvm); 1085 kvm_flush_remote_tlbs(vcpu->kvm);
1085} 1086}
1086 1087
1088static bool spte_is_locklessly_modifiable(u64 spte)
1089{
1090 return !(~spte & (SPTE_HOST_WRITEABLE | SPTE_MMU_WRITEABLE));
1091}
1092
1087/* 1093/*
1088 * Write-protect on the specified @sptep due to dirty page logging or 1094 * Write-protect on the specified @sptep, @pt_protect indicates whether
1089 * protecting shadow page table. @flush indicates whether tlb need be 1095 * spte writ-protection is caused by protecting shadow page table.
1090 * flushed. 1096 * @flush indicates whether tlb need be flushed.
1097 *
1098 * Note: write protection is difference between drity logging and spte
1099 * protection:
1100 * - for dirty logging, the spte can be set to writable at anytime if
1101 * its dirty bitmap is properly set.
1102 * - for spte protection, the spte can be writable only after unsync-ing
1103 * shadow page.
1091 * 1104 *
1092 * Return true if the spte is dropped. 1105 * Return true if the spte is dropped.
1093 */ 1106 */
1094static bool spte_write_protect(struct kvm *kvm, u64 *sptep, bool *flush) 1107static bool
1108spte_write_protect(struct kvm *kvm, u64 *sptep, bool *flush, bool pt_protect)
1095{ 1109{
1096 u64 spte = *sptep; 1110 u64 spte = *sptep;
1097 1111
1098 if (!is_writable_pte(spte)) 1112 if (!is_writable_pte(spte) &&
1113 !(pt_protect && spte_is_locklessly_modifiable(spte)))
1099 return false; 1114 return false;
1100 1115
1101 rmap_printk("rmap_write_protect: spte %p %llx\n", sptep, *sptep); 1116 rmap_printk("rmap_write_protect: spte %p %llx\n", sptep, *sptep);
1102 1117
1103 *flush |= true; 1118 if (__drop_large_spte(kvm, sptep)) {
1104 1119 *flush |= true;
1105 if (__drop_large_spte(kvm, sptep))
1106 return true; 1120 return true;
1121 }
1107 1122
1123 if (pt_protect)
1124 spte &= ~SPTE_MMU_WRITEABLE;
1108 spte = spte & ~PT_WRITABLE_MASK; 1125 spte = spte & ~PT_WRITABLE_MASK;
1109 mmu_spte_update(sptep, spte); 1126
1127 *flush |= mmu_spte_update(sptep, spte);
1110 return false; 1128 return false;
1111} 1129}
1112 1130
1113static bool 1131static bool __rmap_write_protect(struct kvm *kvm, unsigned long *rmapp,
1114__rmap_write_protect(struct kvm *kvm, unsigned long *rmapp, int level) 1132 int level, bool pt_protect)
1115{ 1133{
1116 u64 *sptep; 1134 u64 *sptep;
1117 struct rmap_iterator iter; 1135 struct rmap_iterator iter;
@@ -1119,7 +1137,7 @@ __rmap_write_protect(struct kvm *kvm, unsigned long *rmapp, int level)
1119 1137
1120 for (sptep = rmap_get_first(*rmapp, &iter); sptep;) { 1138 for (sptep = rmap_get_first(*rmapp, &iter); sptep;) {
1121 BUG_ON(!(*sptep & PT_PRESENT_MASK)); 1139 BUG_ON(!(*sptep & PT_PRESENT_MASK));
1122 if (spte_write_protect(kvm, sptep, &flush)) { 1140 if (spte_write_protect(kvm, sptep, &flush, pt_protect)) {
1123 sptep = rmap_get_first(*rmapp, &iter); 1141 sptep = rmap_get_first(*rmapp, &iter);
1124 continue; 1142 continue;
1125 } 1143 }
@@ -1148,7 +1166,7 @@ void kvm_mmu_write_protect_pt_masked(struct kvm *kvm,
1148 1166
1149 while (mask) { 1167 while (mask) {
1150 rmapp = &slot->rmap[gfn_offset + __ffs(mask)]; 1168 rmapp = &slot->rmap[gfn_offset + __ffs(mask)];
1151 __rmap_write_protect(kvm, rmapp, PT_PAGE_TABLE_LEVEL); 1169 __rmap_write_protect(kvm, rmapp, PT_PAGE_TABLE_LEVEL, false);
1152 1170
1153 /* clear the first set bit */ 1171 /* clear the first set bit */
1154 mask &= mask - 1; 1172 mask &= mask - 1;
@@ -1167,7 +1185,7 @@ static bool rmap_write_protect(struct kvm *kvm, u64 gfn)
1167 for (i = PT_PAGE_TABLE_LEVEL; 1185 for (i = PT_PAGE_TABLE_LEVEL;
1168 i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) { 1186 i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
1169 rmapp = __gfn_to_rmap(gfn, i, slot); 1187 rmapp = __gfn_to_rmap(gfn, i, slot);
1170 write_protected |= __rmap_write_protect(kvm, rmapp, i); 1188 write_protected |= __rmap_write_protect(kvm, rmapp, i, true);
1171 } 1189 }
1172 1190
1173 return write_protected; 1191 return write_protected;
@@ -2296,8 +2314,10 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
2296 spte |= shadow_x_mask; 2314 spte |= shadow_x_mask;
2297 else 2315 else
2298 spte |= shadow_nx_mask; 2316 spte |= shadow_nx_mask;
2317
2299 if (pte_access & ACC_USER_MASK) 2318 if (pte_access & ACC_USER_MASK)
2300 spte |= shadow_user_mask; 2319 spte |= shadow_user_mask;
2320
2301 if (level > PT_PAGE_TABLE_LEVEL) 2321 if (level > PT_PAGE_TABLE_LEVEL)
2302 spte |= PT_PAGE_SIZE_MASK; 2322 spte |= PT_PAGE_SIZE_MASK;
2303 if (tdp_enabled) 2323 if (tdp_enabled)
@@ -2322,7 +2342,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
2322 goto done; 2342 goto done;
2323 } 2343 }
2324 2344
2325 spte |= PT_WRITABLE_MASK; 2345 spte |= PT_WRITABLE_MASK | SPTE_MMU_WRITEABLE;
2326 2346
2327 if (!vcpu->arch.mmu.direct_map 2347 if (!vcpu->arch.mmu.direct_map
2328 && !(pte_access & ACC_WRITE_MASK)) { 2348 && !(pte_access & ACC_WRITE_MASK)) {
@@ -2351,8 +2371,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
2351 __func__, gfn); 2371 __func__, gfn);
2352 ret = 1; 2372 ret = 1;
2353 pte_access &= ~ACC_WRITE_MASK; 2373 pte_access &= ~ACC_WRITE_MASK;
2354 if (is_writable_pte(spte)) 2374 spte &= ~(PT_WRITABLE_MASK | SPTE_MMU_WRITEABLE);
2355 spte &= ~PT_WRITABLE_MASK;
2356 } 2375 }
2357 } 2376 }
2358 2377
@@ -3933,7 +3952,7 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
3933 !is_last_spte(pt[i], sp->role.level)) 3952 !is_last_spte(pt[i], sp->role.level))
3934 continue; 3953 continue;
3935 3954
3936 spte_write_protect(kvm, &pt[i], &flush); 3955 spte_write_protect(kvm, &pt[i], &flush, false);
3937 } 3956 }
3938 } 3957 }
3939 kvm_flush_remote_tlbs(kvm); 3958 kvm_flush_remote_tlbs(kvm);