From nobody Thu Aug 13 09:24:11 2026 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=reject dis=none) header.from=citrix.com ARC-Seal: i=1; a=rsa-sha256; t=1785741641; cv=none; d=zohomail.com; s=zohoarc; b=hgUTQxmcACJ9MFH/SadtDJAZ9KH/ANZYLAqa/4fN+48KlDHLtuBIt1nkrlnbb46C/AbhEVQP2ZRyDTklHGvJaR99MWIgNv9KC3Mab8SJbn2seG//21bubTXEiW9fHkQhsaT8lIefKDi/fLj5H6vcQSTdGI/wcVGIcM+PeQq2kUQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785741641; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=ub/V0kRy79kgAjDqq6A4lupnXHVPDMBJb38IyKztucA=; b=YoAZOUO/8yWYIEiGEVFXiV5YdNATZr5c7I4Th00cGOF+gNGpoCurpegZCB8NXStrjT+PpALCE4+yCNrWsziIMBByBZbJfpP+Veqb5/NRmhiWzlNN4tbLepuFEgOLuqnfaurFcwPvDCiAlEubxQD4MU4Umm5b3sHienwW81aKb0Q= 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=reject dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1785741641343343.41734661393184; Mon, 3 Aug 2026 00:20:41 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1381225.1624789 (Exim 4.92) (envelope-from ) id 1wqmy7-0001wj-C9; Mon, 03 Aug 2026 07:20:15 +0000 Received: by outflank-mailman (output) from mailman id 1381225.1624789; Mon, 03 Aug 2026 07:20:15 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wqmy7-0001wb-9I; Mon, 03 Aug 2026 07:20:15 +0000 Received: by outflank-mailman (input) for mailman id 1381225; Mon, 03 Aug 2026 07:20:14 +0000 Received: from mx.expurgate.net ([195.190.135.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wqmy5-0001jf-Q6 for xen-devel@lists.xenproject.org; Mon, 03 Aug 2026 07:20:14 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wqmy5-001lnU-6i for xen-devel@lists.xenproject.org; Mon, 03 Aug 2026 09:20:13 +0200 Received: from [10.42.69.9] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a70411b-2eae-0a2a0a5409dd-0a2a4509eaca-46 for ; Mon, 03 Aug 2026 09:20:13 +0200 Received: from [209.85.128.54] (helo=mail-wm1-f54.google.com) by tlsNG-bad1c0.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a70412c-be1a-0a2a45090019-d1558036d87d-3 for ; Mon, 03 Aug 2026 09:20:12 +0200 Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-496b7622a83so10889715e9.2 for ; Mon, 03 Aug 2026 00:20:12 -0700 (PDT) Received: from localhost.localdomain (host-78-146-248-75.as13285.net. [78.146.248.75]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49807b85be7sm254687935e9.2.2026.08.03.00.20.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 03 Aug 2026 00:20:11 -0700 (PDT) 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" Authentication-Results: eu.smtp.expurgate.cloud; dkim=pass header.s=google header.d=citrix.com header.i="@citrix.com" header.h="Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=citrix.com; s=google; t=1785741612; x=1786346412; darn=lists.xenproject.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=ub/V0kRy79kgAjDqq6A4lupnXHVPDMBJb38IyKztucA=; b=m/LZlSJ73th47EW3aq+8u7uO4RvAinRPHAuSrcmRmu/VIojsArSoAzHjkOkq+woFyb bxzaZjEWUUgNl0UDJx9WAwo04WZ2zWpYjz+CPWH+RuEjXUeBAyQvLHnURVTdVuiFYJ9+ iUyhdT7kCCT9n4MEBMGLzTtxr++iPB67FZmaU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785741612; x=1786346412; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=ub/V0kRy79kgAjDqq6A4lupnXHVPDMBJb38IyKztucA=; b=G7N9oMEKzwoxTXakgiFH+y3bXAu6dZbMLbW3LqaIUJUARQm53445XXYSp/VVrnAB8p 7tVs4sYR83X9/oPCDBWdplFEpv6fxoVOAQdXFF+2HnH6KnnszWgafAFYA7+FUWAYK6ZP in6i+1NdCxToL3tMc2gQ72eiobPATjRRFDMLdRqp7uBVyC7jlxEjfxJp3B81BcRm3hJO OlMoVfRY2bm52UmpLuCID1Jx5tOcbxw4Orc87eouuCJSo8Vwx5z0h6Wy3EvIzHGIGM+V mcjgn6TjxuU+/ga8PmzfEZrfLB3iExlJ3EVwHkl7uO7UpQiCEJQOHG81EL4Oau8YxkVO 1nzw== X-Gm-Message-State: AOJu0YxSsbC62vZxHBECrOAZZ94UXEdxQUMX/y0H7uX0HWjAdVHIgwA3 HdmmU7Ul/0t0baoUIK9QUv5Vlg9BFLB42dd3kc5FfLe24LMwZX+rCL51HNaK0Fzvl3taDo8GQYh 3ppEq X-Gm-Gg: AR+sD11ScO9Q6cCqHtxDNsg+20OL1sYXYsUc41L55IVxh4O5b05G+jolDSUmZg61dRR 6ay9VnXYPLJN9cMI2DvsSjrtyF4V/Peoeny7lnyWr9XhUQfkHtsIoDfgk9dP/+Ia8X6sfAz87Lv cWPFp+dbKcMi+IJoqeKmG7enkqJIfGCFSF5pwAvHQfRE2qjkq9Bm74S1Jg6483q8kJgr/lKWCyp yeILcsX3fHDgW1QrYqwBF4IM4gZ3TTy2p7WSm2FudbSTQmApDVbyaS4c6jPJUrBClNKe1qx/LLZ x5xuN/QBNp9/L35lOECIXgVLFi8BzcCj03Peuunh+jY2A5LnP761VzRecaVyFLf1Hmc9/pc8Y7P wStYONuZsFlnFAT7KGXyY9aZ8qtk96orKyFUhVQcL8bJDsIffG2eEiBVa/5eSKi2KMBq6E6CzIf t9ihKPqGIY6pS9bdo8PK9qwOgt39St0Vd4JBcDDMth4ZIlSr0fWX3W2ERC5FRlU6JqpfWDEaodW nfOlq1HdE7H0R+AiwUHtGt6RPardryfnxUA6CANBdJgbG9C5g== X-Received: by 2002:a05:600c:19cf:b0:498:2b1f:e0c6 with SMTP id 5b1f17b1804b1-4982b1fe255mr23440215e9.18.1785741611381; Mon, 03 Aug 2026 00:20:11 -0700 (PDT) From: Andrew Cooper To: Xen-devel Cc: Andrew Cooper , Jan Beulich , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= , Teddy Astie Subject: [PATCH v3 1/5] x86/emul: Introduce x86_decode_lite() Date: Mon, 3 Aug 2026 08:20:02 +0100 Message-Id: <20260803072006.9678-2-andrew.cooper3@citrix.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260803072006.9678-1-andrew.cooper3@citrix.com> References: <20260803072006.9678-1-andrew.cooper3@citrix.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-purgate-ID: tlsNG-bad1c0/1785741612-3B4D3034-D2B7BA1C/0/0 X-purgate-type: clean X-purgate-size: 14873 X-ZohoMail-DKIM: pass (identity @citrix.com) X-ZM-MESSAGEID: 1785741642131158500 In order to relocate all IP-relative fields in an alternative replacement block, we need to decode the instructions enough to obtain their length and any relative fields. Full x86_decode() is far too heavyweight, so introduce a minimal form which can make several simplifying assumptions. This a mostly-complete decoder for integer instruction in the onebyte and twobyte maps. Some instructions are intentionally unrecognised, as finding them in an alternative is more likely to be a bug than intentional. Some instruction groups and prefixes are unimplemented to reduce decode complexi= ty. This logic can decode all alternative blocks that exist in Xen right now. Signed-off-by: Andrew Cooper --- CC: Jan Beulich CC: Roger Pau Monn=C3=A9 CC: Teddy Astie v3: * Rearrange decode tables to satisfy comment requests without splitting * Recognise UDB now it's used by Xen * Fix MISRA violations * Misc other changes v2: * Switch to 0 on failure, rel_sz in bytes * Mostly complete the integer instructions; paird with userspace harness * Put in .init when !CONFIG_LIVEPATCH --- xen/arch/x86/x86_emulate/Makefile | 6 + xen/arch/x86/x86_emulate/decode-lite.c | 330 +++++++++++++++++++++++++ xen/arch/x86/x86_emulate/x86_emulate.h | 14 ++ 3 files changed, 350 insertions(+) create mode 100644 xen/arch/x86/x86_emulate/decode-lite.c diff --git a/xen/arch/x86/x86_emulate/Makefile b/xen/arch/x86/x86_emulate/M= akefile index 295e602f6b86..679bddbb1584 100644 --- a/xen/arch/x86/x86_emulate/Makefile +++ b/xen/arch/x86/x86_emulate/Makefile @@ -17,3 +17,9 @@ obj-y +=3D decode.o obj-$(CONFIG_HVM) +=3D fpu.o obj-y +=3D util.o obj-y +=3D util-xen.o + +ifeq ($(CONFIG_LIVEPATCH),y) +obj-y +=3D decode-lite.o +else +obj-bin-y +=3D decode-lite.init.o +endif diff --git a/xen/arch/x86/x86_emulate/decode-lite.c b/xen/arch/x86/x86_emul= ate/decode-lite.c new file mode 100644 index 000000000000..131cc07d5516 --- /dev/null +++ b/xen/arch/x86/x86_emulate/decode-lite.c @@ -0,0 +1,330 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifdef __XEN__ +# include +# include +#endif + +#include "private.h" + +#undef ModRM + +/* + * Bare minimum x86 instruction decoder to parse the alternative replaceme= nt + * instructions and locate the IP-relative references that may need updati= ng. + * + * These are: + * - disp8/32 from near direct branches + * - RIP-relative memory references + * + * The following simplifications are used: + * - All code is 64bit, the instruction stream is well formed and safe to + * read. + * - Instruction groups and prefixes not used by Xen's current alternativ= es + * are not implemented in order to reduce the decode complexity. + * - Certain instructions are intentionally not recognised, when it is mo= re + * likely for their presence to be an error than intentional. + * + * Inputs: + * @ip The position to start decoding from. + * @end End of the replacement block. Exceeding this is considered an er= ror. + * + * Returns: x86_decode_lite_t + * - On failure, length of 0. + * - On success, length > 0. For rel_sz > 0, rel points at the relative + * field in the instruction stream. + */ +x86_decode_lite_t init_or_livepatch x86_decode_lite(void *ip, void *end) +{ +#define Imm8 (1 << 0) +#define Imm (1 << 1) +#define Moffs (1 << 2) +#define Branch (1 << 5) /* Near direct branches, which have a displacement= */ +#define ModRM (1 << 6) +#define Known (1 << 7) + + static const uint8_t init_or_livepatch_const onebyte[256] =3D { + +#define ALU_OPS(x) \ + [(x) + 0] =3D (Known|ModRM), \ + [(x) + 1] =3D (Known|ModRM), \ + [(x) + 2] =3D (Known|ModRM), \ + [(x) + 3] =3D (Known|ModRM), \ + [(x) + 4] =3D (Known|Imm8), \ + [(x) + 5] =3D (Known|Imm) + + ALU_OPS(0x00) /* ADD */, ALU_OPS(0x08) /* OR */, + ALU_OPS(0x10) /* ADC */, ALU_OPS(0x18) /* SBB */, + ALU_OPS(0x20) /* AND */, ALU_OPS(0x28) /* SUB */, + ALU_OPS(0x30) /* XOR */, ALU_OPS(0x38) /* CMP */, + +#undef ALU_OPS + + [0x50 ... 0x5f] =3D (Known), /* PUSH/POP %reg */ + + [0x62] =3D 0, /* BOUND, but also EVEX p= refix, not implemented. */ + [0x63] =3D (Known|ModRM), /* MOVSxd */ + + [0x68] =3D (Known|Imm), /* PUSH $imm */ + [0x69] =3D (Known|ModRM|Imm), /* IMUL $imm */ + [0x6a] =3D (Known|Imm8), /* PUSH $imm8 */ + [0x6b] =3D (Known|ModRM|Imm8), /* PUSH $imm8 */ + [0x6c ... 0x6f] =3D (Known), /* INS/OUTS */ + [0x70 ... 0x7f] =3D (Known|Branch|Imm8), /* Jcc disp8 */ + [0x80] =3D (Known|ModRM|Imm8), /* Grp1 */ + [0x81] =3D (Known|ModRM|Imm), /* Grp1 */ + + [0x83] =3D (Known|ModRM|Imm8), /* Grp1 */ + [0x84 ... 0x8e] =3D (Known|ModRM), /* TEST/XCHG/MOV/MOV-SREG= /LEA */ + [0x8f] =3D 0, /* Grp1A - POP but also X= OP prefix, not implemented. */ + [0x90 ... 0x99] =3D (Known), /* NOP/XCHG %rAX/CLTQ/CQT= O */ + + [0x9b ... 0x9f] =3D (Known), /* FWAIT/PUSHF/POPF/SAHF/= LAHF */ + [0xa0 ... 0xa3] =3D (Known|Moffs), /* MOVABS */ + [0xa4 ... 0xa7] =3D (Known), /* MOVS/CMPS */ + [0xa8] =3D (Known|Imm8), /* TEST %al */ + [0xa9] =3D (Known|Imm), /* TEST %rAX */ + [0xaa ... 0xaf] =3D (Known), /* STOS/LODS/SCAS */ + [0xb0 ... 0xb7] =3D (Known|Imm8), /* MOV $imm8, %reg */ + [0xb8 ... 0xbf] =3D (Known|Imm), /* MOV $imm{16,32,64}, %r= eg */ + [0xc0 ... 0xc1] =3D (Known|ModRM|Imm8), /* Grp2 (ROL..SAR $imm8, = %reg) */ + + [0xc3] =3D (Known), /* RET */ + [0xc4 ... 0xc5] =3D 0, /* LES/LDS but also VEX p= refixes, not implemented. */ + [0xc6] =3D (Known|ModRM|Imm8), /* Grp11, Further ModRM d= ecode */ + [0xc7] =3D (Known|ModRM|Imm), /* Grp11, Further ModRM d= ecode */ + + [0xcb ... 0xcc] =3D (Known), /* LRET/INT3 */ + [0xcd] =3D (Known|Imm8), /* INT $imm8 */ + + [0xd0 ... 0xd3] =3D (Known|ModRM), /* Grp2 (ROL..SAR {$1,%cl= }, %reg) */ + + [0xd6] =3D (Known), /* UDB */ + + [0xe4 ... 0xe7] =3D (Known|Imm8), /* IN/OUT $imm8 */ + [0xe8 ... 0xe9] =3D (Known|Branch|Imm), /* CALL/JMP disp32 */ + + [0xeb] =3D (Known|Branch|Imm8), /* JMP disp8 */ + [0xec ... 0xef] =3D (Known), /* IN/OUT %dx */ + + [0xf1] =3D (Known), /* ICEBP */ + + [0xf4] =3D (Known), /* HLT */ + [0xf5] =3D (Known), /* CMC */ + [0xf6 ... 0xf7] =3D (Known|ModRM), /* Grp3, Further ModRM de= code */ + [0xf8 ... 0xfd] =3D (Known), /* CLC ... STD */ + [0xfe ... 0xff] =3D (Known|ModRM), /* Grp4 */ + }; + static const uint8_t init_or_livepatch_const twobyte[256] =3D { + [0x00 ... 0x03] =3D (Known|ModRM), /* Grp6/Grp7/LAR/LSL */ + + [0x0b] =3D (Known), /* UD2 */ + + [0x18 ... 0x1f] =3D (Known|ModRM), /* Grp16 (Hint Nop) */ + [0x20 ... 0x23] =3D (Known|ModRM), /* MOV %cr/%dr */ + + [0x30 ... 0x33] =3D (Known), /* WRMSR/RDTSC/RDMSR/RDPM= C */ + + [0x40 ... 0x4f] =3D (Known|ModRM), /* CMOVcc */ + + [0x80 ... 0x8f] =3D (Known|Branch|Imm), /* Jcc disp32 */ + [0x90 ... 0x9f] =3D (Known|ModRM), /* SETcc */ + + [0xa0 ... 0xa2] =3D (Known), /* PUSH/POP %fs/CPUID */ + [0xa3] =3D (Known|ModRM), /* BT */ + [0xa4] =3D (Known|ModRM|Imm8), /* SHLD $imm8 */ + [0xa5] =3D (Known|ModRM), /* SHLD %cl */ + + [0xa8 ... 0xa9] =3D (Known), /* PUSH/POP %gs */ + + [0xab] =3D (Known|ModRM), /* BTS */ + [0xac] =3D (Known|ModRM|Imm8), /* SHRD $imm8 */ + [0xad ... 0xaf] =3D (Known|ModRM), /* SHRD %cl/Grp15/IMUL */ + + [0xb0 ... 0xb9] =3D (Known|ModRM), /* CMPXCHG/LSS/BTR/LFS/LG= S/MOVZxx/POPCNT/UD1 */ + [0xba] =3D (Known|ModRM|Imm8), /* Grp8 */ + [0xbb ... 0xbf] =3D (Known|ModRM), /* BTC/BSF/BSR/MOVSX */ + [0xc0 ... 0xc1] =3D (Known|ModRM), /* XADD */ + [0xc7] =3D (Known|ModRM), /* Grp9 */ + [0xc8 ... 0xcf] =3D (Known), /* BSWAP */ + }; + + void *start =3D ip, *rel =3D NULL; + unsigned int opc, rel_sz =3D 0; + uint8_t b, d, rex =3D 0, osize =3D 4; + +#define OPC_TWOBYTE (1 << 8) + + /* Mutates IP, uses END. */ +#define FETCH(ty) \ + ({ \ + ty _val; \ + \ + if ( (ip + sizeof(ty)) > end ) \ + goto overrun; \ + _val =3D *(ty *)ip; \ + ip +=3D sizeof(ty); \ + _val; \ + }) + + for ( ;; ) /* Prefixes */ + { + switch ( b =3D FETCH(uint8_t) ) + { + case 0x26: /* ES override */ + case 0x2e: /* CS override */ + case 0x36: /* DS override */ + case 0x3e: /* SS override */ + case 0x64: /* FS override */ + case 0x65: /* GS override */ + case 0xf0: /* LOCK */ + case 0xf2: /* REPNE */ + case 0xf3: /* REP */ + break; + + case 0x66: /* Operand size override */ + osize =3D 2; + break; + + /* case 0x67: Address size override, not implemented */ + + case 0x40 ... 0x4f: /* REX */ + rex =3D b; + continue; + + default: + goto prefixes_done; + } + rex =3D 0; /* REX cancelled by subsequent legacy prefix. */ + } + prefixes_done: + + if ( rex & REX_W ) + osize =3D 8; + + /* Fetch the main opcode byte(s) */ + if ( b =3D=3D 0x0f ) + { + b =3D FETCH(uint8_t); + opc =3D OPC_TWOBYTE | b; + + d =3D twobyte[b]; + } + else + { + opc =3D b; + d =3D onebyte[b]; + } + + if ( unlikely(!(d & Known)) ) + goto unknown; + + if ( d & ModRM ) + { + uint8_t modrm =3D FETCH(uint8_t); + uint8_t mod =3D modrm >> 6; + uint8_t reg =3D (modrm >> 3) & 7; + uint8_t rm =3D modrm & 7; + + /* ModRM/SIB decode */ + if ( mod =3D=3D 0 && rm =3D=3D 5 ) /* RIP relative */ + { + rel =3D ip; + rel_sz =3D 4; + FETCH(int32_t); + } + else if ( mod !=3D 3 && rm =3D=3D 4 ) /* SIB */ + { + uint8_t sib =3D FETCH(uint8_t); + uint8_t base =3D sib & 7; + + if ( mod =3D=3D 0 && base =3D=3D 5 ) + goto disp32; + } + + if ( mod =3D=3D 1 ) /* disp8 */ + FETCH(int8_t); + else if ( mod =3D=3D 2 ) /* disp32 */ + { + disp32: + FETCH(int32_t); + } + + /* ModRM based decode adjustements */ + switch ( opc ) + { + case 0xc7: /* Grp11 XBEGIN is a near direct branch. */ + if ( modrm =3D=3D 0xf8 ) + d |=3D Branch; + break; + + case 0xf6: /* Grp3 TEST(s) have extra Imm8 */ + if ( reg =3D=3D 0 || reg =3D=3D 1 ) + d |=3D Imm8; + break; + + case 0xf7: /* Grp3 TEST(s) have extra Imm */ + if ( reg =3D=3D 0 || reg =3D=3D 1 ) + d |=3D Imm; + break; + } + } + + if ( d & Branch ) + { + /* + * We don't tolerate 66-prefixed call/jmp in alternatives. Some a= re + * genuinely decoded differently between Intel and AMD CPUs. + * + * We also don't implement APX instructions, so don't have to cope + * with JMPABS which is the first branch to have an 8-byte immedia= te. + */ + if ( osize < 4 ) + goto bad_osize; + + rel =3D ip; + rel_sz =3D (d & Imm8) ? 1 : 4; + } + + if ( d & (Imm | Imm8 | Moffs) ) + { + if ( d & Imm8 ) + osize =3D 1; + else if ( d & Moffs ) + osize =3D 8; + else if ( osize =3D=3D 8 && !(opc >=3D 0xb8 && opc <=3D 0xbf) ) + osize =3D 4; + + switch ( osize ) + { + case 1: FETCH(uint8_t); break; + case 2: FETCH(uint16_t); break; + case 4: FETCH(uint32_t); break; + case 8: FETCH(uint64_t); break; + default: goto bad_osize; + } + } + + return (x86_decode_lite_t){ ip - start, rel_sz, rel }; + + bad_osize: + printk(XENLOG_ERR "%s() Bad osize %u in %*ph\n", + __func__, osize, + (int)(unsigned long)(end - start), start); + return (x86_decode_lite_t){ 0, 0, NULL }; + + unknown: + printk(XENLOG_ERR "%s() Unknown opcode in %*ph <%02x> %*ph\n", + __func__, + (int)(unsigned long)(ip - 1 - start), start, b, + (int)(unsigned long)(end - ip), ip); + return (x86_decode_lite_t){ 0, 0, NULL }; + + overrun: + printk(XENLOG_ERR "%s() Decode overrun, got %*ph\n", + __func__, + (int)(unsigned long)(end - start), start); + return (x86_decode_lite_t){ 0, 0, NULL }; + +#undef FETCH +} diff --git a/xen/arch/x86/x86_emulate/x86_emulate.h b/xen/arch/x86/x86_emul= ate/x86_emulate.h index 0fd20747dc43..566a8297d8a5 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.h +++ b/xen/arch/x86/x86_emulate/x86_emulate.h @@ -835,4 +835,18 @@ static inline void x86_emul_reset_event(struct x86_emu= late_ctxt *ctxt) ctxt->event =3D (struct x86_event){}; } =20 +/* + * x86_decode_lite(). Very minimal decoder for managing alternatives. + * + * @len is 0 on error, or nonzero on success. If the instruction has a + * relative field, @rel_sz is nonzero, and @rel points at the field. + */ +typedef struct { + uint8_t len; + uint8_t rel_sz; /* bytes: 0, 1 or 4 */ + void *rel; +} x86_decode_lite_t; + +x86_decode_lite_t x86_decode_lite(void *ip, void *end); + #endif /* __X86_EMULATE_H__ */ --=20 2.39.5 From nobody Thu Aug 13 09:24:11 2026 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=reject dis=none) header.from=citrix.com ARC-Seal: i=1; a=rsa-sha256; t=1785741635; cv=none; d=zohomail.com; s=zohoarc; b=QeAMroJONDCdAF3FTw/mv+7lH6EP96KTKzkl8Brp1KSAUGUG/GIb6R+3nNVrvX8z64/gMiYbu3pev3AzL3HhjcMXOs6isv78L1SHzF0L2jCVeBsZVOHt+aUSVW2GkqGoqH6t4F0QGY1wlBpaU4C6cmO5YeWuDPjALEz3yWrU+9E= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785741635; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=gMKVONwVKWbxkNk3T1xy4QQFBmudUjsDlfFhaJQN3QA=; b=etItpVU+5SaHHOwMNektuifRGXqgZiEzWpB0tqmgBW3PAKT6vhoKkztCLpkUuBSTkLFW3bjdbqujxwcK18lT4C5PILEy/GDGSh8oWF59VjHAs/YuOED5+ldq5OF2zpPnPvgwsqcMBpAcoVmfjtJ5JwBk9MB45mviX5vWlMeBsQs= 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=reject dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1785741635614535.3963538969341; Mon, 3 Aug 2026 00:20:35 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1381227.1624802 (Exim 4.92) (envelope-from ) id 1wqmy8-000254-3m; Mon, 03 Aug 2026 07:20:16 +0000 Received: by outflank-mailman (output) from mailman id 1381227.1624802; Mon, 03 Aug 2026 07:20:16 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wqmy7-000241-PW; Mon, 03 Aug 2026 07:20:15 +0000 Received: by outflank-mailman (input) for mailman id 1381227; Mon, 03 Aug 2026 07:20:14 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wqmy6-0001jg-4z for xen-devel@lists.xenproject.org; Mon, 03 Aug 2026 07:20:14 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wqmy5-003y8B-Hf for xen-devel@lists.xenproject.org; Mon, 03 Aug 2026 09:20:13 +0200 Received: from [10.42.69.3] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a704126-bab6-0a2a0a5309dd-0a2a4503b0a8-16 for ; Mon, 03 Aug 2026 09:20:13 +0200 Received: from [209.85.128.48] (helo=mail-wm1-f48.google.com) by tlsNG-33051d.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a70412d-fae8-0a2a45030019-d1558030ec2b-3 for ; Mon, 03 Aug 2026 09:20:13 +0200 Received: by mail-wm1-f48.google.com with SMTP id 5b1f17b1804b1-4954dff6536so11880315e9.0 for ; Mon, 03 Aug 2026 00:20:13 -0700 (PDT) Received: from localhost.localdomain (host-78-146-248-75.as13285.net. [78.146.248.75]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49807b85be7sm254687935e9.2.2026.08.03.00.20.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 03 Aug 2026 00:20:11 -0700 (PDT) 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" Authentication-Results: eu.smtp.expurgate.cloud; dkim=pass header.s=google header.d=citrix.com header.i="@citrix.com" header.h="Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=citrix.com; s=google; t=1785741613; x=1786346413; darn=lists.xenproject.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=gMKVONwVKWbxkNk3T1xy4QQFBmudUjsDlfFhaJQN3QA=; b=OW9ILTgoJECRpkGok21bENgd6gRtTiP29It/wLi0XXLv8hGTGSnZirCFtqhHFvnKr8 EupYblfooM4MTINs46ZYNObtZXSIhpTsjIrlZ3tgAsfodMB8JM+UXfzSB+iDneJVS2AM M93cM4peIfJya3p0K81xcpq1livvj7GBjRfQM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785741613; x=1786346413; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=gMKVONwVKWbxkNk3T1xy4QQFBmudUjsDlfFhaJQN3QA=; b=lZ6oifkWx02Z7Vp6prfMaz/xnlwf0N7uL63aeLzfmL/g0zVhYce+5lmbOoU9okP03d q+UWENdFw01N1m6h3V2tIBItG69jf2v8eqE/s9quZ+y8pQFG6wITTtAzthu7ilaAta53 CIe34WFxqgVwCfE8kXWJJVYd7rnzz4DCJTtd3zsOb5ZzguG11Q7FgZhDgMVhMEmdbVIH Jw9JAHpAVbpP6qUUB7rT+peq13zVoVs84SXt/o0vsjispVRO+jjsJa4kBXo2A26kNOcz pAL8aUBX/qua9ZSeLptj3/qT7C2om4DZDUw59qtrdCK1HSSAeT/xw7jm9PJqR8VvV5oA f2dQ== X-Gm-Message-State: AOJu0YxLOTmWAVCAh1jXcuhHdWir2pKL/ozh2S4fN30u3Y+s2tNFa2UX vprwfJWDHCEU1kpmn59d+UtepYmUkXA4GF5ban2p+Zx5j5neQS91X/6Ccc/yq3luTS0hR+V/Aix LvMfH X-Gm-Gg: AR+sD11U+JuzZDDXeYaFRe1xeh98XKKkcaEYejJ5kG6YSrItCCrL9wV/WzchxelvL13 vcVSf59s37YxNy1oPdHvVPiMJ7yNDsTXXVIbGlpkF9Y4ZsCGs5CoD2Chsn8XqBCAonBglgXPKhj Ikg1WQd9/S/yiuZ9fEPvVKaRJ0eoNcWwgXhTBkTl1oL0FLgu0utln94AWdAxZ6Kbg8iUiJyjjMd k9MTpEo1ckEk/y1yz5a28q1bWcigwBOTm6D7FMnnpdfmLCfPEYumOhSIQVycqd09SjoJBaIcCWc ZlE5+gOwgXQhC7O1H6ArBcjqvQkAyF8c5bnBVxB1bDDStnYJjxGo2m20kSKw5Jc9qRhMQbH5qKy h925xNP85fxpbXdmep0hLFupnqA1KEY2mOnBacW5vihgEXRjGr7EI793xCY8SLnztkar+LO2j4y p3LKiQDCS7hOVmEf+LX0zcaD69tP726JyOfPIvrkOiVAT/ntcW2kgEgfEKdfbFeOXhDifmgZJnp ArfmmjGmG6CaAU56cAxoNGVJNUIYI9PTeyn8wc= X-Received: by 2002:a05:600c:4ec9:b0:495:62bc:a022 with SMTP id 5b1f17b1804b1-4980c67474amr156128365e9.13.1785741612311; Mon, 03 Aug 2026 00:20:12 -0700 (PDT) From: Andrew Cooper To: Xen-devel Cc: Andrew Cooper , Jan Beulich , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= , Teddy Astie Subject: [PATCH v3 2/5] tests/x86: Introduce a userspace test harness for x86_decode_lite() Date: Mon, 3 Aug 2026 08:20:03 +0100 Message-Id: <20260803072006.9678-3-andrew.cooper3@citrix.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260803072006.9678-1-andrew.cooper3@citrix.com> References: <20260803072006.9678-1-andrew.cooper3@citrix.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-purgate-ID: tlsNG-33051d/1785741613-6F0C94E9-0D410C2D/0/0 X-purgate-type: clean X-purgate-size: 30806 X-ZohoMail-DKIM: pass (identity @citrix.com) X-ZM-MESSAGEID: 1785741636467158500 All the interesting behaviour is in insns.S. There are 4 interesting cases; "not an instruction we tolerate", and one we= do tolerate, split by no relation, disp8 or disp32. The DECL()/END() macros start and terminate the tests_*[] arrays used by C. Between DECL()/END(), a macro named _ adds an entry into the array, includi= ng a name and the length of the instruction according to the assembler, while being as visually unintrusive as possible. Plain labels are ad-hoc and there to aid legibility during disassembly. In= a couple of cases, the macro named n (for name) allows for choosing a name manually, and is used for cases where the assembler doesn't like the mnemon= ic. Clang IAS doesn't like the convience macro, and Binutils of around 2.30 don= 't like sysexitl or movsxd with a 32bit operand. As it's only Ubuntu 18.04 affected by this, skip building the harness in old environments. Signed-off-by: Andrew Cooper --- CC: Jan Beulich CC: Roger Pau Monn=C3=A9 CC: Teddy Astie v3: * Force disable Clang IAS. It doesn't like the _ macro. * Support 32bit builds v2: * New --- tools/tests/Makefile | 1 + tools/tests/x86-decode-lite/.gitignore | 1 + tools/tests/x86-decode-lite/Makefile | 56 ++ tools/tests/x86-decode-lite/insns.S | 703 ++++++++++++++++++++++ tools/tests/x86-decode-lite/macro-magic.h | 62 ++ tools/tests/x86-decode-lite/main.c | 111 ++++ tools/tests/x86-decode-lite/x86-emulate.h | 27 + 7 files changed, 961 insertions(+) create mode 100644 tools/tests/x86-decode-lite/.gitignore create mode 100644 tools/tests/x86-decode-lite/Makefile create mode 100644 tools/tests/x86-decode-lite/insns.S create mode 100644 tools/tests/x86-decode-lite/macro-magic.h create mode 100644 tools/tests/x86-decode-lite/main.c create mode 100644 tools/tests/x86-decode-lite/x86-emulate.h diff --git a/tools/tests/Makefile b/tools/tests/Makefile index fc0ed8091510..ca4f0c707638 100644 --- a/tools/tests/Makefile +++ b/tools/tests/Makefile @@ -14,6 +14,7 @@ SUBDIRS-y +=3D xenstore =20 SUBDIRS-$(CONFIG_X86) +=3D cpu-policy SUBDIRS-$(CONFIG_X86) +=3D tsx +SUBDIRS-$(CONFIG_X86) +=3D x86-decode-lite ifneq ($(clang),y) SUBDIRS-$(CONFIG_X86) +=3D x86_emulator endif diff --git a/tools/tests/x86-decode-lite/.gitignore b/tools/tests/x86-decod= e-lite/.gitignore new file mode 100644 index 000000000000..e726b493c993 --- /dev/null +++ b/tools/tests/x86-decode-lite/.gitignore @@ -0,0 +1 @@ +test-x86-decode-lite diff --git a/tools/tests/x86-decode-lite/Makefile b/tools/tests/x86-decode-= lite/Makefile new file mode 100644 index 000000000000..dc33d5fd173a --- /dev/null +++ b/tools/tests/x86-decode-lite/Makefile @@ -0,0 +1,56 @@ +XEN_ROOT =3D $(CURDIR)/../../.. +include $(XEN_ROOT)/tools/Rules.mk + +TARGET :=3D + +# Clang IAS doesn't like the convenience macros we use +$(call cc-option-add,CFLAGS,CC,-no-integrated-as) + +# Binutils around 2.30 have mutually exclusive expectations of instruction +# suffix validities compared to later versions. Among the distro we test, +# this only excludes Ubuntu 18.04. +ifeq ($(shell echo 'asm(".code64;sysexitl");' | $(CC) -x c -c -o /dev/null= 2>/dev/null - && echo y),y) +TARGET +=3D test-x86-decode-lite +endif + +.PHONY: all +all: $(TARGET) + +.PHONY: run +run: $(TARGET) + ./$< + +.PHONY: clean +clean: + $(RM) -- *.o $(TARGET) $(DEPS_RM) + +.PHONY: distclean +distclean: clean + $(RM) -- *~ + +.PHONY: install +install: all + $(INSTALL_DIR) $(DESTDIR)$(LIBEXEC_BIN)/tests + $(if $(TARGET),$(INSTALL_PROG) $(TARGET) $(DESTDIR)$(LIBEXEC_BIN)/tests) + +.PHONY: uninstall +uninstall: + $(RM) -- $(DESTDIR)$(LIBEXEC_BIN)/$(TARGET) + +.PHONY: uninstall +uninstall: + +vpath decode-lite.c $(XEN_ROOT)/xen/arch/x86/x86_emulate + +CFLAGS +=3D $(CFLAGS_xeninclude) -I. -I$(XEN_ROOT)/xen/arch/x86 +CFLAGS +=3D $(APPEND_CFLAGS) + + +LDFLAGS +=3D $(APPEND_LDFLAGS) + +%.o: Makefile + +$(TARGET): main.o insns.o decode-lite.o + $(CC) -o $@ $^ $(LDFLAGS) + +-include $(DEPS_INCLUDE) diff --git a/tools/tests/x86-decode-lite/insns.S b/tools/tests/x86-decode-l= ite/insns.S new file mode 100644 index 000000000000..8b299cfb594e --- /dev/null +++ b/tools/tests/x86-decode-lite/insns.S @@ -0,0 +1,703 @@ +#include "macro-magic.h" + + .code64 + + .allow_index_reg + + .text + +DECL(tests_rel0) +modrm: + /* Mod=3D0, Reg=3D0, RM {0..f} */ + _ add %al, (%rax) + _ add %al, (%rcx) + _ add %al, (%rdx) + _ add %al, (%rbx) + _ add %al, (%rsp) /* SIB */ + /*add %al, (%rbp) RIP --> tests_rel4 */ + _ add %al, (%rsi) + _ add %al, (%rdi) + _ add %al, (%r8) + _ add %al, (%r9) + _ add %al, (%r10) + _ add %al, (%r11) + _ add %al, (%r12) /* SIB */ + /*add %al, (%r13) RIP --> tests_rel4 */ + _ add %al, (%r14) + _ add %al, (%r15) + + /* Mod=3D1, Reg=3D0, RM {0..f} */ + _ add %al, 0x01(%rax) + _ add %al, 0x01(%rcx) + _ add %al, 0x01(%rdx) + _ add %al, 0x01(%rbx) + _ add %al, 0x01(%rsp) /* SIB */ + _ add %al, 0x01(%rbp) + _ add %al, 0x01(%rsi) + _ add %al, 0x01(%rdi) + _ add %al, 0x01(%r8) + _ add %al, 0x01(%r9) + _ add %al, 0x01(%r10) + _ add %al, 0x01(%r11) + _ add %al, 0x01(%r12) /* SIB */ + _ add %al, 0x01(%r13) + _ add %al, 0x01(%r14) + _ add %al, 0x01(%r15) + + /* Mod=3D2, Reg=3D0, RM {0..f} */ + _ add %al, 0x7f000001(%rax) + _ add %al, 0x7f000001(%rcx) + _ add %al, 0x7f000001(%rdx) + _ add %al, 0x7f000001(%rbx) + _ add %al, 0x7f000001(%rsp) /* SIB */ + _ add %al, 0x7f000001(%rbp) + _ add %al, 0x7f000001(%rsi) + _ add %al, 0x7f000001(%rdi) + _ add %al, 0x7f000001(%r8) + _ add %al, 0x7f000001(%r9) + _ add %al, 0x7f000001(%r10) + _ add %al, 0x7f000001(%r11) + _ add %al, 0x7f000001(%r12) /* SIB */ + _ add %al, 0x7f000001(%r13) + _ add %al, 0x7f000001(%r14) + _ add %al, 0x7f000001(%r15) + + /* Mod=3D3, Reg=3D0, RM {0..f} */ + _ add %al, %al + _ add %al, %cl + _ add %al, %dl + _ add %al, %bl + _ add %al, %ah + _ add %al, %ch + _ add %al, %dh + _ add %al, %dl + _ add %al, %r8b + _ add %al, %r9b + _ add %al, %r10b + _ add %al, %r11b + _ add %al, %r12b + _ add %al, %r13b + _ add %al, %r14b + _ add %al, %r15b + +sib: + /* Mod=3D0, Reg=3D0, RM=3D4, SIB S=3D3, I=3D0, B {0..f} */ + _ add %al, (%rax, %rax, 8) + _ add %al, (%rcx, %rax, 8) + _ add %al, (%rdx, %rax, 8) + _ add %al, (%rbx, %rax, 8) + _ add %al, (%rsp, %rax, 8) + _ add %al, ( , %rax, 8) /* "none", %rbp encoded with mod=3D1/2 = */ + _ add %al, (%rsi, %rax, 8) + _ add %al, (%rdi, %rax, 8) + _ add %al, (%r8, %rax, 8) + _ add %al, (%r9, %rax, 8) + _ add %al, (%r10, %rax, 8) + _ add %al, (%r11, %rax, 8) + _ add %al, (%r12, %rax, 8) + _ rex.b add %al,(,%rax, 8) /* "none", %r13 encoded with mod=3D1/2 = */ + _ add %al, (%r14, %rax, 8) + _ add %al, (%r15, %rax, 8) + + /* Mod=3D1, Reg=3D0, RM=3D4, SIB S=3D3, I=3D0, B {0..f} */ + _ add %al, 0x01(%rax, %rax, 8) + _ add %al, 0x01(%rcx, %rax, 8) + _ add %al, 0x01(%rdx, %rax, 8) + _ add %al, 0x01(%rbx, %rax, 8) + _ add %al, 0x01(%rsp, %rax, 8) + _ add %al, 0x01(%rbp, %rax, 8) + _ add %al, 0x01(%rsi, %rax, 8) + _ add %al, 0x01(%rdi, %rax, 8) + _ add %al, 0x01(%r8, %rax, 8) + _ add %al, 0x01(%r9, %rax, 8) + _ add %al, 0x01(%r10, %rax, 8) + _ add %al, 0x01(%r11, %rax, 8) + _ add %al, 0x01(%r12, %rax, 8) + _ add %al, 0x01(%r13, %rax, 8) + _ add %al, 0x01(%r14, %rax, 8) + _ add %al, 0x01(%r15, %rax, 8) + + /* Mod=3D2, Reg=3D0, RM=3D4, SIB S=3D3, I=3D0, B {0..f} */ + _ add %al, 0x7f000001(%rax, %rax, 8) + _ add %al, 0x7f000001(%rcx, %rax, 8) + _ add %al, 0x7f000001(%rdx, %rax, 8) + _ add %al, 0x7f000001(%rbx, %rax, 8) + _ add %al, 0x7f000001(%rsp, %rax, 8) + _ add %al, 0x7f000001(%rbp, %rax, 8) + _ add %al, 0x7f000001(%rsi, %rax, 8) + _ add %al, 0x7f000001(%rdi, %rax, 8) + _ add %al, 0x7f000001(%r8, %rax, 8) + _ add %al, 0x7f000001(%r9, %rax, 8) + _ add %al, 0x7f000001(%r10, %rax, 8) + _ add %al, 0x7f000001(%r11, %rax, 8) + _ add %al, 0x7f000001(%r12, %rax, 8) + _ add %al, 0x7f000001(%r13, %rax, 8) + _ add %al, 0x7f000001(%r14, %rax, 8) + _ add %al, 0x7f000001(%r15, %rax, 8) + + /* Mod=3D0, Reg=3D0, RM=3D4, SIB S=3D3, I=3D4, B {0..f} */ + _ add %al, (%rax, %riz, 8) + _ add %al, (%rcx, %riz, 8) + _ add %al, (%rdx, %riz, 8) + _ add %al, (%rbx, %riz, 8) + _ add %al, (%rsp, %riz, 8) + _ add %al, ( , %riz, 8) /* %rbp encoded with mod=3D1/2 */ + _ add %al, (%rsi, %riz, 8) + _ add %al, (%rdi, %riz, 8) + _ add %al, (%r8, %riz, 8) + _ add %al, (%r9, %riz, 8) + _ add %al, (%r10, %riz, 8) + _ add %al, (%r11, %riz, 8) + _ add %al, (%r12, %riz, 8) + _ rex.b add %al,(,%riz, 8) /* %r13 encoded with mod=3D1/2 */ + _ add %al, (%r14, %riz, 8) + _ add %al, (%r15, %riz, 8) + + /* Mod=3D1, Reg=3D0, RM=3D4, SIB S=3D3, I=3D4, B {0..f} */ + _ add %al, 0x01(%rax, %riz, 8) + _ add %al, 0x01(%rcx, %riz, 8) + _ add %al, 0x01(%rdx, %riz, 8) + _ add %al, 0x01(%rbx, %riz, 8) + _ add %al, 0x01(%rsp, %riz, 8) + _ add %al, 0x01(%rbp, %riz, 8) + _ add %al, 0x01(%rsi, %riz, 8) + _ add %al, 0x01(%rdi, %riz, 8) + _ add %al, 0x01(%r8, %riz, 8) + _ add %al, 0x01(%r9, %riz, 8) + _ add %al, 0x01(%r10, %riz, 8) + _ add %al, 0x01(%r11, %riz, 8) + _ add %al, 0x01(%r12, %riz, 8) + _ add %al, 0x01(%r13, %riz, 8) + _ add %al, 0x01(%r14, %riz, 8) + _ add %al, 0x01(%r15, %riz, 8) + + /* Mod=3D2, Reg=3D0, RM=3D4, SIB S=3D3, I=3D4, B {0..f} */ + _ add %al, 0x7f000001(%rax, %riz, 8) + _ add %al, 0x7f000001(%rcx, %riz, 8) + _ add %al, 0x7f000001(%rdx, %riz, 8) + _ add %al, 0x7f000001(%rbx, %riz, 8) + _ add %al, 0x7f000001(%rsp, %riz, 8) + _ add %al, 0x7f000001(%rbp, %riz, 8) + _ add %al, 0x7f000001(%rsi, %riz, 8) + _ add %al, 0x7f000001(%rdi, %riz, 8) + _ add %al, 0x7f000001(%r8, %riz, 8) + _ add %al, 0x7f000001(%r9, %riz, 8) + _ add %al, 0x7f000001(%r10, %riz, 8) + _ add %al, 0x7f000001(%r11, %riz, 8) + _ add %al, 0x7f000001(%r12, %riz, 8) + _ add %al, 0x7f000001(%r13, %riz, 8) + _ add %al, 0x7f000001(%r14, %riz, 8) + _ add %al, 0x7f000001(%r15, %riz, 8) + + .macro alu_ops op + _ \op %al, (%rax) + _ \op %eax, (%rax) + _ \op (%rax), %al + _ \op (%rax), %eax + _ \op $1, %al + _ \op $0x7f000001, %eax + + /* Vary osize on imm fields */ + _ data16 \op $1, %al + _ rex.w \op $1, %al + _ data16 rex.w \op $1, %al + + _ \op $0x7f01, %ax + _ \op $0x7f000001, %rax + _ data16 \op $0x7f000001, %rax + .endm + +onebyte_row_0x: + alu_ops add + alu_ops or + +onebyte_row_1x: + alu_ops adc + alu_ops sbb + +onebyte_row_2x: + alu_ops and + .code32 + _ es nop + .code64 + alu_ops sub + _ cs nop + +onebyte_row_3x: + alu_ops xor + .code32 + _ ss nop + .code64 + alu_ops cmp + _ ds nop + +/* onebyte_row_4x --> rex prefixes */ + +onebyte_row_5x: + _ push %rax + _ push %rcx + _ push %rdx + _ push %rbx + _ push %rsp + _ push %rbp + _ push %rsi + _ push %rdi + _ pop %rax + _ pop %rcx + _ pop %rdx + _ pop %rbx + _ pop %rsp + _ pop %rbp + _ pop %rsi + _ pop %rdi + +onebyte_row_6x: + /*pusha,popa,bound --> not supported */ + _ movsxd (%rax), %eax + _ movslq (%rax), %rax + _ fs nop + _ gs nop + _ data16 nop + /* addr32 --> not supported */ + _ pushq $0x7f000001 + _ pushw $0x7f01 + _ rex.w pushq $0x7f000001 + _ imul $0x7f01, %ax, %ax + _ imul $0x7f000001, %eax, %eax + _ imul $0x7f000001, %rax, %rax + _ pushq $0 + _ pushw $0 + _ rex.w pushq $0 + _ imul $0, %ax, %ax + _ imul $0, %eax, %eax + _ imul $0, %rax, %rax + _ insb + _ insw + _ insl + _ outsb + _ outsw + _ outsl + +/* onebyte_row_7x: --> Jcc disp8 */ + +onebyte_row_8x: + _ add $0, %cl /* Grp1 */ + _ data16 add $0, %cl + _ rex.w add $0, %cl + _ add $0x7f01, %cx + _ add $0x7f000001, %ecx + _ add $0x7f000001, %rcx + _ add $0, %cx + _ add $0, %ecx + _ add $0, %rcx + _ test %cl, %cl + _ test %ecx, %ecx + _ xchg %cl, %cl + _ xchg %ecx, %ecx + _ mov %cl, (%rax) + _ mov %ecx, (%rax) + _ mov (%rax), %cl + _ mov (%rax), %ecx + _ mov %cs, (%rax) + _ lea (%rax), %eax + _ mov (%rax), %cs + /*pop mem --> Grp1a, Not supported (XOP prefix adjacent) */ + +onebyte_row_9x: + _ nop + _ pause + _ xchg %ax, %ax + _ xchg %eax, %eax + _ xchg %rax, %rax + _ rex.w xchg %rax, %rax + _ cltq + _ cqto + _ wait + _ pushf + _ popf + _ sahf + _ lahf + +onebyte_row_ax: + _ mov 0x8000000000000001, %al + _ mov 0x8000000000000001, %ax + _ mov 0x8000000000000001, %eax + _ mov 0x8000000000000001, %rax + _ mov %al, 0x8000000000000001 + _ mov %ax, 0x8000000000000001 + _ mov %eax, 0x8000000000000001 + _ mov %rax, 0x8000000000000001 + _ movsb + _ movsl + _ cmpsb + _ cmpsl + _ test $0, %al + _ test $0x80000001, %eax + _ test $0x7f000001, %rax + _ stosb + _ stosl + _ lodsb + _ lodsl + _ scasb + _ scasl + +onebyte_row_bx: + _ mov $0, %al + _ mov $0, %cl + _ mov $0x7f01, %ax + _ mov $0x7f01, %cx + _ mov $0x7f000001, %eax + _ mov $0x7f000001, %ecx + _ mov $0x7f00000000000001, %rax + _ mov $0x7f00000000000001, %rcx + +onebyte_row_cx: + _ rol $0, %al /* Grp2 */ + _ rol $0, %ax + _ rol $0, %eax + _ rol $0, %rax + /*ret $0 --> not supported */ + _ ret + /*les,lds --> not supported */ + _ movb $0, (%rax) /* Grp11 */ + _ movw $0, (%rax) + _ movl $0, (%rax) + _ movq $0, (%rax) + /*xbegin (Grp11) --> disp32 */ + /*enter,leave,lretq $0 --> not supported */ + _ lretq + _ int3 + _ int $0 + /*into,iret --> not supported */ + +onebyte_row_dx: + _ rol $1, %al /* Grp2 */ + _ rol $1, %ax + _ rol $1, %eax + _ rol $1, %rax + _ rol %cl, %al + _ rol %cl, %ax + _ rol %cl, %eax + _ rol %cl, %rax + /*aam,aad --> not supported */ + n "udb" .byte 0xd6 + /*xlat,d8...df --> not supported */ + +onebyte_row_ex: + /*loop{ne,e,},jrcxz --> not supported */ + _ in $0, %al + _ in $0, %eax + _ out %al, $0 + _ out %eax, $0 + /*call,jmp --> disp32 */ + /*ljmp --> not supported */ + /*jmp --> disp8 */ + _ in %dx, %al + _ in %dx, %eax + _ out %al, %dx + _ out %eax, %dx + +onebyte_row_fx: + _ lock addb $0, (%rax) + n "icebp" .byte 0xf1 /* icebp */ + _ repne nop + _ repe nop + _ hlt + _ cmc + _ test $0, %cl /* Grp3, /0 has extra Imm{8,} */ + _ not %cl + _ test $0x7f01, %cx + _ not %cx + _ test $0x7f000001, %ecx + _ not %ecx + _ test $0x7f000001, %rcx + _ not %rcx + _ clc + _ stc + _ cli + _ sti + _ cld + _ std + _ inc %cl /* Grp4 */ + _ dec %cl + _ inc %ecx /* Grp5 */ + _ dec %ecx + _ call *(%rax) + _ lcall *(%rax) + _ jmp *(%rax) + _ ljmp *(%rax) + _ push (%rax) + +twobyte_row_0x: + _ sldt (%rax) /* Grp6 */ + _ sgdt (%rax) /* Grp7 */ + _ lar (%rax), %eax + _ lsl (%rax), %eax + _ ud2a + +twobyte_row_1x: + _ prefetchnta (%rax) /* Grp16 (Hint Nop) */ + _ nopl (%rax) + +twobyte_row_2x: + _ mov %cr0, %rax + _ mov %dr0, %rax + _ mov %rax, %cr0 + _ mov %rax, %dr0 + +twobyte_row_3x: + _ wrmsr + _ rdtsc + _ rdmsr + _ rdpmc + +twobyte_row_4x: + _ cmovo (%rax), %eax + _ cmovg (%rax), %eax + +/* twobyte_row_8x: --> Jcc disp32 */ + +twobyte_row_9x: + _ seto (%rax) + _ setg (%rax) + +twobyte_row_ax: + _ push %fs + _ pop %fs + _ cpuid + _ bt %eax, (%rax) + _ shld $0, %ax, (%rax) + _ shld $0, %eax, (%rax) + _ shld $0, %rax, (%rax) + _ shld %cl, %ax, (%rax) + _ shld %cl, %eax, (%rax) + _ shld %cl, %rax, (%rax) + _ push %gs + _ pop %gs + /*rsm --> not supported */ + _ bts %eax, (%rax) + _ shrd $0, %ax, (%rax) + _ shrd $0, %eax, (%rax) + _ shrd $0, %rax, (%rax) + _ shrd %cl, %ax, (%rax) + _ shrd %cl, %eax, (%rax) + _ shrd %cl, %rax, (%rax) + _ fxsave (%rax) /* Grp15 */ + _ imul (%rax), %eax + +twobyte_row_bx: + _ cmpxchg %al, (%rax) + _ cmpxchg %eax, (%rax) + _ lss (%rax), %eax + _ btr %eax, (%rax) + _ lfs (%rax), %eax + _ lgs (%rax), %eax + _ movzbl (%rax), %eax + _ movzwl (%rax), %eax + _ popcnt (%rax), %eax + _ ud1 (%rax), %eax /* Grp10 */ + _ bt $0, %ax /* Grp8 */ + _ bt $0, %eax + _ bt $0, %rax + _ btc %eax, (%rax) + _ bsf (%rax), %eax + _ bsr (%rax), %eax + _ movsbl (%rax), %eax + _ movswl (%rax), %eax + +twobyte_row_cx: + _ xadd %al, (%rax) + _ xadd %eax, (%rax) + _ cmpxchg8b (%rax) /* Grp9 */ + _ bswap %eax + _ bswap %edi + +END(tests_rel0) + +DECL(tests_rel1) +disp8: +1: + _ jo 1b + _ jno 1b + _ jb 1b + _ jae 1b + _ je 1b + _ jne 1b + _ jbe 1b + _ ja 1b + _ js 1b + _ jns 1b + _ jp 1b + _ jnp 1b + _ jl 1b + _ jge 1b + _ jle 1b + _ jg 1b + _ jmp 1b + +disp8_rex: + _ rex.w jo 1b + _ rex.w jno 1b + _ rex.w jb 1b + _ rex.w jae 1b + _ rex.w je 1b + _ rex.w jne 1b + _ rex.w jbe 1b + _ rex.w ja 1b + _ rex.w js 1b + _ rex.w jns 1b + _ rex.w jp 1b + _ rex.w jnp 1b + _ rex.w jl 1b + _ rex.w jge 1b + _ rex.w jle 1b + _ rex.w jg 1b + _ rex.w jmp 1b +END(tests_rel1) + +DECL(tests_rel4) +disp32: + _ call other_section + _ jmp other_section + _ jo other_section + _ jno other_section + _ jb other_section + _ jae other_section + _ je other_section + _ jne other_section + _ jbe other_section + _ ja other_section + _ js other_section + _ jns other_section + _ jp other_section + _ jnp other_section + _ jl other_section + _ jge other_section + _ jle other_section + _ jg other_section + _ xbegin other_section + +disp32_rex: + _ rex.w call other_section + _ rex.w jmp other_section + _ rex.w jo other_section + _ rex.w jno other_section + _ rex.w jb other_section + _ rex.w jae other_section + _ rex.w je other_section + _ rex.w jne other_section + _ rex.w jbe other_section + _ rex.w ja other_section + _ rex.w js other_section + _ rex.w jns other_section + _ rex.w jp other_section + _ rex.w jnp other_section + _ rex.w jl other_section + _ rex.w jge other_section + _ rex.w jle other_section + _ rex.w jg other_section + _ rex.w xbegin other_section + +riprel: + _ add %al, 0(%rip) + _ rex.b add %al, 0(%rip) + + _ addb $1, 0(%rip) + _ rex.b addb $1, 0(%rip) + + _ addl $0x7f000001, 0(%rip) + _ rex.b addl $0x7f000001, 0(%rip) +END(tests_rel4) + +DECL(tests_unsup) + +unsup_prefix: /* Prefixes unimplemented for simplicity. */ + _ vaddpd %zmm0, %zmm0, %zmm0 /* 0x62 EVEX */ + _ addr32 nop /* 0x67 Address size override */ + _ bextr $0, %eax, %eax /* 0x8f XOP */ + _ bextr %eax, %eax, %eax /* 0xc4 VEX3 */ + _ vaddpd %ymm0, %ymm0, %ymm0 /* 0xc5 VEX2 */ + n "jmpabs 0" .byte 0xd5, 0x00, 0xa1, 0x01, 0, 0, 0, 0, 0, 0, 0x80 = /* 0xd5 REX2 */ + _ fadds (%rax) /* 0xd8 ... 0xdf ESCAPE (x87) */ + _ femms /* 0x0f,0x0e ... 0x0f 3DNOW */ + +unsup_branch: +1: + _ loopne 1b + _ loope 1b + _ loop 1b + _ jrcxz 1b + +opsize_branch: /* 66-prefixed branches are decoded differently by vendors = */ + _ data16 call other_section + _ data16 jmp other_section + _ data16 jo other_section + _ data16 jno other_section + _ data16 jb other_section + _ data16 jae other_section + _ data16 je other_section + _ data16 jne other_section + _ data16 jbe other_section + _ data16 ja other_section + _ data16 js other_section + _ data16 jns other_section + _ data16 jp other_section + _ data16 jnp other_section + _ data16 jl other_section + _ data16 jge other_section + _ data16 jle other_section + _ data16 jg other_section + _ data16 xbegin other_section + +not_64bit: /* Not valid/encodable in 64bit mode */ + .code32 + _ push %es + _ pop %es + _ push %cs + _ push %ss + _ pop %ss + _ push %ds + _ pop %ds + _ daa + _ das + _ aaa + _ aas + _ pusha + _ popa + _ bound %eax, (%eax) + /*arpl %ax, %ax --> movsxd in 64bit mode */ + /* Grp1 */ + _ lcall $-1, $-1 + _ les (%eax), %eax + _ lds (%eax), %eax + _ into + _ aam $0 + _ aad $0 /* Also REX2, also not supported */ + _ ljmp $-1, $-1 + .code64 + +unsup_insn: /* Instructions that would complicated decode, or shouldn't be= used */ + _ ret $0 + _ enter $0, $0 + _ leave + _ lretq $0 + _ iretq + _ xlat + _ clts + _ wbinvd + _ syscall + _ sysretl + _ invd + _ sysenter + _ sysexitl + _ rsm + +END(tests_unsup) + + /* This is here to cause jmps to use their disp32 form. */ + .section .text.other_section, "ax", @progbits +other_section: + int3 + + /* Mark this file as not needing executable stacks. */ + .section .note.GNU-stack, "", @progbits diff --git a/tools/tests/x86-decode-lite/macro-magic.h b/tools/tests/x86-de= code-lite/macro-magic.h new file mode 100644 index 000000000000..b3c8aae39acd --- /dev/null +++ b/tools/tests/x86-decode-lite/macro-magic.h @@ -0,0 +1,62 @@ +#ifndef X86_DECODE_LITE_LINKAGE_H +#define X86_DECODE_LITE_LINKAGE_H + +#ifdef __i386__ +# define PTR_ALIGN 4 +# define PTR .long +#else +# define PTR_ALIGN 8 +# define PTR .quad +#endif + + +/* Start a 'struct test' array */ +.macro start_arr aname + .pushsection .data.rel.ro.\aname, "aw", @progbits + .globl \aname + .align PTR_ALIGN + .type \aname, STT_OBJECT +\aname: + .popsection + + /* Declare a macro wrapping \aname */ + .macro pushsection_arr + .pushsection .data.rel.ro.\aname, "aw", @progbits + .endm +.endm + +/* Macro 'n' to wrap the metadata of an instruction. Name can be differen= t. */ +.macro n name:req insn:vararg + /* Emit the instruction, with start & end markers. */ +.Ls\@: \insn +.Le\@: + + /* Emit \name as a string. */ + .pushsection .rodata.str1, "aMS", @progbits, 1 +.Ln\@: .asciz "\name" + .popsection + + /* Emit an entry into the array. */ + pushsection_arr + PTR .Ln\@, .Ls\@, .Le\@ - .Ls\@ + .popsection +.endm + +/* Macro '_' where the name is the instruction itself. */ +.macro _ insn:vararg + n "\insn" \insn +.endm + +/* Finish a 'struct test' array */ +.macro finish_arr aname + pushsection_arr + PTR 0, 0, 0 + .size \aname, . - \aname + .popsection + .purgem pushsection_arr +.endm + +#define DECL(aname) start_arr aname +#define END(aname) finish_arr aname + +#endif /* X86_DECODE_LITE_LINKAGE_H */ diff --git a/tools/tests/x86-decode-lite/main.c b/tools/tests/x86-decode-li= te/main.c new file mode 100644 index 000000000000..cdae7de8e90e --- /dev/null +++ b/tools/tests/x86-decode-lite/main.c @@ -0,0 +1,111 @@ +/* + * Userspace test harness for x86_decode_lite(). + */ +#include + +#include "x86-emulate.h" + +static unsigned int nr_failures; +#define fail(t, fmt, ...) \ +({ \ + const unsigned char *insn =3D (t)->ip; \ + \ + nr_failures++; \ + \ + (void)printf(" Fail '%s' [%02x", (t)->name, *insn); \ + for ( unsigned int i =3D 1; i < (t)->len; i++ ) \ + printf(" %02x", insn[i]); \ + printf("]\n"); \ + \ + (void)printf(fmt, ##__VA_ARGS__); \ +}) + +struct test { + const char *name; + void *ip; + unsigned long len; +}; + +extern const struct test +/* Defined in insns.S, ends with sentinel */ + tests_rel0[], /* No relocatable entry */ + tests_rel1[], /* disp8 */ + tests_rel4[], /* disp32 or RIP-relative */ + tests_unsup[]; /* Unsupported instructions */ + +static inline void run_tests(const struct test *tests, unsigned int rel_sz) +{ + printf("Test rel%u\n", rel_sz); + + for ( unsigned int i =3D 0; tests[i].name; ++i ) + { + const struct test *t =3D &tests[i]; + x86_decode_lite_t r; + + /* + * Don't end strictly at t->len. This provides better diagnostics= if + * too many bytes end up getting consumed. + */ + r =3D x86_decode_lite(t->ip, t->ip + /* t->len */ 20); + + if ( r.len =3D=3D 0 ) + { + fail(t, " Failed to decode instruction\n"); + + if ( r.rel_sz !=3D 0 || r.rel ) + fail(t, " Rel/sz despite no decode\n"); + + continue; + } + + if ( r.len !=3D t->len ) + { + fail(t, " Expected length %lu, got %u\n", + t->len, r.len); + continue; + } + + if ( r.rel_sz !=3D rel_sz ) + { + fail(t, " Expected relocation size %u, got %u\n", + rel_sz, r.rel_sz); + continue; + } + + if ( r.rel_sz && + (r.rel < t->ip || + r.rel > t->ip + t->len || + r.rel + r.rel_sz > t->ip + t->len) ) + { + fail(t, " Rel [%p,+%u) outside insn [%p,+%lu)\n", + r.rel, r.rel_sz, t->ip, t->len); + continue; + } + } +} + +static void run_tests_unsup(const struct test *tests) +{ + printf("Test unsup\n"); + + for ( unsigned int i =3D 0; tests[i].name; ++i ) + { + const struct test *t =3D &tests[i]; + x86_decode_lite_t r =3D x86_decode_lite(t->ip, t->ip + t->len); + + if ( r.len ) + fail(t, " Got len %u\n", r.len); + } +} + +int main(int argc, char **argv) +{ + printf("Tests for x86_decode_lite()\n"); + + run_tests(tests_rel0, 0); + run_tests(tests_rel1, 1); + run_tests(tests_rel4, 4); + run_tests_unsup(tests_unsup); + + return !!nr_failures; +} diff --git a/tools/tests/x86-decode-lite/x86-emulate.h b/tools/tests/x86-de= code-lite/x86-emulate.h new file mode 100644 index 000000000000..558dab1b768e --- /dev/null +++ b/tools/tests/x86-decode-lite/x86-emulate.h @@ -0,0 +1,27 @@ +#ifndef X86_EMULATE_H +#define X86_EMULATE_H + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define ASSERT assert + +#define printk(...) + +#define likely +#define unlikely +#define cf_check +#define init_or_livepatch +#define init_or_livepatch_const + +#include "x86_emulate/x86_emulate.h" + +#endif /* X86_EMULATE_H */ --=20 2.39.5 From nobody Thu Aug 13 09:24:11 2026 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=reject dis=none) header.from=citrix.com ARC-Seal: i=1; a=rsa-sha256; t=1785741638; cv=none; d=zohomail.com; s=zohoarc; b=MIZue9BBElL79RjbvimfdAuJrxdNMK6HJSYlLPO1dpUP+CHbEy9oyDXAocqfWH/IJhxEF0GHXo5dkcxBRrtrRFRLmXqxhZvef4Js1oPtkqguVZM5pHWmshyaHy/FquK6BaRFpR3JBjSwnZWK5jgFIcuZkjeCxXune1AEqpZK0yg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785741638; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=9oalEqncjdi9YKb26F6ASg1uy+nWQGozZLeLwjudyuk=; b=fN1nkExxcYNA+XZO76/Ad8VR0weBtD2rPptSvg8MIWeXw9ZtDy/1MX+lMgWSEtrN+a1hLPHOEOJAETL5E2sEPV9iNgeOg+N+/M/UmR2Y0xn5AYxl1qDpX4ojnaB9jh1iB1LVWilVJdNk4a9J42LAMwYPjEpr2kk0EMvmhpx7eGc= 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=reject dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1785741638179214.23660235184923; Mon, 3 Aug 2026 00:20:38 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1381226.1624795 (Exim 4.92) (envelope-from ) id 1wqmy7-0001zI-Ld; Mon, 03 Aug 2026 07:20:15 +0000 Received: by outflank-mailman (output) from mailman id 1381226.1624795; Mon, 03 Aug 2026 07:20:15 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wqmy7-0001yY-Fr; Mon, 03 Aug 2026 07:20:15 +0000 Received: by outflank-mailman (input) for mailman id 1381226; Mon, 03 Aug 2026 07:20:14 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wqmy6-0001jl-7i for xen-devel@lists.xenproject.org; Mon, 03 Aug 2026 07:20:14 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wqmy5-003y8B-Km for xen-devel@lists.xenproject.org; Mon, 03 Aug 2026 09:20:13 +0200 Received: from [10.42.69.3] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a704126-bab6-0a2a0a5309dd-0a2a4503b0a8-20 for ; Mon, 03 Aug 2026 09:20:13 +0200 Received: from [209.85.128.52] (helo=mail-wm1-f52.google.com) by tlsNG-33051d.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a70412d-fae8-0a2a45030019-d1558034ac3f-3 for ; Mon, 03 Aug 2026 09:20:13 +0200 Received: by mail-wm1-f52.google.com with SMTP id 5b1f17b1804b1-495590dde14so16957645e9.0 for ; Mon, 03 Aug 2026 00:20:13 -0700 (PDT) Received: from localhost.localdomain (host-78-146-248-75.as13285.net. [78.146.248.75]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49807b85be7sm254687935e9.2.2026.08.03.00.20.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 03 Aug 2026 00:20:12 -0700 (PDT) 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" Authentication-Results: eu.smtp.expurgate.cloud; dkim=pass header.s=google header.d=citrix.com header.i="@citrix.com" header.h="Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=citrix.com; s=google; t=1785741613; x=1786346413; darn=lists.xenproject.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=9oalEqncjdi9YKb26F6ASg1uy+nWQGozZLeLwjudyuk=; b=nXQToXflDY+GL0UfpGRRGa/mTaF3lJrALlJSTIj5pJJp4E1rr6etPaNvXifQYZvDBO pkleLegLT8CnonqfpLkYcpZ3BYoQQ3EFuN34omNUNeG+Y5tmArhhQJK3pdcuB9dBy3L4 +azacdKjGK6mWIgxSvTdUkTfG8dprXzaxbA68= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785741613; x=1786346413; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=9oalEqncjdi9YKb26F6ASg1uy+nWQGozZLeLwjudyuk=; b=Zv8366P381RA65Bu5vAzw4Il85qRvCGOqGNyPNtZkvJpgpq43aAHWyCAQliUVh7Sni YhuD16OLAXaeRfYXpJi0WlHj5uEII/ygZUp1DHoLVNS6wghot1QdjuwMBsyplwpM0kgN M29Qy6JRAGGX1Pi8/368UmaJWjVbbi2ubMFYf5qjmQO1J7C+25y1V5t8LIpKLPB1CM67 Pnl1phN59vpfq1tJG4Jp0c7AqOi5XP9s+zwRNbMjg7RvlncvVMw6/s5XcZl1LZC8v8/q ceCqrxrgLygKwebPjFK50VNJ1l/wyBgbZarSJuzjsqs9MBosPpPBA/2PS9tJQA/ypPUs akdA== X-Gm-Message-State: AOJu0YzSPvBBCyMuGX1etuv3N23UqWGaEigdgUPhjLFOZJtarKJlcbzU fUZ2PaFfwGFX5fsuvo+wVHoAIUA3KCVSupudGZ2/QcBLdMCOieX4bswIWmrjFoOs0FSle6jwI19 +v+lU9mU= X-Gm-Gg: AR+sD10/X+cB1tbPIjI8aiP1eTsAzEY3/BzenZ9AV72bJ1wgtMyHZVOczP9RDOrDQAN ax36zRNRYhL9SqJHYBXWhav8es2hzVk/znrlrEAFM7zy8Sw3C7FXLZZGPojNfH+U9r7LiroTH5c wKKXG/zlJnpEUHcDMpyY51xK7H+QBF6qE9HBSIumuLQzPdlzY2xnf55iiR2dWIwZawYr6rB9t4v EKOyTOqXUdwIt0kProMIrml0/8I+PFQHnnQvk7+lY2BJnX0u80CQoAANrW3D/RhvDtPXcmPxwDh YJG3Lr0O8OT4Q3O92DQ5iPWh53IMktsSYudVBrLNQbF3PB2wY5KB2Oqt7NO0z0uvsPMmGREsBm8 aMvSkIys8v6Wokhkg+FXr9n2h9IElM29EAzp0/ZA1pBzFrdldTsNy14ERprdhrJNd673UREg5JM bu/JJu0emVB0hNZ5RbGz0SrVexZ6Uh2I7iNPfwrEu8ExeirnES+Bj6LP1Cfx5Ph2bFrPYSD3qyY Yla8wm7LLmkxbPTq0E53vKIvTaKeqQ/o+FghKo= X-Received: by 2002:a05:600c:4685:b0:493:e365:7630 with SMTP id 5b1f17b1804b1-4980eb66053mr147150085e9.14.1785741612890; Mon, 03 Aug 2026 00:20:12 -0700 (PDT) From: Andrew Cooper To: Xen-devel Cc: Andrew Cooper , Jan Beulich , Jan Beulich , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= , Teddy Astie Subject: [PATCH v3 3/5] x86/alternative: Walk all replacements during self tests Date: Mon, 3 Aug 2026 08:20:04 +0100 Message-Id: <20260803072006.9678-4-andrew.cooper3@citrix.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260803072006.9678-1-andrew.cooper3@citrix.com> References: <20260803072006.9678-1-andrew.cooper3@citrix.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-purgate-ID: tlsNG-33051d/1785741613-758824E9-8A49664C/0/0 X-purgate-type: clean X-purgate-size: 2998 X-ZohoMail-DKIM: pass (identity @citrix.com) X-ZM-MESSAGEID: 1785741640102158500 When self tests are active, walk all alternative replacements with x86_decode_lite(). This checks that we can decode all instructions, and also lets us check that disp8's don't leave the replacement block as such a case will definitely malfunction. Signed-off-by: Andrew Cooper Reviewed-by: Jan Beulich --- CC: Jan Beulich CC: Roger Pau Monn=C3=A9 CC: Teddy Astie v2: * Rebase over API changes in patch 1 * Use +%lu and drop casts * Swap to CONFIG_SELF_TESTS --- xen/arch/x86/alternative.c | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/xen/arch/x86/alternative.c b/xen/arch/x86/alternative.c index 5ed0c2672589..fd03147bdd12 100644 --- a/xen/arch/x86/alternative.c +++ b/xen/arch/x86/alternative.c @@ -16,6 +16,7 @@ #include #include #include +#include #include =20 #define MAX_PATCH_LEN (255-1) @@ -586,6 +587,57 @@ static void __init _alternative_instructions(unsigned = int what) void __init alternative_instructions(void) { arch_init_ideal_nops(); + + /* + * Walk all replacement instructions with x86_decode_lite(). This che= cks + * both that we can decode all instructions within the replacement, and + * that any near branch with a disp8 stays within the alternative itse= lf. + */ + if ( IS_ENABLED(CONFIG_SELF_TESTS) ) + { + struct alt_instr *a; + + for ( a =3D __alt_instructions; + a < __alt_instructions_end; ++a ) + { + void *repl =3D ALT_REPL_PTR(a); + void *ip =3D repl, *end =3D ip + a->repl_len; + + if ( !a->repl_len ) + continue; + + for ( x86_decode_lite_t res; ip < end; ip +=3D res.len ) + { + const int8_t *d8; + const void *target; + + res =3D x86_decode_lite(ip, end); + + if ( res.len =3D=3D 0 ) + { + printk("Alt for %ps [%*ph]\n", + ALT_ORIG_PTR(a), a->repl_len, repl); + panic(" Unable to decode instruction at +%lu in alter= native\n", + ip - repl); + } + + if ( res.rel_sz !=3D 1 ) + continue; + + d8 =3D res.rel; + target =3D ip + res.len + *d8; + + if ( target < repl || target > end ) + { + printk("Alt for %ps [%*ph]\n", + ALT_ORIG_PTR(a), a->repl_len, repl); + panic(" 'JMP/Jcc disp8' at +%lu leaves alternative bl= ock\n", + ip - repl); + } + } + } + } + _alternative_instructions(ALT_INSNS); } =20 --=20 2.39.5 From nobody Thu Aug 13 09:24:11 2026 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=reject dis=none) header.from=citrix.com ARC-Seal: i=1; a=rsa-sha256; t=1785741640; cv=none; d=zohomail.com; s=zohoarc; b=M4lLR/q88Ygn4gHoEZ+ZNcayG/mY4iKg5vd341iokNmPNl4iw21NIpdm2ZrymW7EjY8UEudUBa+INntsM5aAo9fx/AncaIKTcejsx6nxFuXCe0dNUeu/FO9pBU7hHAnJxmrQ0Wz1dMixaCb1qNHguI/48xSO5TAzUL3APo14ujA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785741640; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=HxkChm6nTI+5JRyuyWipeFtEAkEUxs5crJhjhmOkg8A=; b=T3sDyN+m4ZNd6fY1R0uaDtVQCGL8zzEHFAg67+fU+X0p/ayDmVnaSlCHnM2LB1IkbP8l/dIVpuS+PxuOUA1EkQluHtT0cjLIY8m7LM9+qgqErbCaG5XpwyHuwhstGZ1dGHczPHEv/Zo+xyFOKP9LpGyG9KTjP8R3PRHxwSJNAx4= 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=reject dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1785741640359564.8859700861772; Mon, 3 Aug 2026 00:20:40 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1381228.1624812 (Exim 4.92) (envelope-from ) id 1wqmy8-0002KN-OB; Mon, 03 Aug 2026 07:20:16 +0000 Received: by outflank-mailman (output) from mailman id 1381228.1624812; Mon, 03 Aug 2026 07:20:16 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wqmy8-0002Jr-F9; Mon, 03 Aug 2026 07:20:16 +0000 Received: by outflank-mailman (input) for mailman id 1381228; Mon, 03 Aug 2026 07:20:15 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wqmy7-0001uR-3K for xen-devel@lists.xenproject.org; Mon, 03 Aug 2026 07:20:15 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wqmy6-00Dk99-GY for xen-devel@lists.xenproject.org; Mon, 03 Aug 2026 09:20:14 +0200 Received: from [10.42.69.8] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a70412d-5cb7-0a2a0a5109dd-0a2a45088d92-8 for ; Mon, 03 Aug 2026 09:20:14 +0200 Received: from [209.85.221.46] (helo=mail-wr1-f46.google.com) by tlsNG-c1860d.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a70412e-f659-0a2a45080019-d155dd2ed828-3 for ; Mon, 03 Aug 2026 09:20:14 +0200 Received: by mail-wr1-f46.google.com with SMTP id ffacd0b85a97d-47fd4ee0b01so1842141f8f.2 for ; Mon, 03 Aug 2026 00:20:14 -0700 (PDT) Received: from localhost.localdomain (host-78-146-248-75.as13285.net. [78.146.248.75]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49807b85be7sm254687935e9.2.2026.08.03.00.20.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 03 Aug 2026 00:20:13 -0700 (PDT) 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" Authentication-Results: eu.smtp.expurgate.cloud; dkim=pass header.s=google header.d=citrix.com header.i="@citrix.com" header.h="Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=citrix.com; s=google; t=1785741614; x=1786346414; darn=lists.xenproject.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=HxkChm6nTI+5JRyuyWipeFtEAkEUxs5crJhjhmOkg8A=; b=mtnOI27/DhL8W/LMMi5Pb25C2MuCzmwBVCnj/1A8w/74wMnlI9QJRLIKuWjdOtDNWZ TpvdMA1Ym0MHFBtW/rvUl1SxJa5nIx2tiF9ekqXmp+mZIuFhlyTZBZyJJ1BWyX9oi8Yj wQcnOdcJPyUdtCM6FuvQqaxMyPWf68EcwkkfU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785741614; x=1786346414; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=HxkChm6nTI+5JRyuyWipeFtEAkEUxs5crJhjhmOkg8A=; b=XLy0A+Sd02KCgevNr01X8f4FkldYQoAQvhHMiiOlvz6OHzk99IBKBu8Ib6kr66StV5 fvi6L1Rm2DCLt6LBciNRjHDrUDo4Gehe3pE2vuH7u5Ls4t1KZgPHv/LvC+fTrb7NIRmC wsMyiA+rCPEEEvMSmt3NvUCgwpeeLh7cvM89MfjKaMMnr4G4eEV4ipHICx9PEpc/Se0Y ft8Cp+1JrqA9SP/3QyiEI73PQdHi1uTuWlgEVj8b45huy/6aiDDFn+dZC6aa0hXkK7K1 SnxDP5QbBtoNQye4Co5lA52i13hpP1uN4o1Cx5u9dJyD3vZVGEl69F9tgRjF83fdBIut WjJw== X-Gm-Message-State: AOJu0Yy9hUPVbCXrQ0JISwRLcwanYAyCQ+G//JOXwCS/FzVeucm3m2j/ nH7m90Qo4Lol2bzs8ToPU8KYfUeGEEvRKLRK8k0cBiYutqKarrhTlp7/hS50KEXOsGlRn2wE6PR a0X77oYA= X-Gm-Gg: AR+sD1152/KSo7BQDIqyw2hsgFwZNFwjeI5l3md4uiwfYhmfk7hNODRRRPWcZ/4JLRP oqhvwub9Dkbhs6aCJNoRYb/4zjM3xUCzfVaWDOVXXTESxN4byi7vkhus6yTU9ZleAFwjGEhtQQw v6Z0R+caXC/Xlw7Iwb1lqed/TfDxqp5p9HGH6mscr9zgKKTGK5hzN6/llgWbBLOmPbCTRU8mWF6 QBATqGZJgIaHqtt2gcXxI9mncRNGqmO2MqRxb/P0sueUlVXdIztt+3FT1JRo0rwbx9czoVGnEft 2+1vDXHvV5fqy1ArgaophwS4tEDvMU9bDt7elWIesCCIlvaHSiZvol2bduFQpHM6yqxLhYQHSS+ TpSSc4XF2fj9mu7MyS15V2jrvk2RAF5OhW48cYPhpMVS6s6e+S/uUSR0BvR23mYYTPTOU5uDnEp +N9z693E4LMo2glLveZi7aZR4+JsHd7fpJUiqln24rrFz0yOTYaAlwGgw36C6gUtebyDIxElbPJ 3Fd8OhPnBtQRbeqIhJeNrQuBaOD/eSXSC77WBs= X-Received: by 2002:a05:600d:640f:20b0:495:503f:cf9a with SMTP id 5b1f17b1804b1-4980c672adbmr145404915e9.9.1785741613604; Mon, 03 Aug 2026 00:20:13 -0700 (PDT) From: Andrew Cooper To: Xen-devel Cc: Andrew Cooper , Jan Beulich , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= , Teddy Astie Subject: [PATCH v3 4/5] x86/alternative: Relocate all insn-relative fields Date: Mon, 3 Aug 2026 08:20:05 +0100 Message-Id: <20260803072006.9678-5-andrew.cooper3@citrix.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260803072006.9678-1-andrew.cooper3@citrix.com> References: <20260803072006.9678-1-andrew.cooper3@citrix.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-purgate-ID: tlsNG-c1860d/1785741614-CD54C87B-DC0C22F6/0/0 X-purgate-type: clean X-purgate-size: 3035 X-ZohoMail-DKIM: pass (identity @citrix.com) X-ZM-MESSAGEID: 1785741642072158500 Right now, relocation of displacements is restricted to finding 0xe8/e9 as = the first byte of the replacement, but this is overly restrictive. Use x86_decode_lite() to find and adjust all insn-relative fields. As with disp8's not leaving the replacemnet block, some disp32's don't eith= er. e.g. the RSB stuffing loop. These stay unmodified. Signed-off-by: Andrew Cooper Reviewed-by: Jan Beulich --- CC: Jan Beulich CC: Roger Pau Monn=C3=A9 CC: Teddy Astie v3: * Rebase over the split-out of altcall. Substantially simpler. --- xen/arch/x86/alternative.c | 50 +++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/xen/arch/x86/alternative.c b/xen/arch/x86/alternative.c index fd03147bdd12..a4a65597b2fc 100644 --- a/xen/arch/x86/alternative.c +++ b/xen/arch/x86/alternative.c @@ -349,15 +349,47 @@ static int init_or_livepatch _apply_alternatives(stru= ct alt_instr *start, =20 memcpy(buf, repl, a->repl_len); =20 - /* 0xe8/0xe9 are relative branches; fix the offset. */ - if ( a->repl_len >=3D 5 && (*buf & 0xfe) =3D=3D 0xe8 ) - *(int32_t *)(buf + 1) +=3D repl - orig; - else if ( IS_ENABLED(CONFIG_RETURN_THUNK) && - a->repl_len > 5 && buf[a->repl_len - 5] =3D=3D 0xe9 && - ((long)repl + a->repl_len + - *(int32_t *)(buf + a->repl_len - 4) =3D=3D - (long)__x86_return_thunk) ) - *(int32_t *)(buf + a->repl_len - 4) +=3D repl - orig; + /* + * Walk buf[] and adjust any insn-relative operands which leave the + * replacement block. + */ + if ( a->repl_len ) + { + uint8_t *ip =3D buf, *repl_end =3D ip + a->repl_len; + + for ( x86_decode_lite_t res; ip < repl_end; ip +=3D res.len ) + { + int32_t *d32; + const uint8_t *target; + + res =3D x86_decode_lite(ip, repl_end); + + if ( res.len =3D=3D 0 ) + { + printk("Alt for %ps [%*ph]\n" + " Unable to decode instruction at +%lu in alte= rnative\n", + ALT_ORIG_PTR(a), a->repl_len, repl, ip - repl); + return -EINVAL; + } + + if ( res.rel_sz !=3D 4 ) + continue; + + d32 =3D res.rel; + target =3D ip + res.len + *d32; + + if ( target >=3D buf && target <=3D repl_end ) + { + /* + * Target doesn't leave the replacement block. e.g. R= SB + * stuffing. Leave it unmodified. + */ + continue; + } + + *d32 +=3D repl - orig; + } + } =20 a->priv =3D 1; =20 --=20 2.39.5 From nobody Thu Aug 13 09:24:11 2026 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=reject dis=none) header.from=citrix.com ARC-Seal: i=1; a=rsa-sha256; t=1785741643; cv=none; d=zohomail.com; s=zohoarc; b=n6bpK6AnRix8FlCL0U08cNKtJFnT+gBfbYbuAaKdIH/JfMB9k2XMsXIne5oa3Sl2zy5QJcwDU5Jn9/PXJt9RW870pzdbxOR+xrSv/bBwDnxVaZ1+tMpQd+hn2JwZWfUihkNhbc8gMJvtfAzXXlVM4asRBBzRFIYHBcJ62eVuYeU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785741643; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=SjwuBsICIK/H/Y6+HpcAgCloLVRbw36ixgETurBOkCw=; b=LBlacC9J6jM0UOKnSz9QIUFhmz5qe1j1Ylu9SeKsTuZlGXuIOV6z2JCxA1dfxZHVy3Zu1jTbsDrYlE2YkS2sAhIKkEBYzxE30Lsyqh5bxZn2CZlWdlMyt7jal/46RgGstAt60tKUg/78WUrclqAA5i1k6hGlTPxpZ35XIvOuOu8= 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=reject dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1785741643361135.96602841056097; Mon, 3 Aug 2026 00:20:43 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1381229.1624825 (Exim 4.92) (envelope-from ) id 1wqmy9-0002mb-TG; Mon, 03 Aug 2026 07:20:17 +0000 Received: by outflank-mailman (output) from mailman id 1381229.1624825; Mon, 03 Aug 2026 07:20:17 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wqmy9-0002lb-Of; Mon, 03 Aug 2026 07:20:17 +0000 Received: by outflank-mailman (input) for mailman id 1381229; Mon, 03 Aug 2026 07:20:15 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wqmy7-0001yA-Lc for xen-devel@lists.xenproject.org; Mon, 03 Aug 2026 07:20:15 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wqmy7-00Dk9I-23 for xen-devel@lists.xenproject.org; Mon, 03 Aug 2026 09:20:15 +0200 Received: from [10.42.69.1] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a704119-e002-0a2a0a5209dd-0a2a4501c310-46 for ; Mon, 03 Aug 2026 09:20:15 +0200 Received: from [209.85.128.48] (helo=mail-wm1-f48.google.com) by tlsNG-d62444.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a70412e-5984-0a2a45010019-d1558030c113-3 for ; Mon, 03 Aug 2026 09:20:15 +0200 Received: by mail-wm1-f48.google.com with SMTP id 5b1f17b1804b1-4954aff6088so14417695e9.3 for ; Mon, 03 Aug 2026 00:20:14 -0700 (PDT) Received: from localhost.localdomain (host-78-146-248-75.as13285.net. [78.146.248.75]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49807b85be7sm254687935e9.2.2026.08.03.00.20.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 03 Aug 2026 00:20:13 -0700 (PDT) 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" Authentication-Results: eu.smtp.expurgate.cloud; dkim=pass header.s=google header.d=citrix.com header.i="@citrix.com" header.h="Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=citrix.com; s=google; t=1785741614; x=1786346414; darn=lists.xenproject.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=SjwuBsICIK/H/Y6+HpcAgCloLVRbw36ixgETurBOkCw=; b=X2RSM6EpKUZkN34/3ySIiuU+Be1QmfqrwwfUVPWZ3s24nv2ra0DGlD0MV2Z0rWLA5F 8FyIsGAPcKW4KxrrXu+PNjSM5KA71DU1h9Xh/qSwZFER6W/IpHENQHSSqfXLLHDpYlY9 RWi7WF30Y2N870dZ6G5cEpjGExOVfm6elTg28= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785741614; x=1786346414; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=SjwuBsICIK/H/Y6+HpcAgCloLVRbw36ixgETurBOkCw=; b=HM1Wr4qoYrwPRDFJ0vxYxD2hgXFUQ31CCdmJE3e0WC9Ba6iYTQ1PIWwL7oFnguO56J y4XxO2HEWEgHx4Ijr7WvX553VjhA3YFN6bKnXztKyHHTHrpEIRaouQ0HuZPD9hAMQUXa mFBc4MYxVgfVjYBEcmChKExa88VWdMe9gbBShvGNVtIVwB9+R8KYh4+nOiuaJx4pxeCG 2Cx1XNQLzMOpo2cO2YE/hVdMUEK1p2+QZYqLCRd/J8+Doh5IOo4tT1qzloQJ66nYRT49 sufWzkM5iCg1AhMajv2UCubqRI/LYHEiNeVRMDp63M2Mdx1Z6CXA63rLJ1jUzD/0cJbJ AIqQ== X-Gm-Message-State: AOJu0YyqiVH55tJzQXze4wBFNo0qhRTF8T+jKJRhVrtMXUtteJylnMlj LwTHNlD3V28FCxU3xMvCHBe8POQKj0LrVvV823yT4381vDrv3oLQFZYeTEAG7V3RrPloA0IIaMM Lf9lHHZM= X-Gm-Gg: AR+sD13ElKyup0+QIQBgDZFOpoxm0WmK72UFcy0yVjnvjh1tmiQv1S3i+lba7LP2XRf hIjARuioRldmO6+X+tvb4sJNjC8PnR/mdj3xWRcytEgKPQYmydsmGhBEKFFaiiiOhYxa7tyJBcL rIpz/WqpGWkOglA+FBKViW9EN9h7Pa+NWtrw9tl8vSBP0esDJgalqiB6w0ydFsrc+G5sGyt9+r7 Gs/cgF7XsJ8uKGywYIeBuLhfhBNQVE35lU5klpyzo1HISZL2xiBVfnVuAvHQ4d2rsQ5LTDh52Kt sotDY1UApmrSpILPiJMDWtt5p9PivWxYWfmpFkfZnvlw7rCHj1g1V44geQCNbFyUQ4arXkvgxpi w9VQnzNN0x+a+vzWtqfEWj8Aqli0caTfx7YlT9sE+/aJMfqiNxJou9ytBDlm02fuHjYCem95mYr JHOEywkzNc8ifaWgEBkvZT42bw4OutYWGhuZ4xtRBJ3NgAlMj90FX9Ye+qjUHVJUHlUMHGDVYUw iZcxjTkyUb9nGUBlrAd9eSDyLFRW80br6Gg328= X-Received: by 2002:a05:600c:4504:b0:493:c194:4e7a with SMTP id 5b1f17b1804b1-4980c66c9a8mr181514035e9.3.1785741614271; Mon, 03 Aug 2026 00:20:14 -0700 (PDT) From: Andrew Cooper To: Xen-devel Cc: Andrew Cooper , Jan Beulich , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= , Teddy Astie Subject: [PATCH v3 5/5] x86/spec-ctrl: Introduce and use DO_COND_BHB_SEQ Date: Mon, 3 Aug 2026 08:20:06 +0100 Message-Id: <20260803072006.9678-6-andrew.cooper3@citrix.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260803072006.9678-1-andrew.cooper3@citrix.com> References: <20260803072006.9678-1-andrew.cooper3@citrix.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-purgate-ID: tlsNG-d62444/1785741615-C5540757-3BC6C667/0/0 X-purgate-type: clean X-purgate-size: 4495 X-ZohoMail-DKIM: pass (identity @citrix.com) X-ZM-MESSAGEID: 1785741644063158500 Now that alternatives can fix up call displacements even when they're not t= he first instruction of the replacement, move the SCF_entry_bhb conditional inside the replacement block. This removes a conditional branch from the fastpaths of BHI-unaffected hardware. Signed-off-by: Andrew Cooper Reviewed-by: Jan Beulich --- CC: Jan Beulich CC: Roger Pau Monn=C3=A9 CC: Teddy Astie --- xen/arch/x86/hvm/vmx/entry.S | 12 +++---- xen/arch/x86/include/asm/spec_ctrl_asm.h | 43 +++++++++++++----------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/entry.S b/xen/arch/x86/hvm/vmx/entry.S index cebc70064048..76508c0de2f3 100644 --- a/xen/arch/x86/hvm/vmx/entry.S +++ b/xen/arch/x86/hvm/vmx/entry.S @@ -59,12 +59,12 @@ FUNC(vmx_asm_vmexit_handler) * Clear the BHB to mitigate BHI. Used on eIBRS parts, and uses R= ETs * itself so must be after we've perfomed all the RET-safety we ca= n. */ - testb $SCF_entry_bhb, CPUINFO_scf(%rsp) - jz .L_skip_bhb - ALTERNATIVE_2 "", \ - "call clear_bhb_loops", X86_SPEC_BHB_LOOPS, \ - "call clear_bhb_tsx", X86_SPEC_BHB_TSX -.L_skip_bhb: + .macro VMX_BHB_SEQ fn:req + DO_COND_BHB_SEQ \fn scf=3DCPUINFO_scf(%rsp) + .endm + ALTERNATIVE_2 "", \ + "VMX_BHB_SEQ fn=3Dclear_bhb_loops", X86_SPEC_BHB_LOOPS, \ + "VMX_BHB_SEQ fn=3Dclear_bhb_tsx", X86_SPEC_BHB_TSX =20 ALTERNATIVE "lfence", "", X86_SPEC_NO_LFENCE_ENTRY_VMX /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/includ= e/asm/spec_ctrl_asm.h index abb64ad2b7f9..780ec57f4553 100644 --- a/xen/arch/x86/include/asm/spec_ctrl_asm.h +++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h @@ -92,6 +92,21 @@ .L\@_skip: .endm =20 +.macro DO_COND_BHB_SEQ fn:req, scf=3D%bl +/* + * Requires SCF (defaults to %rbx), fn=3Dclear_bhb_{loops,tsx} + * Clobbers %rax, %rcx + * + * Conditionally use a BHB clearing software sequence. + */ + testb $SCF_entry_bhb, \scf + jz .L\@_skip_bhb + + call \fn + +.L\@_skip_bhb: +.endm + .macro DO_OVERWRITE_RSB tmp=3Drax, xu /* * Requires nothing @@ -277,12 +292,9 @@ * Clear the BHB to mitigate BHI. Used on eIBRS parts, and uses RETs * itself so must be after we've perfomed all the RET-safety we can. */ - testb $SCF_entry_bhb, %bl - jz .L\@_skip_bhb - ALTERNATIVE_2 "", \ - "call clear_bhb_loops", X86_SPEC_BHB_LOOPS, \ - "call clear_bhb_tsx", X86_SPEC_BHB_TSX -.L\@_skip_bhb: + ALTERNATIVE_2 "", \ + "DO_COND_BHB_SEQ clear_bhb_loops", X86_SPEC_BHB_LOOPS, \ + "DO_COND_BHB_SEQ clear_bhb_tsx", X86_SPEC_BHB_TSX =20 ALTERNATIVE "lfence", "", X86_SPEC_NO_LFENCE_ENTRY_PV .endm @@ -322,12 +334,9 @@ ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=3D1), \ X86_FEATURE_SC_MSR_PV =20 - testb $SCF_entry_bhb, %bl - jz .L\@_skip_bhb - ALTERNATIVE_2 "", \ - "call clear_bhb_loops", X86_SPEC_BHB_LOOPS, \ - "call clear_bhb_tsx", X86_SPEC_BHB_TSX -.L\@_skip_bhb: + ALTERNATIVE_2 "", \ + "DO_COND_BHB_SEQ clear_bhb_loops", X86_SPEC_BHB_LOOPS, \ + "DO_COND_BHB_SEQ clear_bhb_tsx", X86_SPEC_BHB_TSX =20 ALTERNATIVE "lfence", "", X86_SPEC_NO_LFENCE_ENTRY_INTR .endm @@ -433,13 +442,9 @@ * Clear the BHB to mitigate BHI. Used on eIBRS parts, and uses RETs * itself so must be after we've perfomed all the RET-safety we can. */ - testb $SCF_entry_bhb, %bl - jz .L\@_skip_bhb - - ALTERNATIVE_2 "", \ - "call clear_bhb_loops", X86_SPEC_BHB_LOOPS, \ - "call clear_bhb_tsx", X86_SPEC_BHB_TSX -.L\@_skip_bhb: + ALTERNATIVE_2 "", \ + "DO_COND_BHB_SEQ clear_bhb_loops", X86_SPEC_BHB_LOOPS, \ + "DO_COND_BHB_SEQ clear_bhb_tsx", X86_SPEC_BHB_TSX =20 lfence .endm --=20 2.39.5