From: Avi Kivity Signed-off-by: Avi Kivity Signed-off-by: Andrew Morton --- drivers/kvm/kvm.h | 4 + drivers/kvm/kvm_main.c | 127 ++-------------------------------- drivers/kvm/vmx.c | 142 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 117 deletions(-) diff -puN drivers/kvm/kvm.h~kvm-make-msr-accessors-arch-operations drivers/kvm/kvm.h --- a/drivers/kvm/kvm.h~kvm-make-msr-accessors-arch-operations +++ a/drivers/kvm/kvm.h @@ -245,6 +245,8 @@ struct kvm_arch_ops { int (*set_guest_debug)(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg); + int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata); + int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); }; extern struct kvm_stat kvm_stat; @@ -401,6 +403,8 @@ static inline struct kvm_mmu_page *page_ #define ASM_VMX_VMXOFF ".byte 0x0f, 0x01, 0xc4" #define ASM_VMX_VMXON_RAX ".byte 0xf3, 0x0f, 0xc7, 0x30" +#define MSR_IA32_TIME_STAMP_COUNTER 0x010 + #ifdef __x86_64__ /* diff -puN drivers/kvm/kvm_main.c~kvm-make-msr-accessors-arch-operations drivers/kvm/kvm_main.c --- a/drivers/kvm/kvm_main.c~kvm-make-msr-accessors-arch-operations +++ a/drivers/kvm/kvm_main.c @@ -122,7 +122,6 @@ static const u32 vmx_msr_index[] = { #define TSS_REDIRECTION_SIZE (256 / 8) #define RMODE_TSS_SIZE (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1) -#define MSR_IA32_TIME_STAMP_COUNTER 0x010 #define MSR_IA32_FEATURE_CONTROL 0x03a #define MSR_IA32_VMX_PINBASED_CTLS_MSR 0x481 #define MSR_IA32_VMX_PROCBASED_CTLS_MSR 0x482 @@ -143,7 +142,7 @@ static const u32 vmx_msr_index[] = { #define HOST_IS_64 0 #endif -static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr) +struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr) { int i; @@ -152,6 +151,7 @@ static struct vmx_msr_entry *find_msr_en return &vcpu->guest_msrs[i]; return 0; } +EXPORT_SYMBOL_GPL(find_msr_entry); struct descriptor_table { u16 limit; @@ -657,7 +657,7 @@ static void inject_gp(struct kvm_vcpu *v * reads and returns guest's timestamp counter "register" * guest_tsc = host_tsc + tsc_offset -- 21.3 */ -static u64 guest_read_tsc(void) +u64 guest_read_tsc(void) { u64 host_tsc, tsc_offset; @@ -665,18 +665,20 @@ static u64 guest_read_tsc(void) tsc_offset = vmcs_read64(TSC_OFFSET); return host_tsc + tsc_offset; } +EXPORT_SYMBOL_GPL(guest_read_tsc); /* * writes 'guest_tsc' into guest's timestamp counter "register" * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc */ -static void guest_write_tsc(u64 guest_tsc) +void guest_write_tsc(u64 guest_tsc) { u64 host_tsc; rdtscll(host_tsc); vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc); } +EXPORT_SYMBOL_GPL(guest_write_tsc); static void update_exception_bitmap(struct kvm_vcpu *vcpu) { @@ -2242,67 +2244,7 @@ static int handle_cpuid(struct kvm_vcpu */ static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) { - u64 data; - struct vmx_msr_entry *msr; - - if (!pdata) { - printk(KERN_ERR "BUG: get_msr called with NULL pdata\n"); - return -EINVAL; - } - - switch (msr_index) { -#ifdef __x86_64__ - case MSR_FS_BASE: - data = vmcs_readl(GUEST_FS_BASE); - break; - case MSR_GS_BASE: - data = vmcs_readl(GUEST_GS_BASE); - break; - case MSR_EFER: - data = vcpu->shadow_efer; - break; -#endif - case MSR_IA32_TIME_STAMP_COUNTER: - data = guest_read_tsc(); - break; - case MSR_IA32_SYSENTER_CS: - data = vmcs_read32(GUEST_SYSENTER_CS); - break; - case MSR_IA32_SYSENTER_EIP: - data = vmcs_read32(GUEST_SYSENTER_EIP); - break; - case MSR_IA32_SYSENTER_ESP: - data = vmcs_read32(GUEST_SYSENTER_ESP); - break; - case MSR_IA32_MC0_CTL: - case MSR_IA32_MCG_STATUS: - case MSR_IA32_MCG_CAP: - case MSR_IA32_MC0_MISC: - case MSR_IA32_MC0_MISC+4: - case MSR_IA32_MC0_MISC+8: - case MSR_IA32_MC0_MISC+12: - case MSR_IA32_MC0_MISC+16: - case MSR_IA32_UCODE_REV: - /* MTRR registers */ - case 0xfe: - case 0x200 ... 0x2ff: - data = 0; - break; - case MSR_IA32_APICBASE: - data = vcpu->apic_base; - break; - default: - msr = find_msr_entry(vcpu, msr_index); - if (!msr) { - printk(KERN_ERR "kvm: unhandled rdmsr: %x\n", msr_index); - return 1; - } - data = msr->data; - break; - } - - *pdata = data; - return 0; + return kvm_arch_ops->get_msr(vcpu, msr_index, pdata); } static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) @@ -2324,7 +2266,7 @@ static int handle_rdmsr(struct kvm_vcpu #ifdef __x86_64__ -static void set_efer(struct kvm_vcpu *vcpu, u64 efer) +void set_efer(struct kvm_vcpu *vcpu, u64 efer) { struct vmx_msr_entry *msr; @@ -2353,10 +2295,10 @@ static void set_efer(struct kvm_vcpu *vc msr->data = efer; skip_emulated_instruction(vcpu); } +EXPORT_SYMBOL_GPL(set_efer); #endif - /* * Writes msr value into into the appropriate "register". * Returns 0 on success, non-0 otherwise. @@ -2364,56 +2306,7 @@ static void set_efer(struct kvm_vcpu *vc */ static int set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) { - struct vmx_msr_entry *msr; - switch (msr_index) { -#ifdef __x86_64__ - case MSR_FS_BASE: - vmcs_writel(GUEST_FS_BASE, data); - break; - case MSR_GS_BASE: - vmcs_writel(GUEST_GS_BASE, data); - break; -#endif - case MSR_IA32_SYSENTER_CS: - vmcs_write32(GUEST_SYSENTER_CS, data); - break; - case MSR_IA32_SYSENTER_EIP: - vmcs_write32(GUEST_SYSENTER_EIP, data); - break; - case MSR_IA32_SYSENTER_ESP: - vmcs_write32(GUEST_SYSENTER_ESP, data); - break; -#ifdef __x86_64 - case MSR_EFER: - set_efer(vcpu, data); - break; - case MSR_IA32_MC0_STATUS: - printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n" - , __FUNCTION__, data); - break; -#endif - case MSR_IA32_TIME_STAMP_COUNTER: { - guest_write_tsc(data); - break; - } - case MSR_IA32_UCODE_REV: - case MSR_IA32_UCODE_WRITE: - case 0x200 ... 0x2ff: /* MTRRs */ - break; - case MSR_IA32_APICBASE: - vcpu->apic_base = data; - break; - default: - msr = find_msr_entry(vcpu, msr_index); - if (!msr) { - printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr_index); - return 1; - } - msr->data = data; - break; - } - - return 0; + return kvm_arch_ops->set_msr(vcpu, msr_index, data); } static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) diff -puN drivers/kvm/vmx.c~kvm-make-msr-accessors-arch-operations drivers/kvm/vmx.c --- a/drivers/kvm/vmx.c~kvm-make-msr-accessors-arch-operations +++ a/drivers/kvm/vmx.c @@ -31,6 +31,146 @@ extern struct vmcs_descriptor { u32 revision_id; } vmcs_descriptor; +u64 guest_read_tsc(void); +void guest_write_tsc(u64 guest_tsc); +struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr); + +#ifdef __x86_64__ + +void set_efer(struct kvm_vcpu *vcpu, u64 efer); + +#endif + + +/* + * Reads an msr value (of 'msr_index') into 'pdata'. + * Returns 0 on success, non-0 otherwise. + * Assumes vcpu_load() was already called. + */ +static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) +{ + u64 data; + struct vmx_msr_entry *msr; + + if (!pdata) { + printk(KERN_ERR "BUG: get_msr called with NULL pdata\n"); + return -EINVAL; + } + + switch (msr_index) { +#ifdef __x86_64__ + case MSR_FS_BASE: + data = vmcs_readl(GUEST_FS_BASE); + break; + case MSR_GS_BASE: + data = vmcs_readl(GUEST_GS_BASE); + break; + case MSR_EFER: + data = vcpu->shadow_efer; + break; +#endif + case MSR_IA32_TIME_STAMP_COUNTER: + data = guest_read_tsc(); + break; + case MSR_IA32_SYSENTER_CS: + data = vmcs_read32(GUEST_SYSENTER_CS); + break; + case MSR_IA32_SYSENTER_EIP: + data = vmcs_read32(GUEST_SYSENTER_EIP); + break; + case MSR_IA32_SYSENTER_ESP: + data = vmcs_read32(GUEST_SYSENTER_ESP); + break; + case MSR_IA32_MC0_CTL: + case MSR_IA32_MCG_STATUS: + case MSR_IA32_MCG_CAP: + case MSR_IA32_MC0_MISC: + case MSR_IA32_MC0_MISC+4: + case MSR_IA32_MC0_MISC+8: + case MSR_IA32_MC0_MISC+12: + case MSR_IA32_MC0_MISC+16: + case MSR_IA32_UCODE_REV: + /* MTRR registers */ + case 0xfe: + case 0x200 ... 0x2ff: + data = 0; + break; + case MSR_IA32_APICBASE: + data = vcpu->apic_base; + break; + default: + msr = find_msr_entry(vcpu, msr_index); + if (!msr) { + printk(KERN_ERR "kvm: unhandled rdmsr: %x\n", msr_index); + return 1; + } + data = msr->data; + break; + } + + *pdata = data; + return 0; +} + +/* + * Writes msr value into into the appropriate "register". + * Returns 0 on success, non-0 otherwise. + * Assumes vcpu_load() was already called. + */ +static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) +{ + struct vmx_msr_entry *msr; + switch (msr_index) { +#ifdef __x86_64__ + case MSR_FS_BASE: + vmcs_writel(GUEST_FS_BASE, data); + break; + case MSR_GS_BASE: + vmcs_writel(GUEST_GS_BASE, data); + break; +#endif + case MSR_IA32_SYSENTER_CS: + vmcs_write32(GUEST_SYSENTER_CS, data); + break; + case MSR_IA32_SYSENTER_EIP: + vmcs_write32(GUEST_SYSENTER_EIP, data); + break; + case MSR_IA32_SYSENTER_ESP: + vmcs_write32(GUEST_SYSENTER_ESP, data); + break; +#ifdef __x86_64 + case MSR_EFER: + set_efer(vcpu, data); + break; + case MSR_IA32_MC0_STATUS: + printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n" + , __FUNCTION__, data); + break; +#endif + case MSR_IA32_TIME_STAMP_COUNTER: { + guest_write_tsc(data); + break; + } + case MSR_IA32_UCODE_REV: + case MSR_IA32_UCODE_WRITE: + case 0x200 ... 0x2ff: /* MTRRs */ + break; + case MSR_IA32_APICBASE: + vcpu->apic_base = data; + break; + default: + msr = find_msr_entry(vcpu, msr_index); + if (!msr) { + printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr_index); + return 1; + } + msr->data = data; + break; + } + + return 0; +} + static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) { unsigned long dr7 = 0x400; @@ -169,6 +309,8 @@ static struct kvm_arch_ops vmx_arch_ops .hardware_disable = hardware_disable, .set_guest_debug = set_guest_debug, + .get_msr = vmx_get_msr, + .set_msr = vmx_set_msr, }; static int __init vmx_init(void) _