Message ID | 1467990099-27853-6-git-send-email-dgilbert@redhat.com |
---|---|
State | New |
Headers | show |
On 08/07/2016 17:01, Dr. David Alan Gilbert (git) wrote: > + uint32_t host_phys_bits = x86_host_phys_bits(); > + static bool warned; > + > + if (cpu->host_phys_bits) { > + /* The user asked for us to use the host physical bits */ > + cpu->phys_bits = host_phys_bits; > + } > + > + /* Print a warning if the user set it to a value that's not the > + * host value. > + */ > + if (cpu->phys_bits != host_phys_bits && cpu->phys_bits != 0 && > + !warned) { > + error_report("Warning: Host physical bits (%u)" > + " does not match phys-bits property (%u)", > + host_phys_bits, cpu->phys_bits); > + warned = true; > + } > + > + if (cpu->phys_bits && > + (cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || > + cpu->phys_bits < 32)) { > error_setg(errp, "phys-bits should be between 32 and %u " > " (but is %u)", > TARGET_PHYS_ADDR_SPACE_BITS, cpu->phys_bits); Michael Tsirkin suggested a way to support guest-phys-bits < host-phys-bits in KVM. I plan to implement it soonish. In the meanwhile I guess this patch is fine, we can refine it later. Paolo
On Fri, Jul 08, 2016 at 04:01:39PM +0100, Dr. David Alan Gilbert (git) wrote: > From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> > > Add the host-phys-bits boolean property, if true, take phys-bits > from the hosts physical bits value, overriding either the default > or the user specified value. > > We can also use the value we read from the host to check the users > explicitly set value and warn them if it doesn't match. > > Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> > --- [...] > @@ -2952,28 +2977,57 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) > & CPUID_EXT2_AMD_ALIASES); > } > > + /* For 64bit systems think about the number of physical bits to present. > + * ideally this should be the same as the host; anything other than matching > + * the host can cause incorrect guest behaviour. > + * QEMU used to pick the magic value of 40 bits that corresponds to > + * consumer AMD devices but nothing else. > + */ > + if (cpu->host_phys_bits && !kvm_enabled()) { > + error_setg(errp, "phys-bits can not be read from the host in" > + " TCG mode"); > + return; > + } > + > if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { > - /* 0 is a special meaning 'use the old default', which matches > - * the value used by TCG (40). > - */ > - if (cpu->phys_bits == 0) { > - cpu->phys_bits = TCG_PHYS_ADDR_BITS; > - } > if (kvm_enabled()) { > - if (cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || > - cpu->phys_bits < 32) { > + uint32_t host_phys_bits = x86_host_phys_bits(); > + static bool warned; > + > + if (cpu->host_phys_bits) { > + /* The user asked for us to use the host physical bits */ > + cpu->phys_bits = host_phys_bits; > + } > + > + /* Print a warning if the user set it to a value that's not the > + * host value. > + */ > + if (cpu->phys_bits != host_phys_bits && cpu->phys_bits != 0 && > + !warned) { > + error_report("Warning: Host physical bits (%u)" > + " does not match phys-bits property (%u)", > + host_phys_bits, cpu->phys_bits); > + warned = true; > + } > + > + if (cpu->phys_bits && > + (cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || > + cpu->phys_bits < 32)) { > error_setg(errp, "phys-bits should be between 32 and %u " > " (but is %u)", > TARGET_PHYS_ADDR_SPACE_BITS, cpu->phys_bits); > return; > } > } else { > - if (cpu->phys_bits != TCG_PHYS_ADDR_BITS) { > + if (cpu->phys_bits && cpu->phys_bits != TCG_PHYS_ADDR_BITS) { > error_setg(errp, "TCG only supports phys-bits=%u", > TCG_PHYS_ADDR_BITS); > return; > } > } > + if (cpu->phys_bits == 0 && !cpu->host_phys_bits) { Why the !cpu->host_phys_bits check? It seems to be impossible to have (cpu->host_phys_bits == true && cpu->phys_bits == 0) here. > + cpu->phys_bits = TCG_PHYS_ADDR_BITS; > + } > } else { > /* For 32 bit systems don't use the user set value, but keep > * phys_bits consistent with what we tell the guest. Shouldn't we return error if host-phys-bits is set in 32-bit mode? > @@ -3290,6 +3344,7 @@ static Property x86_cpu_properties[] = { > DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false), > DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true), > 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), > diff --git a/target-i386/cpu.h b/target-i386/cpu.h > index 9d79146..3c4e64a 100644 > --- a/target-i386/cpu.h > +++ b/target-i386/cpu.h > @@ -1184,6 +1184,9 @@ struct X86CPU { > /* if true fill the top bits of the MTRR_PHYSMASKn variable range */ > bool fill_mtrr_mask; > > + /* if true override the phys_bits value with a value read from the host */ > + bool host_phys_bits; > + > /* Number of physical address bits supported */ > uint32_t phys_bits; > > -- > 2.7.4 >
* Eduardo Habkost (ehabkost@redhat.com) wrote: > On Fri, Jul 08, 2016 at 04:01:39PM +0100, Dr. David Alan Gilbert (git) wrote: > > From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> > > > > Add the host-phys-bits boolean property, if true, take phys-bits > > from the hosts physical bits value, overriding either the default > > or the user specified value. > > > > We can also use the value we read from the host to check the users > > explicitly set value and warn them if it doesn't match. > > > > Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> > > --- > [...] > > @@ -2952,28 +2977,57 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) > > & CPUID_EXT2_AMD_ALIASES); > > } > > > > + /* For 64bit systems think about the number of physical bits to present. > > + * ideally this should be the same as the host; anything other than matching > > + * the host can cause incorrect guest behaviour. > > + * QEMU used to pick the magic value of 40 bits that corresponds to > > + * consumer AMD devices but nothing else. > > + */ > > + if (cpu->host_phys_bits && !kvm_enabled()) { > > + error_setg(errp, "phys-bits can not be read from the host in" > > + " TCG mode"); > > + return; > > + } > > + > > if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { > > - /* 0 is a special meaning 'use the old default', which matches > > - * the value used by TCG (40). > > - */ > > - if (cpu->phys_bits == 0) { > > - cpu->phys_bits = TCG_PHYS_ADDR_BITS; > > - } > > if (kvm_enabled()) { > > - if (cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || > > - cpu->phys_bits < 32) { > > + uint32_t host_phys_bits = x86_host_phys_bits(); > > + static bool warned; > > + > > + if (cpu->host_phys_bits) { > > + /* The user asked for us to use the host physical bits */ > > + cpu->phys_bits = host_phys_bits; > > + } > > + > > + /* Print a warning if the user set it to a value that's not the > > + * host value. > > + */ > > + if (cpu->phys_bits != host_phys_bits && cpu->phys_bits != 0 && > > + !warned) { > > + error_report("Warning: Host physical bits (%u)" > > + " does not match phys-bits property (%u)", > > + host_phys_bits, cpu->phys_bits); > > + warned = true; > > + } > > + > > + if (cpu->phys_bits && > > + (cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || > > + cpu->phys_bits < 32)) { > > error_setg(errp, "phys-bits should be between 32 and %u " > > " (but is %u)", > > TARGET_PHYS_ADDR_SPACE_BITS, cpu->phys_bits); > > return; > > } > > } else { > > - if (cpu->phys_bits != TCG_PHYS_ADDR_BITS) { > > + if (cpu->phys_bits && cpu->phys_bits != TCG_PHYS_ADDR_BITS) { > > error_setg(errp, "TCG only supports phys-bits=%u", > > TCG_PHYS_ADDR_BITS); > > return; > > } > > } > > + if (cpu->phys_bits == 0 && !cpu->host_phys_bits) { > > Why the !cpu->host_phys_bits check? It seems to be impossible to > have (cpu->host_phys_bits == true && cpu->phys_bits == 0) here. Right; I think I added that before I added the TCG check at the top. > > + cpu->phys_bits = TCG_PHYS_ADDR_BITS; > > + } > > } else { > > /* For 32 bit systems don't use the user set value, but keep > > * phys_bits consistent with what we tell the guest. > > Shouldn't we return error if host-phys-bits is set in 32-bit > mode? Yes; easy to add. Do you want me to repost just this patch or the whole set? Dave > > @@ -3290,6 +3344,7 @@ static Property x86_cpu_properties[] = { > > DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false), > > DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true), > > 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), > > diff --git a/target-i386/cpu.h b/target-i386/cpu.h > > index 9d79146..3c4e64a 100644 > > --- a/target-i386/cpu.h > > +++ b/target-i386/cpu.h > > @@ -1184,6 +1184,9 @@ struct X86CPU { > > /* if true fill the top bits of the MTRR_PHYSMASKn variable range */ > > bool fill_mtrr_mask; > > > > + /* if true override the phys_bits value with a value read from the host */ > > + bool host_phys_bits; > > + > > /* Number of physical address bits supported */ > > uint32_t phys_bits; > > > > -- > > 2.7.4 > > > > -- > Eduardo -- Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
On Mon, Jul 11, 2016 at 01:29:56PM +0100, Dr. David Alan Gilbert wrote: [...] > > Do you want me to repost just this patch or the whole set? You can use my x86-next branch as base (it already includes the other patches), so you can repost just this patch. git://github.com/ehabkost/qemu.git x86-next
* Eduardo Habkost (ehabkost@redhat.com) wrote: > On Fri, Jul 08, 2016 at 04:01:39PM +0100, Dr. David Alan Gilbert (git) wrote: > > From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> > > > > Add the host-phys-bits boolean property, if true, take phys-bits > > from the hosts physical bits value, overriding either the default > > or the user specified value. > > > > We can also use the value we read from the host to check the users > > explicitly set value and warn them if it doesn't match. > > > > Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> > > --- > [...] > > @@ -2952,28 +2977,57 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) > > & CPUID_EXT2_AMD_ALIASES); > > } > > > > + /* For 64bit systems think about the number of physical bits to present. > > + * ideally this should be the same as the host; anything other than matching > > + * the host can cause incorrect guest behaviour. > > + * QEMU used to pick the magic value of 40 bits that corresponds to > > + * consumer AMD devices but nothing else. > > + */ > > + if (cpu->host_phys_bits && !kvm_enabled()) { > > + error_setg(errp, "phys-bits can not be read from the host in" > > + " TCG mode"); > > + return; > > + } > > + > > if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { > > - /* 0 is a special meaning 'use the old default', which matches > > - * the value used by TCG (40). > > - */ > > - if (cpu->phys_bits == 0) { > > - cpu->phys_bits = TCG_PHYS_ADDR_BITS; > > - } > > if (kvm_enabled()) { > > - if (cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || > > - cpu->phys_bits < 32) { > > + uint32_t host_phys_bits = x86_host_phys_bits(); > > + static bool warned; > > + > > + if (cpu->host_phys_bits) { > > + /* The user asked for us to use the host physical bits */ > > + cpu->phys_bits = host_phys_bits; > > + } > > + > > + /* Print a warning if the user set it to a value that's not the > > + * host value. > > + */ > > + if (cpu->phys_bits != host_phys_bits && cpu->phys_bits != 0 && > > + !warned) { > > + error_report("Warning: Host physical bits (%u)" > > + " does not match phys-bits property (%u)", > > + host_phys_bits, cpu->phys_bits); > > + warned = true; > > + } > > + > > + if (cpu->phys_bits && > > + (cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || > > + cpu->phys_bits < 32)) { > > error_setg(errp, "phys-bits should be between 32 and %u " > > " (but is %u)", > > TARGET_PHYS_ADDR_SPACE_BITS, cpu->phys_bits); > > return; > > } > > } else { > > - if (cpu->phys_bits != TCG_PHYS_ADDR_BITS) { > > + if (cpu->phys_bits && cpu->phys_bits != TCG_PHYS_ADDR_BITS) { > > error_setg(errp, "TCG only supports phys-bits=%u", > > TCG_PHYS_ADDR_BITS); > > return; > > } > > } > > + if (cpu->phys_bits == 0 && !cpu->host_phys_bits) { > > Why the !cpu->host_phys_bits check? It seems to be impossible to > have (cpu->host_phys_bits == true && cpu->phys_bits == 0) here. > > > + cpu->phys_bits = TCG_PHYS_ADDR_BITS; > > + } > > } else { > > /* For 32 bit systems don't use the user set value, but keep > > * phys_bits consistent with what we tell the guest. > > Shouldn't we return error if host-phys-bits is set in 32-bit > mode? I've just realised there's a reason that erroring in this case is a problem. Imagine a future (or downstream) machine type that made host-phys-bits the default; how would it run with a 32bit CPU? Dave > > @@ -3290,6 +3344,7 @@ static Property x86_cpu_properties[] = { > > DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false), > > DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true), > > 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), > > diff --git a/target-i386/cpu.h b/target-i386/cpu.h > > index 9d79146..3c4e64a 100644 > > --- a/target-i386/cpu.h > > +++ b/target-i386/cpu.h > > @@ -1184,6 +1184,9 @@ struct X86CPU { > > /* if true fill the top bits of the MTRR_PHYSMASKn variable range */ > > bool fill_mtrr_mask; > > > > + /* if true override the phys_bits value with a value read from the host */ > > + bool host_phys_bits; > > + > > /* Number of physical address bits supported */ > > uint32_t phys_bits; > > > > -- > > 2.7.4 > > > > -- > Eduardo -- Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
On Mon, Jul 11, 2016 at 04:39:22PM +0100, Dr. David Alan Gilbert wrote: > * Eduardo Habkost (ehabkost@redhat.com) wrote: [...] > > > + cpu->phys_bits = TCG_PHYS_ADDR_BITS; > > > + } > > > } else { > > > /* For 32 bit systems don't use the user set value, but keep > > > * phys_bits consistent with what we tell the guest. > > > > Shouldn't we return error if host-phys-bits is set in 32-bit > > mode? > > I've just realised there's a reason that erroring in this case is a problem. > Imagine a future (or downstream) machine type that made host-phys-bits the default; > how would it run with a 32bit CPU? Oh, that's right. Ignoring it when explicitly set isn't intuitive, but we need to be able to ignore it when set by a machine compat_props (or if it's enabled by default). And creating two separate properties sounds like overkill... I'm reluctant, but I think it's OK to ignore it if LM is not set. But we need to make sure it's documented somewhere.
* Eduardo Habkost (ehabkost@redhat.com) wrote: > On Mon, Jul 11, 2016 at 04:39:22PM +0100, Dr. David Alan Gilbert wrote: > > * Eduardo Habkost (ehabkost@redhat.com) wrote: > [...] > > > > + cpu->phys_bits = TCG_PHYS_ADDR_BITS; > > > > + } > > > > } else { > > > > /* For 32 bit systems don't use the user set value, but keep > > > > * phys_bits consistent with what we tell the guest. > > > > > > Shouldn't we return error if host-phys-bits is set in 32-bit > > > mode? > > > > I've just realised there's a reason that erroring in this case is a problem. > > Imagine a future (or downstream) machine type that made host-phys-bits the default; > > how would it run with a 32bit CPU? > > Oh, that's right. Ignoring it when explicitly set isn't > intuitive, but we need to be able to ignore it when set by a > machine compat_props (or if it's enabled by default). And > creating two separate properties sounds like overkill... > I'm reluctant, but I think it's OK to ignore it if LM is not set. > But we need to make sure it's documented somewhere. OK, I'll add a comment and a note in the commit message. Dave > > -- > Eduardo -- Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 641c38b..72ca7fb 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2885,6 +2885,31 @@ static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) } #endif +/* Note: Only safe for use on x86(-64) hosts */ +static uint32_t x86_host_phys_bits(void) +{ + uint32_t eax; + uint32_t host_phys_bits; + + host_cpuid(0x80000000, 0, &eax, NULL, NULL, NULL); + if (eax >= 0x80000008) { + host_cpuid(0x80000008, 0, &eax, NULL, NULL, NULL); + /* Note: According to AMD doc 25481 rev 2.34 they have a field + * at 23:16 that can specify a maximum physical address bits for + * the guest that can override this value; but I've not seen + * anything with that set. + */ + host_phys_bits = eax & 0xff; + } else { + /* It's an odd 64 bit machine that doesn't have the leaf for + * physical address bits; fall back to 36 that's most older + * Intel. + */ + host_phys_bits = 36; + } + + return host_phys_bits; +} #define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \ (env)->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && \ @@ -2952,28 +2977,57 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) & CPUID_EXT2_AMD_ALIASES); } + /* For 64bit systems think about the number of physical bits to present. + * ideally this should be the same as the host; anything other than matching + * the host can cause incorrect guest behaviour. + * QEMU used to pick the magic value of 40 bits that corresponds to + * consumer AMD devices but nothing else. + */ + if (cpu->host_phys_bits && !kvm_enabled()) { + error_setg(errp, "phys-bits can not be read from the host in" + " TCG mode"); + return; + } + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { - /* 0 is a special meaning 'use the old default', which matches - * the value used by TCG (40). - */ - if (cpu->phys_bits == 0) { - cpu->phys_bits = TCG_PHYS_ADDR_BITS; - } if (kvm_enabled()) { - if (cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || - cpu->phys_bits < 32) { + uint32_t host_phys_bits = x86_host_phys_bits(); + static bool warned; + + if (cpu->host_phys_bits) { + /* The user asked for us to use the host physical bits */ + cpu->phys_bits = host_phys_bits; + } + + /* Print a warning if the user set it to a value that's not the + * host value. + */ + if (cpu->phys_bits != host_phys_bits && cpu->phys_bits != 0 && + !warned) { + error_report("Warning: Host physical bits (%u)" + " does not match phys-bits property (%u)", + host_phys_bits, cpu->phys_bits); + warned = true; + } + + if (cpu->phys_bits && + (cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || + cpu->phys_bits < 32)) { error_setg(errp, "phys-bits should be between 32 and %u " " (but is %u)", TARGET_PHYS_ADDR_SPACE_BITS, cpu->phys_bits); return; } } else { - if (cpu->phys_bits != TCG_PHYS_ADDR_BITS) { + if (cpu->phys_bits && cpu->phys_bits != TCG_PHYS_ADDR_BITS) { error_setg(errp, "TCG only supports phys-bits=%u", TCG_PHYS_ADDR_BITS); return; } } + if (cpu->phys_bits == 0 && !cpu->host_phys_bits) { + cpu->phys_bits = TCG_PHYS_ADDR_BITS; + } } else { /* For 32 bit systems don't use the user set value, but keep * phys_bits consistent with what we tell the guest. @@ -3290,6 +3344,7 @@ static Property x86_cpu_properties[] = { DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false), DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true), 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), diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 9d79146..3c4e64a 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1184,6 +1184,9 @@ struct X86CPU { /* if true fill the top bits of the MTRR_PHYSMASKn variable range */ bool fill_mtrr_mask; + /* if true override the phys_bits value with a value read from the host */ + bool host_phys_bits; + /* Number of physical address bits supported */ uint32_t phys_bits;