aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2006-12-21 09:42:23 +0000
committerAvi Kivity <avi@qumranet.com>2006-12-21 09:42:23 +0000
commit5d3591f37c26d30dae7a53cb9b48b0a1b7e56980 (patch)
treef70b467a9a117618653cc69f5f91d070b11e07d6
parentec9c42312eb1341ec33002a52915287b35bb55d1 (diff)
kvm: release: merge from trunkkvm-8
........ r4116 | avi | 2006-12-17 10:52:25 +0200 (Sun, 17 Dec 2006) | 11 lines kvm: do not export unsupported msrs to userspace From: Michael Riepe <michael@mr511.de> Some msrs, such as MSR_STAR, are not available on all processors. Exporting them causes qemu to try to fetch them, which will fail. So, check all msrs for validity at module load time. Signed-off-by: Michael Riepe <michael@mr511.de> ........ r4117 | avi | 2006-12-17 11:10:47 +0200 (Sun, 17 Dec 2006) | 4 lines kvm: web: fix -noacpi option in faq noticed by Ingemar Nilsson <init@kth.se> ........ r4119 | avi | 2006-12-17 14:39:24 +0200 (Sun, 17 Dec 2006) | 8 lines kvm: force real-mode cs limit to 64K From: Michael Riepe <michael@mr511.de> this allows opensolaris to boot on kvm/intel. Signed-off-by: Michael Riepe <michael@mr511.de> ........ r4120 | avi | 2006-12-17 14:42:18 +0200 (Sun, 17 Dec 2006) | 8 lines kvm: handle p5 mce msrs From: Michael Riepe <michael@mr511.de> this allows plan9 to get a little further booting. Signed-off-by: Michael Riepe <michael@mr511.de> ........ r4126 | uri | 2006-12-19 11:48:31 +0200 (Tue, 19 Dec 2006) | 4 lines qemu migration interface: add "listening" status #143 Simon's request is my (migration status) command (to be changed) ........ r4127 | uri | 2006-12-19 13:13:08 +0200 (Tue, 19 Dec 2006) | 5 lines qemu migration interface: set FAIL status for every failure (#143) Including failure to open/bind/listen-to a socket. Also migration_cleanup() now always sets the status (even if fd is FD_UNUSED) ........ r4128 | avi | 2006-12-19 17:04:30 +0200 (Tue, 19 Dec 2006) | 2 lines kvm: web: clarify /proc/cpuinfo availability wrt kernel versions ........ r4132 | avi | 2006-12-20 14:11:44 +0200 (Wed, 20 Dec 2006) | 2 lines kvm: web: mention kvm-commits mailing list ........ r4143 | avi | 2006-12-21 11:36:10 +0200 (Thu, 21 Dec 2006) | 2 lines kvm: add api versioning ........ r4144 | avi | 2006-12-21 11:36:43 +0200 (Thu, 21 Dec 2006) | 2 lines kvm: libkvm: add kernel api version check ........
-rw-r--r--kvm/kernel/include/linux/kvm.h3
-rw-r--r--kvm/kernel/kvm_main.c30
-rw-r--r--kvm/kernel/svm.c2
-rw-r--r--kvm/kernel/vmx.c3
-rw-r--r--kvm/user/kvmctl.c25
-rw-r--r--migration.c39
6 files changed, 84 insertions, 18 deletions
diff --git a/kvm/kernel/include/linux/kvm.h b/kvm/kernel/include/linux/kvm.h
index 5bb2c3c58..28fdce1ac 100644
--- a/kvm/kernel/include/linux/kvm.h
+++ b/kvm/kernel/include/linux/kvm.h
@@ -11,6 +11,8 @@
#include <asm/types.h>
#include <linux/ioctl.h>
+#define KVM_API_VERSION 1
+
/*
* Architectural interrupt line count, and the size of the bitmap needed
* to hold them.
@@ -209,6 +211,7 @@ struct kvm_dirty_log {
#define KVMIO 0xAE
+#define KVM_GET_API_VERSION _IO(KVMIO, 1)
#define KVM_RUN _IOWR(KVMIO, 2, struct kvm_run)
#define KVM_GET_REGS _IOWR(KVMIO, 3, struct kvm_regs)
#define KVM_SET_REGS _IOW(KVMIO, 4, struct kvm_regs)
diff --git a/kvm/kernel/kvm_main.c b/kvm/kernel/kvm_main.c
index 4621b4ee6..3df93eff8 100644
--- a/kvm/kernel/kvm_main.c
+++ b/kvm/kernel/kvm_main.c
@@ -1417,6 +1417,9 @@ static int kvm_dev_ioctl_set_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
/*
* List of msr numbers which we expose to userspace through KVM_GET_MSRS
* and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST.
+ *
+ * This list is modified at module load time to reflect the
+ * capabilities of the host cpu.
*/
static u32 msrs_to_save[] = {
MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
@@ -1427,6 +1430,22 @@ static u32 msrs_to_save[] = {
MSR_IA32_TIME_STAMP_COUNTER,
};
+static unsigned num_msrs_to_save = 0;
+
+static __init void kvm_init_msr_list(void)
+{
+ u32 dummy[2];
+ unsigned i, j;
+
+ for (i = j = 0; i < ARRAY_SIZE(msrs_to_save); i++) {
+ if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0)
+ continue;
+ if (j < i)
+ msrs_to_save[j] = msrs_to_save[i];
+ j++;
+ }
+ num_msrs_to_save = j;
+}
/*
* Adapt set_msr() to msr_io()'s calling convention
@@ -1584,6 +1603,9 @@ static long kvm_dev_ioctl(struct file *filp,
int r = -EINVAL;
switch (ioctl) {
+ case KVM_GET_API_VERSION:
+ r = KVM_API_VERSION;
+ break;
case KVM_CREATE_VCPU: {
r = kvm_dev_ioctl_create_vcpu(kvm, arg);
if (r)
@@ -1735,15 +1757,15 @@ static long kvm_dev_ioctl(struct file *filp,
if (copy_from_user(&msr_list, user_msr_list, sizeof msr_list))
goto out;
n = msr_list.nmsrs;
- msr_list.nmsrs = ARRAY_SIZE(msrs_to_save);
+ msr_list.nmsrs = num_msrs_to_save;
if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list))
goto out;
r = -E2BIG;
- if (n < ARRAY_SIZE(msrs_to_save))
+ if (n < num_msrs_to_save)
goto out;
r = -EFAULT;
if (copy_to_user(user_msr_list->indices, &msrs_to_save,
- sizeof msrs_to_save))
+ num_msrs_to_save * sizeof(u32)))
goto out;
r = 0;
}
@@ -1894,6 +1916,8 @@ static __init int kvm_init(void)
kvm_init_debug();
+ kvm_init_msr_list();
+
if ((bad_page = alloc_page(GFP_KERNEL)) == NULL) {
r = -ENOMEM;
goto out;
diff --git a/kvm/kernel/svm.c b/kvm/kernel/svm.c
index 59c930f27..9ec87636d 100644
--- a/kvm/kernel/svm.c
+++ b/kvm/kernel/svm.c
@@ -1073,6 +1073,8 @@ static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_ru
static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
{
switch (ecx) {
+ case MSR_IA32_P5_MC_ADDR:
+ case MSR_IA32_P5_MC_TYPE:
case MSR_IA32_MC0_CTL:
case MSR_IA32_MCG_STATUS:
case MSR_IA32_MCG_CAP:
diff --git a/kvm/kernel/vmx.c b/kvm/kernel/vmx.c
index f0f0b1a78..983a15b19 100644
--- a/kvm/kernel/vmx.c
+++ b/kvm/kernel/vmx.c
@@ -359,6 +359,8 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
case MSR_IA32_SYSENTER_ESP:
data = vmcs_read32(GUEST_SYSENTER_ESP);
break;
+ case MSR_IA32_P5_MC_ADDR:
+ case MSR_IA32_P5_MC_TYPE:
case MSR_IA32_MC0_CTL:
case MSR_IA32_MCG_STATUS:
case MSR_IA32_MCG_CAP:
@@ -726,6 +728,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
vmcs_write32(GUEST_SS_AR_BYTES, 0xf3);
vmcs_write32(GUEST_CS_AR_BYTES, 0xf3);
+ vmcs_write32(GUEST_CS_LIMIT, 0xffff);
vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) >> 4);
fix_rmode_seg(VCPU_SREG_ES, &vcpu->rmode.es);
diff --git a/kvm/user/kvmctl.c b/kvm/user/kvmctl.c
index 844fc57b7..7f712e71a 100644
--- a/kvm/user/kvmctl.c
+++ b/kvm/user/kvmctl.c
@@ -23,6 +23,12 @@
#include <errno.h>
#include "kvmctl.h"
+#define EXPECTED_KVM_API_VERSION 1
+
+#if EXPECTED_KVM_API_VERSION != KVM_API_VERSION
+#error libkvm: userspace and kernel version mismatch
+#endif
+
#define PAGE_SIZE 4096ul
struct kvm_context {
@@ -74,17 +80,34 @@ kvm_context_t kvm_init(struct kvm_callbacks *callbacks,
{
int fd;
kvm_context_t kvm;
+ int r;
fd = open("/dev/kvm", O_RDWR);
if (fd == -1) {
- perror("open");
+ perror("open /dev/kvm");
return NULL;
}
+ r = ioctl(fd, KVM_GET_API_VERSION, 0);
+ if (r == -1) {
+ fprintf(stderr, "kvm kernel version too old\n");
+ goto out_close;
+ }
+ if (r < EXPECTED_KVM_API_VERSION) {
+ fprintf(stderr, "kvm kernel version too old\n");
+ goto out_close;
+ }
+ if (r > EXPECTED_KVM_API_VERSION) {
+ fprintf(stderr, "kvm userspace version too old\n");
+ goto out_close;
+ }
kvm = malloc(sizeof(*kvm));
kvm->fd = fd;
kvm->callbacks = callbacks;
kvm->opaque = opaque;
return kvm;
+ out_close:
+ close(fd);
+ return NULL;
}
void kvm_finalize(kvm_context_t kvm)
diff --git a/migration.c b/migration.c
index 80ec292d5..1bf515efd 100644
--- a/migration.c
+++ b/migration.c
@@ -28,11 +28,12 @@ typedef enum {
typedef enum {
MIG_STAT_NONE = 0, /* disconnected */
- MIG_STAT_CONN = 1, /* connection established */
- MIG_STAT_START = 2, /* migration started */
- MIG_STAT_SUCC = 3, /* migration completed successfully */
- MIG_STAT_FAIL = 4, /* migration failed */
- MIG_STAT_CANCEL = 5 /* migration canceled */
+ MIG_STAT_LISTEN = 1, /* listening, waiting for the other to connect */
+ MIG_STAT_CONN = 2, /* connection established */
+ MIG_STAT_START = 3, /* migration started */
+ MIG_STAT_SUCC = 4, /* migration completed successfully */
+ MIG_STAT_FAIL = 5, /* migration failed */
+ MIG_STAT_CANCEL = 6 /* migration canceled */
} migration_status_t;
typedef struct migration_bandwith_params {
@@ -68,6 +69,7 @@ static const char *writer_default_addr="localhost:4456";
/* forward declarations */
static void migration_start_dst(int online);
+static void migration_cleanup(migration_state_t *pms, migration_status_t stat);
static const char *mig_stat_str(migration_status_t mig_stat)
@@ -76,9 +78,10 @@ static const char *mig_stat_str(migration_status_t mig_stat)
migration_status_t stat;
const char *str;
} stat_strs[] = {
- {MIG_STAT_NONE, "disconnected"},
- {MIG_STAT_CONN, "connected"},
- {MIG_STAT_START, "migration stared"},
+ {MIG_STAT_NONE, "disconnected"},
+ {MIG_STAT_LISTEN, "listening"},
+ {MIG_STAT_CONN, "connected"},
+ {MIG_STAT_START, "migration stared"},
{MIG_STAT_SUCC, "migration completed successfully"},
{MIG_STAT_FAIL, "migration failed"},
{MIG_STAT_CANCEL, "migration canceled"}
@@ -141,7 +144,8 @@ static int parse_host_port_and_message(struct sockaddr_in *saddr,
if (!arg)
arg = default_addr;
if (parse_host_port(saddr, arg) < 0) {
- term_printf("%s: invalid argument '%s'", name, arg);
+ term_printf("%s: invalid argument '%s'\n", name, arg);
+ migration_cleanup(&ms, MIG_STAT_FAIL);
return -1;
}
return 0;
@@ -155,8 +159,8 @@ static void migration_cleanup(migration_state_t *pms, migration_status_t stat)
#endif
close(pms->fd);
pms->fd = FD_UNUSED;
- pms->status = stat;
}
+ pms->status = stat;
}
static int migration_read_from_socket(void *opaque)
@@ -179,6 +183,7 @@ static int migration_read_from_socket(void *opaque)
if (socket_error() == EINTR)
continue;
term_printf("migration_read_from_socket: read failed (%s)\n", strerror(errno) );
+ migration_cleanup(pms, MIG_STAT_FAIL);
return size;
}
if (size == 0) {
@@ -218,6 +223,7 @@ static int migration_write_into_socket(void *opaque, int len)
continue;
term_printf("migration_write_into_socket: write failed (%s)\n",
strerror(socket_error()) );
+ migration_cleanup(pms, MIG_STAT_FAIL);
return size;
}
if (size == 0) {
@@ -252,6 +258,7 @@ static void migration_accept(void *opaque)
if (new_fd < 0 && errno != EINTR) {
term_printf("migration listen: accept failed (%s)\n",
strerror(errno));
+ migration_cleanup(pms, MIG_STAT_FAIL);
return;
} else if (new_fd >= 0) {
break;
@@ -296,6 +303,7 @@ void do_migration_listen(char *arg1, char *arg2)
if (ms.fd < 0) {
term_printf("migration listen: socket() failed (%s)\n",
strerror(errno));
+ migration_cleanup(&ms, MIG_STAT_FAIL);
return;
}
@@ -304,17 +312,18 @@ void do_migration_listen(char *arg1, char *arg2)
setsockopt(ms.fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
if (bind(ms.fd, &local, sizeof local) < 0 ) {
- migration_cleanup(&ms, MIG_STAT_NONE);
+ migration_cleanup(&ms, MIG_STAT_FAIL);
term_printf("migration listen: bind() failed (%s)\n", strerror(errno));
return;
}
if (listen(ms.fd, 1) < 0) { /* allow only one connection */
- migration_cleanup(&ms, MIG_STAT_NONE);
+ migration_cleanup(&ms, MIG_STAT_FAIL);
term_printf("migration listen: listen() failed (%s)\n", strerror(errno));
return;
}
+ ms.status = MIG_STAT_LISTEN;
term_printf("migration listen: listening on fd %d\n", ms.fd);
#ifdef USE_NONBLOCKING_SOCKETS
@@ -451,7 +460,7 @@ static void migration_connect_check(void *opaque)
rc = getsockopt(pms->fd, SOL_SOCKET, SO_ERROR, (void *)&err, &len);
if (rc != 0) {
term_printf("migration connect: getsockopt FAILED (%s)\n", strerror(errno));
- migration_cleanup(pms, MIG_STAT_NONE);
+ migration_cleanup(pms, MIG_STAT_FAIL);
return;
}
if (err == 0) {
@@ -460,6 +469,7 @@ static void migration_connect_check(void *opaque)
}
else {
term_printf("migration connect: failed to conenct (%s)\n", strerror(err));
+ migration_cleanup(pms, MIG_STAT_FAIL);
return;
}
@@ -490,6 +500,7 @@ void do_migration_connect(char *arg1, char *arg2)
if (ms.fd < 0) {
term_printf("migration connect: socket() failed (%s)\n",
strerror(errno));
+ migration_cleanup(&ms, MIG_STAT_FAIL);
return;
}
@@ -504,7 +515,7 @@ void do_migration_connect(char *arg1, char *arg2)
if (errno != EINPROGRESS) {
term_printf("migration connect: connect() failed (%s)\n",
strerror(errno));
- migration_cleanup(&ms, MIG_STAT_NONE);
+ migration_cleanup(&ms, MIG_STAT_FAIL);
}
return;
}