From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Jan Beulich" Subject: [PATCH v5] x86/HVM: make hvm_efer_valid() honor guest features Date: Thu, 22 Jan 2015 13:56:11 +0000 Message-ID: <54C10F8B0200007800058282@mail.emea.novell.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=__Part97A20F6B.1__=" Return-path: Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1YEIF4-00048a-FR for xen-devel@lists.xenproject.org; Thu, 22 Jan 2015 13:56:14 +0000 List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: xen-devel Cc: Andrew Cooper , Keir Fraser List-Id: xen-devel@lists.xenproject.org This is a MIME message. If you are reading this text, you may want to consider changing to a mail reader or gateway that understands how to properly handle MIME multipart messages. --=__Part97A20F6B.1__= Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Following the earlier similar change validating CR4 modifications. Signed-off-by: Jan Beulich --- v5: relax SCE check v4: Drop hvm_cpuid() adjustment and use hvm_funcs.cpuid_intercept() instead for leaf 0x80000001. v3: Drop cr0_pg > 0 test for LMA/LME check: This would need to be >=3D 0, which is then redundant with the check for EFER_LMA (getting cleared when cr0_pg gets passed a negative value). Force SYSCALL feature flag on when guest is in 64-bit mode. v2: consider CR0.PG during restore when checking EFER.LMA --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -1672,20 +1672,64 @@ static int hvm_save_cpu_ctxt(struct doma return 0; } =20 -static bool_t hvm_efer_valid(struct domain *d, - uint64_t value, uint64_t efer_validbits) +static bool_t hvm_efer_valid(const struct vcpu *v, uint64_t value, + signed int cr0_pg) { - if ( nestedhvm_enabled(d) && cpu_has_svm ) - efer_validbits |=3D EFER_SVME; + unsigned int ext1_ecx =3D 0, ext1_edx =3D 0; =20 - return !((value & ~efer_validbits) || - ((sizeof(long) !=3D 8) && (value & EFER_LME)) || - (!cpu_has_svm && (value & EFER_SVME)) || - (!cpu_has_nx && (value & EFER_NX)) || - (!cpu_has_syscall && (value & EFER_SCE)) || - (!cpu_has_lmsl && (value & EFER_LMSLE)) || - (!cpu_has_ffxsr && (value & EFER_FFXSE)) || - ((value & (EFER_LME|EFER_LMA)) =3D=3D EFER_LMA)); + if ( cr0_pg < 0 && !is_hardware_domain(v->domain) ) + { + unsigned int level; + + ASSERT(v =3D=3D current); + hvm_cpuid(0x80000000, &level, NULL, NULL, NULL); + if ( level >=3D 0x80000001 ) + { + unsigned int dummy; + + level =3D 0x80000001; + hvm_funcs.cpuid_intercept(&level, &dummy, &ext1_ecx, = &ext1_edx); + } + } + else + { + ext1_edx =3D boot_cpu_data.x86_capability[X86_FEATURE_LM / 32]; + ext1_ecx =3D boot_cpu_data.x86_capability[X86_FEATURE_SVM / 32]; + } + + /* + * Guests may want to set EFER.SCE and EFER.LME at the same time, so = we + * can't make the check depend on only X86_FEATURE_SYSCALL (which on = VMX + * will be clear without the guest having entered 64-bit mode). + */ + if ( (value & EFER_SCE) && + !(ext1_edx & cpufeat_mask(X86_FEATURE_SYSCALL)) && + (cr0_pg >=3D 0 || !(value & EFER_LME)) ) + return 0; + + if ( (value & (EFER_LME | EFER_LMA)) && + !(ext1_edx & cpufeat_mask(X86_FEATURE_LM)) ) + return 0; + + if ( (value & EFER_LMA) && (!(value & EFER_LME) || !cr0_pg) ) + return 0; + + if ( (value & EFER_NX) && !(ext1_edx & cpufeat_mask(X86_FEATURE_NX)) = ) + return 0; + + if ( (value & EFER_SVME) && + (!(ext1_ecx & cpufeat_mask(X86_FEATURE_SVM)) || + !nestedhvm_enabled(v->domain)) ) + return 0; + + if ( (value & EFER_LMSLE) && !cpu_has_lmsl ) + return 0; + + if ( (value & EFER_FFXSE) && + !(ext1_edx & cpufeat_mask(X86_FEATURE_FFXSR)) ) + return 0; + + return 1; } =20 /* These reserved bits in lower 32 remain 0 after any load of CR0 */ @@ -1763,7 +1807,6 @@ static int hvm_load_cpu_ctxt(struct doma struct vcpu *v; struct hvm_hw_cpu ctxt; struct segment_register seg; - uint64_t efer_validbits; =20 /* Which vcpu is this? */ vcpuid =3D hvm_load_instance(h); @@ -1794,9 +1837,7 @@ static int hvm_load_cpu_ctxt(struct doma return -EINVAL; } =20 - efer_validbits =3D EFER_FFXSE | EFER_LMSLE | EFER_LME | EFER_LMA - | EFER_NX | EFER_SCE; - if ( !hvm_efer_valid(d, ctxt.msr_efer, efer_validbits) ) + if ( !hvm_efer_valid(v, ctxt.msr_efer, MASK_EXTR(ctxt.cr0, X86_CR0_PG)= ) ) { printk(XENLOG_G_ERR "HVM%d restore: bad EFER %#" PRIx64 "\n", d->domain_id, ctxt.msr_efer); @@ -2936,12 +2977,10 @@ err: int hvm_set_efer(uint64_t value) { struct vcpu *v =3D current; - uint64_t efer_validbits; =20 value &=3D ~EFER_LMA; =20 - efer_validbits =3D EFER_FFXSE | EFER_LMSLE | EFER_LME | EFER_NX | = EFER_SCE; - if ( !hvm_efer_valid(v->domain, value, efer_validbits) ) + if ( !hvm_efer_valid(v, value, -1) ) { gdprintk(XENLOG_WARNING, "Trying to set reserved bit in " "EFER: %#"PRIx64"\n", value); --=__Part97A20F6B.1__= Content-Type: text/plain; name="x86-HVM-refine-EFER-reserved-bits-checks.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="x86-HVM-refine-EFER-reserved-bits-checks.patch" x86/HVM: make hvm_efer_valid() honor guest features=0A=0AFollowing the = earlier similar change validating CR4 modifications.=0A=0ASigned-off-by: = Jan Beulich =0A---=0Av5: relax SCE check=0Av4: Drop = hvm_cpuid() adjustment and use hvm_funcs.cpuid_intercept()=0A instead = for leaf 0x80000001.=0Av3: Drop cr0_pg > 0 test for LMA/LME check: This = would need to be >=3D 0,=0A which is then redundant with the check for = EFER_LMA (getting=0A cleared when cr0_pg gets passed a negative value). = Force SYSCALL=0A feature flag on when guest is in 64-bit mode.=0Av2: = consider CR0.PG during restore when checking EFER.LMA=0A=0A--- a/xen/arch/x= 86/hvm/hvm.c=0A+++ b/xen/arch/x86/hvm/hvm.c=0A@@ -1672,20 +1672,64 @@ = static int hvm_save_cpu_ctxt(struct doma=0A return 0;=0A }=0A = =0A-static bool_t hvm_efer_valid(struct domain *d,=0A- = uint64_t value, uint64_t efer_validbits)=0A+static bool_t = hvm_efer_valid(const struct vcpu *v, uint64_t value,=0A+ = signed int cr0_pg)=0A {=0A- if ( nestedhvm_enabled(d) && = cpu_has_svm )=0A- efer_validbits |=3D EFER_SVME;=0A+ unsigned = int ext1_ecx =3D 0, ext1_edx =3D 0;=0A =0A- return !((value & ~efer_vali= dbits) ||=0A- ((sizeof(long) !=3D 8) && (value & EFER_LME)) = ||=0A- (!cpu_has_svm && (value & EFER_SVME)) ||=0A- = (!cpu_has_nx && (value & EFER_NX)) ||=0A- (!cpu_has_syscall = && (value & EFER_SCE)) ||=0A- (!cpu_has_lmsl && (value & = EFER_LMSLE)) ||=0A- (!cpu_has_ffxsr && (value & EFER_FFXSE)) = ||=0A- ((value & (EFER_LME|EFER_LMA)) =3D=3D EFER_LMA));=0A+ = if ( cr0_pg < 0 && !is_hardware_domain(v->domain) )=0A+ {=0A+ = unsigned int level;=0A+=0A+ ASSERT(v =3D=3D current);=0A+ = hvm_cpuid(0x80000000, &level, NULL, NULL, NULL);=0A+ if ( level = >=3D 0x80000001 )=0A+ {=0A+ unsigned int dummy;=0A+=0A+ = level =3D 0x80000001;=0A+ hvm_funcs.cpuid_intercept(&l= evel, &dummy, &ext1_ecx, &ext1_edx);=0A+ }=0A+ }=0A+ else=0A+ = {=0A+ ext1_edx =3D boot_cpu_data.x86_capability[X86_FEATURE_LM / = 32];=0A+ ext1_ecx =3D boot_cpu_data.x86_capability[X86_FEATURE_SVM = / 32];=0A+ }=0A+=0A+ /*=0A+ * Guests may want to set EFER.SCE = and EFER.LME at the same time, so we=0A+ * can't make the check depend = on only X86_FEATURE_SYSCALL (which on VMX=0A+ * will be clear without = the guest having entered 64-bit mode).=0A+ */=0A+ if ( (value & = EFER_SCE) &&=0A+ !(ext1_edx & cpufeat_mask(X86_FEATURE_SYSCALL)) = &&=0A+ (cr0_pg >=3D 0 || !(value & EFER_LME)) )=0A+ return = 0;=0A+=0A+ if ( (value & (EFER_LME | EFER_LMA)) &&=0A+ = !(ext1_edx & cpufeat_mask(X86_FEATURE_LM)) )=0A+ return 0;=0A+=0A+ = if ( (value & EFER_LMA) && (!(value & EFER_LME) || !cr0_pg) )=0A+ = return 0;=0A+=0A+ if ( (value & EFER_NX) && !(ext1_edx & cpufeat_mask(X8= 6_FEATURE_NX)) )=0A+ return 0;=0A+=0A+ if ( (value & EFER_SVME) = &&=0A+ (!(ext1_ecx & cpufeat_mask(X86_FEATURE_SVM)) ||=0A+ = !nestedhvm_enabled(v->domain)) )=0A+ return 0;=0A+=0A+ if ( = (value & EFER_LMSLE) && !cpu_has_lmsl )=0A+ return 0;=0A+=0A+ if = ( (value & EFER_FFXSE) &&=0A+ !(ext1_edx & cpufeat_mask(X86_FEATURE= _FFXSR)) )=0A+ return 0;=0A+=0A+ return 1;=0A }=0A =0A /* These = reserved bits in lower 32 remain 0 after any load of CR0 */=0A@@ -1763,7 = +1807,6 @@ static int hvm_load_cpu_ctxt(struct doma=0A struct vcpu = *v;=0A struct hvm_hw_cpu ctxt;=0A struct segment_register seg;=0A- = uint64_t efer_validbits;=0A =0A /* Which vcpu is this? */=0A = vcpuid =3D hvm_load_instance(h);=0A@@ -1794,9 +1837,7 @@ static int = hvm_load_cpu_ctxt(struct doma=0A return -EINVAL;=0A }=0A =0A- = efer_validbits =3D EFER_FFXSE | EFER_LMSLE | EFER_LME | EFER_LMA=0A- = | EFER_NX | EFER_SCE;=0A- if ( !hvm_efer_valid(d, = ctxt.msr_efer, efer_validbits) )=0A+ if ( !hvm_efer_valid(v, ctxt.msr_ef= er, MASK_EXTR(ctxt.cr0, X86_CR0_PG)) )=0A {=0A printk(XENLOG_G_= ERR "HVM%d restore: bad EFER %#" PRIx64 "\n",=0A d->domain_i= d, ctxt.msr_efer);=0A@@ -2936,12 +2977,10 @@ err:=0A int hvm_set_efer(uint6= 4_t value)=0A {=0A struct vcpu *v =3D current;=0A- uint64_t = efer_validbits;=0A =0A value &=3D ~EFER_LMA;=0A =0A- efer_validbits = =3D EFER_FFXSE | EFER_LMSLE | EFER_LME | EFER_NX | EFER_SCE;=0A- if ( = !hvm_efer_valid(v->domain, value, efer_validbits) )=0A+ if ( !hvm_efer_v= alid(v, value, -1) )=0A {=0A gdprintk(XENLOG_WARNING, "Trying = to set reserved bit in "=0A "EFER: %#"PRIx64"\n", = value);=0A --=__Part97A20F6B.1__= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel --=__Part97A20F6B.1__=--