From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 22E2DCFD313 for ; Mon, 24 Nov 2025 14:58:03 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.1171259.1496274 (Exim 4.92) (envelope-from ) id 1vNY0o-0005G8-Ke; Mon, 24 Nov 2025 14:57:54 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 1171259.1496274; Mon, 24 Nov 2025 14:57:54 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vNY0o-0005G1-HT; Mon, 24 Nov 2025 14:57:54 +0000 Received: by outflank-mailman (input) for mailman id 1171259; Mon, 24 Nov 2025 14:57:53 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vNY0m-0005Ft-Rm for xen-devel@lists.xenproject.org; Mon, 24 Nov 2025 14:57:52 +0000 Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [2a00:1450:4864:20::329]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id f2e38a4f-c945-11f0-9d18-b5c5bf9af7f9; Mon, 24 Nov 2025 15:57:51 +0100 (CET) Received: by mail-wm1-x329.google.com with SMTP id 5b1f17b1804b1-477a219db05so26530955e9.2 for ; Mon, 24 Nov 2025 06:57:51 -0800 (PST) Received: from [10.156.60.236] (ip-037-024-206-209.um08.pools.vodafone-ip.de. [37.24.206.209]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-477bf198a67sm210014975e9.0.2025.11.24.06.57.50 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 24 Nov 2025 06:57:50 -0800 (PST) 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: f2e38a4f-c945-11f0-9d18-b5c5bf9af7f9 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=google; t=1763996271; x=1764601071; darn=lists.xenproject.org; h=content-transfer-encoding:in-reply-to:autocrypt:content-language :references:cc:to:from:subject:user-agent:mime-version:date :message-id:from:to:cc:subject:date:message-id:reply-to; bh=+SosLSI1QkWi5PQ23/DFtIzla71+q6am/d29qqGnVzI=; b=CPxNrnwWUlX7GW4KjzDGiYqjmxdcAiwSRamaZW5z2n0CiMAqNQCp43ASnsY+x4NNj1 xD0iS+Fa92y+MiVTMyG1qIWqa3kVtKmjN6hR374gc7ot+PZAuNypnq6zigoa7jMe0+II kmCZdRQ7mYGOp9DNeRlJqKQeeCH4QqEtNebsI8xbEVYqjnEQBMpqyObLqQv5fkNZqffZ wdxdBBDHMcoKqgTuCrdYMvWXAFNqgka7XrJVgv7VmvKIImq+HOg+kfMaQ2qp66tPqd1R PrwzN9kX/lO3OnZ7WId+xkjByFlUj5+y7j+BiBpv35Yr6SWsR1CO8bEH+QCGGGNbrQrm Nk4A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763996271; x=1764601071; h=content-transfer-encoding:in-reply-to:autocrypt:content-language :references:cc:to:from:subject:user-agent:mime-version:date :message-id:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=+SosLSI1QkWi5PQ23/DFtIzla71+q6am/d29qqGnVzI=; b=nUFfd0lMH4WLt3hW7m+Eg97b6122RcOzF0uZUJOdjiche1eTn5+nsoS6meZ+pSoi6s l6SiKX9gWFhEIez/5y4BOVFGFCEOc3UkxPLBnq0+XPgD94VAg8sXwvsi6YmvaOAoPEcI Xnbi8l5bgrpI2LKk1iG8Qqv0XIJ5A3JiusGnsXIcRBmv9G8+TLGZ47XJbJsknRJ579Kk KSTBbRQpIZJvMWZHcX0urXAYsoDdx2YEf1peYqhNuXyjnKxt04ttzF9JcNhDxpKInUaL 1j7yltehE1lKgEuo9s5JpQ24BEVW9BBZ71cibQ+XoUsN+ebhUJ4zr5B82m6vGlQpaNeJ OrJw== X-Gm-Message-State: AOJu0YzSxdUCwUGsEKgv+8ukKDCANx25b5Gi6gC62OXPsUVHUAz4qBOX GOdkEHttnTDp2TvWgkxZeK9Xj1pAKAccYmoGE/3BjX08LStbVdT2qxur20vNQ5xDw+zl1QoXu2N 41wM= X-Gm-Gg: ASbGncvB6mLs59EGawehvVZwNjjsJGcSoG7KS+ejIH3cYAVcw0Wyka3kJVM71xUoHew lIg158sQW6gjszij2m6gg29rOPRDxW0OIyGjqmKauHiMaUopGHkMtOgGHDy/T0C75jjqw2ugp2I kRP5OLfOgDnLA9bYdnC+YaK3Rprz4v8/twhEW5uAgKofOmEAmNJy7zxIOXuUad0fMue0km8lIux Zlp9FsDVDYVEehRrSLOrp7+0nGkQgXJcmtW82q+LYZNBWFZGfNjfn3hUVJ0F0RWPQJfzYBE48gd COl9tyvwct4xkEF9jxnFv+8I+uXa9lQy8KWYiJhKYG7S2MDrt9azTJiMuJxKIC2r7GuM36Kekxm sRMKjPmfn4115O4BjaZBe3SHXEwq0VdW8nCGwG9bdtK6FsJcGSQz3Le2V4G59+0lcLY9uQo6BFT URC9IKqTrCPbdzBLQDPlpQQcTXX3e9r/V/dD5wofS/d6Q9xPAYWZ43wL+BtwhQAPJGk0EZr4lEX J4= X-Google-Smtp-Source: AGHT+IGzic398cTKgsVALDOsk2EzEi8rRGEaJ3RwjAIdXZZ19REXijjtCjr7D96FZaPcFUGRwJT5rg== X-Received: by 2002:a05:600c:4f82:b0:477:952d:fc11 with SMTP id 5b1f17b1804b1-477c11175a9mr137503265e9.16.1763996270822; Mon, 24 Nov 2025 06:57:50 -0800 (PST) Message-ID: <451ca993-86f2-40dc-b68b-a23c055687c0@suse.com> Date: Mon, 24 Nov 2025 15:57:52 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: [PATCH v9 01/10] x86emul: support LKGS From: Jan Beulich To: "xen-devel@lists.xenproject.org" Cc: Andrew Cooper , =?UTF-8?Q?Roger_Pau_Monn=C3=A9?= References: <926a2315-a2b7-4aad-87e6-d686c9da9e3a@suse.com> Content-Language: en-US Autocrypt: addr=jbeulich@suse.com; keydata= xsDiBFk3nEQRBADAEaSw6zC/EJkiwGPXbWtPxl2xCdSoeepS07jW8UgcHNurfHvUzogEq5xk hu507c3BarVjyWCJOylMNR98Yd8VqD9UfmX0Hb8/BrA+Hl6/DB/eqGptrf4BSRwcZQM32aZK 7Pj2XbGWIUrZrd70x1eAP9QE3P79Y2oLrsCgbZJfEwCgvz9JjGmQqQkRiTVzlZVCJYcyGGsD /0tbFCzD2h20ahe8rC1gbb3K3qk+LpBtvjBu1RY9drYk0NymiGbJWZgab6t1jM7sk2vuf0Py O9Hf9XBmK0uE9IgMaiCpc32XV9oASz6UJebwkX+zF2jG5I1BfnO9g7KlotcA/v5ClMjgo6Gl MDY4HxoSRu3i1cqqSDtVlt+AOVBJBACrZcnHAUSuCXBPy0jOlBhxPqRWv6ND4c9PH1xjQ3NP nxJuMBS8rnNg22uyfAgmBKNLpLgAGVRMZGaGoJObGf72s6TeIqKJo/LtggAS9qAUiuKVnygo 3wjfkS9A3DRO+SpU7JqWdsveeIQyeyEJ/8PTowmSQLakF+3fote9ybzd880fSmFuIEJldWxp Y2ggPGpiZXVsaWNoQHN1c2UuY29tPsJgBBMRAgAgBQJZN5xEAhsDBgsJCAcDAgQVAggDBBYC AwECHgECF4AACgkQoDSui/t3IH4J+wCfQ5jHdEjCRHj23O/5ttg9r9OIruwAn3103WUITZee e7Sbg12UgcQ5lv7SzsFNBFk3nEQQCACCuTjCjFOUdi5Nm244F+78kLghRcin/awv+IrTcIWF hUpSs1Y91iQQ7KItirz5uwCPlwejSJDQJLIS+QtJHaXDXeV6NI0Uef1hP20+y8qydDiVkv6l IreXjTb7DvksRgJNvCkWtYnlS3mYvQ9NzS9PhyALWbXnH6sIJd2O9lKS1Mrfq+y0IXCP10eS FFGg+Av3IQeFatkJAyju0PPthyTqxSI4lZYuJVPknzgaeuJv/2NccrPvmeDg6Coe7ZIeQ8Yj t0ARxu2xytAkkLCel1Lz1WLmwLstV30g80nkgZf/wr+/BXJW/oIvRlonUkxv+IbBM3dX2OV8 AmRv1ySWPTP7AAMFB/9PQK/VtlNUJvg8GXj9ootzrteGfVZVVT4XBJkfwBcpC/XcPzldjv+3 HYudvpdNK3lLujXeA5fLOH+Z/G9WBc5pFVSMocI71I8bT8lIAzreg0WvkWg5V2WZsUMlnDL9 mpwIGFhlbM3gfDMs7MPMu8YQRFVdUvtSpaAs8OFfGQ0ia3LGZcjA6Ik2+xcqscEJzNH+qh8V m5jjp28yZgaqTaRbg3M/+MTbMpicpZuqF4rnB0AQD12/3BNWDR6bmh+EkYSMcEIpQmBM51qM EKYTQGybRCjpnKHGOxG0rfFY1085mBDZCH5Kx0cl0HVJuQKC+dV2ZY5AqjcKwAxpE75MLFkr wkkEGBECAAkFAlk3nEQCGwwACgkQoDSui/t3IH7nnwCfcJWUDUFKdCsBH/E5d+0ZnMQi+G0A nAuWpQkjM1ASeQwSHEeAWPgskBQL In-Reply-To: <926a2315-a2b7-4aad-87e6-d686c9da9e3a@suse.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit Provide support for this insn, which is a prereq to FRED. CPUID-wise, while its and FRED's enumerators were already introduced, their dependency still needs adding. While adding a testcase, also add a SWAPGS one. In order to not affect the behavior of pre-existing tests, install write_{segment,msr} hooks only transiently. Signed-off-by: Jan Beulich --- Instead of ->read_segment() we could of course also use ->read_msr() to fetch the original GS base. I don't think I can see a clear advantage of either approach; the way it's done it matches how we handle SWAPGS. For PV save_segments() would need adjustment, but the insn being restricted to ring 0 means PV guests can't use it anyway (unless we wanted to emulate it as another privileged insn). --- v9: Re-base. v8: Re-base. v6: Use MSR constants in test harness. S->s in cpufeatureset.h. Add NMI_SRC feature bits. Re-base. v5: Re-base. v3: Add dependency on LM. Re-base. v2: Use X86_EXC_*. Add comments. --- a/tools/tests/x86_emulator/predicates.c +++ b/tools/tests/x86_emulator/predicates.c @@ -326,6 +326,7 @@ static const struct { { { 0x00, 0x18 }, { 2, 2 }, T, R }, /* ltr */ { { 0x00, 0x20 }, { 2, 2 }, T, R }, /* verr */ { { 0x00, 0x28 }, { 2, 2 }, T, R }, /* verw */ + { { 0x00, 0x30 }, { 0, 2 }, T, R, pfx_f2 }, /* lkgs */ { { 0x01, 0x00 }, { 2, 2 }, F, W }, /* sgdt */ { { 0x01, 0x08 }, { 2, 2 }, F, W }, /* sidt */ { { 0x01, 0x10 }, { 2, 2 }, F, R }, /* lgdt */ --- a/tools/tests/x86_emulator/test_x86_emulator.c +++ b/tools/tests/x86_emulator/test_x86_emulator.c @@ -672,6 +672,10 @@ static int blk( return x86_emul_blk((void *)offset, p_data, bytes, eflags, state, ctxt); } +#ifdef __x86_64__ +static unsigned long gs_base, gs_base_shadow; +#endif + static int read_segment( enum x86_segment seg, struct segment_register *reg, @@ -681,8 +685,30 @@ static int read_segment( return X86EMUL_UNHANDLEABLE; memset(reg, 0, sizeof(*reg)); reg->p = 1; + +#ifdef __x86_64__ + if ( seg == x86_seg_gs ) + reg->base = gs_base; +#endif + + return X86EMUL_OKAY; +} + +#ifdef __x86_64__ +static int write_segment( + enum x86_segment seg, + const struct segment_register *reg, + struct x86_emulate_ctxt *ctxt) +{ + if ( !is_x86_user_segment(seg) ) + return X86EMUL_UNHANDLEABLE; + + if ( seg == x86_seg_gs ) + gs_base = reg->base; + return X86EMUL_OKAY; } +#endif static int read_msr( unsigned int reg, @@ -695,6 +721,20 @@ static int read_msr( *val = ctxt->addr_size > 32 ? EFER_LME | EFER_LMA : 0; return X86EMUL_OKAY; +#ifdef __x86_64__ + case MSR_GS_BASE: + if ( ctxt->addr_size < 64 ) + break; + *val = gs_base; + return X86EMUL_OKAY; + + case MSR_SHADOW_GS_BASE: + if ( ctxt->addr_size < 64 ) + break; + *val = gs_base_shadow; + return X86EMUL_OKAY; +#endif + case MSR_TSC_AUX: #define TSC_AUX_VALUE 0xCACACACA *val = TSC_AUX_VALUE; @@ -704,6 +744,31 @@ static int read_msr( return X86EMUL_UNHANDLEABLE; } +#ifdef __x86_64__ +static int write_msr( + unsigned int reg, + uint64_t val, + struct x86_emulate_ctxt *ctxt) +{ + switch ( reg ) + { + case MSR_GS_BASE: + if ( ctxt->addr_size < 64 || !is_canonical_address(val) ) + break; + gs_base = val; + return X86EMUL_OKAY; + + case MSR_SHADOW_GS_BASE: + if ( ctxt->addr_size < 64 || !is_canonical_address(val) ) + break; + gs_base_shadow = val; + return X86EMUL_OKAY; + } + + return X86EMUL_UNHANDLEABLE; +} +#endif + #define INVPCID_ADDR 0x12345678 #define INVPCID_PCID 0x123 @@ -1338,6 +1403,41 @@ int main(int argc, char **argv) printf("%u bytes read - ", bytes_read); goto fail; } + printf("okay\n"); + + emulops.write_segment = write_segment; + emulops.write_msr = write_msr; + + printf("%-40s", "Testing swapgs..."); + instr[0] = 0x0f; instr[1] = 0x01; instr[2] = 0xf8; + regs.eip = (unsigned long)&instr[0]; + gs_base = 0xffffeeeecccc8888UL; + gs_base_shadow = 0x0000111122224444UL; + rc = x86_emulate(&ctxt, &emulops); + if ( (rc != X86EMUL_OKAY) || + (regs.eip != (unsigned long)&instr[3]) || + (gs_base != 0x0000111122224444UL) || + (gs_base_shadow != 0xffffeeeecccc8888UL) ) + goto fail; + printf("okay\n"); + + printf("%-40s", "Testing lkgs 2(%rdx)..."); + instr[0] = 0xf2; instr[1] = 0x0f; instr[2] = 0x00; instr[3] = 0x72; instr[4] = 0x02; + regs.eip = (unsigned long)&instr[0]; + regs.edx = (unsigned long)res; + res[0] = 0x00004444; + res[1] = 0x8888cccc; + i = cpu_policy.extd.nscb; cpu_policy.extd.nscb = true; /* for AMD */ + rc = x86_emulate(&ctxt, &emulops); + if ( (rc != X86EMUL_OKAY) || + (regs.eip != (unsigned long)&instr[5]) || + (gs_base != 0x0000111122224444UL) || + gs_base_shadow ) + goto fail; + + cpu_policy.extd.nscb = i; + emulops.write_segment = NULL; + emulops.write_msr = NULL; #endif printf("okay\n"); --- a/tools/tests/x86_emulator/x86-emulate.c +++ b/tools/tests/x86_emulator/x86-emulate.c @@ -85,6 +85,7 @@ bool emul_test_init(void) cpu_policy.feat.invpcid = true; cpu_policy.feat.adx = true; cpu_policy.feat.rdpid = true; + cpu_policy.feat.lkgs = true; cpu_policy.feat.wrmsrns = true; cpu_policy.extd.clzero = true; --- a/xen/arch/x86/x86_emulate/decode.c +++ b/xen/arch/x86/x86_emulate/decode.c @@ -744,8 +744,12 @@ decode_twobyte(struct x86_emulate_state case 0: s->desc |= DstMem | SrcImplicit | Mov; break; + case 6: + if ( !(s->modrm_reg & 1) && mode_64bit() ) + { case 2: case 4: - s->desc |= SrcMem16; + s->desc |= SrcMem16; + } break; } break; --- a/xen/arch/x86/x86_emulate/private.h +++ b/xen/arch/x86/x86_emulate/private.h @@ -608,6 +608,7 @@ amd_like(const struct x86_emulate_ctxt * #define vcpu_has_avx_vnni() (ctxt->cpuid->feat.avx_vnni) #define vcpu_has_avx512_bf16() (ctxt->cpuid->feat.avx512_bf16) #define vcpu_has_cmpccxadd() (ctxt->cpuid->feat.cmpccxadd) +#define vcpu_has_lkgs() (ctxt->cpuid->feat.lkgs) #define vcpu_has_wrmsrns() (ctxt->cpuid->feat.wrmsrns) #define vcpu_has_avx_ifma() (ctxt->cpuid->feat.avx_ifma) #define vcpu_has_avx_vnni_int8() (ctxt->cpuid->feat.avx_vnni_int8) --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -2899,8 +2899,35 @@ x86_emulate( break; } break; - default: - generate_exception_if(true, X86_EXC_UD); + case 6: /* lkgs */ + generate_exception_if((modrm_reg & 1) || vex.pfx != vex_f2, + X86_EXC_UD); + generate_exception_if(!mode_64bit() || !mode_ring0(), X86_EXC_UD); + vcpu_must_have(lkgs); + fail_if(!ops->read_segment || !ops->read_msr || + !ops->write_segment || !ops->write_msr); + if ( (rc = ops->read_msr(MSR_SHADOW_GS_BASE, &msr_val, + ctxt)) != X86EMUL_OKAY || + (rc = ops->read_segment(x86_seg_gs, &sreg, + ctxt)) != X86EMUL_OKAY ) + goto done; + dst.orig_val = sreg.base; /* Preserve full GS Base. */ + if ( (rc = protmode_load_seg(x86_seg_gs, src.val, false, &sreg, + ctxt, ops)) != X86EMUL_OKAY || + /* Write (32-bit) base into SHADOW_GS. */ + (rc = ops->write_msr(MSR_SHADOW_GS_BASE, sreg.base, + ctxt)) != X86EMUL_OKAY ) + goto done; + sreg.base = dst.orig_val; /* Reinstate full GS Base. */ + if ( (rc = ops->write_segment(x86_seg_gs, &sreg, + ctxt)) != X86EMUL_OKAY ) + { + /* Best effort unwind (i.e. no real error checking). */ + if ( ops->write_msr(MSR_SHADOW_GS_BASE, msr_val, + ctxt) == X86EMUL_EXCEPTION ) + x86_emul_reset_event(ctxt); + goto done; + } break; } break; --- a/xen/tools/gen-cpuid.py +++ b/xen/tools/gen-cpuid.py @@ -282,7 +282,8 @@ def crunch_numbers(state): # superpages, PCID and PKU are only available in 4 level paging. # NO_LMSL indicates the absense of Long Mode Segment Limits, which # have been dropped in hardware. - LM: [CX16, PCID, LAHF_LM, PAGE1GB, PKU, NO_LMSL, AMX_TILE, CMPCCXADD], + LM: [CX16, PCID, LAHF_LM, PAGE1GB, PKU, NO_LMSL, AMX_TILE, CMPCCXADD, + LKGS], # AMD K6-2+ and K6-III processors shipped with 3DNow+, beyond the # standard 3DNow in the earlier K6 processors. @@ -351,6 +352,9 @@ def crunch_numbers(state): # computational instructions. All further AMX features are built on top # of AMX-TILE. AMX_TILE: [AMX_BF16, AMX_INT8, AMX_FP16, AMX_COMPLEX], + + # FRED builds on the LKGS instruction. + LKGS: [FRED], } deep_features = tuple(sorted(deps.keys()))