diff options
author | Avi Kivity <avi@qumranet.com> | 2006-12-21 09:42:23 +0000 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2006-12-21 09:42:23 +0000 |
commit | 5d3591f37c26d30dae7a53cb9b48b0a1b7e56980 (patch) | |
tree | f70b467a9a117618653cc69f5f91d070b11e07d6 | |
parent | ec9c42312eb1341ec33002a52915287b35bb55d1 (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.h | 3 | ||||
-rw-r--r-- | kvm/kernel/kvm_main.c | 30 | ||||
-rw-r--r-- | kvm/kernel/svm.c | 2 | ||||
-rw-r--r-- | kvm/kernel/vmx.c | 3 | ||||
-rw-r--r-- | kvm/user/kvmctl.c | 25 | ||||
-rw-r--r-- | migration.c | 39 |
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; } |