Commit 831bf664 authored by Sasha Levin's avatar Sasha Levin Committed by Avi Kivity

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: default avatarSasha Levin <levinsasha928@gmail.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent fb215366
...@@ -183,9 +183,10 @@ static bool supported_xcr0_bit(unsigned bit) ...@@ -183,9 +183,10 @@ static bool supported_xcr0_bit(unsigned bit)
#define F(x) bit(X86_FEATURE_##x) #define F(x) bit(X86_FEATURE_##x)
static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, static int do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
u32 index, int *nent, int maxnent) u32 index, int *nent, int maxnent)
{ {
int r;
unsigned f_nx = is_efer_nx() ? F(NX) : 0; unsigned f_nx = is_efer_nx() ? F(NX) : 0;
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
unsigned f_gbpages = (kvm_x86_ops->get_lpage_level() == PT_PDPE_LEVEL) 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,6 +247,12 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
/* all calls to cpuid_count() should be made on the same cpu */ /* all calls to cpuid_count() should be made on the same cpu */
get_cpu(); get_cpu();
r = -E2BIG;
if (*nent >= maxnent)
goto out;
do_cpuid_1_ent(entry, function, index); do_cpuid_1_ent(entry, function, index);
++*nent; ++*nent;
...@@ -271,7 +278,10 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, ...@@ -271,7 +278,10 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
entry->flags |= KVM_CPUID_FLAG_STATEFUL_FUNC; entry->flags |= KVM_CPUID_FLAG_STATEFUL_FUNC;
entry->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT; entry->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT;
for (t = 1; t < times && *nent < maxnent; ++t) { for (t = 1; t < times; ++t) {
if (*nent >= maxnent)
goto out;
do_cpuid_1_ent(&entry[t], function, 0); do_cpuid_1_ent(&entry[t], function, 0);
entry[t].flags |= KVM_CPUID_FLAG_STATEFUL_FUNC; entry[t].flags |= KVM_CPUID_FLAG_STATEFUL_FUNC;
++*nent; ++*nent;
...@@ -284,7 +294,10 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, ...@@ -284,7 +294,10 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
/* read more entries until cache_type is zero */ /* read more entries until cache_type is zero */
for (i = 1; *nent < maxnent; ++i) { for (i = 1; ; ++i) {
if (*nent >= maxnent)
goto out;
cache_type = entry[i - 1].eax & 0x1f; cache_type = entry[i - 1].eax & 0x1f;
if (!cache_type) if (!cache_type)
break; break;
...@@ -316,7 +329,10 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, ...@@ -316,7 +329,10 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
/* read more entries until level_type is zero */ /* read more entries until level_type is zero */
for (i = 1; *nent < maxnent; ++i) { for (i = 1; ; ++i) {
if (*nent >= maxnent)
goto out;
level_type = entry[i - 1].ecx & 0xff00; level_type = entry[i - 1].ecx & 0xff00;
if (!level_type) if (!level_type)
break; break;
...@@ -331,7 +347,10 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, ...@@ -331,7 +347,10 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
int idx, i; int idx, i;
entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
for (idx = 1, i = 1; *nent < maxnent && idx < 64; ++idx) { for (idx = 1, i = 1; idx < 64; ++idx) {
if (*nent >= maxnent)
goto out;
do_cpuid_1_ent(&entry[i], function, idx); do_cpuid_1_ent(&entry[i], function, idx);
if (entry[i].eax == 0 || !supported_xcr0_bit(idx)) if (entry[i].eax == 0 || !supported_xcr0_bit(idx))
continue; continue;
...@@ -416,17 +435,41 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, ...@@ -416,17 +435,41 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
kvm_x86_ops->set_supported_cpuid(function, entry); kvm_x86_ops->set_supported_cpuid(function, entry);
r = 0;
out:
put_cpu(); put_cpu();
return r;
} }
#undef F #undef F
struct kvm_cpuid_param {
u32 func;
u32 idx;
bool has_leaf_count;
bool (*qualifier)(struct kvm_cpuid_param *param);
};
static bool is_centaur_cpu(struct kvm_cpuid_param *param)
{
return boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR;
}
int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid, int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
struct kvm_cpuid_entry2 __user *entries) struct kvm_cpuid_entry2 __user *entries)
{ {
struct kvm_cpuid_entry2 *cpuid_entries; struct kvm_cpuid_entry2 *cpuid_entries;
int limit, nent = 0, r = -E2BIG; int limit, nent = 0, r = -E2BIG, i;
u32 func; u32 func;
static struct kvm_cpuid_param param[] = {
{ .func = 0, .has_leaf_count = true },
{ .func = 0x80000000, .has_leaf_count = true },
{ .func = 0xC0000000, .qualifier = is_centaur_cpu, .has_leaf_count = true },
{ .func = KVM_CPUID_SIGNATURE },
{ .func = KVM_CPUID_FEATURES },
};
if (cpuid->nent < 1) if (cpuid->nent < 1)
goto out; goto out;
...@@ -437,61 +480,31 @@ int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid, ...@@ -437,61 +480,31 @@ int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
if (!cpuid_entries) if (!cpuid_entries)
goto out; goto out;
do_cpuid_ent(&cpuid_entries[0], 0, 0, &nent, cpuid->nent); r = 0;
limit = cpuid_entries[0].eax; for (i = 0; i < ARRAY_SIZE(param); i++) {
for (func = 1; func <= limit && nent < cpuid->nent; ++func) struct kvm_cpuid_param *ent = &param[i];
do_cpuid_ent(&cpuid_entries[nent], func, 0,
&nent, cpuid->nent);
r = -E2BIG;
if (nent >= cpuid->nent)
goto out_free;
do_cpuid_ent(&cpuid_entries[nent], 0x80000000, 0, &nent, cpuid->nent);
limit = cpuid_entries[nent - 1].eax;
for (func = 0x80000001; func <= limit && nent < cpuid->nent; ++func)
do_cpuid_ent(&cpuid_entries[nent], func, 0,
&nent, cpuid->nent);
r = -E2BIG; if (ent->qualifier && !ent->qualifier(ent))
if (nent >= cpuid->nent) continue;
goto out_free;
/* Add support for Centaur's CPUID instruction. */ r = do_cpuid_ent(&cpuid_entries[nent], ent->func, ent->idx,
if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR) {
do_cpuid_ent(&cpuid_entries[nent], 0xC0000000, 0,
&nent, cpuid->nent); &nent, cpuid->nent);
r = -E2BIG; if (r)
if (nent >= cpuid->nent)
goto out_free; goto out_free;
if (!ent->has_leaf_count)
continue;
limit = cpuid_entries[nent - 1].eax; limit = cpuid_entries[nent - 1].eax;
for (func = 0xC0000001; for (func = ent->func + 1; func <= limit && nent < cpuid->nent && r == 0; ++func)
func <= limit && nent < cpuid->nent; ++func) r = do_cpuid_ent(&cpuid_entries[nent], func, ent->idx,
do_cpuid_ent(&cpuid_entries[nent], func, 0,
&nent, cpuid->nent); &nent, cpuid->nent);
r = -E2BIG; if (r)
if (nent >= cpuid->nent)
goto out_free; goto out_free;
} }
do_cpuid_ent(&cpuid_entries[nent], KVM_CPUID_SIGNATURE, 0, &nent,
cpuid->nent);
r = -E2BIG;
if (nent >= cpuid->nent)
goto out_free;
do_cpuid_ent(&cpuid_entries[nent], KVM_CPUID_FEATURES, 0, &nent,
cpuid->nent);
r = -E2BIG;
if (nent >= cpuid->nent)
goto out_free;
r = -EFAULT; r = -EFAULT;
if (copy_to_user(entries, cpuid_entries, if (copy_to_user(entries, cpuid_entries,
nent * sizeof(struct kvm_cpuid_entry2))) nent * sizeof(struct kvm_cpuid_entry2)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment