From patchwork Fri Aug 19 12:53:25 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Beulich X-Patchwork-Id: 9290233 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3282760574 for ; Fri, 19 Aug 2016 12:56:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 21BF2293EB for ; Fri, 19 Aug 2016 12:56:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1695F29404; Fri, 19 Aug 2016 12:56:02 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 51AFD293EB for ; Fri, 19 Aug 2016 12:56:01 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bajIf-0001CI-Sm; Fri, 19 Aug 2016 12:53:29 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bajIf-0001CC-6N for xen-devel@lists.xenproject.org; Fri, 19 Aug 2016 12:53:29 +0000 Received: from [85.158.137.68] by server-3.bemta-3.messagelabs.com id DC/6C-23620-84107B75; Fri, 19 Aug 2016 12:53:28 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprPIsWRWlGSWpSXmKPExsXS6fjDS9edcXu 4wcctEhbft0xmcmD0OPzhCksAYxRrZl5SfkUCa0bbnE+MBd3uFauPBTYwNlh3MXJwCAnkSZxY qNLFyMnBK2AncWbBJGYQW0LAUOLp++tsICUsAqoSRx7YgoTZBNQl2p5tZwUJiwgYSJw7mgRiM gvoS2xbxwJiCguESWz8zQti8goISvzdIQzSxww0esWhS+wTGLlmIWRmIclA2FoSD3/dYoGwtS WWLXzNPAtsvLTE8n8cEGFLiemfLrGhKgGxXSQufVvNuoCRYxWjenFqUVlqka6pXlJRZnpGSW5 iZo6uoYGxXm5qcXFiempOYlKxXnJ+7iZGYMDVMzAw7mC8/NXpEKMkB5OSKO8v/W3hQnxJ+SmV GYnFGfFFpTmpxYcYZTg4lCR4GRm2hwsJFqWmp1akZeYAQx8mLcHBoyTCe/U/UCtvcUFibnFmO kTqFKOilDjveZCEAEgiozQPrg0Wb5cYZaWEgWYzMAjxFKQW5WaWoMq/YhTnYFQS5r0NMoUnM6 8EbvoroMVMQIt5+beALC5JREhJNTBelOT8MYNRcKPLlfP+0+Lnc0X6X72ylMHi2uHHelv/i71 jjm8PWFX2vE9q14z3X40ZaiZZ+KrOrZr4Pzpxl9j86Je3hD4IaDJ6LbZbttW5jfvyFOnJwYfO xazZde2XyMo7loHf1T7l7uuf/8o+co7xzPKQ7dy7+j2i+rxNsvtuX7wo7Zwz5WC2EktxRqKhF nNRcSIAmrxVIrICAAA= X-Env-Sender: JBeulich@suse.com X-Msg-Ref: server-5.tower-31.messagelabs.com!1471611205!53271646!1 X-Originating-IP: [137.65.248.74] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 8.84; banners=-,-,- X-VirusChecked: Checked Received: (qmail 25877 invoked from network); 19 Aug 2016 12:53:26 -0000 Received: from prv-mh.provo.novell.com (HELO prv-mh.provo.novell.com) (137.65.248.74) by server-5.tower-31.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 19 Aug 2016 12:53:26 -0000 Received: from INET-PRV-MTA by prv-mh.provo.novell.com with Novell_GroupWise; Fri, 19 Aug 2016 06:53:24 -0600 Message-Id: <57B71D6502000078001076C8@prv-mh.provo.novell.com> X-Mailer: Novell GroupWise Internet Agent 14.2.1 Date: Fri, 19 Aug 2016 06:53:25 -0600 From: "Jan Beulich" To: "xen-devel" Mime-Version: 1.0 Cc: Andrew Cooper Subject: [Xen-devel] [PATCH v2] x86/PV: don't wrongly hide/expose CPUID.OSXSAVE from/to user mode X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP User mode code generally cannot be expected to invoke the PV-enabled CPUID Xen supports, and prior to the CPUID levelling changes for 4.7 (as well as even nowadays on levelling incapable hardware) such CPUID invocations actually saw the host CR4.OSXSAVE value, whereas prior to this patch - on Intel guest user mode always saw the flag clear, - on AMD guest user mode saw the flag set even when the guest kernel didn't enable use of XSAVE/XRSTOR. Fold in the guest view of CR4.OSXSAVE when setting the levelling MSRs, just like we do in other CPUID handling. To make guest CR4 changes immediately visible via CPUID, also invoke ctxt_switch_levelling() from the CR4 write path. Signed-off-by: Jan Beulich --- v2: Invert operation on AMD (from OR-ing in to AND-ing out), adjust title, and extend description. x86/PV: don't wrongly hide/expose CPUID.OSXSAVE from/to user mode User mode code generally cannot be expected to invoke the PV-enabled CPUID Xen supports, and prior to the CPUID levelling changes for 4.7 (as well as even nowadays on levelling incapable hardware) such CPUID invocations actually saw the host CR4.OSXSAVE value, whereas prior to this patch - on Intel guest user mode always saw the flag clear, - on AMD guest user mode saw the flag set even when the guest kernel didn't enable use of XSAVE/XRSTOR. Fold in the guest view of CR4.OSXSAVE when setting the levelling MSRs, just like we do in other CPUID handling. To make guest CR4 changes immediately visible via CPUID, also invoke ctxt_switch_levelling() from the CR4 write path. Signed-off-by: Jan Beulich --- v2: Invert operation on AMD (from OR-ing in to AND-ing out), adjust title, and extend description. --- a/xen/arch/x86/cpu/amd.c +++ b/xen/arch/x86/cpu/amd.c @@ -206,17 +206,30 @@ static void __init noinline probe_maskin static void amd_ctxt_switch_levelling(const struct domain *nextd) { struct cpuidmasks *these_masks = &this_cpu(cpuidmasks); - const struct cpuidmasks *masks = - (nextd && is_pv_domain(nextd) && nextd->arch.pv_domain.cpuidmasks) - ? nextd->arch.pv_domain.cpuidmasks : &cpuidmask_defaults; + const struct cpuidmasks *masks = NULL; + unsigned long cr4; + uint64_t val__1cd = 0, val_e1cd = 0, val__7ab0 = 0, val__6c = 0; + + if (nextd && is_pv_domain(nextd) && !is_idle_domain(nextd)) { + cr4 = current->arch.pv_vcpu.ctrlreg[4]; + masks = nextd->arch.pv_domain.cpuidmasks; + } else + cr4 = read_cr4(); + + if (!(cr4 & X86_CR4_OSXSAVE)) + val__1cd |= (uint64_t)cpufeat_mask(X86_FEATURE_OSXSAVE) << 32; + + if (!masks) + masks = &cpuidmask_defaults; #define LAZY(cap, msr, field) \ ({ \ - if (unlikely(these_masks->field != masks->field) && \ + val_##field = ~val_##field & masks->field; \ + if (unlikely(these_masks->field != val_##field) && \ ((levelling_caps & cap) == cap)) \ { \ - wrmsr_amd(msr, masks->field); \ - these_masks->field = masks->field; \ + wrmsr_amd(msr, val_##field); \ + these_masks->field = val_##field; \ } \ }) --- a/xen/arch/x86/cpu/intel.c +++ b/xen/arch/x86/cpu/intel.c @@ -154,7 +154,9 @@ static void __init probe_masking_msrs(vo static void intel_ctxt_switch_levelling(const struct domain *nextd) { struct cpuidmasks *these_masks = &this_cpu(cpuidmasks); - const struct cpuidmasks *masks; + const struct cpuidmasks *masks = NULL; + unsigned long cr4; + uint64_t val__1cd = 0, val_e1cd = 0, val_Da1 = 0; if (cpu_has_cpuid_faulting) { /* @@ -178,16 +180,27 @@ static void intel_ctxt_switch_levelling( return; } - masks = (nextd && is_pv_domain(nextd) && nextd->arch.pv_domain.cpuidmasks) - ? nextd->arch.pv_domain.cpuidmasks : &cpuidmask_defaults; + if (nextd && is_pv_domain(nextd) && !is_idle_domain(nextd)) { + cr4 = current->arch.pv_vcpu.ctrlreg[4]; + masks = nextd->arch.pv_domain.cpuidmasks; + } else + cr4 = read_cr4(); + + /* OSXSAVE cleared by pv_featureset. Fast-forward CR4 back in. */ + if (cr4 & X86_CR4_OSXSAVE) + val__1cd |= cpufeat_mask(X86_FEATURE_OSXSAVE); + + if (!masks) + masks = &cpuidmask_defaults; #define LAZY(msr, field) \ ({ \ - if (unlikely(these_masks->field != masks->field) && \ + val_##field |= masks->field; \ + if (unlikely(these_masks->field != val_##field) && \ (msr)) \ { \ - wrmsrl((msr), masks->field); \ - these_masks->field = masks->field; \ + wrmsrl((msr), val_##field); \ + these_masks->field = val_##field; \ } \ }) --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -2733,6 +2733,7 @@ static int emulate_privileged_op(struct case 4: /* Write CR4 */ v->arch.pv_vcpu.ctrlreg[4] = pv_guest_cr4_fixup(v, *reg); write_cr4(pv_guest_cr4_to_real_cr4(v)); + ctxt_switch_levelling(currd); break; default: --- a/xen/arch/x86/cpu/amd.c +++ b/xen/arch/x86/cpu/amd.c @@ -206,17 +206,30 @@ static void __init noinline probe_maskin static void amd_ctxt_switch_levelling(const struct domain *nextd) { struct cpuidmasks *these_masks = &this_cpu(cpuidmasks); - const struct cpuidmasks *masks = - (nextd && is_pv_domain(nextd) && nextd->arch.pv_domain.cpuidmasks) - ? nextd->arch.pv_domain.cpuidmasks : &cpuidmask_defaults; + const struct cpuidmasks *masks = NULL; + unsigned long cr4; + uint64_t val__1cd = 0, val_e1cd = 0, val__7ab0 = 0, val__6c = 0; + + if (nextd && is_pv_domain(nextd) && !is_idle_domain(nextd)) { + cr4 = current->arch.pv_vcpu.ctrlreg[4]; + masks = nextd->arch.pv_domain.cpuidmasks; + } else + cr4 = read_cr4(); + + if (!(cr4 & X86_CR4_OSXSAVE)) + val__1cd |= (uint64_t)cpufeat_mask(X86_FEATURE_OSXSAVE) << 32; + + if (!masks) + masks = &cpuidmask_defaults; #define LAZY(cap, msr, field) \ ({ \ - if (unlikely(these_masks->field != masks->field) && \ + val_##field = ~val_##field & masks->field; \ + if (unlikely(these_masks->field != val_##field) && \ ((levelling_caps & cap) == cap)) \ { \ - wrmsr_amd(msr, masks->field); \ - these_masks->field = masks->field; \ + wrmsr_amd(msr, val_##field); \ + these_masks->field = val_##field; \ } \ }) --- a/xen/arch/x86/cpu/intel.c +++ b/xen/arch/x86/cpu/intel.c @@ -154,7 +154,9 @@ static void __init probe_masking_msrs(vo static void intel_ctxt_switch_levelling(const struct domain *nextd) { struct cpuidmasks *these_masks = &this_cpu(cpuidmasks); - const struct cpuidmasks *masks; + const struct cpuidmasks *masks = NULL; + unsigned long cr4; + uint64_t val__1cd = 0, val_e1cd = 0, val_Da1 = 0; if (cpu_has_cpuid_faulting) { /* @@ -178,16 +180,27 @@ static void intel_ctxt_switch_levelling( return; } - masks = (nextd && is_pv_domain(nextd) && nextd->arch.pv_domain.cpuidmasks) - ? nextd->arch.pv_domain.cpuidmasks : &cpuidmask_defaults; + if (nextd && is_pv_domain(nextd) && !is_idle_domain(nextd)) { + cr4 = current->arch.pv_vcpu.ctrlreg[4]; + masks = nextd->arch.pv_domain.cpuidmasks; + } else + cr4 = read_cr4(); + + /* OSXSAVE cleared by pv_featureset. Fast-forward CR4 back in. */ + if (cr4 & X86_CR4_OSXSAVE) + val__1cd |= cpufeat_mask(X86_FEATURE_OSXSAVE); + + if (!masks) + masks = &cpuidmask_defaults; #define LAZY(msr, field) \ ({ \ - if (unlikely(these_masks->field != masks->field) && \ + val_##field |= masks->field; \ + if (unlikely(these_masks->field != val_##field) && \ (msr)) \ { \ - wrmsrl((msr), masks->field); \ - these_masks->field = masks->field; \ + wrmsrl((msr), val_##field); \ + these_masks->field = val_##field; \ } \ }) --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -2733,6 +2733,7 @@ static int emulate_privileged_op(struct case 4: /* Write CR4 */ v->arch.pv_vcpu.ctrlreg[4] = pv_guest_cr4_fixup(v, *reg); write_cr4(pv_guest_cr4_to_real_cr4(v)); + ctxt_switch_levelling(currd); break; default: