diff --git a/cutils.c b/cutils.c index f9a7e3689e..28049e0699 100644 --- a/cutils.c +++ b/cutils.c @@ -322,7 +322,8 @@ int fcntl_setfl(int fd, int flag) * value must be terminated by whitespace, ',' or '\0'. Return -1 on * error. */ -int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix) +int64_t strtosz_suffix_unit(const char *nptr, char **end, + const char default_suffix, int64_t unit) { int64_t retval = -1; char *endptr; @@ -362,20 +363,20 @@ int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix) } break; case STRTOSZ_DEFSUFFIX_KB: - mul = 1 << 10; + mul = unit; break; case 0: if (mul_required) { goto fail; } case STRTOSZ_DEFSUFFIX_MB: - mul = 1ULL << 20; + mul = unit * unit; break; case STRTOSZ_DEFSUFFIX_GB: - mul = 1ULL << 30; + mul = unit * unit * unit; break; case STRTOSZ_DEFSUFFIX_TB: - mul = 1ULL << 40; + mul = unit * unit * unit * unit; break; default: goto fail; @@ -405,6 +406,11 @@ fail: return retval; } +int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix) +{ + return strtosz_suffix_unit(nptr, end, default_suffix, 1024); +} + int64_t strtosz(const char *nptr, char **end) { return strtosz_suffix(nptr, end, STRTOSZ_DEFSUFFIX_MB); diff --git a/hw/kvmclock.c b/hw/kvmclock.c index 692ad182f0..b73aec409c 100644 --- a/hw/kvmclock.c +++ b/hw/kvmclock.c @@ -101,11 +101,8 @@ static SysBusDeviceInfo kvmclock_info = { void kvmclock_create(void) { if (kvm_enabled() && - first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE) -#ifdef KVM_FEATURE_CLOCKSOURCE2 - || (1ULL << KVM_FEATURE_CLOCKSOURCE2) -#endif - )) { + first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE) | + (1ULL << KVM_FEATURE_CLOCKSOURCE2))) { sysbus_create_simple("kvmclock", -1, NULL); } } diff --git a/kvm-all.c b/kvm-all.c index cbc253235e..b9c172b664 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1328,7 +1328,6 @@ int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset) int kvm_set_ioeventfd_mmio_long(int fd, uint32_t addr, uint32_t val, bool assign) { -#ifdef KVM_IOEVENTFD int ret; struct kvm_ioeventfd iofd; @@ -1353,14 +1352,10 @@ int kvm_set_ioeventfd_mmio_long(int fd, uint32_t addr, uint32_t val, bool assign } return 0; -#else - return -ENOSYS; -#endif } int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign) { -#ifdef KVM_IOEVENTFD struct kvm_ioeventfd kick = { .datamatch = val, .addr = addr, @@ -1380,9 +1375,6 @@ int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign) return r; } return 0; -#else - return -ENOSYS; -#endif } int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr) diff --git a/qemu-common.h b/qemu-common.h index 0fdecf1ede..74d5c4b962 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -157,6 +157,8 @@ int fcntl_setfl(int fd, int flag); #define STRTOSZ_DEFSUFFIX_B 'B' int64_t strtosz(const char *nptr, char **end); int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix); +int64_t strtosz_suffix_unit(const char *nptr, char **end, + const char default_suffix, int64_t unit); /* path.c */ void init_paths(const char *prefix); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index ae0e4b1438..4a6f675f98 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -743,6 +743,7 @@ typedef struct CPUX86State { uint32_t cpuid_kvm_features; uint32_t cpuid_svm_features; bool tsc_valid; + int tsc_khz; /* in order to simplify APIC support, we leave this pointer to the user */ diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c index e1ae3af1e3..89e9623859 100644 --- a/target-i386/cpuid.c +++ b/target-i386/cpuid.c @@ -224,6 +224,7 @@ typedef struct x86_def_t { int family; int model; int stepping; + int tsc_khz; uint32_t features, ext_features, ext2_features, ext3_features; uint32_t kvm_features, svm_features; uint32_t xlevel; @@ -704,6 +705,17 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) } else if (!strcmp(featurestr, "model_id")) { pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id), val); + } else if (!strcmp(featurestr, "tsc_freq")) { + int64_t tsc_freq; + char *err; + + tsc_freq = strtosz_suffix_unit(val, &err, + STRTOSZ_DEFSUFFIX_B, 1000); + if (!*val || *err) { + fprintf(stderr, "bad numerical value %s\n", val); + goto error; + } + x86_cpu_def->tsc_khz = tsc_freq / 1000; } else { fprintf(stderr, "unrecognized feature %s\n", featurestr); goto error; @@ -872,6 +884,7 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model) env->cpuid_svm_features = def->svm_features; env->cpuid_ext4_features = def->ext4_features; env->cpuid_xlevel2 = def->xlevel2; + env->tsc_khz = def->tsc_khz; if (!kvm_enabled()) { env->cpuid_features &= TCG_FEATURES; env->cpuid_ext_features &= TCG_EXT_FEATURES; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 10fb2c4b07..31b88b7499 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -354,6 +354,7 @@ int kvm_arch_init_vcpu(CPUState *env) uint32_t unused; struct kvm_cpuid_entry2 *c; uint32_t signature[3]; + int r; env->cpuid_features &= kvm_arch_get_supported_cpuid(s, 1, 0, R_EDX); @@ -499,7 +500,20 @@ int kvm_arch_init_vcpu(CPUState *env) qemu_add_vm_change_state_handler(cpu_update_state, env); - return kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data); + r = kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data); + if (r) + return r; + + r = kvm_check_extension(env->kvm_state, KVM_CAP_TSC_CONTROL); + if (r && env->tsc_khz) { + r = kvm_vcpu_ioctl(env, KVM_SET_TSC_KHZ, env->tsc_khz); + if (r < 0) { + fprintf(stderr, "KVM_SET_TSC_KHZ failed\n"); + return r; + } + } + + return 0; } void kvm_arch_reset_vcpu(CPUState *env)