diff options
author | Marcelo Tosatti <mtosatti@redhat.com> | 2009-06-10 11:27:04 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-09-10 01:32:53 -0400 |
commit | 08a3732bf2e68048c9166e929ca2115127a412ab (patch) | |
tree | 6f741496cf7c0932512e8af2833ca2596b4aebf9 /arch/x86/kvm | |
parent | 776e6633363b5616be6fa4493a8b70ef8e2ea04b (diff) |
KVM: MMU audit: update count_writable_mappings / count_rmaps
Under testing, count_writable_mappings returns a value that is 2 integers
larger than what count_rmaps returns.
Suspicion is that either of the two functions is counting a duplicate (either
positively or negatively).
Modifying check_writable_mappings_rmap to check for rmap existance on
all present MMU pages fails to trigger an error, which should keep Avi
happy.
Also introduce mmu_spte_walk to invoke a callback on all present sptes visible
to the current vcpu, might be useful in the future.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r-- | arch/x86/kvm/mmu.c | 104 |
1 files changed, 94 insertions, 10 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index f85d9953a620..fd5579cc8abd 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -3045,6 +3045,55 @@ static gva_t canonicalize(gva_t gva) | |||
3045 | return gva; | 3045 | return gva; |
3046 | } | 3046 | } |
3047 | 3047 | ||
3048 | |||
3049 | typedef void (*inspect_spte_fn) (struct kvm *kvm, struct kvm_mmu_page *sp, | ||
3050 | u64 *sptep); | ||
3051 | |||
3052 | static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp, | ||
3053 | inspect_spte_fn fn) | ||
3054 | { | ||
3055 | int i; | ||
3056 | |||
3057 | for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { | ||
3058 | u64 ent = sp->spt[i]; | ||
3059 | |||
3060 | if (is_shadow_present_pte(ent)) { | ||
3061 | if (sp->role.level > 1 && !is_large_pte(ent)) { | ||
3062 | struct kvm_mmu_page *child; | ||
3063 | child = page_header(ent & PT64_BASE_ADDR_MASK); | ||
3064 | __mmu_spte_walk(kvm, child, fn); | ||
3065 | } | ||
3066 | if (sp->role.level == 1) | ||
3067 | fn(kvm, sp, &sp->spt[i]); | ||
3068 | } | ||
3069 | } | ||
3070 | } | ||
3071 | |||
3072 | static void mmu_spte_walk(struct kvm_vcpu *vcpu, inspect_spte_fn fn) | ||
3073 | { | ||
3074 | int i; | ||
3075 | struct kvm_mmu_page *sp; | ||
3076 | |||
3077 | if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) | ||
3078 | return; | ||
3079 | if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) { | ||
3080 | hpa_t root = vcpu->arch.mmu.root_hpa; | ||
3081 | sp = page_header(root); | ||
3082 | __mmu_spte_walk(vcpu->kvm, sp, fn); | ||
3083 | return; | ||
3084 | } | ||
3085 | for (i = 0; i < 4; ++i) { | ||
3086 | hpa_t root = vcpu->arch.mmu.pae_root[i]; | ||
3087 | |||
3088 | if (root && VALID_PAGE(root)) { | ||
3089 | root &= PT64_BASE_ADDR_MASK; | ||
3090 | sp = page_header(root); | ||
3091 | __mmu_spte_walk(vcpu->kvm, sp, fn); | ||
3092 | } | ||
3093 | } | ||
3094 | return; | ||
3095 | } | ||
3096 | |||
3048 | static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, | 3097 | static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, |
3049 | gva_t va, int level) | 3098 | gva_t va, int level) |
3050 | { | 3099 | { |
@@ -3137,9 +3186,47 @@ static int count_rmaps(struct kvm_vcpu *vcpu) | |||
3137 | return nmaps; | 3186 | return nmaps; |
3138 | } | 3187 | } |
3139 | 3188 | ||
3140 | static int count_writable_mappings(struct kvm_vcpu *vcpu) | 3189 | void inspect_spte_has_rmap(struct kvm *kvm, struct kvm_mmu_page *sp, u64 *sptep) |
3190 | { | ||
3191 | unsigned long *rmapp; | ||
3192 | struct kvm_mmu_page *rev_sp; | ||
3193 | gfn_t gfn; | ||
3194 | |||
3195 | if (*sptep & PT_WRITABLE_MASK) { | ||
3196 | rev_sp = page_header(__pa(sptep)); | ||
3197 | gfn = rev_sp->gfns[sptep - rev_sp->spt]; | ||
3198 | |||
3199 | if (!gfn_to_memslot(kvm, gfn)) { | ||
3200 | if (!printk_ratelimit()) | ||
3201 | return; | ||
3202 | printk(KERN_ERR "%s: no memslot for gfn %ld\n", | ||
3203 | audit_msg, gfn); | ||
3204 | printk(KERN_ERR "%s: index %ld of sp (gfn=%lx)\n", | ||
3205 | audit_msg, sptep - rev_sp->spt, | ||
3206 | rev_sp->gfn); | ||
3207 | dump_stack(); | ||
3208 | return; | ||
3209 | } | ||
3210 | |||
3211 | rmapp = gfn_to_rmap(kvm, rev_sp->gfns[sptep - rev_sp->spt], 0); | ||
3212 | if (!*rmapp) { | ||
3213 | if (!printk_ratelimit()) | ||
3214 | return; | ||
3215 | printk(KERN_ERR "%s: no rmap for writable spte %llx\n", | ||
3216 | audit_msg, *sptep); | ||
3217 | dump_stack(); | ||
3218 | } | ||
3219 | } | ||
3220 | |||
3221 | } | ||
3222 | |||
3223 | void audit_writable_sptes_have_rmaps(struct kvm_vcpu *vcpu) | ||
3224 | { | ||
3225 | mmu_spte_walk(vcpu, inspect_spte_has_rmap); | ||
3226 | } | ||
3227 | |||
3228 | static void check_writable_mappings_rmap(struct kvm_vcpu *vcpu) | ||
3141 | { | 3229 | { |
3142 | int nmaps = 0; | ||
3143 | struct kvm_mmu_page *sp; | 3230 | struct kvm_mmu_page *sp; |
3144 | int i; | 3231 | int i; |
3145 | 3232 | ||
@@ -3156,20 +3243,16 @@ static int count_writable_mappings(struct kvm_vcpu *vcpu) | |||
3156 | continue; | 3243 | continue; |
3157 | if (!(ent & PT_WRITABLE_MASK)) | 3244 | if (!(ent & PT_WRITABLE_MASK)) |
3158 | continue; | 3245 | continue; |
3159 | ++nmaps; | 3246 | inspect_spte_has_rmap(vcpu->kvm, sp, &pt[i]); |
3160 | } | 3247 | } |
3161 | } | 3248 | } |
3162 | return nmaps; | 3249 | return; |
3163 | } | 3250 | } |
3164 | 3251 | ||
3165 | static void audit_rmap(struct kvm_vcpu *vcpu) | 3252 | static void audit_rmap(struct kvm_vcpu *vcpu) |
3166 | { | 3253 | { |
3167 | int n_rmap = count_rmaps(vcpu); | 3254 | check_writable_mappings_rmap(vcpu); |
3168 | int n_actual = count_writable_mappings(vcpu); | 3255 | count_rmaps(vcpu); |
3169 | |||
3170 | if (n_rmap != n_actual) | ||
3171 | printk(KERN_ERR "%s: (%s) rmap %d actual %d\n", | ||
3172 | __func__, audit_msg, n_rmap, n_actual); | ||
3173 | } | 3256 | } |
3174 | 3257 | ||
3175 | static void audit_write_protection(struct kvm_vcpu *vcpu) | 3258 | static void audit_write_protection(struct kvm_vcpu *vcpu) |
@@ -3203,6 +3286,7 @@ static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) | |||
3203 | audit_rmap(vcpu); | 3286 | audit_rmap(vcpu); |
3204 | audit_write_protection(vcpu); | 3287 | audit_write_protection(vcpu); |
3205 | audit_mappings(vcpu); | 3288 | audit_mappings(vcpu); |
3289 | audit_writable_sptes_have_rmaps(vcpu); | ||
3206 | dbg = olddbg; | 3290 | dbg = olddbg; |
3207 | } | 3291 | } |
3208 | 3292 | ||