mirror of
https://github.com/torvalds/linux.git
synced 2024-12-18 00:53:40 +00:00
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>
This commit is contained in:
parent
fb215366b3
commit
831bf664e9
@ -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,
|
|||||||
|
|
||||||
/* 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,
|
|||||||
|
|
||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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 = ¶m[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);
|
if (ent->qualifier && !ent->qualifier(ent))
|
||||||
limit = cpuid_entries[nent - 1].eax;
|
continue;
|
||||||
for (func = 0x80000001; func <= limit && nent < cpuid->nent; ++func)
|
|
||||||
do_cpuid_ent(&cpuid_entries[nent], func, 0,
|
r = do_cpuid_ent(&cpuid_entries[nent], ent->func, ent->idx,
|
||||||
&nent, cpuid->nent);
|
&nent, cpuid->nent);
|
||||||
|
|
||||||
|
if (r)
|
||||||
|
|
||||||
r = -E2BIG;
|
|
||||||
if (nent >= cpuid->nent)
|
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
/* Add support for Centaur's CPUID instruction. */
|
if (!ent->has_leaf_count)
|
||||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR) {
|
continue;
|
||||||
do_cpuid_ent(&cpuid_entries[nent], 0xC0000000, 0,
|
|
||||||
&nent, cpuid->nent);
|
|
||||||
|
|
||||||
r = -E2BIG;
|
|
||||||
if (nent >= cpuid->nent)
|
|
||||||
goto out_free;
|
|
||||||
|
|
||||||
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)))
|
||||||
|
Loading…
Reference in New Issue
Block a user