From patchwork Mon Jul 1 11:56:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Beulich X-Patchwork-Id: 11025763 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 14D3A138B for ; Mon, 1 Jul 2019 12:08:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 050E4286BF for ; Mon, 1 Jul 2019 12:08:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ED8D4286DB; Mon, 1 Jul 2019 12:08: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=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 1E321286D5 for ; Mon, 1 Jul 2019 12:08:01 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hhv4d-0007Oe-IU; Mon, 01 Jul 2019 12:06:19 +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.89) (envelope-from ) id 1hhv4b-0007OU-QM for xen-devel@lists.xenproject.org; Mon, 01 Jul 2019 12:06:17 +0000 X-Inumbo-ID: 9f0aa25c-9bf8-11e9-add2-df2e2e774b8a Received: from m9a0001g.houston.softwaregrp.com (unknown [15.124.64.66]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 9f0aa25c-9bf8-11e9-add2-df2e2e774b8a; Mon, 01 Jul 2019 12:06:14 +0000 (UTC) Received: FROM m9a0001g.houston.softwaregrp.com (15.121.0.191) BY m9a0001g.houston.softwaregrp.com WITH ESMTP; Mon, 1 Jul 2019 12:06:08 +0000 Received: from M9W0068.microfocus.com (2002:f79:bf::f79:bf) by M9W0068.microfocus.com (2002:f79:bf::f79:bf) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Mon, 1 Jul 2019 11:56:04 +0000 Received: from NAM04-SN1-obe.outbound.protection.outlook.com (15.124.72.11) by M9W0068.microfocus.com (15.121.0.191) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10 via Frontend Transport; Mon, 1 Jul 2019 11:56:04 +0000 ARC-Seal: i=1; a=rsa-sha256; s=testarcselector01; d=microsoft.com; cv=none; b=xFbilFvZ90Mk7JHoE6scpdflu/CWM735nphj0ZHplkIwUkBwQcSTGqMFeCE0P9lm+3CCHY/naIkZlpec0a0X8XQtI2GgzxldTUf60hGAVif1G0bDZ5568Fu9h2XJK4efyKFeYFPBmxtkqtHDvaSg/HlFDC7fUwQc2XQtPBX3n6M= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=testarcselector01; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=oFpANnmaXej3gd/MnPKFnMuxGeLPDRqqdvV1FzbIrjk=; b=Z6Ns8xZeC73p6/T6JEMM3QrugnEJS2N6dsDe4xACMWVj6DXNuriIviQjkS5g2ktCgKFktx9N5HhWLl6Sk2OtDfDgwZPX7E7xtUgjJKUyvbp+9A7kb/lczroxBA+usYB21yyfIBWOb+juECdOI11sC5r9KQvl+/ENM31eTxI1Xuo= ARC-Authentication-Results: i=1; test.office365.com 1;spf=none;dmarc=none;dkim=none;arc=none Received: from BY5PR18MB3394.namprd18.prod.outlook.com (10.255.139.95) by BY5PR18MB3364.namprd18.prod.outlook.com (10.255.139.25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2008.16; Mon, 1 Jul 2019 11:56:03 +0000 Received: from BY5PR18MB3394.namprd18.prod.outlook.com ([fe80::2005:4b02:1d60:d1bc]) by BY5PR18MB3394.namprd18.prod.outlook.com ([fe80::2005:4b02:1d60:d1bc%3]) with mapi id 15.20.2008.020; Mon, 1 Jul 2019 11:56:03 +0000 From: Jan Beulich To: "xen-devel@lists.xenproject.org" Thread-Topic: [PATCH 1/6] x86emul: generalize wbinvd() hook Thread-Index: AQHVMAP1xO2bNlA31EuKZ0nW6D/01Q== Date: Mon, 1 Jul 2019 11:56:03 +0000 Message-ID: <3f30c73d-94a7-f9ca-5914-0400f1f98cc3@suse.com> References: <2d69ac51-9c4a-96f9-fd37-578658076571@suse.com> In-Reply-To: <2d69ac51-9c4a-96f9-fd37-578658076571@suse.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: DB7PR08CA0028.eurprd08.prod.outlook.com (2603:10a6:5:16::41) To BY5PR18MB3394.namprd18.prod.outlook.com (2603:10b6:a03:194::31) authentication-results: spf=none (sender IP is ) smtp.mailfrom=JBeulich@suse.com; x-ms-exchange-messagesentrepresentingtype: 1 x-originating-ip: [87.234.252.170] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 9d468ba8-df20-4f09-d5e4-08d6fe1b1762 x-microsoft-antispam: BCL:0; PCL:0; RULEID:(2390118)(7020095)(4652040)(8989299)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(5600148)(711020)(4605104)(1401327)(2017052603328)(7193020); SRVR:BY5PR18MB3364; x-ms-traffictypediagnostic: BY5PR18MB3364: x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:8882; x-forefront-prvs: 00851CA28B x-forefront-antispam-report: SFV:NSPM; SFS:(10019020)(4636009)(346002)(39860400002)(396003)(376002)(366004)(136003)(189003)(199004)(81156014)(76176011)(6916009)(6506007)(26005)(7736002)(8936002)(81166006)(305945005)(80792005)(8676002)(102836004)(99286004)(386003)(72206003)(2906002)(256004)(31686004)(2501003)(25786009)(316002)(52116002)(14444005)(36756003)(14454004)(66066001)(73956011)(5660300002)(5640700003)(66446008)(3846002)(71190400001)(11346002)(6512007)(486006)(71200400001)(6436002)(66946007)(478600001)(66556008)(6486002)(6116002)(86362001)(53936002)(2351001)(476003)(4326008)(68736007)(31696002)(54906003)(30864003)(66476007)(64756008)(2616005)(186003)(446003); DIR:OUT; SFP:1102; SCL:1; SRVR:BY5PR18MB3364; H:BY5PR18MB3394.namprd18.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; MX:1; A:1; received-spf: None (protection.outlook.com: suse.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 x-microsoft-antispam-message-info: YIjaVF2ont8gWXvYy1fuG8jInKLYeTDw5nDuKRbqMMrS0IXOxUbxPuc6XKRq0/Ich6XGlUCi7pBvUAZQULBCIA3vN+GyPnc+dfS0AcLFzvMGWs2mFSs9juwZYhJKDdnVStFwSC7TAISVgCMqO4gFUatyv5c32s1HUllZWN8SpuwJICo7JitJ4H2V3EAItkIsbSvzzYGyQa8Q2oZmGW/vIHdBtjBBTyPsfpDASY2E7A9br5+OFt9l8mAuNa/FWo0IiN8s5iRJiQkAf/QSYMgeJtq7AjEmu9Oc8Wrw1P/vEkHkfKfb3RFuMauKGw7RBQlgSXlHmL3sjRBluQGkaveJDSb+6nUFkmpyXGWjhEXk/tNV0eKjKfNBSgGcOIAX4peAmUwsOf9I/PAkJV1M38wS2FnGJ6cZ2OZu8CvqTL8vwKg= Content-ID: MIME-Version: 1.0 X-MS-Exchange-CrossTenant-Network-Message-Id: 9d468ba8-df20-4f09-d5e4-08d6fe1b1762 X-MS-Exchange-CrossTenant-originalarrivaltime: 01 Jul 2019 11:56:03.1458 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 856b813c-16e5-49a5-85ec-6f081e13b527 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: JBeulich@suse.com X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY5PR18MB3364 X-OriginatorOrg: suse.com Subject: [Xen-devel] [PATCH 1/6] x86emul: generalize wbinvd() hook X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Andrew Cooper , Paul Durrant , Wei Liu , RogerPau Monne Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP The hook is already in use for other purposes, and emulating e.g. CLFLUSH by issuing WBINVD is, well, not very nice. Rename the hook and add parameters. Use lighter weight flushing insns when possible in hvmemul_cache_op(). hvmemul_cache_op() treating x86emul_invd the same as x86emul_wbinvd is to retain original behavior, but I'm not sure this is what we want in the long run. Signed-off-by: Jan Beulich Reviewed-by: Andrew Cooper Acked-by: Paul Durrant --- v2: Use cache_op() as hook name. Convert macros to inline functions in system.h. Re-base. --- I was unsure about PREFETCH* and CLDEMOTE - both are cache management insns too, but the emulator currently treats them as a NOP without invoking any hooks. I was also uncertain about the new cache_flush_permitted() instance - generally I think it wouldn't be too bad if we allowed line flushes in all cases, in which case the checks in the ->wbinvd_intercept() handlers would suffice (as they did until now). --- a/tools/fuzz/x86_instruction_emulator/fuzz-emul.c +++ b/tools/fuzz/x86_instruction_emulator/fuzz-emul.c @@ -382,10 +382,13 @@ static int fuzz_invlpg( return maybe_fail(ctxt, "invlpg", false); } -static int fuzz_wbinvd( +static int fuzz_cache_op( + enum x86emul_cache_op op, + enum x86_segment seg, + unsigned long offset, struct x86_emulate_ctxt *ctxt) { - return maybe_fail(ctxt, "wbinvd", true); + return maybe_fail(ctxt, "cache-management", true); } static int fuzz_write_io( @@ -620,7 +623,7 @@ static const struct x86_emulate_ops all_ SET(read_xcr), SET(read_msr), SET(write_msr), - SET(wbinvd), + SET(cache_op), SET(invlpg), .get_fpu = emul_test_get_fpu, .put_fpu = emul_test_put_fpu, @@ -729,7 +732,7 @@ enum { HOOK_read_xcr, HOOK_read_msr, HOOK_write_msr, - HOOK_wbinvd, + HOOK_cache_op, HOOK_cpuid, HOOK_inject_hw_exception, HOOK_inject_sw_interrupt, @@ -773,7 +776,7 @@ static void disable_hooks(struct x86_emu MAYBE_DISABLE_HOOK(read_xcr); MAYBE_DISABLE_HOOK(read_msr); MAYBE_DISABLE_HOOK(write_msr); - MAYBE_DISABLE_HOOK(wbinvd); + MAYBE_DISABLE_HOOK(cache_op); MAYBE_DISABLE_HOOK(cpuid); MAYBE_DISABLE_HOOK(get_fpu); MAYBE_DISABLE_HOOK(invlpg); --- a/xen/arch/x86/Rules.mk +++ b/xen/arch/x86/Rules.mk @@ -19,7 +19,9 @@ $(call as-option-add,CFLAGS,CC,"crc32 %e $(call as-option-add,CFLAGS,CC,"invept (%rax)$$(comma)%rax",-DHAVE_AS_EPT) $(call as-option-add,CFLAGS,CC,"rdrand %eax",-DHAVE_AS_RDRAND) $(call as-option-add,CFLAGS,CC,"rdfsbase %rax",-DHAVE_AS_FSGSBASE) +$(call as-option-add,CFLAGS,CC,"xsaveopt (%rax)",-DHAVE_AS_XSAVEOPT) $(call as-option-add,CFLAGS,CC,"rdseed %eax",-DHAVE_AS_RDSEED) +$(call as-option-add,CFLAGS,CC,"clwb (%rax)",-DHAVE_AS_CLWB) $(call as-option-add,CFLAGS,CC,".equ \"x\"$$(comma)1", \ -U__OBJECT_LABEL__ -DHAVE_AS_QUOTED_SYM \ '-D__OBJECT_LABEL__=$(subst $(BASEDIR)/,,$(CURDIR))/$$@') --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -25,6 +25,7 @@ #include #include #include +#include #include static void hvmtrace_io_assist(const ioreq_t *p) @@ -555,16 +556,12 @@ static void *hvmemul_map_linear_addr( mfn_t *mfn = &hvmemul_ctxt->mfn[0]; /* - * The caller has no legitimate reason for trying a zero-byte write, but - * all other code here is written to work if the check below was dropped. - * - * The maximum write size depends on the number of adjacent mfns[] which + * The maximum access size depends on the number of adjacent mfns[] which * can be vmap()'d, accouting for possible misalignment within the region. * The higher level emulation callers are responsible for ensuring that - * mfns[] is large enough for the requested write size. + * mfns[] is large enough for the requested access size. */ - if ( bytes == 0 || - nr_frames > ARRAY_SIZE(hvmemul_ctxt->mfn) ) + if ( nr_frames > ARRAY_SIZE(hvmemul_ctxt->mfn) ) { ASSERT_UNREACHABLE(); goto unhandleable; @@ -669,8 +666,6 @@ static void hvmemul_unmap_linear_addr( unsigned int i; mfn_t *mfn = &hvmemul_ctxt->mfn[0]; - ASSERT(bytes > 0); - if ( nr_frames == 1 ) unmap_domain_page(mapping); else @@ -1473,7 +1468,10 @@ static int hvmemul_write_msr_discard( return X86EMUL_OKAY; } -static int hvmemul_wbinvd_discard( +static int hvmemul_cache_op_discard( + enum x86emul_cache_op op, + enum x86_segment seg, + unsigned long offset, struct x86_emulate_ctxt *ctxt) { return X86EMUL_OKAY; @@ -2149,10 +2147,65 @@ static int hvmemul_write_msr( return rc; } -static int hvmemul_wbinvd( +static int hvmemul_cache_op( + enum x86emul_cache_op op, + enum x86_segment seg, + unsigned long offset, struct x86_emulate_ctxt *ctxt) { - alternative_vcall(hvm_funcs.wbinvd_intercept); + struct hvm_emulate_ctxt *hvmemul_ctxt = + container_of(ctxt, struct hvm_emulate_ctxt, ctxt); + unsigned long addr, reps = 1; + uint32_t pfec = PFEC_page_present; + int rc; + void *mapping; + + if ( !cache_flush_permitted(current->domain) ) + return X86EMUL_OKAY; + + switch ( op ) + { + case x86emul_clflush: + case x86emul_clflushopt: + case x86emul_clwb: + ASSERT(!is_x86_system_segment(seg)); + + rc = hvmemul_virtual_to_linear(seg, offset, 0, &reps, + hvm_access_read, hvmemul_ctxt, &addr); + if ( rc != X86EMUL_OKAY ) + break; + + if ( hvmemul_ctxt->seg_reg[x86_seg_ss].dpl == 3 ) + pfec |= PFEC_user_mode; + + mapping = hvmemul_map_linear_addr(addr, 0, pfec, hvmemul_ctxt, + current->arch.hvm.data_cache); + if ( mapping == ERR_PTR(~X86EMUL_EXCEPTION) ) + return X86EMUL_EXCEPTION; + if ( IS_ERR_OR_NULL(mapping) ) + break; + + if ( cpu_has_clflush ) + { + if ( op == x86emul_clwb && cpu_has_clwb ) + clwb(mapping); + else if ( op == x86emul_clflushopt && cpu_has_clflushopt ) + clflushopt(mapping); + else + clflush(mapping); + + hvmemul_unmap_linear_addr(mapping, addr, 0, hvmemul_ctxt); + break; + } + + hvmemul_unmap_linear_addr(mapping, addr, 0, hvmemul_ctxt); + /* fall through */ + case x86emul_invd: + case x86emul_wbinvd: + alternative_vcall(hvm_funcs.wbinvd_intercept); + break; + } + return X86EMUL_OKAY; } @@ -2353,7 +2406,7 @@ static const struct x86_emulate_ops hvm_ .write_xcr = hvmemul_write_xcr, .read_msr = hvmemul_read_msr, .write_msr = hvmemul_write_msr, - .wbinvd = hvmemul_wbinvd, + .cache_op = hvmemul_cache_op, .cpuid = x86emul_cpuid, .get_fpu = hvmemul_get_fpu, .put_fpu = hvmemul_put_fpu, @@ -2380,7 +2433,7 @@ static const struct x86_emulate_ops hvm_ .write_xcr = hvmemul_write_xcr, .read_msr = hvmemul_read_msr, .write_msr = hvmemul_write_msr_discard, - .wbinvd = hvmemul_wbinvd_discard, + .cache_op = hvmemul_cache_op_discard, .cpuid = x86emul_cpuid, .get_fpu = hvmemul_get_fpu, .put_fpu = hvmemul_put_fpu, --- a/xen/arch/x86/pv/emul-priv-op.c +++ b/xen/arch/x86/pv/emul-priv-op.c @@ -1118,9 +1118,11 @@ static int write_msr(unsigned int reg, u return X86EMUL_UNHANDLEABLE; } -/* Name it differently to avoid clashing with wbinvd() */ -static int _wbinvd(struct x86_emulate_ctxt *ctxt) +static int cache_op(enum x86emul_cache_op op, enum x86_segment seg, + unsigned long offset, struct x86_emulate_ctxt *ctxt) { + ASSERT(op == x86emul_wbinvd); + /* Ignore the instruction if unprivileged. */ if ( !cache_flush_permitted(current->domain) ) /* @@ -1238,7 +1240,7 @@ static const struct x86_emulate_ops priv .read_msr = read_msr, .write_msr = write_msr, .cpuid = x86emul_cpuid, - .wbinvd = _wbinvd, + .cache_op = cache_op, }; int pv_emulate_privileged_op(struct cpu_user_regs *regs) --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -5933,8 +5933,11 @@ x86_emulate( case X86EMUL_OPC(0x0f, 0x08): /* invd */ case X86EMUL_OPC(0x0f, 0x09): /* wbinvd */ generate_exception_if(!mode_ring0(), EXC_GP, 0); - fail_if(ops->wbinvd == NULL); - if ( (rc = ops->wbinvd(ctxt)) != 0 ) + fail_if(!ops->cache_op); + if ( (rc = ops->cache_op(b == 0x09 ? x86emul_wbinvd + : x86emul_invd, + x86_seg_none, 0, + ctxt)) != X86EMUL_OKAY ) goto done; break; @@ -7801,8 +7804,9 @@ x86_emulate( /* else clwb */ fail_if(!vex.pfx); vcpu_must_have(clwb); - fail_if(!ops->wbinvd); - if ( (rc = ops->wbinvd(ctxt)) != X86EMUL_OKAY ) + fail_if(!ops->cache_op); + if ( (rc = ops->cache_op(x86emul_clwb, ea.mem.seg, ea.mem.off, + ctxt)) != X86EMUL_OKAY ) goto done; break; case 7: @@ -7818,8 +7822,11 @@ x86_emulate( vcpu_must_have(clflush); else vcpu_must_have(clflushopt); - fail_if(ops->wbinvd == NULL); - if ( (rc = ops->wbinvd(ctxt)) != 0 ) + fail_if(!ops->cache_op); + if ( (rc = ops->cache_op(vex.pfx ? x86emul_clflushopt + : x86emul_clflush, + ea.mem.seg, ea.mem.off, + ctxt)) != X86EMUL_OKAY ) goto done; break; default: --- a/xen/arch/x86/x86_emulate/x86_emulate.h +++ b/xen/arch/x86/x86_emulate/x86_emulate.h @@ -176,6 +176,14 @@ enum x86_emulate_fpu_type { X86EMUL_FPU_none }; +enum x86emul_cache_op { + x86emul_clflush, + x86emul_clflushopt, + x86emul_clwb, + x86emul_invd, + x86emul_wbinvd, +}; + struct x86_emulate_state; /* @@ -452,8 +460,15 @@ struct x86_emulate_ops uint64_t val, struct x86_emulate_ctxt *ctxt); - /* wbinvd: Write-back and invalidate cache contents. */ - int (*wbinvd)( + /* + * cache_op: Write-back and/or invalidate cache contents. + * + * @seg:@offset applicable only to some of enum x86emul_cache_op. + */ + int (*cache_op)( + enum x86emul_cache_op op, + enum x86_segment seg, + unsigned long offset, struct x86_emulate_ctxt *ctxt); /* cpuid: Emulate CPUID via given set of EAX-EDX inputs/outputs. */ --- a/xen/include/asm-x86/cpufeature.h +++ b/xen/include/asm-x86/cpufeature.h @@ -102,6 +102,8 @@ #define cpu_has_rdseed boot_cpu_has(X86_FEATURE_RDSEED) #define cpu_has_smap boot_cpu_has(X86_FEATURE_SMAP) #define cpu_has_avx512_ifma boot_cpu_has(X86_FEATURE_AVX512_IFMA) +#define cpu_has_clflushopt boot_cpu_has(X86_FEATURE_CLFLUSHOPT) +#define cpu_has_clwb boot_cpu_has(X86_FEATURE_CLWB) #define cpu_has_avx512er boot_cpu_has(X86_FEATURE_AVX512ER) #define cpu_has_avx512cd boot_cpu_has(X86_FEATURE_AVX512CD) #define cpu_has_sha boot_cpu_has(X86_FEATURE_SHA) --- a/xen/include/asm-x86/system.h +++ b/xen/include/asm-x86/system.h @@ -21,6 +21,23 @@ static inline void clflush(const void *p asm volatile ( "clflush %0" :: "m" (*(const char *)p) ); } +static inline void clflushopt(const void *p) +{ + asm volatile ( "data16 clflush %0" :: "m" (*(const char *)p) ); +} + +static inline void clwb(const void *p) +{ +#if defined(HAVE_AS_CLWB) + asm volatile ( "clwb %0" :: "m" (*(const char *)p) ); +#elif defined(HAVE_AS_XSAVEOPT) + asm volatile ( "data16 xsaveopt %0" :: "m" (*(const char *)p) ); +#else + asm volatile ( ".byte 0x66, 0x0f, 0xae, 0x32" + :: "d" (p), "m" (*(const char *)p) ); +#endif +} + #define xchg(ptr,v) \ ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))