diff options
author | Marcelo Tosatti <mtosatti@redhat.com> | 2009-06-11 11:07:43 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-09-10 01:32:56 -0400 |
commit | 68f89400bc92421d6da22e1ec8e3ec599c3c8244 (patch) | |
tree | be63fcdb8ddf3513b6011a3fc93aee4b2adcf447 /arch/x86 | |
parent | 94d8b056a20bac4f9905d6dafcf7b7005207684a (diff) |
KVM: VMX: EPT misconfiguration handler
Handler for EPT misconfiguration which checks for valid state
in the shadow pagetables, printing the spte on each level.
The separate WARN_ONs are useful for kerneloops.org.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/kvm/vmx.c | 86 |
1 files changed, 85 insertions, 1 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 6610181267b1..94c07ada103e 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -3227,6 +3227,89 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
3227 | return kvm_mmu_page_fault(vcpu, gpa & PAGE_MASK, 0); | 3227 | return kvm_mmu_page_fault(vcpu, gpa & PAGE_MASK, 0); |
3228 | } | 3228 | } |
3229 | 3229 | ||
3230 | static u64 ept_rsvd_mask(u64 spte, int level) | ||
3231 | { | ||
3232 | int i; | ||
3233 | u64 mask = 0; | ||
3234 | |||
3235 | for (i = 51; i > boot_cpu_data.x86_phys_bits; i--) | ||
3236 | mask |= (1ULL << i); | ||
3237 | |||
3238 | if (level > 2) | ||
3239 | /* bits 7:3 reserved */ | ||
3240 | mask |= 0xf8; | ||
3241 | else if (level == 2) { | ||
3242 | if (spte & (1ULL << 7)) | ||
3243 | /* 2MB ref, bits 20:12 reserved */ | ||
3244 | mask |= 0x1ff000; | ||
3245 | else | ||
3246 | /* bits 6:3 reserved */ | ||
3247 | mask |= 0x78; | ||
3248 | } | ||
3249 | |||
3250 | return mask; | ||
3251 | } | ||
3252 | |||
3253 | static void ept_misconfig_inspect_spte(struct kvm_vcpu *vcpu, u64 spte, | ||
3254 | int level) | ||
3255 | { | ||
3256 | printk(KERN_ERR "%s: spte 0x%llx level %d\n", __func__, spte, level); | ||
3257 | |||
3258 | /* 010b (write-only) */ | ||
3259 | WARN_ON((spte & 0x7) == 0x2); | ||
3260 | |||
3261 | /* 110b (write/execute) */ | ||
3262 | WARN_ON((spte & 0x7) == 0x6); | ||
3263 | |||
3264 | /* 100b (execute-only) and value not supported by logical processor */ | ||
3265 | if (!cpu_has_vmx_ept_execute_only()) | ||
3266 | WARN_ON((spte & 0x7) == 0x4); | ||
3267 | |||
3268 | /* not 000b */ | ||
3269 | if ((spte & 0x7)) { | ||
3270 | u64 rsvd_bits = spte & ept_rsvd_mask(spte, level); | ||
3271 | |||
3272 | if (rsvd_bits != 0) { | ||
3273 | printk(KERN_ERR "%s: rsvd_bits = 0x%llx\n", | ||
3274 | __func__, rsvd_bits); | ||
3275 | WARN_ON(1); | ||
3276 | } | ||
3277 | |||
3278 | if (level == 1 || (level == 2 && (spte & (1ULL << 7)))) { | ||
3279 | u64 ept_mem_type = (spte & 0x38) >> 3; | ||
3280 | |||
3281 | if (ept_mem_type == 2 || ept_mem_type == 3 || | ||
3282 | ept_mem_type == 7) { | ||
3283 | printk(KERN_ERR "%s: ept_mem_type=0x%llx\n", | ||
3284 | __func__, ept_mem_type); | ||
3285 | WARN_ON(1); | ||
3286 | } | ||
3287 | } | ||
3288 | } | ||
3289 | } | ||
3290 | |||
3291 | static int handle_ept_misconfig(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | ||
3292 | { | ||
3293 | u64 sptes[4]; | ||
3294 | int nr_sptes, i; | ||
3295 | gpa_t gpa; | ||
3296 | |||
3297 | gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS); | ||
3298 | |||
3299 | printk(KERN_ERR "EPT: Misconfiguration.\n"); | ||
3300 | printk(KERN_ERR "EPT: GPA: 0x%llx\n", gpa); | ||
3301 | |||
3302 | nr_sptes = kvm_mmu_get_spte_hierarchy(vcpu, gpa, sptes); | ||
3303 | |||
3304 | for (i = PT64_ROOT_LEVEL; i > PT64_ROOT_LEVEL - nr_sptes; --i) | ||
3305 | ept_misconfig_inspect_spte(vcpu, sptes[i-1], i); | ||
3306 | |||
3307 | kvm_run->exit_reason = KVM_EXIT_UNKNOWN; | ||
3308 | kvm_run->hw.hardware_exit_reason = EXIT_REASON_EPT_MISCONFIG; | ||
3309 | |||
3310 | return 0; | ||
3311 | } | ||
3312 | |||
3230 | static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 3313 | static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |
3231 | { | 3314 | { |
3232 | u32 cpu_based_vm_exec_control; | 3315 | u32 cpu_based_vm_exec_control; |
@@ -3306,8 +3389,9 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu, | |||
3306 | [EXIT_REASON_APIC_ACCESS] = handle_apic_access, | 3389 | [EXIT_REASON_APIC_ACCESS] = handle_apic_access, |
3307 | [EXIT_REASON_WBINVD] = handle_wbinvd, | 3390 | [EXIT_REASON_WBINVD] = handle_wbinvd, |
3308 | [EXIT_REASON_TASK_SWITCH] = handle_task_switch, | 3391 | [EXIT_REASON_TASK_SWITCH] = handle_task_switch, |
3309 | [EXIT_REASON_EPT_VIOLATION] = handle_ept_violation, | ||
3310 | [EXIT_REASON_MCE_DURING_VMENTRY] = handle_machine_check, | 3392 | [EXIT_REASON_MCE_DURING_VMENTRY] = handle_machine_check, |
3393 | [EXIT_REASON_EPT_VIOLATION] = handle_ept_violation, | ||
3394 | [EXIT_REASON_EPT_MISCONFIG] = handle_ept_misconfig, | ||
3311 | }; | 3395 | }; |
3312 | 3396 | ||
3313 | static const int kvm_vmx_max_exit_handlers = | 3397 | static const int kvm_vmx_max_exit_handlers = |