7aa81cc047
This patch refactors the current hypercall infrastructure to better support live migration and SMP. It eliminates the hypercall page by trapping the UD exception that would occur if you used the wrong hypercall instruction for the underlying architecture and replacing it with the right one lazily. A fall-out of this patch is that the unhandled hypercalls no longer trap to userspace. There is very little reason though to use a hypercall to communicate with userspace as PIO or MMIO can be used. There is no code in tree that uses userspace hypercalls. [avi: fix #ud injection on vmx] Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
111 lines
2.7 KiB
C
111 lines
2.7 KiB
C
#ifndef __LINUX_KVM_PARA_H
|
|
#define __LINUX_KVM_PARA_H
|
|
|
|
/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
|
|
* should be used to determine that a VM is running under KVM.
|
|
*/
|
|
#define KVM_CPUID_SIGNATURE 0x40000000
|
|
|
|
/* This CPUID returns a feature bitmap in eax. Before enabling a particular
|
|
* paravirtualization, the appropriate feature bit should be checked.
|
|
*/
|
|
#define KVM_CPUID_FEATURES 0x40000001
|
|
|
|
/* Return values for hypercalls */
|
|
#define KVM_ENOSYS 1000
|
|
|
|
#ifdef __KERNEL__
|
|
#include <asm/processor.h>
|
|
|
|
/* This instruction is vmcall. On non-VT architectures, it will generate a
|
|
* trap that we will then rewrite to the appropriate instruction.
|
|
*/
|
|
#define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1"
|
|
|
|
/* For KVM hypercalls, a three-byte sequence of either the vmrun or the vmmrun
|
|
* instruction. The hypervisor may replace it with something else but only the
|
|
* instructions are guaranteed to be supported.
|
|
*
|
|
* Up to four arguments may be passed in rbx, rcx, rdx, and rsi respectively.
|
|
* The hypercall number should be placed in rax and the return value will be
|
|
* placed in rax. No other registers will be clobbered unless explicited
|
|
* noted by the particular hypercall.
|
|
*/
|
|
|
|
static inline long kvm_hypercall0(unsigned int nr)
|
|
{
|
|
long ret;
|
|
asm volatile(KVM_HYPERCALL
|
|
: "=a"(ret)
|
|
: "a"(nr));
|
|
return ret;
|
|
}
|
|
|
|
static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
|
|
{
|
|
long ret;
|
|
asm volatile(KVM_HYPERCALL
|
|
: "=a"(ret)
|
|
: "a"(nr), "b"(p1));
|
|
return ret;
|
|
}
|
|
|
|
static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
|
|
unsigned long p2)
|
|
{
|
|
long ret;
|
|
asm volatile(KVM_HYPERCALL
|
|
: "=a"(ret)
|
|
: "a"(nr), "b"(p1), "c"(p2));
|
|
return ret;
|
|
}
|
|
|
|
static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
|
|
unsigned long p2, unsigned long p3)
|
|
{
|
|
long ret;
|
|
asm volatile(KVM_HYPERCALL
|
|
: "=a"(ret)
|
|
: "a"(nr), "b"(p1), "c"(p2), "d"(p3));
|
|
return ret;
|
|
}
|
|
|
|
static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
|
|
unsigned long p2, unsigned long p3,
|
|
unsigned long p4)
|
|
{
|
|
long ret;
|
|
asm volatile(KVM_HYPERCALL
|
|
: "=a"(ret)
|
|
: "a"(nr), "b"(p1), "c"(p2), "d"(p3), "S"(p4));
|
|
return ret;
|
|
}
|
|
|
|
static inline int kvm_para_available(void)
|
|
{
|
|
unsigned int eax, ebx, ecx, edx;
|
|
char signature[13];
|
|
|
|
cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
|
|
memcpy(signature + 0, &ebx, 4);
|
|
memcpy(signature + 4, &ecx, 4);
|
|
memcpy(signature + 8, &edx, 4);
|
|
signature[12] = 0;
|
|
|
|
if (strcmp(signature, "KVMKVMKVM") == 0)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int kvm_para_has_feature(unsigned int feature)
|
|
{
|
|
if (cpuid_eax(KVM_CPUID_FEATURES) & (1UL << feature))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|