diff mbox

[3/3] target-i386: replace cpuid_*features fields with a feature word array

Message ID 1355350946-28010-4-git-send-email-ehabkost@redhat.com
State New
Headers show

Commit Message

Eduardo Habkost Dec. 12, 2012, 10:22 p.m. UTC
This replaces the feature-bit fields on both X86CPU and x86_def_t
structs with an array.

With this, we will be able to simplify code that simply does the same
operation on all feature words (e.g. kvm_check_features_against_host(),
filter_features_for_kvm(), add_flagname_to_bitmaps(), and CPU
feature-bit property lookup/registration).

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
This patch was created solely using a sed script and no manual changes,
to try to avoid mistakes while converting the code, and make it easier
to rebase if necessary. The sed script can be seen at:
  https://gist.github.com/4271991
---
 hw/kvm/clock.c            |   2 +-
 linux-user/elfload.c      |   2 +-
 linux-user/main.c         |   4 +-
 target-i386/cpu.c         | 578 +++++++++++++++++++++++-----------------------
 target-i386/cpu.h         |  30 +--
 target-i386/helper.c      |   4 +-
 target-i386/kvm.c         |   5 +-
 target-i386/misc_helper.c |  14 +-
 target-i386/translate.c   |  10 +-
 9 files changed, 331 insertions(+), 318 deletions(-)

Comments

Igor Mammedov Dec. 14, 2012, 9:38 a.m. UTC | #1
On Wed, 12 Dec 2012 20:22:26 -0200
Eduardo Habkost <ehabkost@redhat.com> wrote:

> This replaces the feature-bit fields on both X86CPU and x86_def_t
> structs with an array.
> 
> With this, we will be able to simplify code that simply does the same
> operation on all feature words (e.g. kvm_check_features_against_host(),
> filter_features_for_kvm(), add_flagname_to_bitmaps(), and CPU
> feature-bit property lookup/registration).
> 

do you have a patch that simplifies kvm_check_features_against_host() using
this?

> -- 
> 1.7.11.7
>
Eduardo Habkost Dec. 14, 2012, 12:27 p.m. UTC | #2
On Fri, Dec 14, 2012 at 10:38:50AM +0100, Igor Mammedov wrote:
> On Wed, 12 Dec 2012 20:22:26 -0200
> Eduardo Habkost <ehabkost@redhat.com> wrote:
> 
> > This replaces the feature-bit fields on both X86CPU and x86_def_t
> > structs with an array.
> > 
> > With this, we will be able to simplify code that simply does the same
> > operation on all feature words (e.g. kvm_check_features_against_host(),
> > filter_features_for_kvm(), add_flagname_to_bitmaps(), and CPU
> > feature-bit property lookup/registration).
> > 
> 
> do you have a patch that simplifies kvm_check_features_against_host() using
> this?

I have a very old one, based on an older (and more complex) version of
this series:
https://github.com/ehabkost/qemu-hacks/commit/eb01d374baecf6df26fd6f0d0bb23f2e1547f499

It's in the work/cpuid-refactor-v0.22-2012-08-31 branch in my git
repository.

That branch also has some patches to merge kvm_check_features_against_host()
and filter_features_for_kvm() (because the purpose of
kvm_check_features_against_host() is simply to check if anything is
going to be filtered out by filter_features_for_kvm()).

If people are happy with the approach in this series, I plan to write
and submit cleanups for kvm_cpu_fill_host(),
kvm_check_features_against_host(), filter_features_for_kvm(),
add_flagname_to_bitmaps(), and the cpudef -> CPU feature copying code.

There's so much code that could be cleaned up using the array, that I am
afraid that it would cause too much conflicts in the CPU properties
work. So I can wait until the CPU properties series are submitted before
making the cleanups, if necessary.
Igor Mammedov Dec. 14, 2012, 1:52 p.m. UTC | #3
On Fri, 14 Dec 2012 10:27:34 -0200
Eduardo Habkost <ehabkost@redhat.com> wrote:

> On Fri, Dec 14, 2012 at 10:38:50AM +0100, Igor Mammedov wrote:
> > On Wed, 12 Dec 2012 20:22:26 -0200
> > Eduardo Habkost <ehabkost@redhat.com> wrote:
> > 
> > > This replaces the feature-bit fields on both X86CPU and x86_def_t
> > > structs with an array.
> > > 
> > > With this, we will be able to simplify code that simply does the same
> > > operation on all feature words (e.g. kvm_check_features_against_host(),
> > > filter_features_for_kvm(), add_flagname_to_bitmaps(), and CPU
> > > feature-bit property lookup/registration).
> > > 
> > 
> > do you have a patch that simplifies kvm_check_features_against_host() using
> > this?
> 
> I have a very old one, based on an older (and more complex) version of
> this series:
> https://github.com/ehabkost/qemu-hacks/commit/eb01d374baecf6df26fd6f0d0bb23f2e1547f499
> 
> It's in the work/cpuid-refactor-v0.22-2012-08-31 branch in my git
> repository.
> 
> That branch also has some patches to merge kvm_check_features_against_host()
> and filter_features_for_kvm() (because the purpose of
> kvm_check_features_against_host() is simply to check if anything is
> going to be filtered out by filter_features_for_kvm()).
> 
> If people are happy with the approach in this series, I plan to write
> and submit cleanups for kvm_cpu_fill_host(),
> kvm_check_features_against_host(), filter_features_for_kvm(),
> add_flagname_to_bitmaps(), and the cpudef -> CPU feature copying code.
> 
> There's so much code that could be cleaned up using the array, that I am
> afraid that it would cause too much conflicts in the CPU properties
> work. So I can wait until the CPU properties series are submitted before
> making the cleanups, if necessary.
with cpu properties and subclasses in place,
kvm_check_features_against_host() could be expressed as simple subtraction of
host subclass features list from guest cpu features list. Which won't require
access to feature words at all. Just iterating over properties of both to
build lists and then do subtraction and print difference if any, it could be
eventially generalized to other kvm supported targets since it won't use any
x86 specific fields.


> -- 
> Eduardo
>
Eduardo Habkost Dec. 14, 2012, 2:02 p.m. UTC | #4
On Fri, Dec 14, 2012 at 02:52:50PM +0100, Igor Mammedov wrote:
> On Fri, 14 Dec 2012 10:27:34 -0200
> Eduardo Habkost <ehabkost@redhat.com> wrote:
> 
> > On Fri, Dec 14, 2012 at 10:38:50AM +0100, Igor Mammedov wrote:
> > > On Wed, 12 Dec 2012 20:22:26 -0200
> > > Eduardo Habkost <ehabkost@redhat.com> wrote:
> > > 
> > > > This replaces the feature-bit fields on both X86CPU and x86_def_t
> > > > structs with an array.
> > > > 
> > > > With this, we will be able to simplify code that simply does the same
> > > > operation on all feature words (e.g. kvm_check_features_against_host(),
> > > > filter_features_for_kvm(), add_flagname_to_bitmaps(), and CPU
> > > > feature-bit property lookup/registration).
> > > > 
> > > 
> > > do you have a patch that simplifies kvm_check_features_against_host() using
> > > this?
> > 
> > I have a very old one, based on an older (and more complex) version of
> > this series:
> > https://github.com/ehabkost/qemu-hacks/commit/eb01d374baecf6df26fd6f0d0bb23f2e1547f499
> > 
> > It's in the work/cpuid-refactor-v0.22-2012-08-31 branch in my git
> > repository.
> > 
> > That branch also has some patches to merge kvm_check_features_against_host()
> > and filter_features_for_kvm() (because the purpose of
> > kvm_check_features_against_host() is simply to check if anything is
> > going to be filtered out by filter_features_for_kvm()).
> > 
> > If people are happy with the approach in this series, I plan to write
> > and submit cleanups for kvm_cpu_fill_host(),
> > kvm_check_features_against_host(), filter_features_for_kvm(),
> > add_flagname_to_bitmaps(), and the cpudef -> CPU feature copying code.
> > 
> > There's so much code that could be cleaned up using the array, that I am
> > afraid that it would cause too much conflicts in the CPU properties
> > work. So I can wait until the CPU properties series are submitted before
> > making the cleanups, if necessary.
> with cpu properties and subclasses in place,
> kvm_check_features_against_host() could be expressed as simple subtraction of
> host subclass features list from guest cpu features list. Which won't require
> access to feature words at all. Just iterating over properties of both to
> build lists and then do subtraction and print difference if any, it could be
> eventially generalized to other kvm supported targets since it won't use any
> x86 specific fields.

Once we have the CPU properties code, maybe we could do that. I find the
idea a bit confusing (I would like to avoid coupling the "check" code to
the "host" CPU class directly), but may be doeable.

We also have one problem: the host class class_init method may be called
before KVM is initialized, so I don't know if we can really use the
class instrospection system to find out which flags are supported by the
host by looking at the "host" class.

Considering the complexity of what you suggest, I think there's value in
cleaning up that code first (and use the array to allow us to clean up
other code as well), and try to use the solution you suggest later,
after we actually have working CPU properties and subclasses.
Andreas Färber Dec. 14, 2012, 2:53 p.m. UTC | #5
Am 14.12.2012 13:27, schrieb Eduardo Habkost:
> On Fri, Dec 14, 2012 at 10:38:50AM +0100, Igor Mammedov wrote:
>> On Wed, 12 Dec 2012 20:22:26 -0200
>> Eduardo Habkost <ehabkost@redhat.com> wrote:
>>
>>> This replaces the feature-bit fields on both X86CPU and x86_def_t
>>> structs with an array.
>>>
>>> With this, we will be able to simplify code that simply does the same
>>> operation on all feature words (e.g. kvm_check_features_against_host(),
>>> filter_features_for_kvm(), add_flagname_to_bitmaps(), and CPU
>>> feature-bit property lookup/registration).
>>>
>>
>> do you have a patch that simplifies kvm_check_features_against_host() using
>> this?
> 
> I have a very old one, based on an older (and more complex) version of
> this series:
> https://github.com/ehabkost/qemu-hacks/commit/eb01d374baecf6df26fd6f0d0bb23f2e1547f499
> 
> It's in the work/cpuid-refactor-v0.22-2012-08-31 branch in my git
> repository.
> 
> That branch also has some patches to merge kvm_check_features_against_host()
> and filter_features_for_kvm() (because the purpose of
> kvm_check_features_against_host() is simply to check if anything is
> going to be filtered out by filter_features_for_kvm()).
> 
> If people are happy with the approach in this series, I plan to write
> and submit cleanups for kvm_cpu_fill_host(),
> kvm_check_features_against_host(), filter_features_for_kvm(),
> add_flagname_to_bitmaps(), and the cpudef -> CPU feature copying code.
> 
> There's so much code that could be cleaned up using the array, that I am
> afraid that it would cause too much conflicts in the CPU properties
> work. So I can wait until the CPU properties series are submitted before
> making the cleanups, if necessary.

As stated elsewhere, for me a proper way to define new CPU models has
higher priority than feature properties, especially now that we're
headed for a class_init based approach where properties cannot be used
for original initialization.

As suggested with my RFC I would like to take a quick, simplistic route
to subclasses where no major refactoring of data fields happens. If we
prepend a couple coding style and function movement patches, that's fine
with me. But if we do large functional refactorings > 10 patches that
change history will be clobbered by the touch-all conversion and we need
to do intensive functional testing, for which I don't see sufficient
time before the Soft Freeze, given the holidays.

When the feature bits are stored in the classes, setting them via
properties in instance_init seems like overkill (visitor overhead); we
no longer dump them in -cpu ?foo; only +feature/-feature would benefit.
Thus I assume them to mainly conflict where function signatures change
and trivially where def changes to env, making them rather orthogonal to
each other.

Regards,
Andreas
Andreas Färber Dec. 14, 2012, 3:14 p.m. UTC | #6
Am 12.12.2012 23:22, schrieb Eduardo Habkost:
> This replaces the feature-bit fields on both X86CPU and x86_def_t
> structs with an array.
> 
> With this, we will be able to simplify code that simply does the same
> operation on all feature words (e.g. kvm_check_features_against_host(),
> filter_features_for_kvm(), add_flagname_to_bitmaps(), and CPU
> feature-bit property lookup/registration).
> 
> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> ---
> This patch was created solely using a sed script and no manual changes,
> to try to avoid mistakes while converting the code, and make it easier
> to rebase if necessary. The sed script can be seen at:
>   https://gist.github.com/4271991
> ---
>  hw/kvm/clock.c            |   2 +-
>  linux-user/elfload.c      |   2 +-
>  linux-user/main.c         |   4 +-
>  target-i386/cpu.c         | 578 +++++++++++++++++++++++-----------------------
>  target-i386/cpu.h         |  30 +--
>  target-i386/helper.c      |   4 +-
>  target-i386/kvm.c         |   5 +-
>  target-i386/misc_helper.c |  14 +-
>  target-i386/translate.c   |  10 +-
>  9 files changed, 331 insertions(+), 318 deletions(-)

I wonder, if we're touching all these lines anyway, can't we place the
new feature array directly into X86CPU? As far as I see the features are
never changed at runtime, so the only reason to have them in the
instance is the command-line-supplied overrides.

The clock code using first_cpu looks solvable; what about CR4 and MSR
helpers, how performance-sensitive are they? (if they're not yet using
X86CPU for something else)

With the proposed variable change env -> cpu it would not be fully
sed'able, but as a maintainer I need to review the whole patch anyway.

Either way since this change affects not just the core CPU that I have
started to maintain I feel I should give other target-i386 stakeholders
(Blue, Aurélien, malc, ...) sufficient time to object, so not before
Christmas realistically.

Regards,
Andreas
Eduardo Habkost Dec. 14, 2012, 4:52 p.m. UTC | #7
On Fri, Dec 14, 2012 at 04:14:32PM +0100, Andreas Färber wrote:
> Am 12.12.2012 23:22, schrieb Eduardo Habkost:
> > This replaces the feature-bit fields on both X86CPU and x86_def_t
> > structs with an array.
> > 
> > With this, we will be able to simplify code that simply does the same
> > operation on all feature words (e.g. kvm_check_features_against_host(),
> > filter_features_for_kvm(), add_flagname_to_bitmaps(), and CPU
> > feature-bit property lookup/registration).
> > 
> > Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> > ---
> > This patch was created solely using a sed script and no manual changes,
> > to try to avoid mistakes while converting the code, and make it easier
> > to rebase if necessary. The sed script can be seen at:
> >   https://gist.github.com/4271991
> > ---
> >  hw/kvm/clock.c            |   2 +-
> >  linux-user/elfload.c      |   2 +-
> >  linux-user/main.c         |   4 +-
> >  target-i386/cpu.c         | 578 +++++++++++++++++++++++-----------------------
> >  target-i386/cpu.h         |  30 +--
> >  target-i386/helper.c      |   4 +-
> >  target-i386/kvm.c         |   5 +-
> >  target-i386/misc_helper.c |  14 +-
> >  target-i386/translate.c   |  10 +-
> >  9 files changed, 331 insertions(+), 318 deletions(-)
> 
> I wonder, if we're touching all these lines anyway, can't we place the
> new feature array directly into X86CPU? As far as I see the features are
> never changed at runtime, so the only reason to have them in the
> instance is the command-line-supplied overrides.

You mean directly into X86CPUClass? No, we can't: the features are
changed at the CPU instance at runtime, when based in the
+feature,-feature feature string. We also do some extra filtering based
on KVM capabilities at filter_features_for_kvm().

I believe we're moving towards another direction: making the feature
bits live only in the X86CPU object, and they will be initialized based
on the default property values of each CPU class. Probably we won't do
that in the first version of CPU subclasses/properties, but we are
trying to reach that point.

> 
> The clock code using first_cpu looks solvable; what about CR4 and MSR
> helpers, how performance-sensitive are they? (if they're not yet using
> X86CPU for something else)

I guess any CPU-state code inside QEMU is not performance-sensitive, as
it woud already require switching between KVM kernelspace and QEMU
userspace.

> 
> With the proposed variable change env -> cpu it would not be fully
> sed'able, but as a maintainer I need to review the whole patch anyway.

On the other hand, this cleanup will allow us to easily convert some
code to deal with the feature array only (not requiring the full X86CPU
or x86_def_t struct), making it easier to have only one feature array,
in only one place, in the future.

> 
> Either way since this change affects not just the core CPU that I have
> started to maintain I feel I should give other target-i386 stakeholders
> (Blue, Aurélien, malc, ...) sufficient time to object, so not before
> Christmas realistically.

OK.
Eduardo Habkost Dec. 14, 2012, 5:16 p.m. UTC | #8
On Fri, Dec 14, 2012 at 03:53:58PM +0100, Andreas Färber wrote:
> Am 14.12.2012 13:27, schrieb Eduardo Habkost:
> > On Fri, Dec 14, 2012 at 10:38:50AM +0100, Igor Mammedov wrote:
> >> On Wed, 12 Dec 2012 20:22:26 -0200
> >> Eduardo Habkost <ehabkost@redhat.com> wrote:
> >>
> >>> This replaces the feature-bit fields on both X86CPU and x86_def_t
> >>> structs with an array.
> >>>
> >>> With this, we will be able to simplify code that simply does the same
> >>> operation on all feature words (e.g. kvm_check_features_against_host(),
> >>> filter_features_for_kvm(), add_flagname_to_bitmaps(), and CPU
> >>> feature-bit property lookup/registration).
> >>>
> >>
> >> do you have a patch that simplifies kvm_check_features_against_host() using
> >> this?
> > 
> > I have a very old one, based on an older (and more complex) version of
> > this series:
> > https://github.com/ehabkost/qemu-hacks/commit/eb01d374baecf6df26fd6f0d0bb23f2e1547f499
> > 
> > It's in the work/cpuid-refactor-v0.22-2012-08-31 branch in my git
> > repository.
> > 
> > That branch also has some patches to merge kvm_check_features_against_host()
> > and filter_features_for_kvm() (because the purpose of
> > kvm_check_features_against_host() is simply to check if anything is
> > going to be filtered out by filter_features_for_kvm()).
> > 
> > If people are happy with the approach in this series, I plan to write
> > and submit cleanups for kvm_cpu_fill_host(),
> > kvm_check_features_against_host(), filter_features_for_kvm(),
> > add_flagname_to_bitmaps(), and the cpudef -> CPU feature copying code.
> > 
> > There's so much code that could be cleaned up using the array, that I am
> > afraid that it would cause too much conflicts in the CPU properties
> > work. So I can wait until the CPU properties series are submitted before
> > making the cleanups, if necessary.
> 
> As stated elsewhere, for me a proper way to define new CPU models has
> higher priority than feature properties, especially now that we're
> headed for a class_init based approach where properties cannot be used
> for original initialization.

We can go that way. But then I still strongly suggest we add the feature
array before doing that, because it will help a lot to simplify the
"host" CPU subclass code, and kvm_check_features_against_host() and
kvm_cpu_fill_host().

(The main change I see is that kvm_check_features_against_host() won't
need to fill a full x86_def_t struct from the host, just a local
in-stack feature array. Also, kvm_check_features_against_host() and
filter_features_for_kvm() could be unified as well)

(Maybe I can work around the lack of feature array by keeping an
embedded x86_def_t struct inside CPUClass (so kvm_cpu_fill_host() don't
need a full CPUClass struct like in your RFC). I will try and see what's
possible)

> 
> As suggested with my RFC I would like to take a quick, simplistic route
> to subclasses where no major refactoring of data fields happens. If we
> prepend a couple coding style and function movement patches, that's fine
> with me. But if we do large functional refactorings > 10 patches that
> change history will be clobbered by the touch-all conversion and we need
> to do intensive functional testing, for which I don't see sufficient
> time before the Soft Freeze, given the holidays.

I thought we would be in the "we can't introduce major changes" mode
_after_ the soft freeze, not before the soft freeze.  ;-)

So, are we already in soft freeze in practice?


> 
> When the feature bits are stored in the classes, setting them via
> properties in instance_init seems like overkill (visitor overhead);

If performance is an issue (I doubt it would be), we could still keep
the array inside the model/class, and copy it on instance_init. But we
still need a per-instance array as well, in addition to the per-model
data (see below).


> we
> no longer dump them in -cpu ?foo; only +feature/-feature would benefit.
> Thus I assume them to mainly conflict where function signatures change
> and trivially where def changes to env, making them rather orthogonal to
> each other.

We can't just change "env" to "def", because "def" is static and "env"
contains the result of the "<model>,+feature,-feature" parsing.

We could try to go through a route where there's no def->env copy in the
code, but then I believe this would be the opposite of the quick
simplistic route you're trying to take.
Andreas Färber Dec. 14, 2012, 5:20 p.m. UTC | #9
Am 14.12.2012 17:52, schrieb Eduardo Habkost:
> On Fri, Dec 14, 2012 at 04:14:32PM +0100, Andreas Färber wrote:
>> Am 12.12.2012 23:22, schrieb Eduardo Habkost:
>>> This replaces the feature-bit fields on both X86CPU and x86_def_t
>>> structs with an array.
>>>
>>> With this, we will be able to simplify code that simply does the same
>>> operation on all feature words (e.g. kvm_check_features_against_host(),
>>> filter_features_for_kvm(), add_flagname_to_bitmaps(), and CPU
>>> feature-bit property lookup/registration).
>>>
>>> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
>>> ---
>>> This patch was created solely using a sed script and no manual changes,
>>> to try to avoid mistakes while converting the code, and make it easier
>>> to rebase if necessary. The sed script can be seen at:
>>>   https://gist.github.com/4271991
>>> ---
>>>  hw/kvm/clock.c            |   2 +-
>>>  linux-user/elfload.c      |   2 +-
>>>  linux-user/main.c         |   4 +-
>>>  target-i386/cpu.c         | 578 +++++++++++++++++++++++-----------------------
>>>  target-i386/cpu.h         |  30 +--
>>>  target-i386/helper.c      |   4 +-
>>>  target-i386/kvm.c         |   5 +-
>>>  target-i386/misc_helper.c |  14 +-
>>>  target-i386/translate.c   |  10 +-
>>>  9 files changed, 331 insertions(+), 318 deletions(-)
>>
>> I wonder, if we're touching all these lines anyway, can't we place the
>> new feature array directly into X86CPU? As far as I see the features are
>> never changed at runtime, so the only reason to have them in the
>> instance is the command-line-supplied overrides.
> 
> You mean directly into X86CPUClass? [...]

No, I literally meant X86CPU rather than CPUX86State (i.e., the place
within the instance).

>> The clock code using first_cpu looks solvable; what about CR4 and MSR
>> helpers, how performance-sensitive are they? (if they're not yet using
>> X86CPU for something else)
> 
> I guess any CPU-state code inside QEMU is not performance-sensitive, as
> it woud already require switching between KVM kernelspace and QEMU
> userspace.

I mean target-i386/[misc_]helper.c and thus TCG, IIUC. :)

> On the other hand, this cleanup will allow us to easily convert some
> code to deal with the feature array only (not requiring the full X86CPU
> or x86_def_t struct), making it easier to have only one feature array,
> in only one place, in the future.

The alternative line of thought is whether to group KVM stuff together.
Tying it into an array makes that harder. But personally I'm not opposed
to this array proposal.

Andreas
Eduardo Habkost Dec. 14, 2012, 5:36 p.m. UTC | #10
On Fri, Dec 14, 2012 at 06:20:41PM +0100, Andreas Färber wrote:
> Am 14.12.2012 17:52, schrieb Eduardo Habkost:
> > On Fri, Dec 14, 2012 at 04:14:32PM +0100, Andreas Färber wrote:
> >> Am 12.12.2012 23:22, schrieb Eduardo Habkost:
> >>> This replaces the feature-bit fields on both X86CPU and x86_def_t
> >>> structs with an array.
> >>>
> >>> With this, we will be able to simplify code that simply does the same
> >>> operation on all feature words (e.g. kvm_check_features_against_host(),
> >>> filter_features_for_kvm(), add_flagname_to_bitmaps(), and CPU
> >>> feature-bit property lookup/registration).
> >>>
> >>> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> >>> ---
> >>> This patch was created solely using a sed script and no manual changes,
> >>> to try to avoid mistakes while converting the code, and make it easier
> >>> to rebase if necessary. The sed script can be seen at:
> >>>   https://gist.github.com/4271991
> >>> ---
> >>>  hw/kvm/clock.c            |   2 +-
> >>>  linux-user/elfload.c      |   2 +-
> >>>  linux-user/main.c         |   4 +-
> >>>  target-i386/cpu.c         | 578 +++++++++++++++++++++++-----------------------
> >>>  target-i386/cpu.h         |  30 +--
> >>>  target-i386/helper.c      |   4 +-
> >>>  target-i386/kvm.c         |   5 +-
> >>>  target-i386/misc_helper.c |  14 +-
> >>>  target-i386/translate.c   |  10 +-
> >>>  9 files changed, 331 insertions(+), 318 deletions(-)
> >>
> >> I wonder, if we're touching all these lines anyway, can't we place the
> >> new feature array directly into X86CPU? As far as I see the features are
> >> never changed at runtime, so the only reason to have them in the
> >> instance is the command-line-supplied overrides.
> > 
> > You mean directly into X86CPUClass? [...]
> 
> No, I literally meant X86CPU rather than CPUX86State (i.e., the place
> within the instance).

OK. That makes sense. I believe that moving fields to X86CPU would be
much easier if we change the code that will actually use those fields to
use the QOM CPU class.

> 
> >> The clock code using first_cpu looks solvable; what about CR4 and MSR
> >> helpers, how performance-sensitive are they? (if they're not yet using
> >> X86CPU for something else)
> > 
> > I guess any CPU-state code inside QEMU is not performance-sensitive, as
> > it woud already require switching between KVM kernelspace and QEMU
> > userspace.
> 
> I mean target-i386/[misc_]helper.c and thus TCG, IIUC. :)

Oh, right. I wonder how much performance impact it would have, if people
are already using TCG.

Anyway, would this really have any impact at all? I mean:
ENV_GET_CPU(env) is basically subtracing an constant offset from 'env'.
So I expect similar code to be generated, just using a different offset
from 'env' to get the cpuid_features field.


> 
> > On the other hand, this cleanup will allow us to easily convert some
> > code to deal with the feature array only (not requiring the full X86CPU
> > or x86_def_t struct), making it easier to have only one feature array,
> > in only one place, in the future.
> 
> The alternative line of thought is whether to group KVM stuff together.
> Tying it into an array makes that harder. But personally I'm not opposed
> to this array proposal.

I don't think we would gain much from grouping KVM stuff together. It
would just force us to add KVM special-cases to code that deal with
feature bits. KVM feature bits are CPUID bits that work like all others.
Igor Mammedov Dec. 14, 2012, 5:47 p.m. UTC | #11
On Fri, 14 Dec 2012 15:36:22 -0200
Eduardo Habkost <ehabkost@redhat.com> wrote:

> On Fri, Dec 14, 2012 at 06:20:41PM +0100, Andreas Färber wrote:
> > Am 14.12.2012 17:52, schrieb Eduardo Habkost:
> > > On Fri, Dec 14, 2012 at 04:14:32PM +0100, Andreas Färber wrote:
> > >> Am 12.12.2012 23:22, schrieb Eduardo Habkost:
[...]
> > 
> > >> The clock code using first_cpu looks solvable; what about CR4 and MSR
> > >> helpers, how performance-sensitive are they? (if they're not yet using
> > >> X86CPU for something else)
> > > 
> > > I guess any CPU-state code inside QEMU is not performance-sensitive, as
> > > it woud already require switching between KVM kernelspace and QEMU
> > > userspace.
> > 
> > I mean target-i386/[misc_]helper.c and thus TCG, IIUC. :)
> 
> Oh, right. I wonder how much performance impact it would have, if people
> are already using TCG.
> 
> Anyway, would this really have any impact at all? I mean:
> ENV_GET_CPU(env) is basically subtracing an constant offset from 'env'.
> So I expect similar code to be generated, just using a different offset
> from 'env' to get the cpuid_features field.
ENV_GET_CPU(env) does dynamic_cast which is expensive.


> 
> -- 
> Eduardo
Eduardo Habkost Dec. 14, 2012, 6:32 p.m. UTC | #12
On Fri, Dec 14, 2012 at 06:47:20PM +0100, Igor Mammedov wrote:
> On Fri, 14 Dec 2012 15:36:22 -0200
> Eduardo Habkost <ehabkost@redhat.com> wrote:
> 
> > On Fri, Dec 14, 2012 at 06:20:41PM +0100, Andreas Färber wrote:
> > > Am 14.12.2012 17:52, schrieb Eduardo Habkost:
> > > > On Fri, Dec 14, 2012 at 04:14:32PM +0100, Andreas Färber wrote:
> > > >> Am 12.12.2012 23:22, schrieb Eduardo Habkost:
> [...]
> > > 
> > > >> The clock code using first_cpu looks solvable; what about CR4 and MSR
> > > >> helpers, how performance-sensitive are they? (if they're not yet using
> > > >> X86CPU for something else)
> > > > 
> > > > I guess any CPU-state code inside QEMU is not performance-sensitive, as
> > > > it woud already require switching between KVM kernelspace and QEMU
> > > > userspace.
> > > 
> > > I mean target-i386/[misc_]helper.c and thus TCG, IIUC. :)
> > 
> > Oh, right. I wonder how much performance impact it would have, if people
> > are already using TCG.
> > 
> > Anyway, would this really have any impact at all? I mean:
> > ENV_GET_CPU(env) is basically subtracing an constant offset from 'env'.
> > So I expect similar code to be generated, just using a different offset
> > from 'env' to get the cpuid_features field.
> ENV_GET_CPU(env) does dynamic_cast which is expensive.

Oh, I didn't notice that. So the alternatives I see are:
- Use ENV_GET_CPU() and risk performance problems;
- Write a FAST_ENV_GET_CPU() macro for performance-sensitive code, that
  doesn't use dynamic_cast;
- Keep the fields on CPUX86State and move them only after we change the
  TCG code to use the QOM CPU object.

Personally, I prefer the third option. Moving fields from CPUArchState
before making most code use the CPU QOM objects instead of CPUArchState
sounds like a painful task.
diff mbox

Patch

diff --git a/hw/kvm/clock.c b/hw/kvm/clock.c
index 824b978..11af665 100644
--- a/hw/kvm/clock.c
+++ b/hw/kvm/clock.c
@@ -129,7 +129,7 @@  static TypeInfo kvmclock_info = {
 void kvmclock_create(void)
 {
     if (kvm_enabled() &&
-        first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
+        first_cpu->features[FEAT_KVM] & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
                                          (1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
         sysbus_create_simple("kvmclock", -1, NULL);
     }
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 1d8bcb4..71156af 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -130,7 +130,7 @@  static const char *get_elf_platform(void)
 
 static uint32_t get_elf_hwcap(void)
 {
-    return thread_env->cpuid_features;
+    return thread_env->features[FEAT_1_EDX];
 }
 
 #ifdef TARGET_X86_64
diff --git a/linux-user/main.c b/linux-user/main.c
index 25e35cd..5e847dd 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3625,13 +3625,13 @@  int main(int argc, char **argv, char **envp)
 
     env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
     env->hflags |= HF_PE_MASK;
-    if (env->cpuid_features & CPUID_SSE) {
+    if (env->features[FEAT_1_EDX] & CPUID_SSE) {
         env->cr[4] |= CR4_OSFXSR_MASK;
         env->hflags |= HF_OSFXSR_MASK;
     }
 #ifndef TARGET_ABI32
     /* enable 64 bit mode if possible */
-    if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) {
+    if (!(env->features[FEAT_80000001_EDX] & CPUID_EXT2_LM)) {
         fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
         exit(1);
     }
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 25f7500..f73583d 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -274,22 +274,15 @@  static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
 typedef struct x86_def_t {
     struct x86_def_t *next;
     const char *name;
-    uint32_t level;
+    uint32_t level, xlevel, xlevel2;
+    X86CPUFeatureWords features;
     uint32_t vendor1, vendor2, vendor3;
     int family;
     int model;
     int stepping;
     int tsc_khz;
-    uint32_t features, ext_features, ext2_features, ext3_features;
-    uint32_t kvm_features, svm_features;
-    uint32_t xlevel;
     char model_id[48];
     int vendor_override;
-    /* Store the results of Centaur's CPUID instructions */
-    uint32_t ext4_features;
-    uint32_t xlevel2;
-    /* The feature bits on CPUID[EAX=7,ECX=0].EBX */
-    uint32_t cpuid_7_0_ebx_features;
 } x86_def_t;
 
 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -347,13 +340,13 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 6,
         .model = 2,
         .stepping = 3,
-        .features = PPRO_FEATURES |
-            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
-            CPUID_PSE36,
-        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16 | CPUID_EXT_POPCNT,
-        .ext2_features = EXT2_PPRO_FEATURES |
-            CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
-        .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
+        .features[FEAT_1_EDX] = PPRO_FEATURES | CPUID_MTRR | CPUID_CLFLUSH |
+            CPUID_MCA | CPUID_PSE36,
+        .features[FEAT_1_ECX] = CPUID_EXT_SSE3 | CPUID_EXT_CX16 |
+            CPUID_EXT_POPCNT,
+        .features[FEAT_80000001_EDX] = EXT2_PPRO_FEATURES | CPUID_EXT2_LM |
+            CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+        .features[FEAT_80000001_ECX] = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
             CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
         .xlevel = 0x8000000A,
     },
@@ -366,22 +359,21 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 16,
         .model = 2,
         .stepping = 3,
-        .features = PPRO_FEATURES |
-            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
-            CPUID_PSE36 | CPUID_VME | CPUID_HT,
-        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_CX16 |
-            CPUID_EXT_POPCNT,
-        .ext2_features = EXT2_PPRO_FEATURES |
-            CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX |
-            CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_MMXEXT |
-            CPUID_EXT2_FFXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP,
+        .features[FEAT_1_EDX] = PPRO_FEATURES | CPUID_MTRR | CPUID_CLFLUSH |
+            CPUID_MCA | CPUID_PSE36 | CPUID_VME | CPUID_HT,
+        .features[FEAT_1_ECX] = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR |
+            CPUID_EXT_CX16 | CPUID_EXT_POPCNT,
+        .features[FEAT_80000001_EDX] = EXT2_PPRO_FEATURES | CPUID_EXT2_LM |
+            CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_3DNOW |
+            CPUID_EXT2_3DNOWEXT | CPUID_EXT2_MMXEXT | CPUID_EXT2_FFXSR |
+            CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP,
         /* Missing: CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
                     CPUID_EXT3_CR8LEG,
                     CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
                     CPUID_EXT3_OSVW, CPUID_EXT3_IBS */
-        .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
+        .features[FEAT_80000001_ECX] = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
             CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
-        .svm_features = CPUID_SVM_NPT | CPUID_SVM_LBRV,
+        .features[FEAT_SVM] = CPUID_SVM_NPT | CPUID_SVM_LBRV,
         .xlevel = 0x8000001A,
         .model_id = "AMD Phenom(tm) 9550 Quad-Core Processor"
     },
@@ -394,15 +386,16 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 6,
         .model = 15,
         .stepping = 11,
-        .features = PPRO_FEATURES |
-            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
-            CPUID_PSE36 | CPUID_VME | CPUID_DTS | CPUID_ACPI | CPUID_SS |
-            CPUID_HT | CPUID_TM | CPUID_PBE,
-        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
-            CPUID_EXT_DTES64 | CPUID_EXT_DSCPL | CPUID_EXT_VMX | CPUID_EXT_EST |
-            CPUID_EXT_TM2 | CPUID_EXT_CX16 | CPUID_EXT_XTPR | CPUID_EXT_PDCM,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
+        .features[FEAT_1_EDX] = PPRO_FEATURES | CPUID_MTRR | CPUID_CLFLUSH |
+            CPUID_MCA | CPUID_PSE36 | CPUID_VME | CPUID_DTS | CPUID_ACPI |
+            CPUID_SS | CPUID_HT | CPUID_TM | CPUID_PBE,
+        .features[FEAT_1_ECX] = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR |
+            CPUID_EXT_SSSE3 | CPUID_EXT_DTES64 | CPUID_EXT_DSCPL |
+            CPUID_EXT_VMX | CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_CX16 |
+            CPUID_EXT_XTPR | CPUID_EXT_PDCM,
+        .features[FEAT_80000001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL |
+            CPUID_EXT2_NX,
+        .features[FEAT_80000001_ECX] = CPUID_EXT3_LAHF_LM,
         .xlevel = 0x80000008,
         .model_id = "Intel(R) Core(TM)2 Duo CPU     T7700  @ 2.40GHz",
     },
@@ -416,19 +409,18 @@  static x86_def_t builtin_x86_defs[] = {
         .model = 6,
         .stepping = 1,
         /* Missing: CPUID_VME, CPUID_HT */
-        .features = PPRO_FEATURES |
-            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
-            CPUID_PSE36,
+        .features[FEAT_1_EDX] = PPRO_FEATURES | CPUID_MTRR | CPUID_CLFLUSH |
+            CPUID_MCA | CPUID_PSE36,
         /* Missing: CPUID_EXT_POPCNT, CPUID_EXT_MONITOR */
-        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16,
+        .features[FEAT_1_ECX] = CPUID_EXT_SSE3 | CPUID_EXT_CX16,
         /* Missing: CPUID_EXT2_PDPE1GB, CPUID_EXT2_RDTSCP */
-        .ext2_features = EXT2_PPRO_FEATURES |
-            CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+        .features[FEAT_80000001_EDX] = EXT2_PPRO_FEATURES | CPUID_EXT2_LM |
+            CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
         /* Missing: CPUID_EXT3_LAHF_LM, CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
                     CPUID_EXT3_CR8LEG, CPUID_EXT3_ABM, CPUID_EXT3_SSE4A,
                     CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
                     CPUID_EXT3_OSVW, CPUID_EXT3_IBS, CPUID_EXT3_SVM */
-        .ext3_features = 0,
+        .features[FEAT_80000001_ECX] = 0,
         .xlevel = 0x80000008,
         .model_id = "Common KVM processor"
     },
@@ -441,8 +433,8 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 6,
         .model = 3,
         .stepping = 3,
-        .features = PPRO_FEATURES,
-        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_POPCNT,
+        .features[FEAT_1_EDX] = PPRO_FEATURES,
+        .features[FEAT_1_ECX] = CPUID_EXT_SSE3 | CPUID_EXT_POPCNT,
         .xlevel = 0x80000004,
     },
     {
@@ -454,11 +446,11 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 15,
         .model = 6,
         .stepping = 1,
-        .features = PPRO_FEATURES |
-            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_PSE36,
-        .ext_features = CPUID_EXT_SSE3,
-        .ext2_features = EXT2_PPRO_FEATURES,
-        .ext3_features = 0,
+        .features[FEAT_1_EDX] = PPRO_FEATURES | CPUID_MTRR | CPUID_CLFLUSH |
+            CPUID_MCA | CPUID_PSE36,
+        .features[FEAT_1_ECX] = CPUID_EXT_SSE3,
+        .features[FEAT_80000001_EDX] = EXT2_PPRO_FEATURES,
+        .features[FEAT_80000001_ECX] = 0,
         .xlevel = 0x80000008,
         .model_id = "Common 32-bit KVM processor"
     },
@@ -471,12 +463,13 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 6,
         .model = 14,
         .stepping = 8,
-        .features = PPRO_FEATURES | CPUID_VME |
-            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_DTS | CPUID_ACPI |
-            CPUID_SS | CPUID_HT | CPUID_TM | CPUID_PBE,
-        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_VMX |
-            CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR | CPUID_EXT_PDCM,
-        .ext2_features = CPUID_EXT2_NX,
+        .features[FEAT_1_EDX] = PPRO_FEATURES | CPUID_VME | CPUID_MTRR |
+            CPUID_CLFLUSH | CPUID_MCA | CPUID_DTS | CPUID_ACPI | CPUID_SS |
+            CPUID_HT | CPUID_TM | CPUID_PBE,
+        .features[FEAT_1_ECX] = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR |
+            CPUID_EXT_VMX | CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR |
+            CPUID_EXT_PDCM,
+        .features[FEAT_80000001_EDX] = CPUID_EXT2_NX,
         .xlevel = 0x80000008,
         .model_id = "Genuine Intel(R) CPU           T2600  @ 2.16GHz",
     },
@@ -489,7 +482,7 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 4,
         .model = 0,
         .stepping = 0,
-        .features = I486_FEATURES,
+        .features[FEAT_1_EDX] = I486_FEATURES,
         .xlevel = 0,
     },
     {
@@ -501,7 +494,7 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 5,
         .model = 4,
         .stepping = 3,
-        .features = PENTIUM_FEATURES,
+        .features[FEAT_1_EDX] = PENTIUM_FEATURES,
         .xlevel = 0,
     },
     {
@@ -513,7 +506,7 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 6,
         .model = 5,
         .stepping = 2,
-        .features = PENTIUM2_FEATURES,
+        .features[FEAT_1_EDX] = PENTIUM2_FEATURES,
         .xlevel = 0,
     },
     {
@@ -525,7 +518,7 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 6,
         .model = 7,
         .stepping = 3,
-        .features = PENTIUM3_FEATURES,
+        .features[FEAT_1_EDX] = PENTIUM3_FEATURES,
         .xlevel = 0,
     },
     {
@@ -537,10 +530,10 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 6,
         .model = 2,
         .stepping = 3,
-        .features = PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR |
-            CPUID_MCA,
-        .ext2_features = EXT2_PPRO_FEATURES |
-            CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
+        .features[FEAT_1_EDX] = PPRO_FEATURES | CPUID_PSE36 | CPUID_VME |
+            CPUID_MTRR | CPUID_MCA,
+        .features[FEAT_80000001_EDX] = EXT2_PPRO_FEATURES | CPUID_EXT2_MMXEXT |
+            CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
         .xlevel = 0x80000008,
     },
     {
@@ -553,15 +546,15 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 6,
         .model = 28,
         .stepping = 2,
-        .features = PPRO_FEATURES |
-            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_VME | CPUID_DTS |
-            CPUID_ACPI | CPUID_SS | CPUID_HT | CPUID_TM | CPUID_PBE,
+        .features[FEAT_1_EDX] = PPRO_FEATURES | CPUID_MTRR | CPUID_CLFLUSH |
+            CPUID_MCA | CPUID_VME | CPUID_DTS | CPUID_ACPI | CPUID_SS |
+            CPUID_HT | CPUID_TM | CPUID_PBE,
             /* Some CPUs got no CPUID_SEP */
-        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
-            CPUID_EXT_DSCPL | CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR,
-        .ext2_features = EXT2_PPRO_FEATURES |
-            CPUID_EXT2_NX,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
+        .features[FEAT_1_ECX] = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR |
+            CPUID_EXT_SSSE3 | CPUID_EXT_DSCPL | CPUID_EXT_EST | CPUID_EXT_TM2 |
+            CPUID_EXT_XTPR,
+        .features[FEAT_80000001_EDX] = EXT2_PPRO_FEATURES | CPUID_EXT2_NX,
+        .features[FEAT_80000001_ECX] = CPUID_EXT3_LAHF_LM,
         .xlevel = 0x8000000A,
         .model_id = "Intel(R) Atom(TM) CPU N270   @ 1.60GHz",
     },
@@ -574,14 +567,15 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 6,
         .model = 2,
         .stepping = 3,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
-             CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
-             CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
-             CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_SSSE3 | CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
+        .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR |
+            CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV |
+            CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC |
+            CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC |
+            CPUID_PSE | CPUID_DE | CPUID_FP87,
+        .features[FEAT_1_ECX] = CPUID_EXT_SSSE3 | CPUID_EXT_SSE3,
+        .features[FEAT_80000001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_NX |
+            CPUID_EXT2_SYSCALL,
+        .features[FEAT_80000001_ECX] = CPUID_EXT3_LAHF_LM,
         .xlevel = 0x8000000A,
         .model_id = "Intel Celeron_4x0 (Conroe/Merom Class Core 2)",
     },
@@ -594,15 +588,16 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 6,
         .model = 2,
         .stepping = 3,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
-             CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
-             CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
-             CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
-             CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
+        .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR |
+            CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV |
+            CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC |
+            CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC |
+            CPUID_PSE | CPUID_DE | CPUID_FP87,
+        .features[FEAT_1_ECX] = CPUID_EXT_SSE41 | CPUID_EXT_CX16 |
+            CPUID_EXT_SSSE3 | CPUID_EXT_SSE3,
+        .features[FEAT_80000001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_NX |
+            CPUID_EXT2_SYSCALL,
+        .features[FEAT_80000001_ECX] = CPUID_EXT3_LAHF_LM,
         .xlevel = 0x8000000A,
         .model_id = "Intel Core 2 Duo P9xxx (Penryn Class Core 2)",
     },
@@ -615,15 +610,17 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 6,
         .model = 2,
         .stepping = 3,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
-             CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
-             CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
-             CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
-             CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
+        .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR |
+            CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV |
+            CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC |
+            CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC |
+            CPUID_PSE | CPUID_DE | CPUID_FP87,
+        .features[FEAT_1_ECX] = CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
+            CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
+            CPUID_EXT_SSE3,
+        .features[FEAT_80000001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL |
+            CPUID_EXT2_NX,
+        .features[FEAT_80000001_ECX] = CPUID_EXT3_LAHF_LM,
         .xlevel = 0x8000000A,
         .model_id = "Intel Core i7 9xx (Nehalem Class Core i7)",
     },
@@ -636,16 +633,17 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 6,
         .model = 44,
         .stepping = 1,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
-             CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
-             CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
-             CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
-             CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
-             CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
+        .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR |
+            CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV |
+            CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC |
+            CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC |
+            CPUID_PSE | CPUID_DE | CPUID_FP87,
+        .features[FEAT_1_ECX] = CPUID_EXT_AES | CPUID_EXT_POPCNT |
+            CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | CPUID_EXT_CX16 |
+            CPUID_EXT_SSSE3 | CPUID_EXT_SSE3,
+        .features[FEAT_80000001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL |
+            CPUID_EXT2_NX,
+        .features[FEAT_80000001_ECX] = CPUID_EXT3_LAHF_LM,
         .xlevel = 0x8000000A,
         .model_id = "Westmere E56xx/L56xx/X56xx (Nehalem-C)",
     },
@@ -658,19 +656,19 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 6,
         .model = 42,
         .stepping = 1,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
-             CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
-             CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
-             CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
-             CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_POPCNT |
-             CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
-             CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
-             CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
-             CPUID_EXT2_SYSCALL,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
+        .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR |
+            CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV |
+            CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC |
+            CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC |
+            CPUID_PSE | CPUID_DE | CPUID_FP87,
+        .features[FEAT_1_ECX] = CPUID_EXT_AVX | CPUID_EXT_XSAVE |
+            CPUID_EXT_AES | CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_POPCNT |
+            CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
+            CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
+            CPUID_EXT_SSE3,
+        .features[FEAT_80000001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP |
+            CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
+        .features[FEAT_80000001_ECX] = CPUID_EXT3_LAHF_LM,
         .xlevel = 0x8000000A,
         .model_id = "Intel Xeon E312xx (Sandy Bridge)",
     },
@@ -683,21 +681,21 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 6,
         .model = 60,
         .stepping = 1,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
-             CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
-             CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
-             CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
-             CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
-             CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
-             CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
-             CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
-             CPUID_EXT_PCID,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
-             CPUID_EXT2_SYSCALL,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
-        .cpuid_7_0_ebx_features = CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
+        .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR |
+            CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV |
+            CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC |
+            CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC |
+            CPUID_PSE | CPUID_DE | CPUID_FP87,
+        .features[FEAT_1_ECX] = CPUID_EXT_AVX | CPUID_EXT_XSAVE |
+            CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_X2APIC |
+            CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | CPUID_EXT_CX16 |
+            CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
+            CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
+            CPUID_EXT_PCID,
+        .features[FEAT_80000001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP |
+            CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
+        .features[FEAT_80000001_ECX] = CPUID_EXT3_LAHF_LM,
+        .features[FEAT_7_0_EBX] = CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
             CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
             CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
             CPUID_7_0_EBX_RTM,
@@ -713,18 +711,18 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 15,
         .model = 6,
         .stepping = 1,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
-             CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
-             CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
-             CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_FXSR | CPUID_EXT2_MMX |
-             CPUID_EXT2_NX | CPUID_EXT2_PSE36 | CPUID_EXT2_PAT |
+        .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR |
+            CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV |
+            CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC |
+            CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC |
+            CPUID_PSE | CPUID_DE | CPUID_FP87,
+        .features[FEAT_1_ECX] = CPUID_EXT_SSE3,
+        .features[FEAT_80000001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_FXSR |
+            CPUID_EXT2_MMX | CPUID_EXT2_NX | CPUID_EXT2_PSE36 | CPUID_EXT2_PAT |
              CPUID_EXT2_CMOV | CPUID_EXT2_MCA | CPUID_EXT2_PGE |
-             CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC |
-             CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR |
-             CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU,
+            CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC |
+            CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR |
+            CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU,
         .xlevel = 0x80000008,
         .model_id = "AMD Opteron 240 (Gen 1 Class Opteron)",
     },
@@ -737,20 +735,20 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 15,
         .model = 6,
         .stepping = 1,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
-             CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
-             CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
-             CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_CX16 | CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_FXSR |
-             CPUID_EXT2_MMX | CPUID_EXT2_NX | CPUID_EXT2_PSE36 |
-             CPUID_EXT2_PAT | CPUID_EXT2_CMOV | CPUID_EXT2_MCA |
-             CPUID_EXT2_PGE | CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL |
-             CPUID_EXT2_APIC | CPUID_EXT2_CX8 | CPUID_EXT2_MCE |
-             CPUID_EXT2_PAE | CPUID_EXT2_MSR | CPUID_EXT2_TSC | CPUID_EXT2_PSE |
-             CPUID_EXT2_DE | CPUID_EXT2_FPU,
-        .ext3_features = CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
+        .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR |
+            CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV |
+            CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC |
+            CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC |
+            CPUID_PSE | CPUID_DE | CPUID_FP87,
+        .features[FEAT_1_ECX] = CPUID_EXT_CX16 | CPUID_EXT_SSE3,
+        .features[FEAT_80000001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP |
+            CPUID_EXT2_FXSR | CPUID_EXT2_MMX | CPUID_EXT2_NX |
+            CPUID_EXT2_PSE36 | CPUID_EXT2_PAT | CPUID_EXT2_CMOV |
+            CPUID_EXT2_MCA | CPUID_EXT2_PGE | CPUID_EXT2_MTRR |
+            CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC | CPUID_EXT2_CX8 |
+            CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR | CPUID_EXT2_TSC |
+            CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU,
+        .features[FEAT_80000001_ECX] = CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
         .xlevel = 0x80000008,
         .model_id = "AMD Opteron 22xx (Gen 2 Class Opteron)",
     },
@@ -763,22 +761,23 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 15,
         .model = 6,
         .stepping = 1,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
-             CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
-             CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
-             CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_POPCNT | CPUID_EXT_CX16 | CPUID_EXT_MONITOR |
-             CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_FXSR |
-             CPUID_EXT2_MMX | CPUID_EXT2_NX | CPUID_EXT2_PSE36 |
-             CPUID_EXT2_PAT | CPUID_EXT2_CMOV | CPUID_EXT2_MCA |
-             CPUID_EXT2_PGE | CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL |
-             CPUID_EXT2_APIC | CPUID_EXT2_CX8 | CPUID_EXT2_MCE |
-             CPUID_EXT2_PAE | CPUID_EXT2_MSR | CPUID_EXT2_TSC | CPUID_EXT2_PSE |
-             CPUID_EXT2_DE | CPUID_EXT2_FPU,
-        .ext3_features = CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A |
-             CPUID_EXT3_ABM | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
+        .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR |
+            CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV |
+            CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC |
+            CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC |
+            CPUID_PSE | CPUID_DE | CPUID_FP87,
+        .features[FEAT_1_ECX] = CPUID_EXT_POPCNT | CPUID_EXT_CX16 |
+            CPUID_EXT_MONITOR | CPUID_EXT_SSE3,
+        .features[FEAT_80000001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP |
+            CPUID_EXT2_FXSR | CPUID_EXT2_MMX | CPUID_EXT2_NX |
+            CPUID_EXT2_PSE36 | CPUID_EXT2_PAT | CPUID_EXT2_CMOV |
+            CPUID_EXT2_MCA | CPUID_EXT2_PGE | CPUID_EXT2_MTRR |
+            CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC | CPUID_EXT2_CX8 |
+            CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR | CPUID_EXT2_TSC |
+            CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU,
+        .features[FEAT_80000001_ECX] = CPUID_EXT3_MISALIGNSSE |
+            CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM |
+            CPUID_EXT3_LAHF_LM,
         .xlevel = 0x80000008,
         .model_id = "AMD Opteron 23xx (Gen 3 Class Opteron)",
     },
@@ -791,26 +790,26 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 21,
         .model = 1,
         .stepping = 2,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
-             CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
-             CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
-             CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
-             CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
-             CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
-             CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP |
-             CPUID_EXT2_PDPE1GB | CPUID_EXT2_FXSR | CPUID_EXT2_MMX |
-             CPUID_EXT2_NX | CPUID_EXT2_PSE36 | CPUID_EXT2_PAT |
-             CPUID_EXT2_CMOV | CPUID_EXT2_MCA | CPUID_EXT2_PGE |
-             CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC |
-             CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR |
-             CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU,
-        .ext3_features = CPUID_EXT3_FMA4 | CPUID_EXT3_XOP |
-             CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE |
-             CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM |
-             CPUID_EXT3_LAHF_LM,
+        .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR |
+            CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV |
+            CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC |
+            CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC |
+            CPUID_PSE | CPUID_DE | CPUID_FP87,
+        .features[FEAT_1_ECX] = CPUID_EXT_AVX | CPUID_EXT_XSAVE |
+            CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
+            CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
+            CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
+        .features[FEAT_80000001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP |
+            CPUID_EXT2_PDPE1GB | CPUID_EXT2_FXSR | CPUID_EXT2_MMX |
+            CPUID_EXT2_NX | CPUID_EXT2_PSE36 | CPUID_EXT2_PAT |
+            CPUID_EXT2_CMOV | CPUID_EXT2_MCA | CPUID_EXT2_PGE |
+            CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC |
+            CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR |
+            CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU,
+        .features[FEAT_80000001_ECX] = CPUID_EXT3_FMA4 | CPUID_EXT3_XOP |
+            CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE |
+            CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM |
+            CPUID_EXT3_LAHF_LM,
         .xlevel = 0x8000001A,
         .model_id = "AMD Opteron 62xx class CPU",
     },
@@ -823,26 +822,26 @@  static x86_def_t builtin_x86_defs[] = {
         .family = 21,
         .model = 2,
         .stepping = 0,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
-             CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
-             CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
-             CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_F16C | CPUID_EXT_AVX | CPUID_EXT_XSAVE |
-             CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
-             CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_FMA |
+        .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR |
+            CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV |
+            CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC |
+            CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC |
+            CPUID_PSE | CPUID_DE | CPUID_FP87,
+        .features[FEAT_1_ECX] = CPUID_EXT_F16C | CPUID_EXT_AVX |
+            CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT |
+            CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_FMA |
              CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP |
-             CPUID_EXT2_PDPE1GB | CPUID_EXT2_FXSR | CPUID_EXT2_MMX |
-             CPUID_EXT2_NX | CPUID_EXT2_PSE36 | CPUID_EXT2_PAT |
-             CPUID_EXT2_CMOV | CPUID_EXT2_MCA | CPUID_EXT2_PGE |
-             CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC |
-             CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR |
-             CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU,
-        .ext3_features = CPUID_EXT3_TBM | CPUID_EXT3_FMA4 | CPUID_EXT3_XOP |
-             CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE |
+        .features[FEAT_80000001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP |
+            CPUID_EXT2_PDPE1GB | CPUID_EXT2_FXSR | CPUID_EXT2_MMX |
+            CPUID_EXT2_NX | CPUID_EXT2_PSE36 | CPUID_EXT2_PAT |
+            CPUID_EXT2_CMOV | CPUID_EXT2_MCA | CPUID_EXT2_PGE |
+            CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC |
+            CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR |
+            CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU,
+        .features[FEAT_80000001_ECX] = CPUID_EXT3_TBM | CPUID_EXT3_FMA4 |
+            CPUID_EXT3_XOP | CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE |
              CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM |
-             CPUID_EXT3_LAHF_LM,
+            CPUID_EXT3_LAHF_LM,
         .xlevel = 0x8000001A,
         .model_id = "AMD Opteron 63xx class CPU",
     },
@@ -890,20 +889,22 @@  static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
     x86_cpu_def->stepping = eax & 0x0F;
 
     x86_cpu_def->level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
-    x86_cpu_def->features = kvm_arch_get_supported_cpuid(s, 0x1, 0, R_EDX);
-    x86_cpu_def->ext_features = kvm_arch_get_supported_cpuid(s, 0x1, 0, R_ECX);
+    x86_cpu_def->features[FEAT_1_EDX] =
+                kvm_arch_get_supported_cpuid(s, 0x1, 0, R_EDX);
+    x86_cpu_def->features[FEAT_1_ECX] =
+                kvm_arch_get_supported_cpuid(s, 0x1, 0, R_ECX);
 
     if (x86_cpu_def->level >= 7) {
-        x86_cpu_def->cpuid_7_0_ebx_features =
+        x86_cpu_def->features[FEAT_7_0_EBX] =
                     kvm_arch_get_supported_cpuid(s, 0x7, 0, R_EBX);
     } else {
-        x86_cpu_def->cpuid_7_0_ebx_features = 0;
+        x86_cpu_def->features[FEAT_7_0_EBX] = 0;
     }
 
     x86_cpu_def->xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
-    x86_cpu_def->ext2_features =
+    x86_cpu_def->features[FEAT_80000001_EDX] =
                 kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX);
-    x86_cpu_def->ext3_features =
+    x86_cpu_def->features[FEAT_80000001_ECX] =
                 kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX);
 
     cpu_x86_fill_model_id(x86_cpu_def->model_id);
@@ -919,7 +920,7 @@  static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
             /* Support VIA max extended level */
             x86_cpu_def->xlevel2 = eax;
             host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx);
-            x86_cpu_def->ext4_features =
+            x86_cpu_def->features[FEAT_C0000001_EDX] =
                     kvm_arch_get_supported_cpuid(s, 0xC0000001, 0, R_EDX);
         }
     }
@@ -930,7 +931,7 @@  static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
      * available on the host hardware. Just set all bits and mask out the
      * unsupported ones later.
      */
-    x86_cpu_def->svm_features = -1;
+    x86_cpu_def->features[FEAT_SVM] = -1;
 #endif /* CONFIG_KVM */
 }
 
@@ -961,13 +962,17 @@  static int kvm_check_features_against_host(x86_def_t *guest_def)
     uint32_t mask;
     int rv, i;
     struct model_features_t ft[] = {
-        {&guest_def->features, &host_def.features,
+        {&guest_def->features[FEAT_1_EDX],
+            &host_def.features[FEAT_1_EDX],
             ~0, feature_name, 0x00000000},
-        {&guest_def->ext_features, &host_def.ext_features,
+        {&guest_def->features[FEAT_1_ECX],
+            &host_def.features[FEAT_1_ECX],
             ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001},
-        {&guest_def->ext2_features, &host_def.ext2_features,
+        {&guest_def->features[FEAT_80000001_EDX],
+            &host_def.features[FEAT_80000001_EDX],
             ~PPRO_FEATURES, ext2_feature_name, 0x80000000},
-        {&guest_def->ext3_features, &host_def.ext3_features,
+        {&guest_def->features[FEAT_80000001_ECX],
+            &host_def.features[FEAT_80000001_ECX],
             ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}};
 
     assert(kvm_enabled());
@@ -1249,15 +1254,15 @@  static void cpudef_2_x86_cpu(X86CPU *cpu, x86_def_t *def, Error **errp)
     object_property_set_int(OBJECT(cpu), def->family, "family", errp);
     object_property_set_int(OBJECT(cpu), def->model, "model", errp);
     object_property_set_int(OBJECT(cpu), def->stepping, "stepping", errp);
-    env->cpuid_features = def->features;
-    env->cpuid_ext_features = def->ext_features;
-    env->cpuid_ext2_features = def->ext2_features;
-    env->cpuid_ext3_features = def->ext3_features;
+    env->features[FEAT_1_EDX] = def->features[FEAT_1_EDX];
+    env->features[FEAT_1_ECX] = def->features[FEAT_1_ECX];
+    env->features[FEAT_80000001_EDX] = def->features[FEAT_80000001_EDX];
+    env->features[FEAT_80000001_ECX] = def->features[FEAT_80000001_ECX];
     object_property_set_int(OBJECT(cpu), def->xlevel, "xlevel", errp);
-    env->cpuid_kvm_features = def->kvm_features;
-    env->cpuid_svm_features = def->svm_features;
-    env->cpuid_ext4_features = def->ext4_features;
-    env->cpuid_7_0_ebx_features = def->cpuid_7_0_ebx_features;
+    env->features[FEAT_KVM] = def->features[FEAT_KVM];
+    env->features[FEAT_SVM] = def->features[FEAT_SVM];
+    env->features[FEAT_C0000001_EDX] = def->features[FEAT_C0000001_EDX];
+    env->features[FEAT_7_0_EBX] = def->features[FEAT_7_0_EBX];
     env->cpuid_xlevel2 = def->xlevel2;
     object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000,
                             "tsc-frequency", errp);
@@ -1415,20 +1420,20 @@  static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features)
         }
         featurestr = strtok(NULL, ",");
     }
-    x86_cpu_def->features |= plus_features;
-    x86_cpu_def->ext_features |= plus_ext_features;
-    x86_cpu_def->ext2_features |= plus_ext2_features;
-    x86_cpu_def->ext3_features |= plus_ext3_features;
-    x86_cpu_def->kvm_features |= plus_kvm_features;
-    x86_cpu_def->svm_features |= plus_svm_features;
-    x86_cpu_def->cpuid_7_0_ebx_features |= plus_7_0_ebx_features;
-    x86_cpu_def->features &= ~minus_features;
-    x86_cpu_def->ext_features &= ~minus_ext_features;
-    x86_cpu_def->ext2_features &= ~minus_ext2_features;
-    x86_cpu_def->ext3_features &= ~minus_ext3_features;
-    x86_cpu_def->kvm_features &= ~minus_kvm_features;
-    x86_cpu_def->svm_features &= ~minus_svm_features;
-    x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_7_0_ebx_features;
+    x86_cpu_def->features[FEAT_1_EDX] |= plus_features;
+    x86_cpu_def->features[FEAT_1_ECX] |= plus_ext_features;
+    x86_cpu_def->features[FEAT_80000001_EDX] |= plus_ext2_features;
+    x86_cpu_def->features[FEAT_80000001_ECX] |= plus_ext3_features;
+    x86_cpu_def->features[FEAT_KVM] |= plus_kvm_features;
+    x86_cpu_def->features[FEAT_SVM] |= plus_svm_features;
+    x86_cpu_def->features[FEAT_7_0_EBX] |= plus_7_0_ebx_features;
+    x86_cpu_def->features[FEAT_1_EDX] &= ~minus_features;
+    x86_cpu_def->features[FEAT_1_ECX] &= ~minus_ext_features;
+    x86_cpu_def->features[FEAT_80000001_EDX] &= ~minus_ext2_features;
+    x86_cpu_def->features[FEAT_80000001_ECX] &= ~minus_ext3_features;
+    x86_cpu_def->features[FEAT_KVM] &= ~minus_kvm_features;
+    x86_cpu_def->features[FEAT_SVM] &= ~minus_svm_features;
+    x86_cpu_def->features[FEAT_7_0_EBX] &= ~minus_7_0_ebx_features;
     if (check_cpuid && kvm_enabled()) {
         if (kvm_check_features_against_host(x86_cpu_def) && enforce_cpuid)
             goto error;
@@ -1520,21 +1525,21 @@  static void filter_features_for_kvm(X86CPU *cpu)
     CPUX86State *env = &cpu->env;
     KVMState *s = kvm_state;
 
-    env->cpuid_features &=
+    env->features[FEAT_1_EDX] &=
         kvm_arch_get_supported_cpuid(s, 1, 0, R_EDX);
-    env->cpuid_ext_features &=
+    env->features[FEAT_1_ECX] &=
         kvm_arch_get_supported_cpuid(s, 1, 0, R_ECX);
-    env->cpuid_ext2_features &=
+    env->features[FEAT_80000001_EDX] &=
         kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX);
-    env->cpuid_ext3_features &=
+    env->features[FEAT_80000001_ECX] &=
         kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX);
-    env->cpuid_svm_features  &=
+    env->features[FEAT_SVM]  &=
         kvm_arch_get_supported_cpuid(s, 0x8000000A, 0, R_EDX);
-    env->cpuid_7_0_ebx_features &=
+    env->features[FEAT_7_0_EBX] &=
         kvm_arch_get_supported_cpuid(s, 7, 0, R_EBX);
-    env->cpuid_kvm_features &=
+    env->features[FEAT_KVM] &=
         kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
-    env->cpuid_ext4_features &=
+    env->features[FEAT_C0000001_EDX] &=
         kvm_arch_get_supported_cpuid(s, 0xC0000001, 0, R_EDX);
 
 }
@@ -1571,11 +1576,14 @@  X86CPU *cpu_x86_create(const char *cpu_model, Error **errp)
         goto error;
     }
 
-    def->kvm_features |= kvm_default_features;
-    add_flagname_to_bitmaps("hypervisor", &def->features,
-                            &def->ext_features, &def->ext2_features,
-                            &def->ext3_features, &def->kvm_features,
-                            &def->svm_features, &def->cpuid_7_0_ebx_features);
+    def->features[FEAT_KVM] |= kvm_default_features;
+    add_flagname_to_bitmaps("hypervisor", &def->features[FEAT_1_EDX],
+                            &def->features[FEAT_1_ECX],
+                            &def->features[FEAT_80000001_EDX],
+                            &def->features[FEAT_80000001_ECX],
+                            &def->features[FEAT_KVM],
+                            &def->features[FEAT_SVM],
+                            &def->features[FEAT_7_0_EBX]);
 
     if (cpu_x86_parse_featurestr(def, features) < 0) {
         error_setg(errp, "Error parsing feature string: %s",
@@ -1603,7 +1611,7 @@  error:
 
 void cpu_clear_apic_feature(CPUX86State *env)
 {
-    env->cpuid_features &= ~CPUID_APIC;
+    env->features[FEAT_1_EDX] &= ~CPUID_APIC;
 }
 
 #endif /* !CONFIG_USER_ONLY */
@@ -1684,8 +1692,8 @@  void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
     case 1:
         *eax = env->cpuid_version;
         *ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
-        *ecx = env->cpuid_ext_features;
-        *edx = env->cpuid_features;
+        *ecx = env->features[FEAT_1_ECX];
+        *edx = env->features[FEAT_1_EDX];
         if (env->nr_cores * env->nr_threads > 1) {
             *ebx |= (env->nr_cores * env->nr_threads) << 16;
             *edx |= 1 << 28;    /* HTT bit */
@@ -1753,7 +1761,7 @@  void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
         /* Structured Extended Feature Flags Enumeration Leaf */
         if (count == 0) {
             *eax = 0; /* Maximum ECX value for sub-leaves */
-            *ebx = env->cpuid_7_0_ebx_features; /* Feature flags */
+            *ebx = env->features[FEAT_7_0_EBX]; /* Feature flags */
             *ecx = 0; /* Reserved */
             *edx = 0; /* Reserved */
         } else {
@@ -1788,7 +1796,7 @@  void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
         break;
     case 0xD:
         /* Processor Extended State */
-        if (!(env->cpuid_ext_features & CPUID_EXT_XSAVE)) {
+        if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
             *eax = 0;
             *ebx = 0;
             *ecx = 0;
@@ -1818,8 +1826,8 @@  void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
     case 0x80000001:
         *eax = env->cpuid_version;
         *ebx = 0;
-        *ecx = env->cpuid_ext3_features;
-        *edx = env->cpuid_ext2_features;
+        *ecx = env->features[FEAT_80000001_ECX];
+        *edx = env->features[FEAT_80000001_EDX];
 
         /* The Linux kernel checks for the CMPLegacy bit and
          * discards multiple thread information if it is set.
@@ -1860,12 +1868,12 @@  void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
     case 0x80000008:
         /* virtual & phys address size in low 2 bytes. */
 /* XXX: This value must match the one used in the MMU code. */
-        if (env->cpuid_ext2_features & CPUID_EXT2_LM) {
+        if (env->features[FEAT_80000001_EDX] & CPUID_EXT2_LM) {
             /* 64 bit processor */
 /* XXX: The physical address space is limited to 42 bits in exec.c. */
             *eax = 0x00003028;	/* 48 bits virtual, 40 bits physical */
         } else {
-            if (env->cpuid_features & CPUID_PSE36) {
+            if (env->features[FEAT_1_EDX] & CPUID_PSE36) {
                 *eax = 0x00000024; /* 36 bits physical */
             } else {
                 *eax = 0x00000020; /* 32 bits physical */
@@ -1879,11 +1887,11 @@  void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
         }
         break;
     case 0x8000000A:
-        if (env->cpuid_ext3_features & CPUID_EXT3_SVM) {
+        if (env->features[FEAT_80000001_ECX] & CPUID_EXT3_SVM) {
             *eax = 0x00000001; /* SVM Revision */
             *ebx = 0x00000010; /* nr of ASIDs */
             *ecx = 0;
-            *edx = env->cpuid_svm_features; /* optional features */
+            *edx = env->features[FEAT_SVM]; /* optional features */
         } else {
             *eax = 0;
             *ebx = 0;
@@ -1902,7 +1910,7 @@  void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
         *eax = env->cpuid_version;
         *ebx = 0;
         *ecx = 0;
-        *edx = env->cpuid_ext4_features;
+        *edx = env->features[FEAT_C0000001_EDX];
         break;
     case 0xC0000002:
     case 0xC0000003:
@@ -2034,7 +2042,7 @@  static void mce_init(X86CPU *cpu)
     unsigned int bank;
 
     if (((cenv->cpuid_version >> 8) & 0xf) >= 6
-        && (cenv->cpuid_features & (CPUID_MCE | CPUID_MCA)) ==
+        && (cenv->features[FEAT_1_EDX] & (CPUID_MCE | CPUID_MCA)) ==
             (CPUID_MCE | CPUID_MCA)) {
         cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF;
         cenv->mcg_ctl = ~(uint64_t)0;
@@ -2095,7 +2103,7 @@  void x86_cpu_realize(Object *obj, Error **errp)
     X86CPU *cpu = X86_CPU(obj);
     CPUX86State *env = &cpu->env;
 
-    if (env->cpuid_7_0_ebx_features && env->cpuid_level < 7) {
+    if (env->features[FEAT_7_0_EBX] && env->cpuid_level < 7) {
         env->cpuid_level = 7;
     }
 
@@ -2105,21 +2113,21 @@  void x86_cpu_realize(Object *obj, Error **errp)
     if (env->cpuid_vendor1 == CPUID_VENDOR_AMD_1 &&
         env->cpuid_vendor2 == CPUID_VENDOR_AMD_2 &&
         env->cpuid_vendor3 == CPUID_VENDOR_AMD_3) {
-        env->cpuid_ext2_features &= ~CPUID_EXT2_AMD_ALIASES;
-        env->cpuid_ext2_features |= (env->cpuid_features &
-                                     CPUID_EXT2_AMD_ALIASES);
+        env->features[FEAT_80000001_EDX] &= ~CPUID_EXT2_AMD_ALIASES;
+        env->features[FEAT_80000001_EDX] |= (env->features[FEAT_1_EDX] &
+                                             CPUID_EXT2_AMD_ALIASES);
     }
 
     if (!kvm_enabled()) {
-        env->cpuid_features &= TCG_FEATURES;
-        env->cpuid_ext_features &= TCG_EXT_FEATURES;
-        env->cpuid_ext2_features &= (TCG_EXT2_FEATURES
+        env->features[FEAT_1_EDX] &= TCG_FEATURES;
+        env->features[FEAT_1_ECX] &= TCG_EXT_FEATURES;
+        env->features[FEAT_80000001_EDX] &= (TCG_EXT2_FEATURES
 #ifdef TARGET_X86_64
             | CPUID_EXT2_SYSCALL | CPUID_EXT2_LM
 #endif
             );
-        env->cpuid_ext3_features &= TCG_EXT3_FEATURES;
-        env->cpuid_svm_features &= TCG_SVM_FEATURES;
+        env->features[FEAT_80000001_ECX] &= TCG_EXT3_FEATURES;
+        env->features[FEAT_SVM] &= TCG_SVM_FEATURES;
     } else {
 #ifdef CONFIG_KVM
         filter_features_for_kvm(cpu);
@@ -2129,7 +2137,7 @@  void x86_cpu_realize(Object *obj, Error **errp)
 #ifndef CONFIG_USER_ONLY
     qemu_register_reset(x86_cpu_machine_reset_cb, cpu);
 
-    if (cpu->env.cpuid_features & CPUID_APIC || smp_cpus > 1) {
+    if (cpu->env.features[FEAT_1_EDX] & CPUID_APIC || smp_cpus > 1) {
         x86_cpu_apic_init(cpu, errp);
         if (error_is_set(errp)) {
             return;
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 8ce9b9f..76f0d27 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -694,6 +694,21 @@  typedef enum TPRAccess {
     TPR_ACCESS_WRITE,
 } TPRAccess;
 
+typedef enum X86CPUFeatureWord {
+    FEAT_1_EDX,         /* CPUID[1].EDX */
+    FEAT_1_ECX,         /* CPUID[1].ECX */
+    FEAT_7_0_EBX,       /* CPUID[EAX=7,ECX=0].EBX */
+    FEAT_80000001_EDX,  /* CPUID[8000_0001].EDX */
+    FEAT_80000001_ECX,  /* CPUID[8000_0001].ECX */
+    FEAT_C0000001_EDX,  /* CPUID[C000_0001].EDX */
+    FEAT_KVM,           /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */
+    FEAT_SVM,           /* CPUID[8000_000A].EDX */
+    FEATURE_WORDS,      /* Size of the features arrays */
+} FeatureWord;
+
+/* An array of feature words */
+typedef uint32_t X86CPUFeatureWords[FEATURE_WORDS];
+
 typedef struct CPUX86State {
     /* standard registers */
     target_ulong regs[CPU_NB_REGS];
@@ -800,24 +815,15 @@  typedef struct CPUX86State {
     uint64_t pat;
 
     /* processor features (e.g. for CPUID insn) */
-    uint32_t cpuid_level;
+    uint32_t cpuid_level, cpuid_xlevel, cpuid_xlevel2;
+    X86CPUFeatureWords features;
     uint32_t cpuid_vendor1;
     uint32_t cpuid_vendor2;
     uint32_t cpuid_vendor3;
     uint32_t cpuid_version;
-    uint32_t cpuid_features;
-    uint32_t cpuid_ext_features;
-    uint32_t cpuid_xlevel;
     uint32_t cpuid_model[12];
-    uint32_t cpuid_ext2_features;
-    uint32_t cpuid_ext3_features;
     uint32_t cpuid_apic_id;
     int cpuid_vendor_override;
-    /* Store the results of Centaur's CPUID instructions */
-    uint32_t cpuid_xlevel2;
-    uint32_t cpuid_ext4_features;
-    /* Flags from CPUID[EAX=7,ECX=0].EBX */
-    uint32_t cpuid_7_0_ebx_features;
 
     /* MTRRs */
     uint64_t mtrr_fixed[11];
@@ -831,8 +837,6 @@  typedef struct CPUX86State {
     uint8_t soft_interrupt;
     uint8_t has_error_code;
     uint32_t sipi_vector;
-    uint32_t cpuid_kvm_features;
-    uint32_t cpuid_svm_features;
     bool tsc_valid;
     int tsc_khz;
     void *kvm_xsave_buf;
diff --git a/target-i386/helper.c b/target-i386/helper.c
index dafa666..a1b25b6 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -450,7 +450,7 @@  void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
         tlb_flush(env, 1);
     }
     /* SSE handling */
-    if (!(env->cpuid_features & CPUID_SSE)) {
+    if (!(env->features[FEAT_1_EDX] & CPUID_SSE)) {
         new_cr4 &= ~CR4_OSFXSR_MASK;
     }
     env->hflags &= ~HF_OSFXSR_MASK;
@@ -458,7 +458,7 @@  void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
         env->hflags |= HF_OSFXSR_MASK;
     }
 
-    if (!(env->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)) {
+    if (!(env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_SMAP)) {
         new_cr4 &= ~CR4_SMAP_MASK;
     }
     env->hflags &= ~HF_SMAP_MASK;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index f669281..5b614fa 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -438,7 +438,7 @@  int kvm_arch_init_vcpu(CPUX86State *env)
     c = &cpuid_data.entries[cpuid_i++];
     memset(c, 0, sizeof(*c));
     c->function = KVM_CPUID_FEATURES;
-    c->eax = env->cpuid_kvm_features;
+    c->eax = env->features[FEAT_KVM];
 
     if (hyperv_enabled()) {
         memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12);
@@ -573,7 +573,8 @@  int kvm_arch_init_vcpu(CPUX86State *env)
     cpuid_data.cpuid.nent = cpuid_i;
 
     if (((env->cpuid_version >> 8)&0xF) >= 6
-        && (env->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA)
+        && (env->features[FEAT_1_EDX] & (CPUID_MCE|CPUID_MCA)) ==
+            (CPUID_MCE|CPUID_MCA)
         && kvm_check_extension(env->kvm_state, KVM_CAP_MCE) > 0) {
         uint64_t mcg_cap;
         int banks;
diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c
index a020379..546b8b9 100644
--- a/target-i386/misc_helper.c
+++ b/target-i386/misc_helper.c
@@ -291,22 +291,22 @@  void helper_wrmsr(CPUX86State *env)
             uint64_t update_mask;
 
             update_mask = 0;
-            if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL) {
+            if (env->features[FEAT_80000001_EDX] & CPUID_EXT2_SYSCALL) {
                 update_mask |= MSR_EFER_SCE;
             }
-            if (env->cpuid_ext2_features & CPUID_EXT2_LM) {
+            if (env->features[FEAT_80000001_EDX] & CPUID_EXT2_LM) {
                 update_mask |= MSR_EFER_LME;
             }
-            if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR) {
+            if (env->features[FEAT_80000001_EDX] & CPUID_EXT2_FFXSR) {
                 update_mask |= MSR_EFER_FFXSR;
             }
-            if (env->cpuid_ext2_features & CPUID_EXT2_NX) {
+            if (env->features[FEAT_80000001_EDX] & CPUID_EXT2_NX) {
                 update_mask |= MSR_EFER_NXE;
             }
-            if (env->cpuid_ext3_features & CPUID_EXT3_SVM) {
+            if (env->features[FEAT_80000001_ECX] & CPUID_EXT3_SVM) {
                 update_mask |= MSR_EFER_SVME;
             }
-            if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR) {
+            if (env->features[FEAT_80000001_EDX] & CPUID_EXT2_FFXSR) {
                 update_mask |= MSR_EFER_FFXSR;
             }
             cpu_load_efer(env, (env->efer & ~update_mask) |
@@ -513,7 +513,7 @@  void helper_rdmsr(CPUX86State *env)
         val = env->mtrr_deftype;
         break;
     case MSR_MTRRcap:
-        if (env->cpuid_features & CPUID_MTRR) {
+        if (env->features[FEAT_1_EDX] & CPUID_MTRR) {
             val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT |
                 MSR_MTRRcap_WC_SUPPORTED;
         } else {
diff --git a/target-i386/translate.c b/target-i386/translate.c
index f394ea6..8ff4af9 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -7926,11 +7926,11 @@  static inline void gen_intermediate_code_internal(CPUX86State *env,
     if (flags & HF_SOFTMMU_MASK) {
         dc->mem_index = (cpu_mmu_index(env) + 1) << 2;
     }
-    dc->cpuid_features = env->cpuid_features;
-    dc->cpuid_ext_features = env->cpuid_ext_features;
-    dc->cpuid_ext2_features = env->cpuid_ext2_features;
-    dc->cpuid_ext3_features = env->cpuid_ext3_features;
-    dc->cpuid_7_0_ebx_features = env->cpuid_7_0_ebx_features;
+    dc->cpuid_features = env->features[FEAT_1_EDX];
+    dc->cpuid_ext_features = env->features[FEAT_1_ECX];
+    dc->cpuid_ext2_features = env->features[FEAT_80000001_EDX];
+    dc->cpuid_ext3_features = env->features[FEAT_80000001_ECX];
+    dc->cpuid_7_0_ebx_features = env->features[FEAT_7_0_EBX];
 #ifdef TARGET_X86_64
     dc->lma = (flags >> HF_LMA_SHIFT) & 1;
     dc->code64 = (flags >> HF_CS64_SHIFT) & 1;