aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorSasha Levin <levinsasha928@gmail.com>2011-11-28 04:20:29 -0500
committerAvi Kivity <avi@redhat.com>2011-12-27 04:22:02 -0500
commit831bf664e9c1fc08fc6b3984d00d275cac82f5e9 (patch)
treea75b2baafbd58e9b20991dbab7bdadf2552e756d /arch/x86/kvm
parentfb215366b3c7320ac25dca766a0152df16534932 (diff)
KVM: Refactor and simplify kvm_dev_ioctl_get_supported_cpuid
This patch cleans and simplifies kvm_dev_ioctl_get_supported_cpuid by using a table instead of duplicating code as Avi suggested. This patch also fixes a bug where kvm_dev_ioctl_get_supported_cpuid would return -E2BIG when amount of entries passed was just right. Signed-off-by: Sasha Levin <levinsasha928@gmail.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/cpuid.c113
1 files changed, 63 insertions, 50 deletions
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 47be763e1b60..52593e8e1ae8 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -183,9 +183,10 @@ static bool supported_xcr0_bit(unsigned bit)
183 183
184#define F(x) bit(X86_FEATURE_##x) 184#define F(x) bit(X86_FEATURE_##x)
185 185
186static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, 186static int do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
187 u32 index, int *nent, int maxnent) 187 u32 index, int *nent, int maxnent)
188{ 188{
189 int r;
189 unsigned f_nx = is_efer_nx() ? F(NX) : 0; 190 unsigned f_nx = is_efer_nx() ? F(NX) : 0;
190#ifdef CONFIG_X86_64 191#ifdef CONFIG_X86_64
191 unsigned f_gbpages = (kvm_x86_ops->get_lpage_level() == PT_PDPE_LEVEL) 192 unsigned f_gbpages = (kvm_x86_ops->get_lpage_level() == PT_PDPE_LEVEL)
@@ -246,6 +247,12 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
246 247
247 /* all calls to cpuid_count() should be made on the same cpu */ 248 /* all calls to cpuid_count() should be made on the same cpu */
248 get_cpu(); 249 get_cpu();
250
251 r = -E2BIG;
252
253 if (*nent >= maxnent)
254 goto out;
255
249 do_cpuid_1_ent(entry, function, index); 256 do_cpuid_1_ent(entry, function, index);
250 ++*nent; 257 ++*nent;
251 258
@@ -271,7 +278,10 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
271 278
272 entry->flags |= KVM_CPUID_FLAG_STATEFUL_FUNC; 279 entry->flags |= KVM_CPUID_FLAG_STATEFUL_FUNC;
273 entry->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT; 280 entry->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT;
274 for (t = 1; t < times && *nent < maxnent; ++t) { 281 for (t = 1; t < times; ++t) {
282 if (*nent >= maxnent)
283 goto out;
284
275 do_cpuid_1_ent(&entry[t], function, 0); 285 do_cpuid_1_ent(&entry[t], function, 0);
276 entry[t].flags |= KVM_CPUID_FLAG_STATEFUL_FUNC; 286 entry[t].flags |= KVM_CPUID_FLAG_STATEFUL_FUNC;
277 ++*nent; 287 ++*nent;
@@ -284,7 +294,10 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
284 294
285 entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; 295 entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
286 /* read more entries until cache_type is zero */ 296 /* read more entries until cache_type is zero */
287 for (i = 1; *nent < maxnent; ++i) { 297 for (i = 1; ; ++i) {
298 if (*nent >= maxnent)
299 goto out;
300
288 cache_type = entry[i - 1].eax & 0x1f; 301 cache_type = entry[i - 1].eax & 0x1f;
289 if (!cache_type) 302 if (!cache_type)
290 break; 303 break;
@@ -316,7 +329,10 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
316 329
317 entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; 330 entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
318 /* read more entries until level_type is zero */ 331 /* read more entries until level_type is zero */
319 for (i = 1; *nent < maxnent; ++i) { 332 for (i = 1; ; ++i) {
333 if (*nent >= maxnent)
334 goto out;
335
320 level_type = entry[i - 1].ecx & 0xff00; 336 level_type = entry[i - 1].ecx & 0xff00;
321 if (!level_type) 337 if (!level_type)
322 break; 338 break;
@@ -331,7 +347,10 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
331 int idx, i; 347 int idx, i;
332 348
333 entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; 349 entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
334 for (idx = 1, i = 1; *nent < maxnent && idx < 64; ++idx) { 350 for (idx = 1, i = 1; idx < 64; ++idx) {
351 if (*nent >= maxnent)
352 goto out;
353
335 do_cpuid_1_ent(&entry[i], function, idx); 354 do_cpuid_1_ent(&entry[i], function, idx);
336 if (entry[i].eax == 0 || !supported_xcr0_bit(idx)) 355 if (entry[i].eax == 0 || !supported_xcr0_bit(idx))
337 continue; 356 continue;
@@ -416,17 +435,41 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
416 435
417 kvm_x86_ops->set_supported_cpuid(function, entry); 436 kvm_x86_ops->set_supported_cpuid(function, entry);
418 437
438 r = 0;
439
440out:
419 put_cpu(); 441 put_cpu();
442
443 return r;
420} 444}
421 445
422#undef F 446#undef F
423 447
448struct kvm_cpuid_param {
449 u32 func;
450 u32 idx;
451 bool has_leaf_count;
452 bool (*qualifier)(struct kvm_cpuid_param *param);
453};
454
455static bool is_centaur_cpu(struct kvm_cpuid_param *param)
456{
457 return boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR;
458}
459
424int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid, 460int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
425 struct kvm_cpuid_entry2 __user *entries) 461 struct kvm_cpuid_entry2 __user *entries)
426{ 462{
427 struct kvm_cpuid_entry2 *cpuid_entries; 463 struct kvm_cpuid_entry2 *cpuid_entries;
428 int limit, nent = 0, r = -E2BIG; 464 int limit, nent = 0, r = -E2BIG, i;
429 u32 func; 465 u32 func;
466 static struct kvm_cpuid_param param[] = {
467 { .func = 0, .has_leaf_count = true },
468 { .func = 0x80000000, .has_leaf_count = true },
469 { .func = 0xC0000000, .qualifier = is_centaur_cpu, .has_leaf_count = true },
470 { .func = KVM_CPUID_SIGNATURE },
471 { .func = KVM_CPUID_FEATURES },
472 };
430 473
431 if (cpuid->nent < 1) 474 if (cpuid->nent < 1)
432 goto out; 475 goto out;
@@ -437,61 +480,31 @@ int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
437 if (!cpuid_entries) 480 if (!cpuid_entries)
438 goto out; 481 goto out;
439 482
440 do_cpuid_ent(&cpuid_entries[0], 0, 0, &nent, cpuid->nent); 483 r = 0;
441 limit = cpuid_entries[0].eax; 484 for (i = 0; i < ARRAY_SIZE(param); i++) {
442 for (func = 1; func <= limit && nent < cpuid->nent; ++func) 485 struct kvm_cpuid_param *ent = &param[i];
443 do_cpuid_ent(&cpuid_entries[nent], func, 0,
444 &nent, cpuid->nent);
445 r = -E2BIG;
446 if (nent >= cpuid->nent)
447 goto out_free;
448
449 do_cpuid_ent(&cpuid_entries[nent], 0x80000000, 0, &nent, cpuid->nent);
450 limit = cpuid_entries[nent - 1].eax;
451 for (func = 0x80000001; func <= limit && nent < cpuid->nent; ++func)
452 do_cpuid_ent(&cpuid_entries[nent], func, 0,
453 &nent, cpuid->nent);
454
455
456 486
457 r = -E2BIG; 487 if (ent->qualifier && !ent->qualifier(ent))
458 if (nent >= cpuid->nent) 488 continue;
459 goto out_free;
460 489
461 /* Add support for Centaur's CPUID instruction. */ 490 r = do_cpuid_ent(&cpuid_entries[nent], ent->func, ent->idx,
462 if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR) {
463 do_cpuid_ent(&cpuid_entries[nent], 0xC0000000, 0,
464 &nent, cpuid->nent); 491 &nent, cpuid->nent);
465 492
466 r = -E2BIG; 493 if (r)
467 if (nent >= cpuid->nent)
468 goto out_free; 494 goto out_free;
469 495
496 if (!ent->has_leaf_count)
497 continue;
498
470 limit = cpuid_entries[nent - 1].eax; 499 limit = cpuid_entries[nent - 1].eax;
471 for (func = 0xC0000001; 500 for (func = ent->func + 1; func <= limit && nent < cpuid->nent && r == 0; ++func)
472 func <= limit && nent < cpuid->nent; ++func) 501 r = do_cpuid_ent(&cpuid_entries[nent], func, ent->idx,
473 do_cpuid_ent(&cpuid_entries[nent], func, 0, 502 &nent, cpuid->nent);
474 &nent, cpuid->nent);
475 503
476 r = -E2BIG; 504 if (r)
477 if (nent >= cpuid->nent)
478 goto out_free; 505 goto out_free;
479 } 506 }
480 507
481 do_cpuid_ent(&cpuid_entries[nent], KVM_CPUID_SIGNATURE, 0, &nent,
482 cpuid->nent);
483
484 r = -E2BIG;
485 if (nent >= cpuid->nent)
486 goto out_free;
487
488 do_cpuid_ent(&cpuid_entries[nent], KVM_CPUID_FEATURES, 0, &nent,
489 cpuid->nent);
490
491 r = -E2BIG;
492 if (nent >= cpuid->nent)
493 goto out_free;
494
495 r = -EFAULT; 508 r = -EFAULT;
496 if (copy_to_user(entries, cpuid_entries, 509 if (copy_to_user(entries, cpuid_entries,
497 nent * sizeof(struct kvm_cpuid_entry2))) 510 nent * sizeof(struct kvm_cpuid_entry2)))