Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/kvm/uq/master' into staging
Browse files Browse the repository at this point in the history
* remotes/kvm/uq/master:
  kvm: Fix eax for cpuid leaf 0x40000000
  kvmclock: Ensure proper env->tsc value for kvmclock_current_nsec calculation
  kvm: Enable -cpu option to hide KVM
  kvm: Ensure negative return value on kvm_init() error handling path
  target-i386: set CC_OP to CC_OP_EFLAGS in cpu_load_eflags
  target-i386: get CPL from SS.DPL
  target-i386: rework CPL checks during task switch, preparing for next patch
  target-i386: fix segment flags for SMM and VM86 mode
  target-i386: Fix vm86 mode regression introduced in fd46060.
  kvm_stat: allow choosing between tracepoints and old stats
  kvmclock: Ensure time in migration never goes backward

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Jun 5, 2014
2 parents d4f005d + 79b6f2f commit 9f0355b
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 77 deletions.
2 changes: 1 addition & 1 deletion bsd-user/main.c
Expand Up @@ -1004,7 +1004,7 @@ int main(int argc, char **argv)

#if defined(TARGET_I386)
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
env->hflags |= HF_PE_MASK;
env->hflags |= HF_PE_MASK | HF_CPL_MASK;
if (env->features[FEAT_1_EDX] & CPUID_SSE) {
env->cr[4] |= CR4_OSFXSR_MASK;
env->hflags |= HF_OSFXSR_MASK;
Expand Down
52 changes: 52 additions & 0 deletions hw/i386/kvm/clock.c
Expand Up @@ -14,8 +14,10 @@
*/

#include "qemu-common.h"
#include "qemu/host-utils.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
#include "sysemu/cpus.h"
#include "hw/sysbus.h"
#include "hw/kvm/clock.h"

Expand All @@ -34,6 +36,48 @@ typedef struct KVMClockState {
bool clock_valid;
} KVMClockState;

struct pvclock_vcpu_time_info {
uint32_t version;
uint32_t pad0;
uint64_t tsc_timestamp;
uint64_t system_time;
uint32_t tsc_to_system_mul;
int8_t tsc_shift;
uint8_t flags;
uint8_t pad[2];
} __attribute__((__packed__)); /* 32 bytes */

static uint64_t kvmclock_current_nsec(KVMClockState *s)
{
CPUState *cpu = first_cpu;
CPUX86State *env = cpu->env_ptr;
hwaddr kvmclock_struct_pa = env->system_time_msr & ~1ULL;
uint64_t migration_tsc = env->tsc;
struct pvclock_vcpu_time_info time;
uint64_t delta;
uint64_t nsec_lo;
uint64_t nsec_hi;
uint64_t nsec;

if (!(env->system_time_msr & 1ULL)) {
/* KVM clock not active */
return 0;
}

cpu_physical_memory_read(kvmclock_struct_pa, &time, sizeof(time));

assert(time.tsc_timestamp <= migration_tsc);
delta = migration_tsc - time.tsc_timestamp;
if (time.tsc_shift < 0) {
delta >>= -time.tsc_shift;
} else {
delta <<= time.tsc_shift;
}

mulu64(&nsec_lo, &nsec_hi, delta, time.tsc_to_system_mul);
nsec = (nsec_lo >> 32) | (nsec_hi << 32);
return nsec + time.system_time;
}

static void kvmclock_vm_state_change(void *opaque, int running,
RunState state)
Expand All @@ -45,9 +89,15 @@ static void kvmclock_vm_state_change(void *opaque, int running,

if (running) {
struct kvm_clock_data data;
uint64_t time_at_migration = kvmclock_current_nsec(s);

s->clock_valid = false;

/* We can't rely on the migrated clock value, just discard it */
if (time_at_migration) {
s->clock = time_at_migration;
}

data.clock = s->clock;
data.flags = 0;
ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
Expand Down Expand Up @@ -75,6 +125,8 @@ static void kvmclock_vm_state_change(void *opaque, int running,
if (s->clock_valid) {
return;
}

cpu_synchronize_all_states();
ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
if (ret < 0) {
fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
Expand Down
4 changes: 3 additions & 1 deletion kvm-all.c
Expand Up @@ -1410,7 +1410,7 @@ int kvm_init(MachineClass *mc)

ret = kvm_ioctl(s, KVM_GET_API_VERSION, 0);
if (ret < KVM_API_VERSION) {
if (ret > 0) {
if (ret >= 0) {
ret = -EINVAL;
}
fprintf(stderr, "kvm version too old\n");
Expand Down Expand Up @@ -1461,6 +1461,7 @@ int kvm_init(MachineClass *mc)
if (mc->kvm_type) {
type = mc->kvm_type(kvm_type);
} else if (kvm_type) {
ret = -EINVAL;
fprintf(stderr, "Invalid argument kvm-type=%s\n", kvm_type);
goto err;
}
Expand Down Expand Up @@ -1561,6 +1562,7 @@ int kvm_init(MachineClass *mc)
return 0;

err:
assert(ret < 0);
if (s->vmfd >= 0) {
close(s->vmfd);
}
Expand Down
2 changes: 1 addition & 1 deletion linux-user/main.c
Expand Up @@ -4052,7 +4052,7 @@ int main(int argc, char **argv, char **envp)

#if defined(TARGET_I386)
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
env->hflags |= HF_PE_MASK;
env->hflags |= HF_PE_MASK | HF_CPL_MASK;
if (env->features[FEAT_1_EDX] & CPUID_SSE) {
env->cr[4] |= CR4_OSFXSR_MASK;
env->hflags |= HF_OSFXSR_MASK;
Expand Down
60 changes: 41 additions & 19 deletions scripts/kvm/kvm_stat
Expand Up @@ -352,8 +352,8 @@ class TracepointProvider(object):
return ret

class Stats:
def __init__(self, provider, fields = None):
self.provider = provider
def __init__(self, providers, fields = None):
self.providers = providers
self.fields_filter = fields
self._update()
def _update(self):
Expand All @@ -362,22 +362,25 @@ class Stats:
if not self.fields_filter:
return True
return re.match(self.fields_filter, key) is not None
self.values = dict([(key, None)
for key in provider.fields()
if wanted(key)])
self.provider.select(self.values.keys())
self.values = dict()
for d in providers:
provider_fields = [key for key in d.fields() if wanted(key)]
for key in provider_fields:
self.values[key] = None
d.select(provider_fields)
def set_fields_filter(self, fields_filter):
self.fields_filter = fields_filter
self._update()
def get(self):
new = self.provider.read()
for key in self.provider.fields():
oldval = self.values.get(key, (0, 0))
newval = new[key]
newdelta = None
if oldval is not None:
newdelta = newval - oldval[0]
self.values[key] = (newval, newdelta)
for d in providers:
new = d.read()
for key in d.fields():
oldval = self.values.get(key, (0, 0))
newval = new[key]
newdelta = None
if oldval is not None:
newdelta = newval - oldval[0]
self.values[key] = (newval, newdelta)
return self.values

if not os.access('/sys/kernel/debug', os.F_OK):
Expand Down Expand Up @@ -487,6 +490,18 @@ options.add_option('-l', '--log',
dest = 'log',
help = 'run in logging mode (like vmstat)',
)
options.add_option('-t', '--tracepoints',
action = 'store_true',
default = False,
dest = 'tracepoints',
help = 'retrieve statistics from tracepoints',
)
options.add_option('-d', '--debugfs',
action = 'store_true',
default = False,
dest = 'debugfs',
help = 'retrieve statistics from debugfs',
)
options.add_option('-f', '--fields',
action = 'store',
default = None,
Expand All @@ -495,12 +510,19 @@ options.add_option('-f', '--fields',
)
(options, args) = options.parse_args(sys.argv)

try:
provider = TracepointProvider()
except:
provider = DebugfsProvider()
providers = []
if options.tracepoints:
providers.append(TracepointProvider())
if options.debugfs:
providers.append(DebugfsProvider())

if len(providers) == 0:
try:
providers = [TracepointProvider()]
except:
providers = [DebugfsProvider()]

stats = Stats(provider, fields = options.fields)
stats = Stats(providers, fields = options.fields)

if options.log:
log(stats)
Expand Down
1 change: 1 addition & 0 deletions target-i386/cpu-qom.h
Expand Up @@ -87,6 +87,7 @@ typedef struct X86CPU {
bool hyperv_time;
bool check_cpuid;
bool enforce_cpuid;
bool expose_kvm;

/* if true the CPUID code directly forward host cache leaves to the guest */
bool cache_info_passthrough;
Expand Down
1 change: 1 addition & 0 deletions target-i386/cpu.c
Expand Up @@ -2792,6 +2792,7 @@ static Property x86_cpu_properties[] = {
DEFINE_PROP_BOOL("hv-time", X86CPU, hyperv_time, false),
DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, false),
DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false),
DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true),
DEFINE_PROP_END_OF_LIST()
};

Expand Down
13 changes: 7 additions & 6 deletions target-i386/cpu.h
Expand Up @@ -986,7 +986,6 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env,
/* update the hidden flags */
{
if (seg_reg == R_CS) {
int cpl = selector & 3;
#ifdef TARGET_X86_64
if ((env->hflags & HF_LMA_MASK) && (flags & DESC_L_MASK)) {
/* long mode */
Expand All @@ -996,15 +995,14 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env,
#endif
{
/* legacy / compatibility case */
if (!(env->cr[0] & CR0_PE_MASK))
cpl = 0;
else if (env->eflags & VM_MASK)
cpl = 3;
new_hflags = (env->segs[R_CS].flags & DESC_B_MASK)
>> (DESC_B_SHIFT - HF_CS32_SHIFT);
env->hflags = (env->hflags & ~(HF_CS32_MASK | HF_CS64_MASK)) |
new_hflags;
}
}
if (seg_reg == R_SS) {
int cpl = (flags >> DESC_DPL_SHIFT) & 3;
#if HF_CPL_MASK != 3
#error HF_CPL_MASK is hardcoded
#endif
Expand Down Expand Up @@ -1234,11 +1232,14 @@ static inline uint32_t cpu_compute_eflags(CPUX86State *env)
return env->eflags | cpu_cc_compute_all(env, CC_OP) | (env->df & DF_MASK);
}

/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */
/* NOTE: the translator must set DisasContext.cc_op to CC_OP_EFLAGS
* after generating a call to a helper that uses this.
*/
static inline void cpu_load_eflags(CPUX86State *env, int eflags,
int update_mask)
{
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
CC_OP = CC_OP_EFLAGS;
env->df = 1 - (2 * ((eflags >> 10) & 1));
env->eflags = (env->eflags & ~update_mask) |
(eflags & update_mask) | 0x2;
Expand Down
4 changes: 3 additions & 1 deletion target-i386/gdbstub.c
Expand Up @@ -127,9 +127,11 @@ static int x86_cpu_gdb_load_seg(X86CPU *cpu, int sreg, uint8_t *mem_buf)
target_ulong base;

if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
int dpl = (env->eflags & VM_MASK) ? 3 : 0;
base = selector << 4;
limit = 0xffff;
flags = 0;
flags = DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
DESC_A_MASK | (dpl << DESC_DPL_SHIFT);
} else {
if (!cpu_x86_get_descr_debug(env, selector, &base, &limit,
&flags)) {
Expand Down
30 changes: 16 additions & 14 deletions target-i386/kvm.c
Expand Up @@ -528,23 +528,25 @@ int kvm_arch_init_vcpu(CPUState *cs)
has_msr_hv_hypercall = true;
}

memcpy(signature, "KVMKVMKVM\0\0\0", 12);
c = &cpuid_data.entries[cpuid_i++];
c->function = KVM_CPUID_SIGNATURE | kvm_base;
c->eax = 0;
c->ebx = signature[0];
c->ecx = signature[1];
c->edx = signature[2];
if (cpu->expose_kvm) {
memcpy(signature, "KVMKVMKVM\0\0\0", 12);
c = &cpuid_data.entries[cpuid_i++];
c->function = KVM_CPUID_SIGNATURE | kvm_base;
c->eax = KVM_CPUID_FEATURES | kvm_base;
c->ebx = signature[0];
c->ecx = signature[1];
c->edx = signature[2];

c = &cpuid_data.entries[cpuid_i++];
c->function = KVM_CPUID_FEATURES | kvm_base;
c->eax = env->features[FEAT_KVM];
c = &cpuid_data.entries[cpuid_i++];
c->function = KVM_CPUID_FEATURES | kvm_base;
c->eax = env->features[FEAT_KVM];

has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);

has_msr_pv_eoi_en = c->eax & (1 << KVM_FEATURE_PV_EOI);
has_msr_pv_eoi_en = c->eax & (1 << KVM_FEATURE_PV_EOI);

has_msr_kvm_steal_time = c->eax & (1 << KVM_FEATURE_STEAL_TIME);
has_msr_kvm_steal_time = c->eax & (1 << KVM_FEATURE_STEAL_TIME);
}

cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);

Expand Down Expand Up @@ -1430,7 +1432,7 @@ static int kvm_get_sregs(X86CPU *cpu)
HF_OSFXSR_MASK | HF_LMA_MASK | HF_CS32_MASK | \
HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)

hflags = (env->segs[R_CS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
hflags = (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
hflags |= (env->cr[0] & CR0_PE_MASK) << (HF_PE_SHIFT - CR0_PE_SHIFT);
hflags |= (env->cr[0] << (HF_MP_SHIFT - CR0_MP_SHIFT)) &
(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK);
Expand Down
8 changes: 8 additions & 0 deletions target-i386/machine.c
Expand Up @@ -312,6 +312,14 @@ static int cpu_post_load(void *opaque, int version_id)
env->segs[R_SS].flags &= ~(env->segs[R_SS].flags & DESC_DPL_MASK);
}

/* Older versions of QEMU incorrectly used CS.DPL as the CPL when
* running under KVM. This is wrong for conforming code segments.
* Luckily, in our implementation the CPL field of hflags is redundant
* and we can get the right value from the SS descriptor privilege level.
*/
env->hflags &= ~HF_CPL_MASK;
env->hflags |= (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;

/* XXX: restore FPU round state */
env->fpstt = (env->fpus_vmstate >> 11) & 7;
env->fpus = env->fpus_vmstate & ~0x3800;
Expand Down

0 comments on commit 9f0355b

Please sign in to comment.