Skip to contentSkip to conversation

qemu-kvm.git uq/master queue

GIT PULL In review Marcelo Tosatti 5 participants 12 messages Apr 16, 2011 – Apr 27, 2011 KVM

lore
Share & tools
lore
#0 lore raw

The following changes since commit adc56dda0c4eed62149d28939b7d7e329ad95ae8:

migration: move some declarations to migration.h (2011-04-15 20:14:54 +0000)

are available in the git repository at:
git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git uq/master

Glauber Costa (3):
kvm: use kernel-provided para_features instead of statically coming up with new capabilities
kvm: add kvmclock to its second bit
kvm: create kvmclock when one of the flags are present

Jan Kiszka (3):
Break up user and system cpu_interrupt implementations Redirect cpu_interrupt to callback handler
kvm: Install specialized interrupt handler

 cpu-all.h           |   14 ++++++++-
 exec.c              |   18 ++++++++---
 hw/kvmclock.c       |    6 +++-
 kvm-all.c           |   11 +++++++
 target-i386/cpuid.c |    3 +-
 target-i386/kvm.c   |   78 ++++++++++++++++++++++++++++++++-------------------
 6 files changed, 92 insertions(+), 38 deletions(-)
#1 lore raw

PATCH 1/6 kvm: use kernel-provided para_features instead of statically coming up with new capabilities

From: Glauber Costa <[email protected]>

Use the features provided by KVM_GET_SUPPORTED_CPUID directly to mask out features from guest-visible cpuid.

The old get_para_features() mechanism is kept for older kernels that do not implement it.

---
 target-i386/kvm.c |   78 +++++++++++++++++++++++++++++++++-------------------
 1 files changed, 49 insertions(+), 29 deletions(-)
target-i386/kvm.c +49 -29
index a13599d..485572f 100644
@@ -92,6 +92,35 @@ static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
     return cpuid;
 }
 
+#ifdef CONFIG_KVM_PARA
+struct kvm_para_features {
+    int cap;
+    int feature;
+} para_features[] = {
+    { KVM_CAP_CLOCKSOURCE, KVM_FEATURE_CLOCKSOURCE },
+    { KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY },
+    { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP },
+#ifdef KVM_CAP_ASYNC_PF
+    { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF },
+#endif
+    { -1, -1 }
+};
+
+static int get_para_features(CPUState *env)
+{
+    int i, features = 0;
+
+    for (i = 0; i < ARRAY_SIZE(para_features) - 1; i++) {
+        if (kvm_check_extension(env->kvm_state, para_features[i].cap)) {
+            features |= (1 << para_features[i].feature);
+        }
+    }
+
+    return features;
+}
+#endif
+
+
 uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
                                       uint32_t index, int reg)
 {
@@ -99,6 +128,9 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
     int i, max;
     uint32_t ret = 0;
     uint32_t cpuid_1_edx;
+#ifdef CONFIG_KVM_PARA
+    int has_kvm_features = 0;
+#endif
 
     max = 1;
     while ((cpuid = try_get_cpuid(env->kvm_state, max)) == NULL) {
@@ -108,6 +140,11 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
     for (i = 0; i < cpuid->nent; ++i) {
         if (cpuid->entries[i].function == function &&
             cpuid->entries[i].index == index) {
+#ifdef CONFIG_KVM_PARA
+            if (cpuid->entries[i].function == KVM_CPUID_FEATURES) {
+                has_kvm_features = 1;
+            }
+#endif
             switch (reg) {
             case R_EAX:
                 ret = cpuid->entries[i].eax;
@@ -140,38 +177,15 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
 
     qemu_free(cpuid);
 
-    return ret;
-}
-
 #ifdef CONFIG_KVM_PARA
-struct kvm_para_features {
-    int cap;
-    int feature;
-} para_features[] = {
-    { KVM_CAP_CLOCKSOURCE, KVM_FEATURE_CLOCKSOURCE },
-    { KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY },
-    { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP },
-#ifdef KVM_CAP_ASYNC_PF
-    { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF },
-#endif
-    { -1, -1 }
-};
-
-static int get_para_features(CPUState *env)
-{
-    int i, features = 0;
-
-    for (i = 0; i < ARRAY_SIZE(para_features) - 1; i++) {
-        if (kvm_check_extension(env->kvm_state, para_features[i].cap)) {
-            features |= (1 << para_features[i].feature);
-        }
+    /* fallback for older kernels */
+    if (!has_kvm_features && (function == KVM_CPUID_FEATURES)) {
+        ret = get_para_features(env);
     }
-#ifdef KVM_CAP_ASYNC_PF
-    has_msr_async_pf_en = features & (1 << KVM_FEATURE_ASYNC_PF);
 #endif
-    return features;
+
+    return ret;
 }
-#endif /* CONFIG_KVM_PARA */
 
 typedef struct HWPoisonPage {
     ram_addr_t ram_addr;
@@ -397,7 +411,13 @@ int kvm_arch_init_vcpu(CPUState *env)
     c = &cpuid_data.entries[cpuid_i++];
     memset(c, 0, sizeof(*c));
     c->function = KVM_CPUID_FEATURES;
-    c->eax = env->cpuid_kvm_features & get_para_features(env);
+    c->eax = env->cpuid_kvm_features & kvm_arch_get_supported_cpuid(env,
+                                                KVM_CPUID_FEATURES, 0, R_EAX);
+
+#ifdef KVM_CAP_ASYNC_PF
+    has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
+#endif
+
 #endif
 
     cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
Signature · 1 line
1.7.4.2
#2 lore raw

PATCH 2/6 kvm: add kvmclock to its second bit

In reply to Marcelo Tosatti

From: Glauber Costa <[email protected]>

We have two bits that can represent kvmclock in cpuid.
They signal the guest which msr set to use. When we tweak flags involving this value - specially when we use "-", we have to act on both.

Besides adding it to the kvm features list, we also have to "break" the assumption represented by the break in lookup_feature.

---
 target-i386/cpuid.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)
target-i386/cpuid.c +1 -2
index 814d13e..5e48d35 100644
@@ -73,7 +73,7 @@ static const char *ext3_feature_name[] = {
 };
 
 static const char *kvm_feature_name[] = {
-    "kvmclock", "kvm_nopiodelay", "kvm_mmu", NULL, "kvm_asyncpf", NULL, NULL, NULL,
+    "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", "kvm_asyncpf", NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -193,7 +193,6 @@ static int lookup_feature(uint32_t *pval, const char *s, const char *e,
     for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc)
         if (*ppc && !altcmp(s, e, *ppc)) {
             *pval |= mask;
-            break;
         }
     return (mask ? 1 : 0);
 }
Signature · 1 line
1.7.4.2
#3 lore raw

Re: [PATCH 2/6] kvm: add kvmclock to its second bit

Quoted 29 lines · Marcelo Tosatti

From: Glauber Costa <[email protected]>

We have two bits that can represent kvmclock in cpuid.
They signal the guest which msr set to use. When we tweak flags involving this value - specially when we use "-", we have to act on both.

Besides adding it to the kvm features list, we also have to "break" the assumption represented by the break in lookup_feature.

---
 target-i386/cpuid.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)
target-i386/cpuid.c +1 -1
index 814d13e..5e48d35 100644
@@ -73,7 +73,7 @@ static const char *ext3_feature_name[] = {
 };
 
 static const char *kvm_feature_name[] = {
-    "kvmclock", "kvm_nopiodelay", "kvm_mmu", NULL, "kvm_asyncpf", NULL, NULL, NULL,
+    "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", "kvm_asyncpf", NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

target-i386/cpuid.c static int lookup_feature(uint32_t *pval, const char *s, const char *e, · line 198

Quoted 7 lines
target-i386/cpuid.c +0 -1
@@ -193,7 +193,6 @@ static int lookup_feature(uint32_t *pval, const char *s, const char *e,
     for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc)
         if (*ppc && !altcmp(s, e, *ppc)) {
             *pval |= mask;
-            break;
         }
     return (mask ? 1 : 0);
 }

This is required on top to fix the issues Anthony was seeing:

target-i386/cpuid.c +3 -1
index 5e48d35..b7e20e8 100644
@@ -189,12 +189,14 @@ static int lookup_feature(uint32_t *pval, const char *s, const char *e,
 {
     uint32_t mask;
     const char **ppc;
+    int found = 0;
 
     for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc)
         if (*ppc && !altcmp(s, e, *ppc)) {
             *pval |= mask;
+            found = 1;
         }
-    return (mask ? 1 : 0);
+    return found;
 }
 
 static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
#4 lore raw

PATCH v2 1/1 x86: Allow multiple cpu feature matches of lookup_feature

kvmclock is represented by two feature bits. Therefore, lookup_feature needs to continue its search even after the first match. Enhance it accordingly and switch to a bool return type at this chance.

---
 target-i386/cpuid.c |   14 ++++++++------
 1 files changed, 8 insertions(+), 6 deletions(-)

Glauber, could you check/ack this? Marcelo, please respin the series afterward. I'd like to see all bits upstream and merged back into qemu-kvm to proceed with switching the latter to upstream's kvm infrastructure.

target-i386/cpuid.c +8 -6
index 814d13e..0ac592f 100644
@@ -182,20 +182,22 @@ static int altcmp(const char *s, const char *e, const char *altstr)
 }
 
 /* search featureset for flag *[s..e), if found set corresponding bit in
- * *pval and return success, otherwise return zero
+ * *pval and return true, otherwise return false
  */
-static int lookup_feature(uint32_t *pval, const char *s, const char *e,
-    const char **featureset)
+static bool lookup_feature(uint32_t *pval, const char *s, const char *e,
+                           const char **featureset)
 {
     uint32_t mask;
     const char **ppc;
+    bool found = false;
 
-    for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc)
+    for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc) {
         if (*ppc && !altcmp(s, e, *ppc)) {
             *pval |= mask;
-            break;
+            found = true;
         }
-    return (mask ? 1 : 0);
+    }
+    return found;
 }
 
 static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
Signature · 1 line
1.7.1
#5 lore raw

Re: [PATCH v2 2a/6] x86: Allow multiple cpu feature matches of lookup_feature

Quoted 5 lines · Jan Kiszka

kvmclock is represented by two feature bits. Therefore, lookup_feature needs to continue its search even after the first match. Enhance it accordingly and switch to a bool return type at this chance.

Quoted 8 lines
---
 target-i386/cpuid.c |   14 ++++++++------
 1 files changed, 8 insertions(+), 6 deletions(-)

Glauber, could you check/ack this? Marcelo, please respin the series afterward. I'd like to see all bits upstream and merged back into qemu-kvm to proceed with switching the latter to upstream's kvm infrastructure.

Yes, this patch is okay.

Actually, I did sent out something like this, maybe Marcelo applied only part of the series?

Anyway, Jan's version is handy, please apply it.

Quoted 33 lines
target-i386/cpuid.c +8 -6
index 814d13e..0ac592f 100644
@@ -182,20 +182,22 @@ static int altcmp(const char *s, const char *e, const char *altstr)
 }
 
 /* search featureset for flag *[s..e), if found set corresponding bit in
- * *pval and return success, otherwise return zero
+ * *pval and return true, otherwise return false
  */
-static int lookup_feature(uint32_t *pval, const char *s, const char *e,
-    const char **featureset)
+static bool lookup_feature(uint32_t *pval, const char *s, const char *e,
+                           const char **featureset)
 {
     uint32_t mask;
     const char **ppc;
+    bool found = false;
 
-    for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc)
+    for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc) {
         if (*ppc && !altcmp(s, e, *ppc)) {
             *pval |= mask;
-            break;
+            found = true;
         }
-    return (mask ? 1 : 0);
+    }
+    return found;
 }
 
 static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
#6 lore raw

PATCH v2 1/1 kvm: add kvmclock to its second bit

In reply to Jan Kiszka

From: Glauber Costa <[email protected]>

We have two bits that can represent kvmclock in cpuid. They signal the guest which msr set to use. When we tweak flags involving this value - specially when we use "-", we have to act on both.

[Jan: factored out lookup_feature changes]
---
 target-i386/cpuid.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
target-i386/cpuid.c +1 -1
index 0ac592f..e479a4d 100644
@@ -73,7 +73,7 @@ static const char *ext3_feature_name[] = {
 };
 
 static const char *kvm_feature_name[] = {
-    "kvmclock", "kvm_nopiodelay", "kvm_mmu", NULL, "kvm_asyncpf", NULL, NULL, NULL,
+    "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", "kvm_asyncpf", NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Signature · 1 line
1.7.1
#7 lore raw

PATCH 3/6 kvm: create kvmclock when one of the flags are present

In reply to Marcelo Tosatti

From: Glauber Costa <[email protected]>

kvmclock presence can be signalled by two different flags. So for device creation, we have to test for both.

---
 hw/kvmclock.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)
hw/kvmclock.c +5 -1
index b6ceddf..004c4ad 100644
@@ -103,7 +103,11 @@ static SysBusDeviceInfo kvmclock_info = {
 void kvmclock_create(void)
 {
     if (kvm_enabled() &&
-        first_cpu->cpuid_kvm_features & (1ULL << KVM_FEATURE_CLOCKSOURCE)) {
+        first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE)
+#ifdef KVM_FEATURE_CLOCKSOURCE2
+        || (1ULL << KVM_FEATURE_CLOCKSOURCE2)
+#endif
+    )) {
         sysbus_create_simple("kvmclock", -1, NULL);
     }
 }
Signature · 1 line
1.7.4.2
#8 lore raw

PATCH 4/6 Break up user and system cpu_interrupt implementations

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Both have only two lines in common, and we will convert the system service into a callback which is of no use for user mode operation.

---
 exec.c |   14 ++++++++++----
 1 files changed, 10 insertions(+), 4 deletions(-)
exec.c +10 -4
index b1ee52a..cc0806e 100644
@@ -1630,6 +1630,7 @@ static void cpu_unlink_tb(CPUState *env)
     spin_unlock(&interrupt_lock);
 }
 
+#ifndef CONFIG_USER_ONLY
 /* mask must never be zero, except for A20 change call */
 void cpu_interrupt(CPUState *env, int mask)
 {
@@ -1638,7 +1639,6 @@ void cpu_interrupt(CPUState *env, int mask)
     old_mask = env->interrupt_request;
     env->interrupt_request |= mask;
 
-#ifndef CONFIG_USER_ONLY
     /*
      * If called from iothread context, wake the target cpu in
      * case its halted.
@@ -1647,21 +1647,27 @@ void cpu_interrupt(CPUState *env, int mask)
         qemu_cpu_kick(env);
         return;
     }
-#endif
 
     if (use_icount) {
         env->icount_decr.u16.high = 0xffff;
-#ifndef CONFIG_USER_ONLY
         if (!can_do_io(env)
             && (mask & ~old_mask) != 0) {
             cpu_abort(env, "Raised interrupt while not in I/O function");
         }
-#endif
     } else {
         cpu_unlink_tb(env);
     }
 }
 
+#else /* CONFIG_USER_ONLY */
+
+void cpu_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request |= mask;
+    cpu_unlink_tb(env);
+}
+#endif /* CONFIG_USER_ONLY */
+
 void cpu_reset_interrupt(CPUState *env, int mask)
 {
     env->interrupt_request &= ~mask;
Signature · 1 line
1.7.4.2
#9 lore raw

PATCH 5/6 Redirect cpu_interrupt to callback handler

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

This allows to override the interrupt handling of QEMU in system mode. KVM will make use of it to set a specialized handler.

---
 cpu-all.h |   14 +++++++++++++-
 exec.c    |    4 +++-
 2 files changed, 16 insertions(+), 2 deletions(-)
cpu-all.h +13 -1
index dc0f2f0..628206e 100644
@@ -789,7 +789,19 @@ extern CPUState *cpu_single_env;
 #define CPU_INTERRUPT_SIPI   0x800 /* SIPI pending. */
 #define CPU_INTERRUPT_MCE    0x1000 /* (x86 only) MCE pending. */
 
-void cpu_interrupt(CPUState *s, int mask);
+#ifndef CONFIG_USER_ONLY
+typedef void (*CPUInterruptHandler)(CPUState *, int);
+
+extern CPUInterruptHandler cpu_interrupt_handler;
+
+static inline void cpu_interrupt(CPUState *s, int mask)
+{
+    cpu_interrupt_handler(s, mask);
+}
+#else /* USER_ONLY */
+void cpu_interrupt(CPUState *env, int mask);
+#endif /* USER_ONLY */
+
 void cpu_reset_interrupt(CPUState *env, int mask);
 
 void cpu_exit(CPUState *s);
exec.c +3 -1
index cc0806e..72f4784 100644
@@ -1632,7 +1632,7 @@ static void cpu_unlink_tb(CPUState *env)
 
 #ifndef CONFIG_USER_ONLY
 /* mask must never be zero, except for A20 change call */
-void cpu_interrupt(CPUState *env, int mask)
+static void tcg_handle_interrupt(CPUState *env, int mask)
 {
     int old_mask;
 
@@ -1659,6 +1659,8 @@ void cpu_interrupt(CPUState *env, int mask)
     }
 }
 
+CPUInterruptHandler cpu_interrupt_handler = tcg_handle_interrupt;
+
 #else /* CONFIG_USER_ONLY */
 
 void cpu_interrupt(CPUState *env, int mask)
Signature · 1 line
1.7.4.2
#10 lore raw

PATCH 6/6 kvm: Install specialized interrupt handler

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

KVM only requires to set the raised IRQ in CPUState and to kick the receiving vcpu if it is remote. Installing a specialized handler allows potential future changes to the TCG code path without risking KVM side effects.

---
 kvm-all.c |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)
kvm-all.c +11 -0
index 1d7e8ea..fd1fbfe 100644
@@ -651,6 +651,15 @@ static CPUPhysMemoryClient kvm_cpu_phys_memory_client = {
     .log_stop = kvm_log_stop,
 };
 
+static void kvm_handle_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request |= mask;
+
+    if (!qemu_cpu_is_self(env)) {
+        qemu_cpu_kick(env);
+    }
+}
+
 int kvm_init(void)
 {
     static const char upgrade_note[] =
@@ -759,6 +768,8 @@ int kvm_init(void)
 
     s->many_ioeventfds = kvm_check_many_ioeventfds();
 
+    cpu_interrupt_handler = kvm_handle_interrupt;
+
     return 0;
 
 err:
Signature · 1 line
1.7.4.2
#11 lore raw
In reply to Marcelo Tosatti
Quoted 9 lines · Marcelo Tosatti

The following changes since commit adc56dda0c4eed62149d28939b7d7e329ad95ae8:

   migration: move some declarations to migration.h (2011-04-15 20:14:54 +0000)

are available in the git repository at:
git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git uq/master

Glauber Costa (3):
kvm: use kernel-provided para_features instead of statically coming up with new capabilities

It's hard to follow this logic, but something in this series introduces a ton of chatter on stdout. For instance:

anthony@titi:~/build/qemu$ x86_64-softmmu/qemu-system-x86_64 -hda ~/images/linux.img -snapshot
error: feature "sse2" not available in set
error: bad option value [feature_edx = sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36]
error: feature "sse2" not available in set
error: bad option value [feature_edx = sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36]
error: feature "sse2" not available in set
error: bad option value [feature_edx = sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36]
error: feature "sse2" not available in set
error: bad option value [feature_edx = sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36]
error: feature "sse2" not available in set
error: bad option value [feature_edx = sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36]
error: feature "sse2" not available in set
error: bad option value [feature_edx = sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36]
CPU feature hypervisor not found

This is with or without KVM enabled.

Regards,

Anthony Liguori

Quoted 15 lines

kvm: add kvmclock to its second bit
kvm: create kvmclock when one of the flags are present

Jan Kiszka (3):
Break up user and system cpu_interrupt implementations Redirect cpu_interrupt to callback handler
kvm: Install specialized interrupt handler

  cpu-all.h           |   14 ++++++++-
  exec.c              |   18 ++++++++---
  hw/kvmclock.c       |    6 +++-
  kvm-all.c           |   11 +++++++
  target-i386/cpuid.c |    3 +-
  target-i386/kvm.c   |   78 ++++++++++++++++++++++++++++++++-------------------
  6 files changed, 92 insertions(+), 38 deletions(-)