diff options
author | Josh Wilsdon <jwilsdon@joyent.com> | 2011-04-06 16:00:25 -0700 |
---|---|---|
committer | Josh Wilsdon <jwilsdon@joyent.com> | 2011-04-06 16:00:25 -0700 |
commit | 8ddb3439b2f21ccfb06e6d0b4a8a1fb0f944cf07 (patch) | |
tree | 0f6315b0729487ed1aaf08d1fac3b1b247f4a41f /linux/x86 | |
parent | 4cfee15efd14f6dec47e679a3c29fe1718178095 (diff) | |
download | illumos-kvm-8ddb3439b2f21ccfb06e6d0b4a8a1fb0f944cf07.tar.gz |
[HVM-29] Add in Linux source from http://sourceforge.net/projects/kvm/files/kvm-kmod/2.6.34/kvm-kmod-2.6.34.tar.bz2/download (minus ia64 bits, powerpc bits and some scripts we definitely don't need)
Diffstat (limited to 'linux/x86')
-rw-r--r-- | linux/x86/Kbuild | 14 | ||||
-rw-r--r-- | linux/x86/Makefile.pre | 1 | ||||
-rw-r--r-- | linux/x86/debug.h | 23 | ||||
-rw-r--r-- | linux/x86/external-module-compat.h | 756 | ||||
-rw-r--r-- | linux/x86/preempt.c | 247 | ||||
-rw-r--r-- | linux/x86/vmx-debug.c | 1117 |
6 files changed, 2158 insertions, 0 deletions
diff --git a/linux/x86/Kbuild b/linux/x86/Kbuild new file mode 100644 index 0000000..fad05d5 --- /dev/null +++ b/linux/x86/Kbuild @@ -0,0 +1,14 @@ +obj-m := kvm.o kvm-intel.o kvm-amd.o +kvm-objs := kvm_main.o x86.o mmu.o emulate.o ../anon_inodes.o irq.o i8259.o \ + lapic.o ioapic.o preempt.o i8254.o coalesced_mmio.o irq_comm.o \ + timer.o eventfd.o assigned-dev.o \ + ../external-module-compat.o ../request-irq-compat.o +ifeq ($(CONFIG_IOMMU_API),y) +kvm-objs += iommu.o +endif +kvm-intel-objs := vmx.o vmx-debug.o +kvm-amd-objs := svm.o + +kvm-objs += ../srcu.o + +CFLAGS_kvm_main.o = -DKVM_MAIN diff --git a/linux/x86/Makefile.pre b/linux/x86/Makefile.pre new file mode 100644 index 0000000..e38baf1 --- /dev/null +++ b/linux/x86/Makefile.pre @@ -0,0 +1 @@ +prerequisite: diff --git a/linux/x86/debug.h b/linux/x86/debug.h new file mode 100644 index 0000000..3579365 --- /dev/null +++ b/linux/x86/debug.h @@ -0,0 +1,23 @@ +#ifndef __KVM_DEBUG_H +#define __KVM_DEBUG_H + +#ifdef KVM_DEBUG + +void show_msrs(struct kvm_vcpu *vcpu); + + +void show_irq(struct kvm_vcpu *vcpu, int irq); +void show_page(struct kvm_vcpu *vcpu, gva_t addr); +void show_u64(struct kvm_vcpu *vcpu, gva_t addr); +void show_code(struct kvm_vcpu *vcpu); +int vm_entry_test(struct kvm_vcpu *vcpu); + +void vmcs_dump(struct kvm_vcpu *vcpu); +void regs_dump(struct kvm_vcpu *vcpu); +void sregs_dump(struct kvm_vcpu *vcpu); +void show_pending_interrupts(struct kvm_vcpu *vcpu); +void vcpu_dump(struct kvm_vcpu *vcpu); + +#endif + +#endif diff --git a/linux/x86/external-module-compat.h b/linux/x86/external-module-compat.h new file mode 100644 index 0000000..5626954 --- /dev/null +++ b/linux/x86/external-module-compat.h @@ -0,0 +1,756 @@ + +/* + * Compatibility header for building as an external module. + */ + +#include <linux/compiler.h> +#include <linux/version.h> + +#include <linux/types.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) + +typedef u64 phys_addr_t; + +#endif + +#include "../external-module-compat-comm.h" + +#include <asm/msr.h> +#include <asm/asm.h> + +#ifndef CONFIG_HAVE_KVM_EVENTFD +#define CONFIG_HAVE_KVM_EVENTFD 1 +#endif + +#ifndef CONFIG_KVM_APIC_ARCHITECTURE +#define CONFIG_KVM_APIC_ARCHITECTURE +#endif + +#ifndef CONFIG_KVM_MMIO +#define CONFIG_KVM_MMIO +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) + +#ifdef CONFIG_X86_64 +#define DECLARE_ARGS(val, low, high) unsigned low, high +#define EAX_EDX_VAL(val, low, high) ((low) | ((u64)(high) << 32)) +#define EAX_EDX_ARGS(val, low, high) "a" (low), "d" (high) +#define EAX_EDX_RET(val, low, high) "=a" (low), "=d" (high) +#else +#define DECLARE_ARGS(val, low, high) unsigned long long val +#define EAX_EDX_VAL(val, low, high) (val) +#define EAX_EDX_ARGS(val, low, high) "A" (val) +#define EAX_EDX_RET(val, low, high) "=A" (val) +#endif + +#ifndef __ASM_EX_SEC +# define __ASM_EX_SEC " .section __ex_table,\"a\"\n" +#endif + +#ifndef _ASM_EXTABLE +# define _ASM_EXTABLE(from,to) \ + __ASM_EX_SEC \ + _ASM_ALIGN "\n" \ + _ASM_PTR #from "," #to "\n" \ + " .previous\n" +#endif + +#ifndef __ASM_SEL +#ifdef CONFIG_X86_32 +# define __ASM_SEL(a,b) __ASM_FORM(a) +#else +# define __ASM_SEL(a,b) __ASM_FORM(b) +#endif +#endif + +#ifndef __ASM_FORM +# define __ASM_FORM(x) " " #x " " +#endif + +#ifndef _ASM_PTR +#define _ASM_PTR __ASM_SEL(.long, .quad) +#endif + +#ifndef _ASM_ALIGN +#define _ASM_ALIGN __ASM_SEL(.balign 4, .balign 8) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) || defined(CONFIG_X86_64) + +static inline unsigned long long native_read_msr_safe(unsigned int msr, + int *err) +{ + DECLARE_ARGS(val, low, high); + + asm volatile("2: rdmsr ; xor %[err],%[err]\n" + "1:\n\t" + ".section .fixup,\"ax\"\n\t" + "3: mov %[fault],%[err] ; jmp 1b\n\t" + ".previous\n\t" + _ASM_EXTABLE(2b, 3b) + : [err] "=r" (*err), EAX_EDX_RET(val, low, high) + : "c" (msr), [fault] "i" (-EFAULT)); + return EAX_EDX_VAL(val, low, high); +} + +#endif + +static inline unsigned long long kvm_native_read_tsc(void) +{ + DECLARE_ARGS(val, low, high); + + asm volatile("rdtsc" : EAX_EDX_RET(val, low, high)); + return EAX_EDX_VAL(val, low, high); +} + +#else /* >= 2.6.25 */ + +#define kvm_native_read_tsc native_read_tsc + +#endif /* >= 2.6.25 */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) + +static inline int rdmsrl_safe(unsigned msr, unsigned long long *p) +{ + int err; + + *p = native_read_msr_safe(msr, &err); + return err; +} + +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + +#ifndef _EFER_SCE +#define _EFER_SCE 0 /* SYSCALL/SYSRET */ +#endif + +#ifndef EFER_SCE +#define EFER_SCE (1<<_EFER_SCE) +#endif + +#endif + +#ifndef MSR_KERNEL_GS_BASE +#define MSR_KERNEL_GS_BASE 0xc0000102 +#endif + +#ifndef MSR_TSC_AUX +#define MSR_TSC_AUX 0xc0000103 +#endif + +#ifndef MSR_VM_CR +#define MSR_VM_CR 0xc0010114 +#endif + +#ifndef MSR_VM_HSAVE_PA +#define MSR_VM_HSAVE_PA 0xc0010117 +#endif + +#ifndef _EFER_SVME +#define _EFER_SVME 12 +#define EFER_SVME (1<<_EFER_SVME) +#endif + +#ifndef _EFER_FFXSR +#define _EFER_FFXSR 14 /* Enable Fast FXSAVE/FXRSTOR */ +#define EFER_FFXSR (1<<_EFER_FFXSR) +#endif + +#ifndef MSR_STAR +#define MSR_STAR 0xc0000081 +#endif + +#ifndef MSR_K8_INT_PENDING_MSG +#define MSR_K8_INT_PENDING_MSG 0xc0010055 +#endif + +#include <asm/cpufeature.h> + +#ifndef X86_FEATURE_SVM +#define X86_FEATURE_SVM (6*32+ 2) /* Secure virtual machine */ +#endif + +#ifndef X86_FEATURE_FXSR_OPT +#define X86_FEATURE_FXSR_OPT (1*32+25) +#endif + +#ifndef X86_FEATURE_GBPAGES +#define X86_FEATURE_GBPAGES (1*32+26) /* GB pages */ +#endif + +#ifndef X86_FEATURE_SSSE3 +#define X86_FEATURE_SSSE3 (4*32+ 9) /* Supplemental SSE-3 */ +#endif + +#ifndef X86_FEATURE_XMM4_1 +#define X86_FEATURE_XMM4_1 (4*32+19) /* "sse4_1" SSE-4.1 */ +#endif + +#ifndef X86_FEATURE_XMM4_2 +#define X86_FEATURE_XMM4_2 (4*32+20) /* "sse4_2" SSE-4.2 */ +#endif + +#ifndef X86_FEATURE_MOVBE +#define X86_FEATURE_MOVBE (4*32+22) /* MOVBE instruction */ +#endif + +#ifndef X86_FEATURE_POPCNT +#define X86_FEATURE_POPCNT (4*32+23) /* POPCNT instruction */ +#endif + +#ifndef X86_FEATURE_CR8_LEGACY +#define X86_FEATURE_CR8_LEGACY (6*32+ 4) /* CR8 in 32-bit mode */ +#endif + +#ifndef X86_FEATURE_ABM +#define X86_FEATURE_ABM (6*32+ 5) /* Advanced bit manipulation */ +#endif + +#ifndef X86_FEATURE_SSE4A +#define X86_FEATURE_SSE4A (6*32+ 6) /* SSE-4A */ +#endif + +#ifndef X86_FEATURE_MISALIGNSSE +#define X86_FEATURE_MISALIGNSSE (6*32+ 7) /* Misaligned SSE mode */ +#endif + +#ifndef X86_FEATURE_3DNOWPREFETCH +#define X86_FEATURE_3DNOWPREFETCH (6*32+ 8) /* 3DNow prefetch instructions */ +#endif + +#ifndef X86_FEATURE_SSE5 +#define X86_FEATURE_SSE5 (6*32+11) /* SSE-5 */ +#endif + +#ifndef X86_FEATURE_X2APIC +#define X86_FEATURE_X2APIC (4*32+21) /* x2APIC */ +#endif + +#ifndef MSR_AMD64_PATCH_LOADER +#define MSR_AMD64_PATCH_LOADER 0xc0010020 +#endif + +#include <linux/smp.h> + +#ifndef X86_CR0_PE +#define X86_CR0_PE 0x00000001 +#endif + +#ifndef X86_CR0_MP +#define X86_CR0_MP 0x00000002 +#endif + +#ifndef X86_CR0_EM +#define X86_CR0_EM 0x00000004 +#endif + +#ifndef X86_CR0_TS +#define X86_CR0_TS 0x00000008 +#endif + +#ifndef X86_CR0_ET +#define X86_CR0_ET 0x00000010 +#endif + +#ifndef X86_CR0_NE +#define X86_CR0_NE 0x00000020 +#endif + +#ifndef X86_CR0_WP +#define X86_CR0_WP 0x00010000 +#endif + +#ifndef X86_CR0_AM +#define X86_CR0_AM 0x00040000 +#endif + +#ifndef X86_CR0_NW +#define X86_CR0_NW 0x20000000 +#endif + +#ifndef X86_CR0_CD +#define X86_CR0_CD 0x40000000 +#endif + +#ifndef X86_CR0_PG +#define X86_CR0_PG 0x80000000 +#endif + +#ifndef X86_CR3_PWT +#define X86_CR3_PWT 0x00000008 +#endif + +#ifndef X86_CR3_PCD +#define X86_CR3_PCD 0x00000010 +#endif + +#ifndef X86_CR4_VMXE +#define X86_CR4_VMXE 0x00002000 +#endif + +#undef X86_CR8_TPR +#define X86_CR8_TPR 0x0f + +/* + * 2.6.22 does not define set_64bit() under nonpae + */ +#ifdef CONFIG_X86_32 + +#include <asm/cmpxchg.h> + +static inline void __kvm_set_64bit(u64 *ptr, u64 val) +{ + unsigned int low = val; + unsigned int high = val >> 32; + + __asm__ __volatile__ ( + "\n1:\t" + "movl (%0), %%eax\n\t" + "movl 4(%0), %%edx\n\t" + "lock cmpxchg8b (%0)\n\t" + "jnz 1b" + : /* no outputs */ + : "D"(ptr), + "b"(low), + "c"(high) + : "ax","dx","memory"); +} + +#undef set_64bit +#define set_64bit __kvm_set_64bit + +static inline unsigned long long __kvm_cmpxchg64(volatile void *ptr, + unsigned long long old, + unsigned long long new) +{ + unsigned long long prev; + __asm__ __volatile__("lock cmpxchg8b %3" + : "=A"(prev) + : "b"((unsigned long)new), + "c"((unsigned long)(new >> 32)), + "m"(*__xg(ptr)), + "0"(old) + : "memory"); + return prev; +} + +#define kvm_cmpxchg64(ptr,o,n)\ + ((__typeof__(*(ptr)))__kvm_cmpxchg64((ptr),(unsigned long long)(o),\ + (unsigned long long)(n))) + +#undef cmpxchg64 +#define cmpxchg64(ptr, o, n) kvm_cmpxchg64(ptr, o, n) + +#endif + +#ifndef CONFIG_PREEMPT_NOTIFIERS + +#ifdef CONFIG_HAVE_HW_BREAKPOINT +#error Preemption notifier emulation does not work for this kernel. +#endif + +/* + * Include sched|preempt.h before defining CONFIG_PREEMPT_NOTIFIERS to avoid + * a miscompile. + */ +#include <linux/sched.h> +#include <linux/preempt.h> +#define CONFIG_PREEMPT_NOTIFIERS +#define CONFIG_PREEMPT_NOTIFIERS_COMPAT + +struct preempt_notifier; + +struct preempt_ops { + void (*sched_in)(struct preempt_notifier *notifier, int cpu); + void (*sched_out)(struct preempt_notifier *notifier, + struct task_struct *next); +}; + +struct preempt_notifier { + struct list_head link; + struct task_struct *tsk; + struct preempt_ops *ops; +}; + +void preempt_notifier_register(struct preempt_notifier *notifier); +void preempt_notifier_unregister(struct preempt_notifier *notifier); + +static inline void preempt_notifier_init(struct preempt_notifier *notifier, + struct preempt_ops *ops) +{ + notifier->ops = ops; +} + +void start_special_insn(void); +void end_special_insn(void); +void in_special_section(void); + +void preempt_notifier_sys_init(void); +void preempt_notifier_sys_exit(void); + +#else + +static inline void start_special_insn(void) {} +static inline void end_special_insn(void) {} +static inline void in_special_section(void) {} + +static inline void preempt_notifier_sys_init(void) {} +static inline void preempt_notifier_sys_exit(void) {} + +#endif + +/* CONFIG_HAS_IOMEM is apparently fairly new too (2.6.21 for x86_64). */ +#ifndef CONFIG_HAS_IOMEM +#define CONFIG_HAS_IOMEM 1 +#endif + +/* X86_FEATURE_NX is missing in some x86_64 kernels */ + +#include <asm/cpufeature.h> + +#ifndef X86_FEATURE_NX +#define X86_FEATURE_NX (1*32+20) +#endif + +/* EFER_LMA and EFER_LME are missing in pre 2.6.24 i386 kernels */ +#ifndef EFER_LME +#define _EFER_LME 8 /* Long mode enable */ +#define _EFER_LMA 10 /* Long mode active (read-only) */ +#define EFER_LME (1<<_EFER_LME) +#define EFER_LMA (1<<_EFER_LMA) +#endif + +struct kvm_desc_struct { + union { + struct { unsigned int a, b; }; + struct { + u16 limit0; + u16 base0; + unsigned base1: 8, type: 4, s: 1, dpl: 2, p: 1; + unsigned limit: 4, avl: 1, l: 1, d: 1, g: 1, base2: 8; + }; + + }; +} __attribute__((packed)); + +struct kvm_ldttss_desc64 { + u16 limit0; + u16 base0; + unsigned base1 : 8, type : 5, dpl : 2, p : 1; + unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8; + u32 base3; + u32 zero1; +} __attribute__((packed)); + +struct kvm_desc_ptr { + unsigned short size; + unsigned long address; +} __attribute__((packed)); + +static inline unsigned long +kvm_get_desc_base(const struct kvm_desc_struct *desc) +{ + return desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24); +} + +static inline void +kvm_set_desc_base(struct kvm_desc_struct *desc, unsigned long base) +{ + desc->base0 = base & 0xffff; + desc->base1 = (base >> 16) & 0xff; + desc->base2 = (base >> 24) & 0xff; +} + +static inline unsigned long +kvm_get_desc_limit(const struct kvm_desc_struct *desc) +{ + return desc->limit0 | (desc->limit << 16); +} + +static inline void +kvm_set_desc_limit(struct kvm_desc_struct *desc, unsigned long limit) +{ + desc->limit0 = limit & 0xffff; + desc->limit = (limit >> 16) & 0xf; +} + +static inline void kvm_native_store_gdt(struct kvm_desc_ptr *dtr) +{ + asm volatile("sgdt %0":"=m" (*dtr)); +} + +static inline void kvm_native_store_idt(struct kvm_desc_ptr *dtr) +{ + asm volatile("sidt %0":"=m" (*dtr)); +} + +#include <asm/msr.h> +#ifndef MSR_FS_BASE +#define MSR_FS_BASE 0xc0000100 +#endif +#ifndef MSR_GS_BASE +#define MSR_GS_BASE 0xc0000101 +#endif + +/* undefine lapic */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) + +#undef lapic + +#endif + +#include <asm/hw_irq.h> +#ifndef NMI_VECTOR +#define NMI_VECTOR 2 +#endif + +#ifndef MSR_MTRRcap +#define MSR_MTRRcap 0x0fe +#define MSR_MTRRfix64K_00000 0x250 +#define MSR_MTRRfix16K_80000 0x258 +#define MSR_MTRRfix16K_A0000 0x259 +#define MSR_MTRRfix4K_C0000 0x268 +#define MSR_MTRRfix4K_C8000 0x269 +#define MSR_MTRRfix4K_D0000 0x26a +#define MSR_MTRRfix4K_D8000 0x26b +#define MSR_MTRRfix4K_E0000 0x26c +#define MSR_MTRRfix4K_E8000 0x26d +#define MSR_MTRRfix4K_F0000 0x26e +#define MSR_MTRRfix4K_F8000 0x26f +#define MSR_MTRRdefType 0x2ff +#endif + +#ifndef MSR_IA32_CR_PAT +#define MSR_IA32_CR_PAT 0x00000277 +#endif + +#ifndef MSR_VM_IGNNE +#define MSR_VM_IGNNE 0xc0010115 +#endif + +/* Define DEBUGCTLMSR bits */ +#ifndef DEBUGCTLMSR_LBR + +#define _DEBUGCTLMSR_LBR 0 /* last branch recording */ +#define _DEBUGCTLMSR_BTF 1 /* single-step on branches */ + +#define DEBUGCTLMSR_LBR (1UL << _DEBUGCTLMSR_LBR) +#define DEBUGCTLMSR_BTF (1UL << _DEBUGCTLMSR_BTF) + +#endif + +#ifndef MSR_FAM10H_MMIO_CONF_BASE +#define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058 +#endif + +#ifndef MSR_AMD64_NB_CFG +#define MSR_AMD64_NB_CFG 0xc001001f +#endif + +#include <asm/asm.h> + +#ifndef __ASM_SIZE +# define ____ASM_FORM(x) " " #x " " +# ifdef CONFIG_X86_64 +# define __ASM_SIZE(inst) ____ASM_FORM(inst##q) +# else +# define __ASM_SIZE(inst) ____ASM_FORM(inst##l) +# endif +#endif + +#ifndef _ASM_PTR +# ifdef CONFIG_X86_64 +# define _ASM_PTR ".quad" +# else +# define _ASM_PTR ".long" +# endif +#endif + +/* Intel VT MSRs */ +#ifndef MSR_IA32_VMX_BASIC +#define MSR_IA32_VMX_BASIC 0x00000480 +#define MSR_IA32_VMX_PINBASED_CTLS 0x00000481 +#define MSR_IA32_VMX_PROCBASED_CTLS 0x00000482 +#define MSR_IA32_VMX_EXIT_CTLS 0x00000483 +#define MSR_IA32_VMX_ENTRY_CTLS 0x00000484 +#define MSR_IA32_VMX_MISC 0x00000485 +#define MSR_IA32_VMX_CR0_FIXED0 0x00000486 +#define MSR_IA32_VMX_CR0_FIXED1 0x00000487 +#define MSR_IA32_VMX_CR4_FIXED0 0x00000488 +#define MSR_IA32_VMX_CR4_FIXED1 0x00000489 +#define MSR_IA32_VMX_VMCS_ENUM 0x0000048a +#define MSR_IA32_VMX_PROCBASED_CTLS2 0x0000048b +#define MSR_IA32_VMX_EPT_VPID_CAP 0x0000048c +#endif + +#ifndef MSR_IA32_FEATURE_CONTROL +#define MSR_IA32_FEATURE_CONTROL 0x0000003a + +#define FEATURE_CONTROL_LOCKED (1<<0) +#define FEATURE_CONTROL_VMXON_ENABLED (1<<2) +#endif + +#ifndef MSR_IA32_TSC +#define MSR_IA32_TSC 0x00000010 +#endif + +#ifndef MSR_K7_HWCR +#define MSR_K7_HWCR 0xc0010015 +#endif + +#ifndef MSR_K8_SYSCFG +#define MSR_K8_SYSCFG 0xc0010010 +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) && defined(__x86_64__) + +#undef set_debugreg +#define set_debugreg(value, register) \ + __asm__("movq %0,%%db" #register \ + : /* no output */ \ + :"r" ((unsigned long)value)) + +#endif + +#if !defined(CONFIG_X86_64) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) +#define kvm_compat_debugreg(x) debugreg[x] +#else +#define kvm_compat_debugreg(x) debugreg##x +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + +struct mtrr_var_range { + u32 base_lo; + u32 base_hi; + u32 mask_lo; + u32 mask_hi; +}; + +/* In the Intel processor's MTRR interface, the MTRR type is always held in + an 8 bit field: */ +typedef u8 mtrr_type; + +#define MTRR_NUM_FIXED_RANGES 88 +#define MTRR_MAX_VAR_RANGES 256 + +struct mtrr_state_type { + struct mtrr_var_range var_ranges[MTRR_MAX_VAR_RANGES]; + mtrr_type fixed_ranges[MTRR_NUM_FIXED_RANGES]; + unsigned char enabled; + unsigned char have_fixed; + mtrr_type def_type; +}; + +#endif + +#ifndef CONFIG_HAVE_KVM_IRQCHIP +#define CONFIG_HAVE_KVM_IRQCHIP 1 +#endif + +#include <asm/mce.h> + +#ifndef MCG_CTL_P +#define MCG_CTL_P (1ULL<<8) +#define MCG_STATUS_MCIP (1ULL<<2) +#define MCI_STATUS_VAL (1ULL<<63) +#define MCI_STATUS_OVER (1ULL<<62) +#define MCI_STATUS_UC (1ULL<<61) +#endif + +/* do_machine_check() exported in 2.6.31 */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) + +static inline void kvm_do_machine_check(struct pt_regs *regs, long error_code) +{ + panic("kvm machine check!\n"); +} + +#else + +#define kvm_do_machine_check do_machine_check + +#endif + +/* pt_regs.flags was once pt_regs.eflags */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) + +#define kvm_pt_regs_flags eflags + +# ifdef CONFIG_X86_64 +# define kvm_pt_regs_cs cs +# else +# define kvm_pt_regs_cs xcs +# endif + +#else + +#define kvm_pt_regs_flags flags +#define kvm_pt_regs_cs cs + +#endif + +/* boot_cpu_data.x86_phys_bits only appeared for i386 in 2.6.30 */ + +#if !defined(CONFIG_X86_64) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) + +#define kvm_x86_phys_bits 40 + +#else + +#define kvm_x86_phys_bits (boot_cpu_data.x86_phys_bits) + +#endif + +#include <asm/apicdef.h> + +#ifndef APIC_BASE_MSR +#define APIC_BASE_MSR 0x800 +#endif + +#ifndef APIC_SPIV_DIRECTED_EOI +#define APIC_SPIV_DIRECTED_EOI (1 << 12) +#endif + +#ifndef APIC_LVR_DIRECTED_EOI +#define APIC_LVR_DIRECTED_EOI (1 << 24) +#endif + +#ifndef APIC_SELF_IPI +#define APIC_SELF_IPI 0x3F0 +#endif + +#ifndef X2APIC_ENABLE +#define X2APIC_ENABLE (1UL << 10) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) + +static inline int hw_breakpoint_active(void) +{ + return test_thread_flag(TIF_DEBUG); +} + +static inline void hw_breakpoint_restore(void) +{ + set_debugreg(current->thread.kvm_compat_debugreg(0), 0); + set_debugreg(current->thread.kvm_compat_debugreg(1), 1); + set_debugreg(current->thread.kvm_compat_debugreg(2), 2); + set_debugreg(current->thread.kvm_compat_debugreg(3), 3); + set_debugreg(current->thread.kvm_compat_debugreg(6), 6); + set_debugreg(current->thread.kvm_compat_debugreg(7), 7); +} + +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24) && defined(CONFIG_X86_64) +#define kvm_check_tsc_unstable() 1 +#else +#define kvm_check_tsc_unstable check_tsc_unstable +#endif diff --git a/linux/x86/preempt.c b/linux/x86/preempt.c new file mode 100644 index 0000000..440060b --- /dev/null +++ b/linux/x86/preempt.c @@ -0,0 +1,247 @@ + +#ifdef CONFIG_PREEMPT_NOTIFIERS_COMPAT + +#include <linux/sched.h> +#include <linux/percpu.h> + +static DEFINE_SPINLOCK(pn_lock); +static LIST_HEAD(pn_list); + +#define dprintk(fmt) do { \ + if (0) \ + printk("%s (%d/%d): " fmt, __FUNCTION__, \ + current->pid, raw_smp_processor_id()); \ + } while (0) + +static void preempt_enable_sched_out_notifiers(void) +{ + asm volatile ("mov %0, %%db0" : : "r"(schedule)); + asm volatile ("mov %0, %%db7" : : "r"(0x701ul)); + current->thread.kvm_compat_debugreg(7) = 0ul; +#ifdef TIF_DEBUG + clear_tsk_thread_flag(current, TIF_DEBUG); +#endif +} + +static void preempt_enable_sched_in_notifiers(void * addr) +{ + asm volatile ("mov %0, %%db0" : : "r"(addr)); + asm volatile ("mov %0, %%db7" : : "r"(0x701ul)); + current->thread.kvm_compat_debugreg(0) = (unsigned long) addr; + current->thread.kvm_compat_debugreg(7) = 0x701ul; +#ifdef TIF_DEBUG + set_tsk_thread_flag(current, TIF_DEBUG); +#endif +} + +static void __preempt_disable_notifiers(void) +{ + asm volatile ("mov %0, %%db7" : : "r"(0ul)); +} + +static void preempt_disable_notifiers(void) +{ + __preempt_disable_notifiers(); + current->thread.kvm_compat_debugreg(7) = 0ul; +#ifdef TIF_DEBUG + clear_tsk_thread_flag(current, TIF_DEBUG); +#endif +} + +static void fastcall __attribute__((used)) preempt_notifier_trigger(void *** ip) +{ + struct preempt_notifier *pn; + int cpu = raw_smp_processor_id(); + int found = 0; + + dprintk(" - in\n"); + //dump_stack(); + spin_lock(&pn_lock); + list_for_each_entry(pn, &pn_list, link) + if (pn->tsk == current) { + found = 1; + break; + } + spin_unlock(&pn_lock); + + if (found) { + if ((void *) *ip != schedule) { + dprintk("sched_in\n"); + preempt_enable_sched_out_notifiers(); + + preempt_disable(); + local_irq_enable(); + pn->ops->sched_in(pn, cpu); + local_irq_disable(); + preempt_enable_no_resched(); + } else { + void * sched_in_addr; + dprintk("sched_out\n"); +#ifdef CONFIG_X86_64 + sched_in_addr = **(ip+3); +#else + /* no special debug stack switch on x86 */ + sched_in_addr = (void *) *(ip+3); +#endif + preempt_enable_sched_in_notifiers(sched_in_addr); + + preempt_disable(); + local_irq_enable(); + pn->ops->sched_out(pn, NULL); + local_irq_disable(); + preempt_enable_no_resched(); + } + } else + __preempt_disable_notifiers(); + dprintk(" - out\n"); +} + +unsigned long orig_int1_handler; + +#ifdef CONFIG_X86_64 + +#define SAVE_REGS \ + "push %rax; push %rbx; push %rcx; push %rdx; " \ + "push %rsi; push %rdi; push %rbp; " \ + "push %r8; push %r9; push %r10; push %r11; " \ + "push %r12; push %r13; push %r14; push %r15" + +#define RESTORE_REGS \ + "pop %r15; pop %r14; pop %r13; pop %r12; " \ + "pop %r11; pop %r10; pop %r9; pop %r8; " \ + "pop %rbp; pop %rdi; pop %rsi; " \ + "pop %rdx; pop %rcx; pop %rbx; pop %rax " + +#define TMP "%rax" + +#else + +#define SAVE_REGS "pusha" +#define RESTORE_REGS "popa" +#define TMP "%eax" + +#endif + +asm ("pn_int1_handler: \n\t" + "push " TMP " \n\t" + "mov %db7, " TMP " \n\t" + "cmp $0x701, " TMP " \n\t" + "pop " TMP " \n\t" + "jnz .Lnotme \n\t" + "push " TMP " \n\t" + "mov %db6, " TMP " \n\t" + "test $0x1, " TMP " \n\t" + "pop " TMP " \n\t" + "jz .Lnotme \n\t" + SAVE_REGS "\n\t" +#ifdef CONFIG_X86_64 + "leaq 120(%rsp),%rdi\n\t" +#else + "leal 32(%esp),%eax\n\t" +#endif + "call preempt_notifier_trigger \n\t" + RESTORE_REGS "\n\t" +#ifdef CONFIG_X86_64 + "orq $0x10000, 16(%rsp) \n\t" + "iretq \n\t" +#else + "orl $0x10000, 8(%esp) \n\t" + "iret \n\t" +#endif + ".Lnotme: \n\t" +#ifdef CONFIG_X86_64 + "jmpq *orig_int1_handler\n\t" +#else + "jmpl *orig_int1_handler\n\t" +#endif + ); + +void preempt_notifier_register(struct preempt_notifier *notifier) +{ + unsigned long flags; + + dprintk(" - in\n"); + spin_lock_irqsave(&pn_lock, flags); + preempt_enable_sched_out_notifiers(); + notifier->tsk = current; + list_add(¬ifier->link, &pn_list); + spin_unlock_irqrestore(&pn_lock, flags); + dprintk(" - out\n"); +} + +void preempt_notifier_unregister(struct preempt_notifier *notifier) +{ + unsigned long flags; + + dprintk(" - in\n"); + spin_lock_irqsave(&pn_lock, flags); + list_del(¬ifier->link); + spin_unlock_irqrestore(&pn_lock, flags); + preempt_disable_notifiers(); + dprintk(" - out\n"); +} + +struct intr_gate { + u16 offset0; + u16 segment; + u16 junk; + u16 offset1; +#ifdef CONFIG_X86_64 + u32 offset2; + u32 blah; +#endif +} __attribute__((packed)); + +struct idt_desc { + u16 limit; + struct intr_gate *gates; +} __attribute__((packed)); + +static struct intr_gate orig_int1_gate; + +void pn_int1_handler(void); + +void preempt_notifier_sys_init(void) +{ + struct idt_desc idt_desc; + struct intr_gate *int1_gate; + + printk("kvm: emulating preempt notifiers;" + " do not benchmark on this machine\n"); + dprintk("\n"); + asm ("sidt %0" : "=m"(idt_desc)); + int1_gate = &idt_desc.gates[1]; + orig_int1_gate = *int1_gate; + orig_int1_handler = int1_gate->offset0 + | ((u32)int1_gate->offset1 << 16); +#ifdef CONFIG_X86_64 + orig_int1_handler |= (u64)int1_gate->offset2 << 32; +#endif + int1_gate->offset0 = (unsigned long)pn_int1_handler; + int1_gate->offset1 = (unsigned long)pn_int1_handler >> 16; +#ifdef CONFIG_X86_64 + int1_gate->offset2 = (unsigned long)pn_int1_handler >> 32; +#endif +} + +static void do_disable(void *blah) +{ +#ifdef TIF_DEBUG + if (!test_tsk_thread_flag(current, TIF_DEBUG)) +#else + if (!current->thread.kvm_compat_debugreg(7)) +#endif + __preempt_disable_notifiers(); +} + +void preempt_notifier_sys_exit(void) +{ + struct idt_desc idt_desc; + + dprintk("\n"); + kvm_on_each_cpu(do_disable, NULL, 1); + asm ("sidt %0" : "=m"(idt_desc)); + idt_desc.gates[1] = orig_int1_gate; +} + +#endif diff --git a/linux/x86/vmx-debug.c b/linux/x86/vmx-debug.c new file mode 100644 index 0000000..1549b39 --- /dev/null +++ b/linux/x86/vmx-debug.c @@ -0,0 +1,1117 @@ +/* + * 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 <yaniv@qumranet.com> + * Avi Kivity <avi@qumranet.com> + * + */ + +#include <linux/highmem.h> + +#include <linux/kvm_host.h> +#include <asm/vmx.h> +#include <asm/kvm_host.h> +#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 + |