@ -1643,9 +1643,12 @@ static void host_x86_cpu_initfn(Object *obj)
/* If KVM is disabled, x86_cpu_realizefn() will report an error later */
if ( kvm_enabled ( ) ) {
env - > cpuid_level = kvm_arch_get_supported_cpuid ( s , 0x0 , 0 , R_EAX ) ;
env - > cpuid_xlevel = kvm_arch_get_supported_cpuid ( s , 0x80000000 , 0 , R_EAX ) ;
env - > cpuid_xlevel2 = kvm_arch_get_supported_cpuid ( s , 0xC0000000 , 0 , R_EAX ) ;
env - > cpuid_min_level =
kvm_arch_get_supported_cpuid ( s , 0x0 , 0 , R_EAX ) ;
env - > cpuid_min_xlevel =
kvm_arch_get_supported_cpuid ( s , 0x80000000 , 0 , R_EAX ) ;
env - > cpuid_min_xlevel2 =
kvm_arch_get_supported_cpuid ( s , 0xC0000000 , 0 , R_EAX ) ;
if ( lmce_supported ( ) ) {
object_property_set_bool ( OBJECT ( cpu ) , true , " lmce " , & error_abort ) ;
@ -2208,11 +2211,13 @@ static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp)
char host_vendor [ CPUID_VENDOR_SZ + 1 ] ;
FeatureWord w ;
object_property_set_int ( OBJECT ( cpu ) , def - > level , " level " , errp ) ;
/* CPU models only set _minimum_ values for level/xlevel: */
object_property_set_int ( OBJECT ( cpu ) , def - > level , " min-level " , errp ) ;
object_property_set_int ( OBJECT ( cpu ) , def - > xlevel , " min-xlevel " , 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 ) ;
object_property_set_int ( OBJECT ( cpu ) , def - > xlevel , " xlevel " , errp ) ;
object_property_set_str ( OBJECT ( cpu ) , def - > model_id , " model-id " , errp ) ;
for ( w = 0 ; w < FEATURE_WORDS ; w + + ) {
env - > features [ w ] = def - > features [ w ] ;
@ -2951,6 +2956,38 @@ static uint32_t x86_host_phys_bits(void)
return host_phys_bits ;
}
static void x86_cpu_adjust_level ( X86CPU * cpu , uint32_t * min , uint32_t value )
{
if ( * min < value ) {
* min = value ;
}
}
/* Increase cpuid_min_{level,xlevel,xlevel2} automatically, if appropriate */
static void x86_cpu_adjust_feat_level ( X86CPU * cpu , FeatureWord w )
{
CPUX86State * env = & cpu - > env ;
FeatureWordInfo * fi = & feature_word_info [ w ] ;
uint32_t eax = fi - > cpuid_eax ;
uint32_t region = eax & 0xF0000000 ;
if ( ! env - > features [ w ] ) {
return ;
}
switch ( region ) {
case 0x00000000 :
x86_cpu_adjust_level ( cpu , & env - > cpuid_min_level , eax ) ;
break ;
case 0x80000000 :
x86_cpu_adjust_level ( cpu , & env - > cpuid_min_xlevel , eax ) ;
break ;
case 0xC0000000 :
x86_cpu_adjust_level ( cpu , & env - > cpuid_min_xlevel2 , eax ) ;
break ;
}
}
# define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \
( env ) - > cpuid_vendor2 = = CPUID_VENDOR_INTEL_2 & & \
( env ) - > cpuid_vendor3 = = CPUID_VENDOR_INTEL_3 )
@ -2996,8 +3033,31 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
cpu - > env . features [ w ] & = ~ minus_features [ w ] ;
}
if ( env - > features [ FEAT_7_0_EBX ] & & env - > cpuid_level < 7 ) {
env - > cpuid_level = 7 ;
/* CPUID[EAX=7,ECX=0].EBX always increased level automatically: */
x86_cpu_adjust_feat_level ( cpu , FEAT_7_0_EBX ) ;
if ( cpu - > full_cpuid_auto_level ) {
x86_cpu_adjust_feat_level ( cpu , FEAT_1_EDX ) ;
x86_cpu_adjust_feat_level ( cpu , FEAT_1_ECX ) ;
x86_cpu_adjust_feat_level ( cpu , FEAT_6_EAX ) ;
x86_cpu_adjust_feat_level ( cpu , FEAT_7_0_ECX ) ;
x86_cpu_adjust_feat_level ( cpu , FEAT_8000_0001_EDX ) ;
x86_cpu_adjust_feat_level ( cpu , FEAT_8000_0001_ECX ) ;
x86_cpu_adjust_feat_level ( cpu , FEAT_8000_0007_EDX ) ;
x86_cpu_adjust_feat_level ( cpu , FEAT_C000_0001_EDX ) ;
x86_cpu_adjust_feat_level ( cpu , FEAT_SVM ) ;
x86_cpu_adjust_feat_level ( cpu , FEAT_XSAVE ) ;
}
/* Set cpuid_*level* based on cpuid_min_*level, if not explicitly set */
if ( env - > cpuid_level = = UINT32_MAX ) {
env - > cpuid_level = env - > cpuid_min_level ;
}
if ( env - > cpuid_xlevel = = UINT32_MAX ) {
env - > cpuid_xlevel = env - > cpuid_min_xlevel ;
}
if ( env - > cpuid_xlevel2 = = UINT32_MAX ) {
env - > cpuid_xlevel2 = env - > cpuid_min_xlevel2 ;
}
if ( x86_cpu_filter_features ( cpu ) & & cpu - > enforce_cpuid ) {
@ -3403,9 +3463,13 @@ static Property x86_cpu_properties[] = {
DEFINE_PROP_UINT32 ( " phys-bits " , X86CPU , phys_bits , 0 ) ,
DEFINE_PROP_BOOL ( " host-phys-bits " , X86CPU , host_phys_bits , false ) ,
DEFINE_PROP_BOOL ( " fill-mtrr-mask " , X86CPU , fill_mtrr_mask , true ) ,
DEFINE_PROP_UINT32 ( " level " , X86CPU , env . cpuid_level , 0 ) ,
DEFINE_PROP_UINT32 ( " xlevel " , X86CPU , env . cpuid_xlevel , 0 ) ,
DEFINE_PROP_UINT32 ( " xlevel2 " , X86CPU , env . cpuid_xlevel2 , 0 ) ,
DEFINE_PROP_UINT32 ( " level " , X86CPU , env . cpuid_level , UINT32_MAX ) ,
DEFINE_PROP_UINT32 ( " xlevel " , X86CPU , env . cpuid_xlevel , UINT32_MAX ) ,
DEFINE_PROP_UINT32 ( " xlevel2 " , X86CPU , env . cpuid_xlevel2 , UINT32_MAX ) ,
DEFINE_PROP_UINT32 ( " min-level " , X86CPU , env . cpuid_min_level , 0 ) ,
DEFINE_PROP_UINT32 ( " min-xlevel " , X86CPU , env . cpuid_min_xlevel , 0 ) ,
DEFINE_PROP_UINT32 ( " min-xlevel2 " , X86CPU , env . cpuid_min_xlevel2 , 0 ) ,
DEFINE_PROP_BOOL ( " full-cpuid-auto-level " , X86CPU , full_cpuid_auto_level , true ) ,
DEFINE_PROP_STRING ( " hv-vendor-id " , X86CPU , hyperv_vendor_id ) ,
DEFINE_PROP_BOOL ( " cpuid-0xb " , X86CPU , enable_cpuid_0xb , true ) ,
DEFINE_PROP_BOOL ( " lmce " , X86CPU , enable_lmce , false ) ,