diff options
author | Robert Mustacchi <rm@joyent.com> | 2011-06-08 14:40:08 -0700 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2011-06-08 14:40:08 -0700 |
commit | 27b148dd0083b94a2c6a46dfd46c02eb557cc9e3 (patch) | |
tree | 9770371aab2d4f5ca9a3d4331f370936fd31ce02 | |
parent | fc81a7032577914bac149316323d225e6c268a18 (diff) | |
download | illumos-kvm-27b148dd0083b94a2c6a46dfd46c02eb557cc9e3.tar.gz |
HVM-335 kvm_subr.c has reached the end of the line
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | kvm.c | 91 | ||||
-rw-r--r-- | kvm_mmu.c | 46 | ||||
-rw-r--r-- | kvm_subr.c | 496 | ||||
-rw-r--r-- | kvm_x86.c | 330 | ||||
-rw-r--r-- | msr.h | 9 |
6 files changed, 465 insertions, 517 deletions
@@ -20,11 +20,10 @@ HEADERS= \ kvm.h \ kvm_bitops.h -kvm: kvm.c kvm_x86.c kvm_emulate.c kvm.h kvm_x86host.h msr.h kvm_bitops.h kvm_subr.c kvm_irq.c kvm_i8254.c kvm_lapic.c kvm_mmu.c kvm_iodev.c kvm_ioapic.c kvm_vmx.c kvm_i8259.c kvm_coalesced_mmio.c kvm_irq_comm.c kvm_cache_regs.c kvm_bitops.c +kvm: kvm.c kvm_x86.c kvm_emulate.c kvm.h kvm_x86host.h msr.h kvm_bitops.h kvm_irq.c kvm_i8254.c kvm_lapic.c kvm_mmu.c kvm_iodev.c kvm_ioapic.c kvm_vmx.c kvm_i8259.c kvm_coalesced_mmio.c kvm_irq_comm.c kvm_cache_regs.c kvm_bitops.c $(CC) $(CFLAGS) $(INCLUDEDIR) kvm.c $(CC) $(CFLAGS) $(INCLUDEDIR) kvm_x86.c $(CC) $(CFLAGS) $(INCLUDEDIR) kvm_emulate.c - $(CC) $(CFLAGS) $(INCLUDEDIR) kvm_subr.c $(CC) $(CFLAGS) $(INCLUDEDIR) kvm_irq.c $(CC) $(CFLAGS) $(INCLUDEDIR) kvm_i8254.c $(CC) $(CFLAGS) $(INCLUDEDIR) kvm_lapic.c @@ -40,7 +39,6 @@ kvm: kvm.c kvm_x86.c kvm_emulate.c kvm.h kvm_x86host.h msr.h kvm_bitops.h kvm_su $(CTFCONVERT) -i -L VERSION kvm.o $(CTFCONVERT) -i -L VERSION kvm_x86.o $(CTFCONVERT) -i -L VERSION kvm_emulate.o - $(CTFCONVERT) -i -L VERSION kvm_subr.o $(CTFCONVERT) -i -L VERSION kvm_irq.o $(CTFCONVERT) -i -L VERSION kvm_i8254.o $(CTFCONVERT) -i -L VERSION kvm_lapic.o @@ -53,8 +51,8 @@ kvm: kvm.c kvm_x86.c kvm_emulate.c kvm.h kvm_x86host.h msr.h kvm_bitops.h kvm_su $(CTFCONVERT) -i -L VERSION kvm_irq_comm.o $(CTFCONVERT) -i -L VERSION kvm_cache_regs.o $(CTFCONVERT) -i -L VERSION kvm_bitops.o - $(LD) -r -o kvm kvm.o kvm_x86.o kvm_emulate.o kvm_subr.o kvm_irq.o kvm_i8254.o kvm_lapic.o kvm_mmu.o kvm_iodev.o kvm_ioapic.o kvm_vmx.o kvm_i8259.o kvm_coalesced_mmio.o kvm_irq_comm.o kvm_cache_regs.o kvm_bitops.o - $(CTFMERGE) -L VERSION -o kvm kvm.o kvm_x86.o kvm_emulate.o kvm_subr.o kvm_irq.o kvm_i8254.o kvm_lapic.o kvm_mmu.o kvm_iodev.o kvm_ioapic.o kvm_vmx.o kvm_i8259.o kvm_coalesced_mmio.o kvm_irq_comm.o kvm_cache_regs.o kvm_bitops.o + $(LD) -r -o kvm kvm.o kvm_x86.o kvm_emulate.o kvm_irq.o kvm_i8254.o kvm_lapic.o kvm_mmu.o kvm_iodev.o kvm_ioapic.o kvm_vmx.o kvm_i8259.o kvm_coalesced_mmio.o kvm_irq_comm.o kvm_cache_regs.o kvm_bitops.o + $(CTFMERGE) -L VERSION -o kvm kvm.o kvm_x86.o kvm_emulate.o kvm_irq.o kvm_i8254.o kvm_lapic.o kvm_mmu.o kvm_iodev.o kvm_ioapic.o kvm_vmx.o kvm_i8259.o kvm_coalesced_mmio.o kvm_irq_comm.o kvm_cache_regs.o kvm_bitops.o kvm.so: kvm_mdb.c gcc -m64 -shared \ @@ -67,7 +65,7 @@ install: kvm @pfexec cp kvm.conf /usr/kernel/drv check: - @$(CSTYLE) kvm.c kvm_mdb.c kvm_emulate.c kvm_x86.c kvm_irq.c kvm_lapic.c kvm_i8254.c kvm_mmu.c kvm_iodev.c kvm_subr.c kvm_ioapic.c kvm_vmx.c kvm_i8259.c kvm_coalesced_mmio.c kvm_irq_comm.c kvm_cache_regs.c kvm_bitops.c $(HEADERS) + @$(CSTYLE) kvm.c kvm_mdb.c kvm_emulate.c kvm_x86.c kvm_irq.c kvm_lapic.c kvm_i8254.c kvm_mmu.c kvm_iodev.c kvm_ioapic.c kvm_vmx.c kvm_i8259.c kvm_coalesced_mmio.c kvm_irq_comm.c kvm_cache_regs.c kvm_bitops.c $(HEADERS) @./tools/xxxcheck kvm_x86.c kvm.c kvm_irq.c kvm_lapic.c kvm_i8254.c kvm_mmu.c kvm_iodev.c kvm_ioapic.c kvm_vmx.c kvm_i8259.c kvm_coalesced_mmio.c kvm_irq_comm.c kvm_cache_regs.c kvm_bitops.c load: install @@ -96,6 +96,34 @@ static kmutex_t kvm_lock; static int ignore_msrs = 0; static unsigned long empty_zero_page[PAGESIZE / sizeof (unsigned long)]; +int +kvm_xcall_func(kvm_xcall_t func, void *arg) +{ + if (func != NULL) + (*func)(arg); + + return (0); +} + +void +kvm_xcall(processorid_t cpu, kvm_xcall_t func, void *arg) +{ + cpuset_t set; + + CPUSET_ZERO(set); + + if (cpu == KVM_CPUALL) { + CPUSET_ALL(set); + } else { + CPUSET_ADD(set, cpu); + } + + kpreempt_disable(); + xc_sync((xc_arg_t)func, (xc_arg_t)arg, 0, CPUSET2BV(set), + (xc_func_t) kvm_xcall_func); + kpreempt_enable(); +} + void kvm_user_return_notifier_register(struct kvm_vcpu *vcpu, struct kvm_user_return_notifier *urn) @@ -143,6 +171,12 @@ kvm_ctx_restore(void *arg) kvm_arch_vcpu_load(vcpu, cpu); } +void +kvm_migrate_timers(struct kvm_vcpu *vcpu) +{ + set_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests); +} + #ifdef XXX_KVM_DECLARATION #define pfn_valid(pfn) ((pfn < physmax) && (pfn != PFN_INVALID)) #else @@ -181,6 +215,17 @@ vcpu_load(struct kvm_vcpu *vcpu) kpreempt_enable(); } +struct kvm_vcpu * +kvm_get_vcpu(struct kvm *kvm, int i) +{ +#ifdef XXX + smp_rmb(); +#else + XXX_KVM_PROBE; +#endif + return (kvm->vcpus[i]); +} + void vcpu_put(struct kvm_vcpu *vcpu) { @@ -480,13 +525,18 @@ kvm_free_physmem(struct kvm *kvm) kmem_free(kvm->memslots, sizeof (struct kvm_memslots)); } - void kvm_get_kvm(struct kvm *kvm) { atomic_inc_32(&kvm->users_count); } +unsigned long +kvm_dirty_bitmap_bytes(struct kvm_memory_slot *memslot) +{ + return (BT_SIZEOFMAP(memslot->npages)); +} + /* * Allocate some memory and give it an address in the guest physical address * space. @@ -1149,6 +1199,12 @@ mark_page_dirty(struct kvm *kvm, gfn_t gfn) } } +int +kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu) +{ + return (vcpu->kvm->bsp_vcpu_id == vcpu->vcpu_id); +} + /* * The vCPU has executed a HLT instruction with in-kernel mode enabled. */ @@ -1659,6 +1715,39 @@ kvm_guest_enter(void) #endif } +/* + * Find the first cleared bit in a memory region. + */ +unsigned long +find_first_zero_bit(const unsigned long *addr, unsigned long size) +{ + const unsigned long *p = addr; + unsigned long result = 0; + unsigned long tmp; + + while (size & ~(64-1)) { + if (~(tmp = *(p++))) + goto found; + result += 64; + size -= 64; + } + if (!size) + return (result); + + tmp = (*p) | (~0UL << size); + if (tmp == ~0UL) /* Are any bits zero? */ + return (result + size); /* Nope. */ +found: + return (result + ffz(tmp)); +} + +int +zero_constructor(void *buf, void *arg, int tags) +{ + bzero(buf, (size_t)arg); + return (0); +} + static int kvm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { @@ -3028,3 +3028,49 @@ kvm_avlmmucmp(const void *arg1, const void *arg2) ASSERT(mp1->kmp_avlspt == mp2->kmp_avlspt); return (0); } + +inline page_t * +compound_head(page_t *page) +{ + /* XXX - linux links page_t together. */ + return (page); +} + +inline void +get_page(page_t *page) +{ + page = compound_head(page); +} + +page_t * +pfn_to_page(pfn_t pfn) +{ + return (page_numtopp_nolock(pfn)); +} + +page_t * +alloc_page(size_t size, int flag) +{ + caddr_t page_addr; + pfn_t pfn; + page_t *pp; + + if ((page_addr = kmem_zalloc(size, flag)) == NULL) + return ((page_t *)NULL); + + pp = page_numtopp_nolock(hat_getpfnum(kas.a_hat, page_addr)); + return (pp); +} + +/* + * Often times we have pages that correspond to addresses that are in a users + * virtual address space. Rather than trying to constantly map them in and out + * of our address space we instead go through and use the kpm segment to + * facilitate this for us. This always returns an address that is always in the + * kernel's virtual address space. + */ +caddr_t +page_address(page_t *page) +{ + return (hat_kpm_mapin_pfn(page->p_pagenum)); +} diff --git a/kvm_subr.c b/kvm_subr.c deleted file mode 100644 index 845fb5f..0000000 --- a/kvm_subr.c +++ /dev/null @@ -1,496 +0,0 @@ -#include <sys/types.h> -#include <sys/param.h> -#include <sys/errno.h> -#include <sys/uio.h> -#include <sys/buf.h> -#include <sys/modctl.h> -#include <sys/open.h> -#include <sys/kmem.h> -#include <sys/poll.h> -#include <sys/conf.h> -#include <sys/cmn_err.h> -#include <sys/stat.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/atomic.h> -#include <sys/spl.h> -#include <sys/cpuvar.h> -#include <sys/segments.h> - -#include "kvm_bitops.h" -#include "msr.h" -#include "kvm_vmx.h" -#include "irqflags.h" -#include "kvm_iodev.h" -#include "kvm_x86impl.h" -#include "kvm_host.h" -#include "kvm_x86host.h" -#include "kvm.h" - -extern int lwp_sigmask(int, uint_t, uint_t, uint_t, uint_t); - -unsigned long -kvm_dirty_bitmap_bytes(struct kvm_memory_slot *memslot) -{ - return (BT_SIZEOFMAP(memslot->npages)); -} - -struct kvm_vcpu * -kvm_get_vcpu(struct kvm *kvm, int i) -{ -#ifdef XXX - smp_rmb(); -#endif - return (kvm->vcpus[i]); -} - -void -kvm_fx_save(struct i387_fxsave_struct *image) -{ - __asm__("fxsave (%0)":: "r" (image)); -} - -void -kvm_fx_restore(struct i387_fxsave_struct *image) -{ - __asm__("fxrstor (%0)":: "r" (image)); -} - -void -kvm_fx_finit(void) -{ - __asm__("finit"); -} - -uint32_t -get_rdx_init_val(void) -{ - return (0x600); /* P6 family */ -} - -void -kvm_inject_gp(struct kvm_vcpu *vcpu, uint32_t error_code) -{ - kvm_queue_exception_e(vcpu, GP_VECTOR, error_code); -} - -void -kvm_sigprocmask(int how, sigset_t *setp, sigset_t *osetp) -{ - k_sigset_t kset; - - ASSERT(how == SIG_SETMASK); - ASSERT(setp != NULL); - - sigutok(setp, &kset); - - if (osetp != NULL) - sigktou(&curthread->t_hold, osetp); - - (void) lwp_sigmask(SIG_SETMASK, - kset.__sigbits[0], kset.__sigbits[1], kset.__sigbits[2], 0); -} - -unsigned long long -native_read_tscp(unsigned int *aux) -{ - unsigned long low, high; - __asm__ volatile(".byte 0x0f,0x01,0xf9" - : "=a" (low), "=d" (high), "=c" (*aux)); - return (low | ((uint64_t)high << 32)); -} - -unsigned long long -native_read_msr(unsigned int msr) -{ - DECLARE_ARGS(val, low, high); - - __asm__ volatile("rdmsr" : EAX_EDX_RET(val, low, high) : "c" (msr)); - return (EAX_EDX_VAL(val, low, high)); -} - -void -native_write_msr(unsigned int msr, unsigned low, unsigned high) -{ - __asm__ volatile("wrmsr" : : "c" (msr), - "a"(low), "d" (high) : "memory"); -} - -unsigned long long -__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)); -} - -unsigned long long -native_read_pmc(int counter) -{ - DECLARE_ARGS(val, low, high); - - __asm__ volatile("rdpmc" : EAX_EDX_RET(val, low, high) : "c" (counter)); - return (EAX_EDX_VAL(val, low, high)); -} - -int -wrmsr_safe(unsigned msr, unsigned low, unsigned high) -{ - return (native_write_msr_safe(msr, low, high)); -} - -int -rdmsrl_safe(unsigned msr, unsigned long long *p) -{ - int err; - - *p = native_read_msr_safe(msr, &err); - return (err); -} - -unsigned long -read_msr(unsigned long msr) -{ - uint64_t value; - - rdmsrl(msr, value); - return (value); -} - -unsigned long -kvm_read_tr_base(void) -{ - unsigned short tr; - __asm__("str %0" : "=g"(tr)); - return (segment_base(tr)); -} - -int -kvm_xcall_func(kvm_xcall_t func, void *arg) -{ - if (func != NULL) - (*func)(arg); - - return (0); -} - -void -kvm_xcall(processorid_t cpu, kvm_xcall_t func, void *arg) -{ - cpuset_t set; - - CPUSET_ZERO(set); - - if (cpu == KVM_CPUALL) { - CPUSET_ALL(set); - } else { - CPUSET_ADD(set, cpu); - } - - kpreempt_disable(); - xc_sync((xc_arg_t)func, (xc_arg_t)arg, 0, CPUSET2BV(set), - (xc_func_t) kvm_xcall_func); - kpreempt_enable(); -} - - - -unsigned short -kvm_read_fs(void) -{ - unsigned short seg; - __asm__("mov %%fs, %0" : "=g"(seg)); - return (seg); -} - -unsigned short -kvm_read_gs(void) -{ - unsigned short seg; - __asm__("mov %%gs, %0" : "=g"(seg)); - return (seg); -} - -unsigned short -kvm_read_ldt(void) -{ - unsigned short ldt; - __asm__("sldt %0" : "=g"(ldt)); - return (ldt); -} - -void -kvm_load_fs(unsigned short sel) -{ - __asm__("mov %0, %%fs" : : "rm"(sel)); -} - -void -kvm_load_gs(unsigned short sel) -{ - __asm__("mov %0, %%gs" : : "rm"(sel)); -} - -void -kvm_load_ldt(unsigned short sel) -{ - __asm__("lldt %0" : : "rm"(sel)); -} - - -void -kvm_get_idt(struct descriptor_table *table) -{ - __asm__("sidt %0" : "=m"(*table)); -} - -void -kvm_get_gdt(struct descriptor_table *table) -{ - __asm__("sgdt %0" : "=m"(*table)); -} - -/* - * Find the first cleared bit in a memory region. - */ -unsigned long -find_first_zero_bit(const unsigned long *addr, unsigned long size) -{ - const unsigned long *p = addr; - unsigned long result = 0; - unsigned long tmp; - - while (size & ~(64-1)) { - if (~(tmp = *(p++))) - goto found; - result += 64; - size -= 64; - } - if (!size) - return (result); - - tmp = (*p) | (~0UL << size); - if (tmp == ~0UL) /* Are any bits zero? */ - return (result + size); /* Nope. */ -found: - return (result + ffz(tmp)); -} - -int -zero_constructor(void *buf, void *arg, int tags) -{ - bzero(buf, (size_t)arg); - return (0); -} - -/* - * Volatile isn't enough to prevent the compiler from reordering the - * read/write functions for the control registers and messing everything up. - * A memory clobber would solve the problem, but would prevent reordering of - * all loads stores around it, which can hurt performance. Solution is to - * use a variable and mimic reads and writes to it to enforce serialization - */ -static unsigned long __force_order; - -unsigned long -native_read_cr0(void) -{ - unsigned long val; - __asm__ volatile("mov %%cr0,%0\n\t" : "=r" (val), "=m" (__force_order)); - return (val); -} - -unsigned long -native_read_cr4(void) -{ - unsigned long val; - __asm__ volatile("mov %%cr4,%0\n\t" : "=r" (val), "=m" (__force_order)); - return (val); -} - -unsigned long -native_read_cr3(void) -{ - unsigned long val; - __asm__ volatile("mov %%cr3,%0\n\t" : "=r" (val), "=m" (__force_order)); - return (val); -} - -inline unsigned long -get_desc_limit(const struct desc_struct *desc) -{ - return (desc->c.b.limit0 | (desc->c.b.limit << 16)); -} - -unsigned long -get_desc_base(const struct desc_struct *desc) -{ - return (unsigned)(desc->c.b.base0 | ((desc->c.b.base1) << 16) | - ((desc->c.b.base2) << 24)); -} - -inline page_t * -compound_head(page_t *page) -{ - /* XXX - linux links page_t together. */ - return (page); -} - -inline void -get_page(page_t *page) -{ - page = compound_head(page); -} - - -page_t * -pfn_to_page(pfn_t pfn) -{ - return (page_numtopp_nolock(pfn)); -} - - -inline void -kvm_clear_exception_queue(struct kvm_vcpu *vcpu) -{ - vcpu->arch.exception.pending = 0; -} - -inline void -kvm_queue_interrupt(struct kvm_vcpu *vcpu, uint8_t vector, int soft) -{ - vcpu->arch.interrupt.pending = 1; - vcpu->arch.interrupt.soft = soft; - vcpu->arch.interrupt.nr = vector; -} - -inline void -kvm_clear_interrupt_queue(struct kvm_vcpu *vcpu) -{ - vcpu->arch.interrupt.pending = 0; -} - -int -kvm_event_needs_reinjection(struct kvm_vcpu *vcpu) -{ - return (vcpu->arch.exception.pending || vcpu->arch.interrupt.pending || - vcpu->arch.nmi_injected); -} - -inline int -kvm_exception_is_soft(unsigned int nr) -{ - return (nr == BP_VECTOR) || (nr == OF_VECTOR); -} - -inline int -is_protmode(struct kvm_vcpu *vcpu) -{ - return (kvm_read_cr0_bits(vcpu, X86_CR0_PE)); -} - -int -is_long_mode(struct kvm_vcpu *vcpu) -{ -#ifdef CONFIG_X86_64 - return (vcpu->arch.efer & EFER_LMA); -#else - return (0); -#endif -} - -inline int -is_pae(struct kvm_vcpu *vcpu) -{ - return (kvm_read_cr4_bits(vcpu, X86_CR4_PAE)); -} - -int -is_pse(struct kvm_vcpu *vcpu) -{ - return (kvm_read_cr4_bits(vcpu, X86_CR4_PSE)); -} - -int -is_paging(struct kvm_vcpu *vcpu) -{ - return (kvm_read_cr0_bits(vcpu, X86_CR0_PG)); -} - -uint64_t -native_read_msr_safe(unsigned int msr, int *err) -{ - DECLARE_ARGS(val, low, high); - uint64_t ret = 0; - on_trap_data_t otd; - - if (on_trap(&otd, OT_DATA_ACCESS) == 0) { - ret = native_read_msr(msr); - *err = 0; - } else { - *err = EINVAL; /* XXX probably not right... */ - } - no_trap(); - - return (ret); -} - -/* Can be uninlined because referenced by paravirt */ -int -native_write_msr_safe(unsigned int msr, unsigned low, unsigned high) -{ - int err = 0; - on_trap_data_t otd; - - if (on_trap(&otd, OT_DATA_ACCESS) == 0) { - native_write_msr(msr, low, high); - } else { - err = EINVAL; /* XXX probably not right... */ - } - no_trap(); - - return (err); -} - - -/* XXX Where should this live */ -page_t * -alloc_page(size_t size, int flag) -{ - caddr_t page_addr; - pfn_t pfn; - page_t *pp; - - if ((page_addr = kmem_zalloc(size, flag)) == NULL) - return ((page_t *)NULL); - - pp = page_numtopp_nolock(hat_getpfnum(kas.a_hat, page_addr)); - return (pp); -} - -int -kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu) -{ - return (vcpu->kvm->bsp_vcpu_id == vcpu->vcpu_id); -} - -/* - * Often times we have pages that correspond to addresses that are in a users - * virtual address space. Rather than trying to constantly map them in and out - * of our address space we instead go through and use the kpm segment to - * facilitate this for us. This always returns an address that is always in the - * kernel's virtual address space. - */ -caddr_t -page_address(page_t *page) -{ - return (hat_kpm_mapin_pfn(page->p_pagenum)); -} - -uint32_t -bit(int bitno) -{ - return (1 << (bitno & 31)); -} @@ -39,9 +39,16 @@ /* XXX These don't belong here! */ extern caddr_t smmap64(caddr_t addr, size_t len, int prot, int flags, int fd, off_t pos); +extern int lwp_sigmask(int, uint_t, uint_t, uint_t, uint_t); static unsigned long empty_zero_page[PAGESIZE / sizeof (unsigned long)]; +/* + * Globals + */ +struct kvm_x86_ops *kvm_x86_ops; +int ignore_msrs = 0; + #define MAX_IO_MSRS 256 #define CR0_RESERVED_BITS \ (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \ @@ -67,11 +74,24 @@ static uint64_t efer_reserved_bits = 0xfffffffffffffffeULL; #endif static void update_cr8_intercept(struct kvm_vcpu *); +static struct kvm_shared_msrs_global shared_msrs_global; -struct kvm_x86_ops *kvm_x86_ops; -int ignore_msrs = 0; +void +kvm_sigprocmask(int how, sigset_t *setp, sigset_t *osetp) +{ + k_sigset_t kset; -static struct kvm_shared_msrs_global shared_msrs_global; + ASSERT(how == SIG_SETMASK); + ASSERT(setp != NULL); + + sigutok(setp, &kset); + + if (osetp != NULL) + sigktou(&curthread->t_hold, osetp); + + (void) lwp_sigmask(SIG_SETMASK, + kset.__sigbits[0], kset.__sigbits[1], kset.__sigbits[2], 0); +} static void kvm_on_user_return(struct kvm_vcpu *vcpu, struct kvm_user_return_notifier *urn) @@ -293,6 +313,12 @@ kvm_inject_nmi(struct kvm_vcpu *vcpu) } void +kvm_inject_gp(struct kvm_vcpu *vcpu, uint32_t error_code) +{ + kvm_queue_exception_e(vcpu, GP_VECTOR, error_code); +} + +void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, uint32_t error_code) { kvm_multiple_exception(vcpu, nr, 1, error_code); @@ -4600,6 +4626,24 @@ typedef struct fxsave { #endif } fxsave_t; +void +kvm_fx_save(struct i387_fxsave_struct *image) +{ + __asm__("fxsave (%0)":: "r" (image)); +} + +void +kvm_fx_restore(struct i387_fxsave_struct *image) +{ + __asm__("fxrstor (%0)":: "r" (image)); +} + +void +kvm_fx_finit(void) +{ + __asm__("finit"); +} + int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { @@ -5248,8 +5292,284 @@ kvm_va2pa(caddr_t va) return (pa); } +uint32_t +get_rdx_init_val(void) +{ + return (0x600); /* P6 family */ +} + +unsigned long long +native_read_msr(unsigned int msr) +{ + DECLARE_ARGS(val, low, high); + + __asm__ volatile("rdmsr" : EAX_EDX_RET(val, low, high) : "c" (msr)); + return (EAX_EDX_VAL(val, low, high)); +} + void -kvm_migrate_timers(struct kvm_vcpu *vcpu) +native_write_msr(unsigned int msr, unsigned low, unsigned high) +{ + __asm__ volatile("wrmsr" : : "c" (msr), + "a"(low), "d" (high) : "memory"); +} + +unsigned long long +__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)); +} + +unsigned long long +native_read_pmc(int counter) +{ + DECLARE_ARGS(val, low, high); + + __asm__ volatile("rdpmc" : EAX_EDX_RET(val, low, high) : "c" (counter)); + return (EAX_EDX_VAL(val, low, high)); +} + +int +wrmsr_safe(unsigned msr, unsigned low, unsigned high) +{ + return (native_write_msr_safe(msr, low, high)); +} + +int +rdmsrl_safe(unsigned msr, unsigned long long *p) +{ + int err; + + *p = native_read_msr_safe(msr, &err); + return (err); +} + +unsigned long +read_msr(unsigned long msr) +{ + uint64_t value; + + rdmsrl(msr, value); + return (value); +} + +uint64_t +native_read_msr_safe(unsigned int msr, int *err) +{ + DECLARE_ARGS(val, low, high); + uint64_t ret = 0; + on_trap_data_t otd; + + if (on_trap(&otd, OT_DATA_ACCESS) == 0) { + ret = native_read_msr(msr); + *err = 0; + } else { + *err = EINVAL; /* XXX probably not right... */ + } + no_trap(); + + return (ret); +} + +/* Can be uninlined because referenced by paravirt */ +int +native_write_msr_safe(unsigned int msr, unsigned low, unsigned high) +{ + int err = 0; + on_trap_data_t otd; + + if (on_trap(&otd, OT_DATA_ACCESS) == 0) { + native_write_msr(msr, low, high); + } else { + err = EINVAL; /* XXX probably not right... */ + } + no_trap(); + + return (err); +} + +unsigned long +kvm_read_tr_base(void) +{ + unsigned short tr; + __asm__("str %0" : "=g"(tr)); + return (segment_base(tr)); +} + +unsigned short +kvm_read_fs(void) +{ + unsigned short seg; + __asm__("mov %%fs, %0" : "=g"(seg)); + return (seg); +} + +unsigned short +kvm_read_gs(void) +{ + unsigned short seg; + __asm__("mov %%gs, %0" : "=g"(seg)); + return (seg); +} + +unsigned short +kvm_read_ldt(void) +{ + unsigned short ldt; + __asm__("sldt %0" : "=g"(ldt)); + return (ldt); +} + +void +kvm_load_fs(unsigned short sel) +{ + __asm__("mov %0, %%fs" : : "rm"(sel)); +} + +void +kvm_load_gs(unsigned short sel) +{ + __asm__("mov %0, %%gs" : : "rm"(sel)); +} + +void +kvm_load_ldt(unsigned short sel) +{ + __asm__("lldt %0" : : "rm"(sel)); +} + + +void +kvm_get_idt(struct descriptor_table *table) +{ + __asm__("sidt %0" : "=m"(*table)); +} + +void +kvm_get_gdt(struct descriptor_table *table) +{ + __asm__("sgdt %0" : "=m"(*table)); +} + +/* + * Volatile isn't enough to prevent the compiler from reordering the + * read/write functions for the control registers and messing everything up. + * A memory clobber would solve the problem, but would prevent reordering of + * all loads stores around it, which can hurt performance. Solution is to + * use a variable and mimic reads and writes to it to enforce serialization + */ +static unsigned long __force_order; + +unsigned long +native_read_cr0(void) +{ + unsigned long val; + __asm__ volatile("mov %%cr0,%0\n\t" : "=r" (val), "=m" (__force_order)); + return (val); +} + +unsigned long +native_read_cr4(void) +{ + unsigned long val; + __asm__ volatile("mov %%cr4,%0\n\t" : "=r" (val), "=m" (__force_order)); + return (val); +} + +unsigned long +native_read_cr3(void) +{ + unsigned long val; + __asm__ volatile("mov %%cr3,%0\n\t" : "=r" (val), "=m" (__force_order)); + return (val); +} + +inline unsigned long +get_desc_limit(const struct desc_struct *desc) +{ + return (desc->c.b.limit0 | (desc->c.b.limit << 16)); +} + +unsigned long +get_desc_base(const struct desc_struct *desc) +{ + return (unsigned)(desc->c.b.base0 | ((desc->c.b.base1) << 16) | + ((desc->c.b.base2) << 24)); +} + +inline void +kvm_clear_exception_queue(struct kvm_vcpu *vcpu) +{ + vcpu->arch.exception.pending = 0; +} + +inline void +kvm_queue_interrupt(struct kvm_vcpu *vcpu, uint8_t vector, int soft) +{ + vcpu->arch.interrupt.pending = 1; + vcpu->arch.interrupt.soft = soft; + vcpu->arch.interrupt.nr = vector; +} + +inline void +kvm_clear_interrupt_queue(struct kvm_vcpu *vcpu) +{ + vcpu->arch.interrupt.pending = 0; +} + +int +kvm_event_needs_reinjection(struct kvm_vcpu *vcpu) +{ + return (vcpu->arch.exception.pending || vcpu->arch.interrupt.pending || + vcpu->arch.nmi_injected); +} + +inline int +kvm_exception_is_soft(unsigned int nr) +{ + return (nr == BP_VECTOR) || (nr == OF_VECTOR); +} + +inline int +is_protmode(struct kvm_vcpu *vcpu) +{ + return (kvm_read_cr0_bits(vcpu, X86_CR0_PE)); +} + +int +is_long_mode(struct kvm_vcpu *vcpu) +{ +#ifdef CONFIG_X86_64 + return (vcpu->arch.efer & EFER_LMA); +#else + return (0); +#endif +} + +inline int +is_pae(struct kvm_vcpu *vcpu) +{ + return (kvm_read_cr4_bits(vcpu, X86_CR4_PAE)); +} + +int +is_pse(struct kvm_vcpu *vcpu) +{ + return (kvm_read_cr4_bits(vcpu, X86_CR4_PSE)); +} + +int +is_paging(struct kvm_vcpu *vcpu) +{ + return (kvm_read_cr0_bits(vcpu, X86_CR0_PG)); +} + +uint32_t +bit(int bitno) { - set_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests); + return (1 << (bitno & 31)); } @@ -132,15 +132,6 @@ do { \ (high) = (uint32_t)(_l >> 32); \ } while (0) -#define rdtscp(low, high, aux) \ -do { \ - unsigned long long _val = native_read_tscp(&(aux)); \ - (low) = (uint32_t)_val; \ - (high) = (uint32_t)(_val >> 32); \ -} while (0) - -#define rdtscpll(val, aux) (val) = native_read_tscp(&(aux)) - #endif /* !CONFIG_PARAVIRT */ |