Commit 7ba1e619 authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Add KVM support to QEMU



This patch adds very basic KVM support.  KVM is a kernel module for Linux that
allows userspace programs to make use of hardware virtualization support.  It
current supports x86 hardware virtualization using Intel VT-x or AMD-V.  It
also supports IA64 VT-i, PPC 440, and S390.

This patch only implements the bare minimum support to get a guest booting.  It
has very little impact the rest of QEMU and attempts to integrate nicely with
the rest of QEMU.

Even though this implementation is basic, it is significantly faster than TCG.
Booting and shutting down a Linux guest:

w/TCG:  1:32.36 elapsed  84% CPU

w/KVM:  0:31.14 elapsed  59% CPU

Right now, KVM is disabled by default and must be explicitly enabled with
 -enable-kvm.  We can enable it by default later when we have had better
testing.

Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5627 c046a42c-6fe2-441c-8c8c-71466251a162
parent 6fd805e1
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -183,6 +183,9 @@ CFLAGS+=-I/opt/SUNWspro/prod/include/cc
endif
endif

kvm.o: CFLAGS+=$(KVM_CFLAGS)
kvm-all.o: CFLAGS+=$(KVM_CFLAGS)

all: $(PROGS)

#########################################################
@@ -581,6 +584,9 @@ ifndef CONFIG_USER_ONLY
OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o net-checksum.o
OBJS+=fw_cfg.o aio.o buffered_file.o migration.o migration-tcp.o qemu-char.o
OBJS+=net.o
ifdef CONFIG_KVM
OBJS+=kvm.o kvm-all.o
endif
ifdef CONFIG_WIN32
OBJS+=block-raw-win32.o
else
+48 −0
Original line number Diff line number Diff line
@@ -115,6 +115,7 @@ aio="yes"
nptl="yes"
mixemu="no"
bluez="yes"
kvm="yes"

# OS specific
targetos=`uname -s`
@@ -303,6 +304,8 @@ for opt do
  ;;
  --disable-bluez) bluez="no"
  ;;
  --disable-kvm) kvm="no"
  ;;
  --enable-profiler) profiler="yes"
  ;;
  --enable-cocoa)
@@ -448,6 +451,7 @@ echo " --disable-brlapi disable BrlAPI"
echo "  --disable-vnc-tls        disable TLS encryption for VNC server"
echo "  --disable-curses         disable curses output"
echo "  --disable-bluez          disable bluez stack connectivity"
echo "  --disable-kvm            disable KVM acceleration support"
echo "  --disable-nptl           disable usermode NPTL support"
echo "  --enable-system          enable all system emulation targets"
echo "  --disable-system         disable all system emulation targets"
@@ -950,6 +954,30 @@ EOF
  fi
fi

##########################################
# kvm probe
if test "$kvm" = "yes" ; then
    cat > $TMPC <<EOF
#include <linux/kvm.h>
#if !defined(KVM_API_VERSION) || \
    KVM_API_VERSION < 12 || \
    KVM_API_VERSION > 12 || \
    !defined(KVM_CAP_USER_MEMORY) || \
    !defined(KVM_CAP_SET_TSS_ADDR)
#error Invalid KVM version
#endif
int main(void) { return 0; }
EOF
  # FIXME make this configurable
  kvm_cflags=-I/lib/modules/`uname -r`/build/include
  if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $kvm_cflags $TMPC \
      2>/dev/null ; then
    :
  else
    kvm="no"
  fi
fi

##########################################
# AIO probe
if test "$aio" = "yes" ; then
@@ -1036,6 +1064,7 @@ echo "uname -r $uname_release"
echo "NPTL support      $nptl"
echo "vde support       $vde"
echo "AIO support       $aio"
echo "KVM support       $kvm"

if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -1411,6 +1440,15 @@ interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
gdb_xml_files=""

# FIXME allow i386 to build on x86_64 and vice versa
if test "$kvm" = "yes" -a "$target_cpu" != "$cpu" ; then
  kvm="no"
fi
# Disable KVM for linux-user
if test "$kvm" = "yes" -a "$target_softmmu" = "no" ; then
  kvm="no"
fi

case "$target_cpu" in
  i386)
    echo "TARGET_ARCH=i386" >> $config_mak
@@ -1420,6 +1458,11 @@ case "$target_cpu" in
    then
      echo "#define USE_KQEMU 1" >> $config_h
    fi
    if test "$kvm" = "yes" ; then
      echo "CONFIG_KVM=yes" >> $config_mak
      echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
      echo "#define CONFIG_KVM" >> $config_h
    fi
    gcc3minver=`$cc --version 2> /dev/null| fgrep "(GCC) 3." | awk '{ print $3 }' | cut -f2 -d.`
    if test -n "$gcc3minver" && test $gcc3minver -gt 3
    then
@@ -1437,6 +1480,11 @@ case "$target_cpu" in
    then
      echo "#define USE_KQEMU 1" >> $config_h
    fi
    if test "$kvm" = "yes" ; then
      echo "CONFIG_KVM=yes" >> $config_mak
      echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
      echo "#define CONFIG_KVM 1" >> $config_h
    fi
  ;;
  alpha)
    echo "TARGET_ARCH=alpha" >> $config_mak
+7 −1
Original line number Diff line number Diff line
@@ -142,6 +142,9 @@ typedef struct icount_decr_u16 {
} icount_decr_u16;
#endif

struct kvm_run;
struct KVMState;

#define CPU_TEMP_BUF_NLONGS 128
#define CPU_COMMON                                                      \
    struct TranslationBlock *current_tb; /* currently executing TB  */  \
@@ -199,6 +202,9 @@ typedef struct icount_decr_u16 {
    /* user data */                                                     \
    void *opaque;                                                       \
                                                                        \
    const char *cpu_model_str;
    const char *cpu_model_str;                                          \
    struct KVMState *kvm_state;                                         \
    struct kvm_run *kvm_run;                                            \
    int kvm_fd;

#endif
+14 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include "exec.h"
#include "disas.h"
#include "tcg.h"
#include "kvm.h"

#if !defined(CONFIG_SOFTMMU)
#undef EAX
@@ -371,6 +372,19 @@ int cpu_exec(CPUState *env1)
            }
#endif

            if (kvm_enabled()) {
                int ret;
                ret = kvm_cpu_exec(env);
                if ((env->interrupt_request & CPU_INTERRUPT_EXIT)) {
                    env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
                    env->exception_index = EXCP_INTERRUPT;
                    cpu_loop_exit();
                } else if (env->halted) {
                    cpu_loop_exit();
                } else
                    longjmp(env->jmp_env, 1);
            }

            next_tb = 0; /* force lookup of first TB */
            for(;;) {
                interrupt_request = env->interrupt_request;
+4 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#include "tcg.h"
#include "hw/hw.h"
#include "osdep.h"
#include "kvm.h"
#if defined(CONFIG_USER_ONLY)
#include <qemu.h>
#endif
@@ -2212,6 +2213,9 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr,
        kqemu_set_phys_mem(start_addr, size, phys_offset);
    }
#endif
    if (kvm_enabled())
        kvm_set_phys_mem(start_addr, size, phys_offset);

    size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
    end_addr = start_addr + (target_phys_addr_t)size;
    for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
Loading