/* * Kernel-based Virtual Machine driver for Linux * * This module enables machines with Intel VT-x extensions to run virtual * machines without emulation or binary translation. * * Debug support * * Copyright (C) 2006 Qumranet, Inc. * * Authors: * Yaniv Kamay * Avi Kivity * */ #include #include #include #include #include "mmu.h" #include "lapic.h" #include "debug.h" #include "x86.h" #ifdef KVM_DEBUG static unsigned long vmcs_readl(unsigned long field) { unsigned long value; asm volatile (ASM_VMX_VMREAD_RDX_RAX : "=a"(value) : "d"(field) : "cc"); return value; } static u16 vmcs_read16(unsigned long field) { return vmcs_readl(field); } static u32 vmcs_read32(unsigned long field) { return vmcs_readl(field); } static u64 vmcs_read64(unsigned long field) { #ifdef CONFIG_X86_64 return vmcs_readl(field); #else return vmcs_readl(field) | ((u64)vmcs_readl(field+1) << 32); #endif } void show_code(struct kvm_vcpu *vcpu) { gva_t rip = vmcs_readl(GUEST_RIP); u8 code[50]; char buf[30 + 3 * sizeof code]; int i; gpa_t gpa; if (!is_long_mode(vcpu)) rip += vmcs_readl(GUEST_CS_BASE); gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, rip, 0, NULL); if (gpa == UNMAPPED_GVA) return; kvm_read_guest(vcpu->kvm, gpa, code, sizeof code); for (i = 0; i < sizeof code; ++i) sprintf(buf + i * 3, " %02x", code[i]); vcpu_printf(vcpu, "code: %lx%s\n", rip, buf); } struct gate_struct { u16 offset_low; u16 segment; unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1; u16 offset_middle; u32 offset_high; u32 zero1; } __attribute__((packed)); void show_irq(struct kvm_vcpu *vcpu, int irq) { unsigned long idt_base = vmcs_readl(GUEST_IDTR_BASE); unsigned long idt_limit = vmcs_readl(GUEST_IDTR_LIMIT); struct gate_struct gate; gpa_t gpa; if (!is_long_mode(vcpu)) vcpu_printf(vcpu, "%s: not in long mode\n", __FUNCTION__); if (!is_long_mode(vcpu) || idt_limit < irq * sizeof(gate)) { vcpu_printf(vcpu, "%s: 0x%x read_guest err\n", __FUNCTION__, irq); return; } gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, idt_base + irq * sizeof(gate), 0, NULL); if (gpa == UNMAPPED_GVA) return; if (kvm_read_guest(vcpu->kvm, gpa, &gate, sizeof(gate)) != sizeof(gate)) { vcpu_printf(vcpu, "%s: 0x%x read_guest err\n", __FUNCTION__, irq); return; } vcpu_printf(vcpu, "%s: 0x%x handler 0x%llx\n", __FUNCTION__, irq, ((u64)gate.offset_high << 32) | ((u64)gate.offset_middle << 16) | gate.offset_low); } void show_page(struct kvm_vcpu *vcpu, gva_t addr) { u64 *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); gpa_t gpa; if (!buf) return; addr &= PAGE_MASK; gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, 0, NULL); if (gpa == UNMAPPED_GVA) return; if (kvm_read_guest(vcpu->kvm, gpa, buf, PAGE_SIZE)) { int i; for (i = 0; i < PAGE_SIZE / sizeof(u64) ; i++) { u8 *ptr = (u8*)&buf[i]; int j; vcpu_printf(vcpu, " 0x%16.16lx:", addr + i * sizeof(u64)); for (j = 0; j < sizeof(u64) ; j++) vcpu_printf(vcpu, " 0x%2.2x", ptr[j]); vcpu_printf(vcpu, "\n"); } } kfree(buf); } void show_u64(struct kvm_vcpu *vcpu, gva_t addr) { u64 buf; gpa_t gpa; gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, 0, NULL); if (gpa == UNMAPPED_GVA) return; if (kvm_read_guest(vcpu->kvm, gpa, &buf, sizeof(u64)) == sizeof(u64)) { u8 *ptr = (u8*)&buf; int j; vcpu_printf(vcpu, " 0x%16.16lx:", addr); for (j = 0; j < sizeof(u64) ; j++) vcpu_printf(vcpu, " 0x%2.2x", ptr[j]); vcpu_printf(vcpu, "\n"); } } #define IA32_DEBUGCTL_RESERVED_BITS 0xfffffffffffffe3cULL static int is_canonical(unsigned long addr) { return addr == ((long)addr << 16) >> 16; } int vm_entry_test_guest(struct kvm_vcpu *vcpu) { unsigned long cr0; unsigned long cr4; unsigned long cr3; unsigned long dr7; u64 ia32_debugctl; unsigned long sysenter_esp; unsigned long sysenter_eip; unsigned long rflags; unsigned long cpu_exec_ctrl, cpu_secondary_exec_ctrl; unsigned long tpr_threshold; int long_mode; int virtual8086; #define RFLAGS_VM (1 << 17) #define RFLAGS_RF (1 << 9) #define VIR8086_SEG_BASE_TEST(seg)\ if (vmcs_readl(GUEST_##seg##_BASE) != \ (unsigned long)vmcs_read16(GUEST_##seg##_SELECTOR) << 4) {\ vcpu_printf(vcpu, "%s: "#seg" base 0x%lx in "\ "virtual8086 is not "#seg" selector 0x%x"\ " shifted right 4 bits\n",\ __FUNCTION__,\ vmcs_readl(GUEST_##seg##_BASE),\ vmcs_read16(GUEST_##seg##_SELECTOR));\ return 0;\ } #define VIR8086_SEG_LIMIT_TEST(seg)\ if (vmcs_readl(GUEST_##seg##_LIMIT) != 0x0ffff) { \ vcpu_printf(vcpu, "%s: "#seg" limit 0x%lx in "\ "virtual8086 is not 0xffff\n",\ __FUNCTION__,\ vmcs_readl(GUEST_##seg##_LIMIT));\ return 0;\ } #define VIR8086_SEG_AR_TEST(seg)\ if (vmcs_read32(GUEST_##seg##_AR_BYTES) != 0x0f3) { \ vcpu_printf(vcpu, "%s: "#seg" AR 0x%x in "\ "virtual8086 is not 0xf3\n",\ __FUNCTION__,\ vmcs_read32(GUEST_##seg##_AR_BYTES));\ return 0;\ } cr0 = vmcs_readl(GUEST_CR0); if (!(cr0 & X86_CR0_PG)) { vcpu_printf(vcpu, "%s: cr0 0x%lx, PG is not set\n", __FUNCTION__, cr0); return 0; } if (!(cr0 & X86_CR0_PE)) { vcpu_printf(vcpu, "%s: cr0 0x%lx, PE is not set\n", __FUNCTION__, cr0); return 0; } if (!(cr0 & X86_CR0_NE)) { vcpu_printf(vcpu, "%s: cr0 0x%lx, NE is not set\n", __FUNCTION__, cr0); return 0; } if (!(cr0 & X86_CR0_WP)) { vcpu_printf(vcpu, "%s: cr0 0x%lx, WP is not set\n", __FUNCTION__, cr0); } cr4 = vmcs_readl(GUEST_CR4); if (!(cr4 & X86_CR4_VMXE)) { vcpu_printf(vcpu, "%s: cr4 0x%lx, VMXE is not set\n", __FUNCTION__, cr4); return 0; } if (!(cr4 & X86_CR4_PAE)) { vcpu_printf(vcpu, "%s: cr4 0x%lx, PAE is not set\n", __FUNCTION__, cr4); } ia32_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL); if (ia32_debugctl & IA32_DEBUGCTL_RESERVED_BITS ) { vcpu_printf(vcpu, "%s: ia32_debugctl 0x%llx, reserve bits\n", __FUNCTION__, ia32_debugctl); return 0; } long_mode = is_long_mode(vcpu); if (long_mode) { } if ( long_mode && !(cr4 & X86_CR4_PAE)) { vcpu_printf(vcpu, "%s: long mode and not PAE\n", __FUNCTION__); return 0; } cr3 = vmcs_readl(GUEST_CR3); if (cr3 & CR3_L_MODE_RESERVED_BITS) { vcpu_printf(vcpu, "%s: cr3 0x%lx, reserved bits\n", __FUNCTION__, cr3); return 0; } if ( !long_mode && (cr4 & X86_CR4_PAE)) { /* check the 4 PDPTEs for reserved bits */ unsigned long pdpt_pfn = cr3 >> PAGE_SHIFT; int i; u64 pdpte; unsigned offset = (cr3 & (PAGE_SIZE-1)) >> 5; u64 *pdpt = kmap_atomic(pfn_to_page(pdpt_pfn), KM_USER0); for (i = 0; i < 4; ++i) { pdpte = pdpt[offset + i]; if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) break; } kunmap_atomic(pdpt, KM_USER0); if (i != 4) { vcpu_printf(vcpu, "%s: pae cr3[%d] 0x%llx, reserved bits\n", __FUNCTION__, i, pdpte); return 0; } } dr7 = vmcs_readl(GUEST_DR7); if (dr7 & ~((1ULL << 32) - 1)) { vcpu_printf(vcpu, "%s: dr7 0x%lx, reserved bits\n", __FUNCTION__, dr7); return 0; } sysenter_esp = vmcs_readl(GUEST_SYSENTER_ESP); if (!is_canonical(sysenter_esp)) { vcpu_printf(vcpu, "%s: sysenter_esp 0x%lx, not canonical\n", __FUNCTION__, sysenter_esp); return 0; } sysenter_eip = vmcs_readl(GUEST_SYSENTER_EIP); if (!is_canonical(sysenter_eip)) { vcpu_printf(vcpu, "%s: sysenter_eip 0x%lx, not canonical\n", __FUNCTION__, sysenter_eip); return 0; } rflags = vmcs_readl(GUEST_RFLAGS); virtual8086 = rflags & RFLAGS_VM; if (vmcs_read16(GUEST_TR_SELECTOR) & SELECTOR_TI_MASK) { vcpu_printf(vcpu, "%s: tr selctor 0x%x, TI is set\n", __FUNCTION__, vmcs_read16(GUEST_TR_SELECTOR)); return 0; } if (!(vmcs_read32(GUEST_LDTR_AR_BYTES) & AR_UNUSABLE_MASK) && vmcs_read16(GUEST_LDTR_SELECTOR) & SELECTOR_TI_MASK) { vcpu_printf(vcpu, "%s: ldtr selctor 0x%x," " is usable and TI is set\n", __FUNCTION__, vmcs_read16(GUEST_LDTR_SELECTOR)); return 0; } if (!virtual8086 && (vmcs_read16(GUEST_SS_SELECTOR) & SELECTOR_RPL_MASK) != (vmcs_read16(GUEST_CS_SELECTOR) & SELECTOR_RPL_MASK)) { vcpu_printf(vcpu, "%s: ss selctor 0x%x cs selctor 0x%x," " not same RPL\n", __FUNCTION__, vmcs_read16(GUEST_SS_SELECTOR), vmcs_read16(GUEST_CS_SELECTOR)); return 0; } if (virtual8086) { VIR8086_SEG_BASE_TEST(CS); VIR8086_SEG_BASE_TEST(SS); VIR8086_SEG_BASE_TEST(DS); VIR8086_SEG_BASE_TEST(ES); VIR8086_SEG_BASE_TEST(FS); VIR8086_SEG_BASE_TEST(GS); } if (!is_canonical(vmcs_readl(GUEST_TR_BASE)) || !is_canonical(vmcs_readl(GUEST_FS_BASE)) || !is_canonical(vmcs_readl(GUEST_GS_BASE)) ) { vcpu_printf(vcpu, "%s: TR 0x%lx FS 0x%lx or GS 0x%lx base" " is not canonical\n", __FUNCTION__, vmcs_readl(GUEST_TR_BASE), vmcs_readl(GUEST_FS_BASE), vmcs_readl(GUEST_GS_BASE)); return 0; } if (!(vmcs_read32(GUEST_LDTR_AR_BYTES) & AR_UNUSABLE_MASK) && !is_canonical(vmcs_readl(GUEST_LDTR_BASE))) { vcpu_printf(vcpu, "%s: LDTR base 0x%lx, usable and is not" " canonical\n", __FUNCTION__, vmcs_readl(GUEST_LDTR_BASE)); return 0; } if ((vmcs_readl(GUEST_CS_BASE) & ~((1ULL << 32) - 1))) { vcpu_printf(vcpu, "%s: CS base 0x%lx, not all bits 63-32" " are zero\n", __FUNCTION__, vmcs_readl(GUEST_CS_BASE)); return 0; } #define SEG_BASE_TEST(seg)\ if ( !(vmcs_read32(GUEST_##seg##_AR_BYTES) & AR_UNUSABLE_MASK) &&\ (vmcs_readl(GUEST_##seg##_BASE) & ~((1ULL << 32) - 1))) {\ vcpu_printf(vcpu, "%s: "#seg" base 0x%lx, is usable and not"\ " all bits 63-32 are zero\n",\ __FUNCTION__,\ vmcs_readl(GUEST_##seg##_BASE));\ return 0;\ } SEG_BASE_TEST(SS); SEG_BASE_TEST(DS); SEG_BASE_TEST(ES); if (virtual8086) { VIR8086_SEG_LIMIT_TEST(CS); VIR8086_SEG_LIMIT_TEST(SS); VIR8086_SEG_LIMIT_TEST(DS); VIR8086_SEG_LIMIT_TEST(ES); VIR8086_SEG_LIMIT_TEST(FS); VIR8086_SEG_LIMIT_TEST(GS); } if (virtual8086) { VIR8086_SEG_AR_TEST(CS); VIR8086_SEG_AR_TEST(SS); VIR8086_SEG_AR_TEST(DS); VIR8086_SEG_AR_TEST(ES); VIR8086_SEG_AR_TEST(FS); VIR8086_SEG_AR_TEST(GS); } else { u32 cs_ar = vmcs_read32(GUEST_CS_AR_BYTES); u32 ss_ar = vmcs_read32(GUEST_SS_AR_BYTES); u32 tr_ar = vmcs_read32(GUEST_TR_AR_BYTES); u32 ldtr_ar = vmcs_read32(GUEST_LDTR_AR_BYTES); #define SEG_G_TEST(seg) { \ u32 lim = vmcs_read32(GUEST_##seg##_LIMIT); \ u32 ar = vmcs_read32(GUEST_##seg##_AR_BYTES); \ int err = 0; \ if (((lim & ~PAGE_MASK) != ~PAGE_MASK) && (ar & AR_G_MASK)) \ err = 1; \ if ((lim & ~((1u << 20) - 1)) && !(ar & AR_G_MASK)) \ err = 1; \ if (err) { \ vcpu_printf(vcpu, "%s: "#seg" AR 0x%x, G err. lim" \ " is 0x%x\n", \ __FUNCTION__, \ ar, lim); \ return 0; \ } \ } if (!(cs_ar & AR_TYPE_ACCESSES_MASK)) { vcpu_printf(vcpu, "%s: cs AR 0x%x, accesses is clear\n", __FUNCTION__, cs_ar); return 0; } if (!(cs_ar & AR_TYPE_CODE_MASK)) { vcpu_printf(vcpu, "%s: cs AR 0x%x, code is clear\n", __FUNCTION__, cs_ar); return 0; } if (!(cs_ar & AR_S_MASK)) { vcpu_printf(vcpu, "%s: cs AR 0x%x, type is sys\n", __FUNCTION__, cs_ar); return 0; } if ((cs_ar & AR_TYPE_MASK) >= 8 && (cs_ar & AR_TYPE_MASK) < 12 && AR_DPL(cs_ar) != (vmcs_read16(GUEST_CS_SELECTOR) & SELECTOR_RPL_MASK) ) { vcpu_printf(vcpu, "%s: cs AR 0x%x, " "DPL(0x%x) not as RPL(0x%x)\n", __FUNCTION__, cs_ar, AR_DPL(cs_ar), vmcs_read16(GUEST_CS_SELECTOR) & SELECTOR_RPL_MASK); return 0; } if ((cs_ar & AR_TYPE_MASK) >= 13 && (cs_ar & AR_TYPE_MASK) < 16 && AR_DPL(cs_ar) > (vmcs_read16(GUEST_CS_SELECTOR) & SELECTOR_RPL_MASK) ) { vcpu_printf(vcpu, "%s: cs AR 0x%x, " "DPL greater than RPL\n", __FUNCTION__, cs_ar); return 0; } if (!(cs_ar & AR_P_MASK)) { vcpu_printf(vcpu, "%s: CS AR 0x%x, not " "present\n", __FUNCTION__, cs_ar); return 0; } if ((cs_ar & AR_RESERVD_MASK)) { vcpu_printf(vcpu, "%s: CS AR 0x%x, reseved" " bits are set\n", __FUNCTION__, cs_ar); return 0; } if (long_mode & (cs_ar & AR_L_MASK) && (cs_ar & AR_DB_MASK)) { vcpu_printf(vcpu, "%s: CS AR 0x%x, DB and L are set" " in long mode\n", __FUNCTION__, cs_ar); return 0; } SEG_G_TEST(CS); if (!(ss_ar & AR_UNUSABLE_MASK)) { if ((ss_ar & AR_TYPE_MASK) != 3 && (ss_ar & AR_TYPE_MASK) != 7 ) { vcpu_printf(vcpu, "%s: ss AR 0x%x, usable and type" " is not 3 or 7\n", __FUNCTION__, ss_ar); return 0; } if (!(ss_ar & AR_S_MASK)) { vcpu_printf(vcpu, "%s: ss AR 0x%x, usable and" " is sys\n", __FUNCTION__, ss_ar); return 0; } if (!(ss_ar & AR_P_MASK)) { vcpu_printf(vcpu, "%s: SS AR 0x%x, usable" " and not present\n", __FUNCTION__, ss_ar); return 0; } if ((ss_ar & AR_RESERVD_MASK)) { vcpu_printf(vcpu, "%s: SS AR 0x%x, reseved" " bits are set\n", __FUNCTION__, ss_ar); return 0; } SEG_G_TEST(SS); } if (AR_DPL(ss_ar) != (vmcs_read16(GUEST_SS_SELECTOR) & SELECTOR_RPL_MASK) ) { vcpu_printf(vcpu, "%s: SS AR 0x%x, " "DPL not as RPL\n", __FUNCTION__, ss_ar); return 0; } #define SEG_AR_TEST(seg) {\ u32 ar = vmcs_read32(GUEST_##seg##_AR_BYTES);\ if (!(ar & AR_UNUSABLE_MASK)) {\ if (!(ar & AR_TYPE_ACCESSES_MASK)) {\ vcpu_printf(vcpu, "%s: "#seg" AR 0x%x, "\ "usable and not accesses\n",\ __FUNCTION__,\ ar);\ return 0;\ }\ if ((ar & AR_TYPE_CODE_MASK) &&\ !(ar & AR_TYPE_READABLE_MASK)) {\ vcpu_printf(vcpu, "%s: "#seg" AR 0x%x, "\ "code and not readable\n",\ __FUNCTION__,\ ar);\ return 0;\ }\ if (!(ar & AR_S_MASK)) {\ vcpu_printf(vcpu, "%s: "#seg" AR 0x%x, usable and"\ " is sys\n",\ __FUNCTION__,\ ar);\ return 0;\ }\ if ((ar & AR_TYPE_MASK) >= 0 && \ (ar & AR_TYPE_MASK) < 12 && \ AR_DPL(ar) < (vmcs_read16(GUEST_##seg##_SELECTOR) & \ SELECTOR_RPL_MASK) ) {\ vcpu_printf(vcpu, "%s: "#seg" AR 0x%x, "\ "DPL less than RPL\n",\ __FUNCTION__,\ ar);\ return 0;\ }\ if (!(ar & AR_P_MASK)) {\ vcpu_printf(vcpu, "%s: "#seg" AR 0x%x, usable and"\ " not present\n",\ __FUNCTION__,\ ar);\ return 0;\ }\ if ((ar & AR_RESERVD_MASK)) {\ vcpu_printf(vcpu, "%s: "#seg" AR"\ " 0x%x, reseved"\ " bits are set\n",\ __FUNCTION__,\ ar);\ return 0;\ }\ SEG_G_TEST(seg)\ }\ } #undef DS #undef ES #undef FS #undef GS SEG_AR_TEST(DS); SEG_AR_TEST(ES); SEG_AR_TEST(FS); SEG_AR_TEST(GS); // TR test if (long_mode) { if ((tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) { vcpu_printf(vcpu, "%s: TR AR 0x%x, long" " mode and not 64bit busy" " tss\n", __FUNCTION__, tr_ar); return 0; } } else { if ((tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_32_TSS && (tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_16_TSS) { vcpu_printf(vcpu, "%s: TR AR 0x%x, legacy" " mode and not 16/32bit " "busy tss\n", __FUNCTION__, tr_ar); return 0; } } if ((tr_ar & AR_S_MASK)) { vcpu_printf(vcpu, "%s: TR AR 0x%x, S is set\n", __FUNCTION__, tr_ar); return 0; } if (!(tr_ar & AR_P_MASK)) { vcpu_printf(vcpu, "%s: TR AR 0x%x, P is not set\n", __FUNCTION__, tr_ar); return 0; } if ((tr_ar & (AR_RESERVD_MASK| AR_UNUSABLE_MASK))) { vcpu_printf(vcpu, "%s: TR AR 0x%x, reserved bit are" " set\n", __FUNCTION__, tr_ar); return 0; } SEG_G_TEST(TR); // TR test if (!(ldtr_ar & AR_UNUSABLE_MASK)) { if ((ldtr_ar & AR_TYPE_MASK) != AR_TYPE_LDT) { vcpu_printf(vcpu, "%s: LDTR AR 0x%x," " bad type\n", __FUNCTION__, ldtr_ar); return 0; } if ((ldtr_ar & AR_S_MASK)) { vcpu_printf(vcpu, "%s: LDTR AR 0x%x," " S is set\n", __FUNCTION__, ldtr_ar); return 0; } if (!(ldtr_ar & AR_P_MASK)) { vcpu_printf(vcpu, "%s: LDTR AR 0x%x," " P is not set\n", __FUNCTION__, ldtr_ar); return 0; } if ((ldtr_ar & AR_RESERVD_MASK)) { vcpu_printf(vcpu, "%s: LDTR AR 0x%x," " reserved bit are set\n", __FUNCTION__, ldtr_ar); return 0; } SEG_G_TEST(LDTR); } } // GDTR and IDTR #define IDT_GDT_TEST(reg)\ if (!is_canonical(vmcs_readl(GUEST_##reg##_BASE))) {\ vcpu_printf(vcpu, "%s: "#reg" BASE 0x%lx, not canonical\n",\ __FUNCTION__,\ vmcs_readl(GUEST_##reg##_BASE));\ return 0;\ }\ if (vmcs_read32(GUEST_##reg##_LIMIT) >> 16) {\ vcpu_printf(vcpu, "%s: "#reg" LIMIT 0x%x, size err\n",\ __FUNCTION__,\ vmcs_read32(GUEST_##reg##_LIMIT));\ return 0;\ }\ IDT_GDT_TEST(GDTR); IDT_GDT_TEST(IDTR); // RIP if ((!long_mode || !(vmcs_read32(GUEST_CS_AR_BYTES) & AR_L_MASK)) && vmcs_readl(GUEST_RIP) & ~((1ULL << 32) - 1) ){ vcpu_printf(vcpu, "%s: RIP 0x%lx, size err\n", __FUNCTION__, vmcs_readl(GUEST_RIP)); return 0; } if (!is_canonical(vmcs_readl(GUEST_RIP))) { vcpu_printf(vcpu, "%s: RIP 0x%lx, not canonical\n", __FUNCTION__, vmcs_readl(GUEST_RIP)); return 0; } // RFLAGS #define RFLAGS_RESEVED_CLEAR_BITS\ (~((1ULL << 22) - 1) | (1ULL << 15) | (1ULL << 5) | (1ULL << 3)) #define RFLAGS_RESEVED_SET_BITS (1 << 1) if ((rflags & RFLAGS_RESEVED_CLEAR_BITS) || !(rflags & RFLAGS_RESEVED_SET_BITS)) { vcpu_printf(vcpu, "%s: RFLAGS 0x%lx, reserved bits 0x%llx 0x%x\n", __FUNCTION__, rflags, RFLAGS_RESEVED_CLEAR_BITS, RFLAGS_RESEVED_SET_BITS); return 0; } if (long_mode && virtual8086) { vcpu_printf(vcpu, "%s: RFLAGS 0x%lx, vm and long mode\n", __FUNCTION__, rflags); return 0; } if (!(rflags & RFLAGS_RF)) { u32 vm_entry_info = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD); if ((vm_entry_info & INTR_INFO_VALID_MASK) && (vm_entry_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_EXT_INTR) { vcpu_printf(vcpu, "%s: RFLAGS 0x%lx, external" " interrupt and RF is clear\n", __FUNCTION__, rflags); return 0; } } cpu_exec_ctrl = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); cpu_secondary_exec_ctrl = vmcs_read32(SECONDARY_VM_EXEC_CONTROL); tpr_threshold = vmcs_read32(TPR_THRESHOLD); if ((cpu_exec_ctrl & CPU_BASED_TPR_SHADOW)) { if (tpr_threshold & ~0xf) { vcpu_printf(vcpu, "%s: if TPR shadow execution control" " is 1 bits 31:4 of TPR threshold must" " be 0", __FUNCTION__); return 0; } if (!(cpu_secondary_exec_ctrl & SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) { u32 apic_tpr = *((u32 *)(vcpu->arch.apic->regs + 0x80)); apic_tpr >>= 4; if (tpr_threshold > apic_tpr) { vcpu_printf(vcpu, "%s: if TPR shadow execution control" " is 1 and virtual apic accesses is 0" " the value of bits 3:0 of the TPR " "threshold VM-execution control field" " should not be greater than the value" " of bits 7:4 in byte 80H on the " "virtual-APIC page", __FUNCTION__); return 0; } } } // to be continued from Checks on Guest Non-Register State (22.3.1.5) return 1; } static int check_fixed_bits(struct kvm_vcpu *vcpu, const char *reg, unsigned long cr, u32 msr_fixed_0, u32 msr_fixed_1) { u64 fixed_bits_0, fixed_bits_1; rdmsrl(msr_fixed_0, fixed_bits_0); rdmsrl(msr_fixed_1, fixed_bits_1); if ((cr & fixed_bits_0) != fixed_bits_0) { vcpu_printf(vcpu, "%s: %s (%lx) has one of %llx unset\n", __FUNCTION__, reg, cr, fixed_bits_0); return 0; } if ((~cr & ~fixed_bits_1) != ~fixed_bits_1) { vcpu_printf(vcpu, "%s: %s (%lx) has one of %llx set\n", __FUNCTION__, reg, cr, ~fixed_bits_1); return 0; } return 1; } static int phys_addr_width(void) { unsigned eax, ebx, ecx, edx; cpuid(0x80000008, &eax, &ebx, &ecx, &edx); return eax & 0xff; } static int check_canonical(struct kvm_vcpu *vcpu, const char *name, unsigned long reg) { #ifdef CONFIG_X86_64 unsigned long x; if (sizeof(reg) == 4) return 1; x = (long)reg >> 48; if (!(x == 0 || x == ~0UL)) { vcpu_printf(vcpu, "%s: %s (%lx) not canonical\n", __FUNCTION__, name, reg); return 0; } #endif return 1; } static int check_selector(struct kvm_vcpu *vcpu, const char *name, int rpl_ti, int null, u16 sel) { if (rpl_ti && (sel & 7)) { vcpu_printf(vcpu, "%s: %s (%x) nonzero rpl or ti\n", __FUNCTION__, name, sel); return 0; } if (null && !sel) { vcpu_printf(vcpu, "%s: %s (%x) zero\n", __FUNCTION__, name, sel); return 0; } return 1; } //#define MSR_IA32_VMX_CR0_FIXED0 0x486 //#define MSR_IA32_VMX_CR0_FIXED1 0x487 //#define MSR_IA32_VMX_CR4_FIXED0 0x488 //#define MSR_IA32_VMX_CR4_FIXED1 0x489 #define VM_EXIT_HOST_ADD_SPACE_SIZE 0x00000200 int vm_entry_test_host(struct kvm_vcpu *vcpu) { int r = 1; unsigned long cr0 = vmcs_readl(HOST_CR0); unsigned long cr4 = vmcs_readl(HOST_CR4); unsigned long cr3 = vmcs_readl(HOST_CR3); int host_64; host_64 = vmcs_read32(VM_EXIT_CONTROLS) & VM_EXIT_HOST_ADD_SPACE_SIZE; /* 22.2.2 */ r &= check_fixed_bits(vcpu, "host cr0", cr0, MSR_IA32_VMX_CR0_FIXED0, MSR_IA32_VMX_CR0_FIXED1); r &= check_fixed_bits(vcpu, "host cr0", cr4, MSR_IA32_VMX_CR4_FIXED0, MSR_IA32_VMX_CR4_FIXED1); if ((u64)cr3 >> phys_addr_width()) { vcpu_printf(vcpu, "%s: cr3 (%lx) vs phys addr width\n", __FUNCTION__, cr3); r = 0; } r &= check_canonical(vcpu, "host ia32_sysenter_eip", vmcs_readl(HOST_IA32_SYSENTER_EIP)); r &= check_canonical(vcpu, "host ia32_sysenter_esp", vmcs_readl(HOST_IA32_SYSENTER_ESP)); /* 22.2.3 */ r &= check_selector(vcpu, "host cs", 1, 1, vmcs_read16(HOST_CS_SELECTOR)); r &= check_selector(vcpu, "host ss", 1, !host_64, vmcs_read16(HOST_SS_SELECTOR)); r &= check_selector(vcpu, "host ds", 1, 0, vmcs_read16(HOST_DS_SELECTOR)); r &= check_selector(vcpu, "host es", 1, 0, vmcs_read16(HOST_ES_SELECTOR)); r &= check_selector(vcpu, "host fs", 1, 0, vmcs_read16(HOST_FS_SELECTOR)); r &= check_selector(vcpu, "host gs", 1, 0, vmcs_read16(HOST_GS_SELECTOR)); r &= check_selector(vcpu, "host tr", 1, 1, vmcs_read16(HOST_TR_SELECTOR)); #ifdef CONFIG_X86_64 r &= check_canonical(vcpu, "host fs base", vmcs_readl(HOST_FS_BASE)); r &= check_canonical(vcpu, "host gs base", vmcs_readl(HOST_GS_BASE)); r &= check_canonical(vcpu, "host gdtr base", vmcs_readl(HOST_GDTR_BASE)); r &= check_canonical(vcpu, "host idtr base", vmcs_readl(HOST_IDTR_BASE)); #endif /* 22.2.4 */ #ifdef CONFIG_X86_64 if (!host_64) { vcpu_printf(vcpu, "%s: vm exit controls: !64 bit host\n", __FUNCTION__); r = 0; } if (!(cr4 & X86_CR4_PAE)) { vcpu_printf(vcpu, "%s: cr4 (%lx): !pae\n", __FUNCTION__, cr4); r = 0; } r &= check_canonical(vcpu, "host rip", vmcs_readl(HOST_RIP)); #endif return r; } int vm_entry_test(struct kvm_vcpu *vcpu) { int rg, rh; rg = vm_entry_test_guest(vcpu); rh = vm_entry_test_host(vcpu); return rg && rh; } void vmcs_dump(struct kvm_vcpu *vcpu) { vcpu_printf(vcpu, "************************ vmcs_dump ************************\n"); vcpu_printf(vcpu, "VM_ENTRY_CONTROLS 0x%x\n", vmcs_read32(VM_ENTRY_CONTROLS)); vcpu_printf(vcpu, "GUEST_CR0 0x%lx\n", vmcs_readl(GUEST_CR0)); vcpu_printf(vcpu, "GUEST_CR3 0x%lx\n", vmcs_readl(GUEST_CR3)); vcpu_printf(vcpu, "GUEST_CR4 0x%lx\n", vmcs_readl(GUEST_CR4)); vcpu_printf(vcpu, "GUEST_SYSENTER_ESP 0x%lx\n", vmcs_readl(GUEST_SYSENTER_ESP)); vcpu_printf(vcpu, "GUEST_SYSENTER_EIP 0x%lx\n", vmcs_readl(GUEST_SYSENTER_EIP)); vcpu_printf(vcpu, "GUEST_IA32_DEBUGCTL 0x%llx\n", vmcs_read64(GUEST_IA32_DEBUGCTL)); vcpu_printf(vcpu, "GUEST_DR7 0x%lx\n", vmcs_readl(GUEST_DR7)); vcpu_printf(vcpu, "GUEST_RFLAGS 0x%lx\n", vmcs_readl(GUEST_RFLAGS)); vcpu_printf(vcpu, "GUEST_RIP 0x%lx\n", vmcs_readl(GUEST_RIP)); vcpu_printf(vcpu, "GUEST_CS_SELECTOR 0x%x\n", vmcs_read16(GUEST_CS_SELECTOR)); vcpu_printf(vcpu, "GUEST_DS_SELECTOR 0x%x\n", vmcs_read16(GUEST_DS_SELECTOR)); vcpu_printf(vcpu, "GUEST_ES_SELECTOR 0x%x\n", vmcs_read16(GUEST_ES_SELECTOR)); vcpu_printf(vcpu, "GUEST_FS_SELECTOR 0x%x\n", vmcs_read16(GUEST_FS_SELECTOR)); vcpu_printf(vcpu, "GUEST_GS_SELECTOR 0x%x\n", vmcs_read16(GUEST_GS_SELECTOR)); vcpu_printf(vcpu, "GUEST_SS_SELECTOR 0x%x\n", vmcs_read16(GUEST_SS_SELECTOR)); vcpu_printf(vcpu, "GUEST_TR_SELECTOR 0x%x\n", vmcs_read16(GUEST_TR_SELECTOR)); vcpu_printf(vcpu, "GUEST_LDTR_SELECTOR 0x%x\n", vmcs_read16(GUEST_LDTR_SELECTOR)); vcpu_printf(vcpu, "GUEST_CS_AR_BYTES 0x%x\n", vmcs_read32(GUEST_CS_AR_BYTES)); vcpu_printf(vcpu, "GUEST_DS_AR_BYTES 0x%x\n", vmcs_read32(GUEST_DS_AR_BYTES)); vcpu_printf(vcpu, "GUEST_ES_AR_BYTES 0x%x\n", vmcs_read32(GUEST_ES_AR_BYTES)); vcpu_printf(vcpu, "GUEST_FS_AR_BYTES 0x%x\n", vmcs_read32(GUEST_FS_AR_BYTES)); vcpu_printf(vcpu, "GUEST_GS_AR_BYTES 0x%x\n", vmcs_read32(GUEST_GS_AR_BYTES)); vcpu_printf(vcpu, "GUEST_SS_AR_BYTES 0x%x\n", vmcs_read32(GUEST_SS_AR_BYTES)); vcpu_printf(vcpu, "GUEST_LDTR_AR_BYTES 0x%x\n", vmcs_read32(GUEST_LDTR_AR_BYTES)); vcpu_printf(vcpu, "GUEST_TR_AR_BYTES 0x%x\n", vmcs_read32(GUEST_TR_AR_BYTES)); vcpu_printf(vcpu, "GUEST_CS_BASE 0x%lx\n", vmcs_readl(GUEST_CS_BASE)); vcpu_printf(vcpu, "GUEST_DS_BASE 0x%lx\n", vmcs_readl(GUEST_DS_BASE)); vcpu_printf(vcpu, "GUEST_ES_BASE 0x%lx\n", vmcs_readl(GUEST_ES_BASE)); vcpu_printf(vcpu, "GUEST_FS_BASE 0x%lx\n", vmcs_readl(GUEST_FS_BASE)); vcpu_printf(vcpu, "GUEST_GS_BASE 0x%lx\n", vmcs_readl(GUEST_GS_BASE)); vcpu_printf(vcpu, "GUEST_SS_BASE 0x%lx\n", vmcs_readl(GUEST_SS_BASE)); vcpu_printf(vcpu, "GUEST_LDTR_BASE 0x%lx\n", vmcs_readl(GUEST_LDTR_BASE)); vcpu_printf(vcpu, "GUEST_TR_BASE 0x%lx\n", vmcs_readl(GUEST_TR_BASE)); vcpu_printf(vcpu, "GUEST_CS_LIMIT 0x%x\n", vmcs_read32(GUEST_CS_LIMIT)); vcpu_printf(vcpu, "GUEST_DS_LIMIT 0x%x\n", vmcs_read32(GUEST_DS_LIMIT)); vcpu_printf(vcpu, "GUEST_ES_LIMIT 0x%x\n", vmcs_read32(GUEST_ES_LIMIT)); vcpu_printf(vcpu, "GUEST_FS_LIMIT 0x%x\n", vmcs_read32(GUEST_FS_LIMIT)); vcpu_printf(vcpu, "GUEST_GS_LIMIT 0x%x\n", vmcs_read32(GUEST_GS_LIMIT)); vcpu_printf(vcpu, "GUEST_SS_LIMIT 0x%x\n", vmcs_read32(GUEST_SS_LIMIT)); vcpu_printf(vcpu, "GUEST_LDTR_LIMIT 0x%x\n", vmcs_read32(GUEST_LDTR_LIMIT)); vcpu_printf(vcpu, "GUEST_TR_LIMIT 0x%x\n", vmcs_read32(GUEST_TR_LIMIT)); vcpu_printf(vcpu, "GUEST_GDTR_BASE 0x%lx\n", vmcs_readl(GUEST_GDTR_BASE)); vcpu_printf(vcpu, "GUEST_IDTR_BASE 0x%lx\n", vmcs_readl(GUEST_IDTR_BASE)); vcpu_printf(vcpu, "GUEST_GDTR_LIMIT 0x%x\n", vmcs_read32(GUEST_GDTR_LIMIT)); vcpu_printf(vcpu, "GUEST_IDTR_LIMIT 0x%x\n", vmcs_read32(GUEST_IDTR_LIMIT)); vcpu_printf(vcpu, "EXCEPTION_BITMAP 0x%x\n", vmcs_read32(EXCEPTION_BITMAP)); vcpu_printf(vcpu, "CPU_BASED_VM_EXEC_CONTROL 0x%x\n", vmcs_read32(CPU_BASED_VM_EXEC_CONTROL)); vcpu_printf(vcpu, "SECONDARY_VM_EXEC_CONTROL 0x%x\n", vmcs_read32(SECONDARY_VM_EXEC_CONTROL)); vcpu_printf(vcpu, "TPR_THREASHOLD 0x%x\n", vmcs_read32(TPR_THRESHOLD)); vcpu_printf(vcpu, "TPR 0x%x\n", *((u32 *) (vcpu->arch.apic->regs + 0x80))); vcpu_printf(vcpu, "***********************************************************\n"); } void regs_dump(struct kvm_vcpu *vcpu) { #define REG_DUMP(reg) \ vcpu_printf(vcpu, #reg" = 0x%lx(VCPU)\n", vcpu->arch.regs[VCPU_REGS_##reg]) #define VMCS_REG_DUMP(reg) \ vcpu_printf(vcpu, #reg" = 0x%lx(VMCS)\n", vmcs_readl(GUEST_##reg)) vcpu_printf(vcpu, "************************ regs_dump ************************\n"); REG_DUMP(RAX); REG_DUMP(RBX); REG_DUMP(RCX); REG_DUMP(RDX); REG_DUMP(RSP); REG_DUMP(RBP); REG_DUMP(RSI); REG_DUMP(RDI); #ifdef CONFIG_X86_64 REG_DUMP(R8); REG_DUMP(R9); REG_DUMP(R10); REG_DUMP(R11); REG_DUMP(R12); REG_DUMP(R13); REG_DUMP(R14); REG_DUMP(R15); #endif VMCS_REG_DUMP(RSP); VMCS_REG_DUMP(RIP); VMCS_REG_DUMP(RFLAGS); vcpu_printf(vcpu, "***********************************************************\n"); } void sregs_dump(struct kvm_vcpu *vcpu) { vcpu_printf(vcpu, "************************ sregs_dump ************************\n"); vcpu_printf(vcpu, "cr0 = 0x%lx\n", vcpu->arch.cr0); vcpu_printf(vcpu, "cr2 = 0x%lx\n", vcpu->arch.cr2); vcpu_printf(vcpu, "cr3 = 0x%lx\n", vcpu->arch.cr3); vcpu_printf(vcpu, "cr4 = 0x%lx\n", vcpu->arch.cr4); vcpu_printf(vcpu, "cr8 = 0x%lx\n", vcpu->arch.cr8); vcpu_printf(vcpu, "efer = 0x%llx\n", vcpu->arch.efer); vcpu_printf(vcpu, "***********************************************************\n"); } void show_pending_interrupts(struct kvm_vcpu *vcpu) { vcpu_printf(vcpu, "************************ pending interrupts ****************\n"); if (vcpu->arch.interrupt.pending) vcpu_printf(vcpu, "nr = %d%s\n", vcpu->arch.interrupt.nr, vcpu->arch.interrupt.soft?"(soft)":""); vcpu_printf(vcpu, "************************************************************\n"); } void vcpu_dump(struct kvm_vcpu *vcpu) { regs_dump(vcpu); sregs_dump(vcpu); vmcs_dump(vcpu); show_pending_interrupts(vcpu); /* more ... */ } #endif