From nobody Sun May 5 05:33:21 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=quarantine dis=none) header.from=suse.com ARC-Seal: i=1; a=rsa-sha256; t=1618579030; cv=none; d=zohomail.com; s=zohoarc; b=BCYTd3Sh7Uzw3h+Vp9gZ9unEZbqg9sBUJkHn23GGVjTdI+pIg0awuwgQwPmdWeDzw19SHIt43l3WfWxP+8XB/9hazzBZ2VoIBhTk+512U2ezmILyXpj5pxHFN7GtG45WRj/s8Zz5XeStJyKhMkt2XKSlQ3BL8aLrWo+KhZmVo1o= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1618579030; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:To; bh=GWMb2nTdNosSGv/vN708YUhwk/cUBkUU7Dm5oA2g0ak=; b=ERuks+vCGhGg/QcJatRKCjSHpVn36ZdUOgYtqtcr4BzaCaLO54RJ1MMtdNoFOjfU2fdbFr9WwivN2oJoj11RxIpWvt+8VFxnDc3/Xme7wOcMU0rIzFqu67p00hYgQnSLiB6AOqvxiOxxhJQzCN1Qjt1gqVzb8iN1+lCObwlMVoM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=quarantine dis=none) header.from= Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1618579030060711.0262856568329; Fri, 16 Apr 2021 06:17:10 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.111727.213678 (Exim 4.92) (envelope-from ) id 1lXOKz-0007qd-VE; Fri, 16 Apr 2021 13:16:45 +0000 Received: by outflank-mailman (output) from mailman id 111727.213678; Fri, 16 Apr 2021 13:16:45 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1lXOKz-0007qW-S2; Fri, 16 Apr 2021 13:16:45 +0000 Received: by outflank-mailman (input) for mailman id 111727; Fri, 16 Apr 2021 13:16:44 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1lXOKy-0007qR-Qh for xen-devel@lists.xenproject.org; Fri, 16 Apr 2021 13:16:44 +0000 Received: from mx2.suse.de (unknown [195.135.220.15]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id c300a326-e2b3-450e-a3c5-07e2c361dd49; Fri, 16 Apr 2021 13:16:42 +0000 (UTC) Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 814A7B158; Fri, 16 Apr 2021 13:16:41 +0000 (UTC) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: c300a326-e2b3-450e-a3c5-07e2c361dd49 X-Virus-Scanned: by amavisd-new at test-mx.suse.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1618579001; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=GWMb2nTdNosSGv/vN708YUhwk/cUBkUU7Dm5oA2g0ak=; b=TiPKevv+YZISbB/1tAI83CYNOHrlDe/gQMDsUO/Nj1u23w7K/ifDMhONg+wB2YKSf/RgSR KHusAZ+mXwQWBK4Q5nz2Lx0N2n54nMkW5/VSE9KL3XEMPhje5aJb3gIV6M2eJhhCV14wik FeTp1B/prMnW1Byec+GhQG9DY7kBBcM= To: "xen-devel@lists.xenproject.org" Cc: Andrew Cooper , Wei Liu , =?UTF-8?Q?Roger_Pau_Monn=c3=a9?= From: Jan Beulich Subject: [PATCH v3] x86/CPUID: shrink max_{,sub}leaf fields according to actual leaf contents Message-ID: <9ecd03b2-f8fa-2a8b-69ad-4b31920ea205@suse.com> Date: Fri, 16 Apr 2021 15:16:41 +0200 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.9.1 MIME-Version: 1.0 Content-Language: en-US Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @suse.com) Content-Type: text/plain; charset="utf-8" Zapping leaf data for out of range leaves is just one half of it: To avoid guests (bogusly or worse) inferring information from mere leaf presence, also shrink maximum indicators such that the respective trailing entry is not all blank (unless of course it's the initial subleaf of a leaf that's not the final one). This is also in preparation of bumping the maximum basic leaf we support, to ensure guests not getting exposed related features won't observe a change in behavior. Signed-off-by: Jan Beulich --- v3: Record the actual non-empty subleaf in p->basic.raw[0x7], rather than subleaf 0. Re-base over Viridian leaf 40000005 addition. v2: New. --- a/tools/tests/cpu-policy/test-cpu-policy.c +++ b/tools/tests/cpu-policy/test-cpu-policy.c @@ -8,10 +8,13 @@ #include =20 #include +#include #include #include #include =20 +#define XSTATE_FP_SSE (X86_XCR0_FP | X86_XCR0_SSE) + static unsigned int nr_failures; #define fail(fmt, ...) \ ({ \ @@ -553,6 +556,103 @@ static void test_cpuid_out_of_range_clea } } =20 +static void test_cpuid_maximum_leaf_shrinking(void) +{ + static const struct test { + const char *name; + struct cpuid_policy p; + } tests[] =3D { + { + .name =3D "basic", + .p =3D { + /* Very basic information only. */ + .basic.max_leaf =3D 1, + .basic.raw_fms =3D 0xc2, + }, + }, + { + .name =3D "cache", + .p =3D { + /* Cache subleaves present. */ + .basic.max_leaf =3D 4, + .cache.subleaf[0].type =3D 1, + }, + }, + { + .name =3D "feat#0", + .p =3D { + /* Subleaf 0 only with some valid bit. */ + .basic.max_leaf =3D 7, + .feat.max_subleaf =3D 0, + .feat.fsgsbase =3D 1, + }, + }, + { + .name =3D "feat#1", + .p =3D { + /* Subleaf 1 only with some valid bit. */ + .basic.max_leaf =3D 7, + .feat.max_subleaf =3D 1, + .feat.avx_vnni =3D 1, + }, + }, + { + .name =3D "topo", + .p =3D { + /* Topology subleaves present. */ + .basic.max_leaf =3D 0xb, + .topo.subleaf[0].type =3D 1, + }, + }, + { + .name =3D "xstate", + .p =3D { + /* First subleaf always valid (and then non-zero). */ + .basic.max_leaf =3D 0xd, + .xstate.xcr0_low =3D XSTATE_FP_SSE, + }, + }, + { + .name =3D "extd", + .p =3D { + /* Commonly available information only. */ + .extd.max_leaf =3D 0x80000008, + .extd.maxphysaddr =3D 0x28, + .extd.maxlinaddr =3D 0x30, + }, + }, + }; + + printf("Testing CPUID maximum leaf shrinking:\n"); + + for ( size_t i =3D 0; i < ARRAY_SIZE(tests); ++i ) + { + const struct test *t =3D &tests[i]; + struct cpuid_policy *p =3D memdup(&t->p); + + p->basic.max_leaf =3D ARRAY_SIZE(p->basic.raw) - 1; + p->feat.max_subleaf =3D ARRAY_SIZE(p->feat.raw) - 1; + p->extd.max_leaf =3D 0x80000000 | (ARRAY_SIZE(p->extd.raw) - 1); + + x86_cpuid_policy_shrink_max_leaves(p); + + /* Check the the resulting max (sub)leaf values against expecation= s. */ + if ( p->basic.max_leaf !=3D t->p.basic.max_leaf ) + fail(" Test %s basic fail - expected %#x, got %#x\n", + t->name, t->p.basic.max_leaf, p->basic.max_leaf); + + if ( p->extd.max_leaf !=3D t->p.extd.max_leaf ) + fail(" Test %s extd fail - expected %#x, got %#x\n", + t->name, t->p.extd.max_leaf, p->extd.max_leaf); + + if ( p->feat.max_subleaf !=3D t->p.feat.max_subleaf ) + fail(" Test %s feat fail - expected %#x, got %#x\n", + t->name, t->p.feat.max_subleaf, p->feat.max_subleaf); + + free(p); + } +} + static void test_is_compatible_success(void) { static struct test { @@ -668,6 +768,7 @@ int main(int argc, char **argv) test_cpuid_serialise_success(); test_cpuid_deserialise_failure(); test_cpuid_out_of_range_clearing(); + test_cpuid_maximum_leaf_shrinking(); =20 test_msr_serialise_success(); test_msr_deserialise_failure(); --- a/xen/arch/x86/cpuid.c +++ b/xen/arch/x86/cpuid.c @@ -341,6 +341,8 @@ static void __init calculate_host_policy p->extd.raw[0xa].d |=3D ((1u << SVM_FEATURE_VMCBCLEAN) | (1u << SVM_FEATURE_TSCRATEMSR)); } + + x86_cpuid_policy_shrink_max_leaves(p); } =20 static void __init guest_common_default_feature_adjustments(uint32_t *fs) @@ -410,6 +412,8 @@ static void __init calculate_pv_max_poli recalculate_xstate(p); =20 p->extd.raw[0xa] =3D EMPTY_LEAF; /* No SVM for PV guests. */ + + x86_cpuid_policy_shrink_max_leaves(p); } =20 static void __init calculate_pv_def_policy(void) @@ -430,6 +434,8 @@ static void __init calculate_pv_def_poli sanitise_featureset(pv_featureset); cpuid_featureset_to_policy(pv_featureset, p); recalculate_xstate(p); + + x86_cpuid_policy_shrink_max_leaves(p); } =20 static void __init calculate_hvm_max_policy(void) @@ -495,6 +501,8 @@ static void __init calculate_hvm_max_pol sanitise_featureset(hvm_featureset); cpuid_featureset_to_policy(hvm_featureset, p); recalculate_xstate(p); + + x86_cpuid_policy_shrink_max_leaves(p); } =20 static void __init calculate_hvm_def_policy(void) @@ -519,6 +527,8 @@ static void __init calculate_hvm_def_pol sanitise_featureset(hvm_featureset); cpuid_featureset_to_policy(hvm_featureset, p); recalculate_xstate(p); + + x86_cpuid_policy_shrink_max_leaves(p); } =20 void __init init_guest_cpuid(void) @@ -699,6 +709,8 @@ void recalculate_cpuid_policy(struct dom =20 if ( !p->extd.page1gb ) p->extd.raw[0x19] =3D EMPTY_LEAF; + + x86_cpuid_policy_shrink_max_leaves(p); } =20 int init_domain_cpuid_policy(struct domain *d) --- a/xen/arch/x86/hvm/viridian/viridian.c +++ b/xen/arch/x86/hvm/viridian/viridian.c @@ -124,7 +124,15 @@ void cpuid_viridian_leaves(const struct switch ( leaf ) { case 0: - res->a =3D 0x40000006; /* Maximum leaf */ + /* Maximum leaf */ + cpuid_viridian_leaves(v, 0x40000006, 0, res); + if ( res->a | res->b | res->c | res->d ) + res->a =3D 0x40000006; + else + { + cpuid_viridian_leaves(v, 0x40000005, 0, res); + res->a =3D 0x40000005 - !(res->a | res->b | res->c | res->d); + } memcpy(&res->b, "Micr", 4); memcpy(&res->c, "osof", 4); memcpy(&res->d, "t Hv", 4); --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -964,13 +964,15 @@ void cpuid_hypervisor_leaves(const struc uint32_t base =3D is_viridian_domain(d) ? 0x40000100 : 0x40000000; uint32_t idx =3D leaf - base; unsigned int limit =3D is_viridian_domain(d) ? p->hv2_limit : p->hv_li= mit; + unsigned int dflt =3D is_pv_domain(d) ? XEN_CPUID_MAX_PV_NUM_LEAVES + : XEN_CPUID_MAX_HVM_NUM_LEAVES; =20 if ( limit =3D=3D 0 ) /* Default number of leaves */ - limit =3D XEN_CPUID_MAX_NUM_LEAVES; + limit =3D dflt; else /* Clamp toolstack value between 2 and MAX_NUM_LEAVES. */ - limit =3D min(max(limit, 2u), XEN_CPUID_MAX_NUM_LEAVES + 0u); + limit =3D min(max(limit, 2u), dflt); =20 if ( idx > limit ) return; --- a/xen/include/public/arch-x86/cpuid.h +++ b/xen/include/public/arch-x86/cpuid.h @@ -113,6 +113,10 @@ /* Max. address width in bits taking memory hotplug into account. */ #define XEN_CPUID_MACHINE_ADDRESS_WIDTH_MASK (0xffu << 0) =20 -#define XEN_CPUID_MAX_NUM_LEAVES 5 +#define XEN_CPUID_MAX_PV_NUM_LEAVES 5 +#define XEN_CPUID_MAX_HVM_NUM_LEAVES 4 +#define XEN_CPUID_MAX_NUM_LEAVES \ + (XEN_CPUID_MAX_PV_NUM_LEAVES > XEN_CPUID_MAX_HVM_NUM_LEAVES ? \ + XEN_CPUID_MAX_PV_NUM_LEAVES : XEN_CPUID_MAX_HVM_NUM_LEAVES) =20 #endif /* __XEN_PUBLIC_ARCH_X86_CPUID_H__ */ --- a/xen/include/xen/lib/x86/cpuid.h +++ b/xen/include/xen/lib/x86/cpuid.h @@ -351,6 +351,13 @@ void x86_cpuid_policy_fill_native(struct */ void x86_cpuid_policy_clear_out_of_range_leaves(struct cpuid_policy *p); =20 +/** + * Shrink max leaf/subleaf values such that the last respective valid entry + * isn't all blank. While permitted by the spec, such extraneous leaves m= ay + * provide undue "hints" to guests. + */ +void x86_cpuid_policy_shrink_max_leaves(struct cpuid_policy *p); + #ifdef __XEN__ #include typedef XEN_GUEST_HANDLE_64(xen_cpuid_leaf_t) cpuid_leaf_buffer_t; --- a/xen/lib/x86/cpuid.c +++ b/xen/lib/x86/cpuid.c @@ -236,6 +236,45 @@ void x86_cpuid_policy_clear_out_of_range ARRAY_SIZE(p->extd.raw) - 1); } =20 +void x86_cpuid_policy_shrink_max_leaves(struct cpuid_policy *p) +{ + unsigned int i; + + p->basic.raw[0x4] =3D p->cache.raw[0]; + + for ( i =3D p->feat.max_subleaf; i; --i ) + if ( p->feat.raw[i].a | p->feat.raw[i].b | + p->feat.raw[i].c | p->feat.raw[i].d ) + break; + p->feat.max_subleaf =3D i; + p->basic.raw[0x7] =3D p->feat.raw[i]; + + p->basic.raw[0xb] =3D p->topo.raw[0]; + + /* + * Due to the way xstate gets handled in the hypervisor (see + * recalculate_xstate()) there is (for now at least) no need to fiddle + * with the xstate subleaves (IOW we assume they're already in consist= ent + * shape, for coming from either hardware or recalculate_xstate()). + */ + p->basic.raw[0xd] =3D p->xstate.raw[0]; + + for ( i =3D p->basic.max_leaf; i; --i ) + if ( p->basic.raw[i].a | p->basic.raw[i].b | + p->basic.raw[i].c | p->basic.raw[i].d ) + break; + p->basic.max_leaf =3D i; + + for ( i =3D p->extd.max_leaf & 0xffff; i; --i ) + if ( p->extd.raw[i].a | p->extd.raw[i].b | + p->extd.raw[i].c | p->extd.raw[i].d ) + break; + if ( i | p->extd.raw[0].b | p->extd.raw[0].c | p->extd.raw[0].d ) + p->extd.max_leaf =3D 0x80000000 | i; + else + p->extd.max_leaf =3D 0; +} + const uint32_t *x86_cpuid_lookup_deep_deps(uint32_t feature) { static const uint32_t deep_features[] =3D INIT_DEEP_FEATURES;