summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraaijo, Jos <jos.craaijo@ou.nl>2026-06-23 13:21:22 +0000
committerMichael Tokarev <mjt@tls.msk.ru>2026-08-21 20:02:37 +0300
commitb610e0ad00d8a7b34bee52e5b2ffabe154161f97 (patch)
treecba7bbcf6c5822687da071bdef043a4da4d6f9d0
parentc3a10e2b596bdd186b463ad07b89b0d514a3372d (diff)
downloadqemu-b610e0ad00d8a7b34bee52e5b2ffabe154161f97.tar.gz
qemu-b610e0ad00d8a7b34bee52e5b2ffabe154161f97.zip
target/i386: fix long mode segment override prefix decoding
On x86, the ES/CS/SS/DS segment override prefixes are null prefixes in long mode, and should be ignored. (AMD APM Volume 3, Section 1.2.4) This patch fixes the prefix decoding to correctly ignore the prefixes in 64-bit mode. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3391 Signed-off-by: Jos Craaijo <jos.craaijo@ou.nl> Tested-by: Yudistira Putra <pyudistira519@gmail.com> Link: https://lore.kernel.org/r/20260623-fix-x86-long-mode-segment-override-decoding-v1-1-26d9d4b5804e@ou.nl Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> (cherry picked from commit 3589cd995b4facf34071e944fd8ec2294524e25a) Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
-rw-r--r--target/i386/hvf/x86_decode.c6
-rw-r--r--target/i386/tcg/decode-new.c.inc16
-rw-r--r--tests/tcg/x86_64/Makefile.target1
-rw-r--r--tests/tcg/x86_64/segment-prefixes.c25
4 files changed, 44 insertions, 4 deletions
diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c
index 5fea2dd3cc..c8820fd163 100644
--- a/target/i386/hvf/x86_decode.c
+++ b/target/i386/hvf/x86_decode.c
@@ -1867,6 +1867,12 @@ static void decode_prefix(CPUX86State *env, struct x86_decode *decode)
case PREFIX_SS_SEG_OVERRIDE:
case PREFIX_DS_SEG_OVERRIDE:
case PREFIX_ES_SEG_OVERRIDE:
+ if (x86_is_long_mode(env_cpu(env))) {
+ /* ES/CS/SS/DS segment overrides are ignored in long mode */
+ decode->rex.rex = 0;
+ break;
+ }
+ /* fall through when not in long mode */
case PREFIX_FS_SEG_OVERRIDE:
case PREFIX_GS_SEG_OVERRIDE:
decode->segment_override = byte;
diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc
index b12fb77559..93d2b2c812 100644
--- a/target/i386/tcg/decode-new.c.inc
+++ b/target/i386/tcg/decode-new.c.inc
@@ -2583,16 +2583,24 @@ static void disas_insn(DisasContext *s, CPUState *cpu)
s->prefix |= PREFIX_LOCK;
goto next_byte;
case 0x2e:
- s->override = R_CS;
+ if (!CODE64(s)) {
+ s->override = R_CS;
+ }
goto next_byte;
case 0x36:
- s->override = R_SS;
+ if (!CODE64(s)) {
+ s->override = R_SS;
+ }
goto next_byte;
case 0x3e:
- s->override = R_DS;
+ if (!CODE64(s)) {
+ s->override = R_DS;
+ }
goto next_byte;
case 0x26:
- s->override = R_ES;
+ if (!CODE64(s)) {
+ s->override = R_ES;
+ }
goto next_byte;
case 0x64:
s->override = R_FS;
diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target
index be20fc64e8..c48767fef8 100644
--- a/tests/tcg/x86_64/Makefile.target
+++ b/tests/tcg/x86_64/Makefile.target
@@ -15,6 +15,7 @@ X86_64_TESTS += vsyscall
X86_64_TESTS += noexec
X86_64_TESTS += cmpxchg
X86_64_TESTS += adox
+X86_64_TESTS += segment-prefixes
X86_64_TESTS += test-1648
X86_64_TESTS += test-2175
X86_64_TESTS += cross-modifying-code
diff --git a/tests/tcg/x86_64/segment-prefixes.c b/tests/tcg/x86_64/segment-prefixes.c
new file mode 100644
index 0000000000..a7e6e285b2
--- /dev/null
+++ b/tests/tcg/x86_64/segment-prefixes.c
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* See https://gitlab.com/qemu-project/qemu/-/work_items/3391 */
+
+int main()
+{
+ int data = 0;
+
+ /* Ensure that ignored segment override prefixes are actually ignored */
+ asm volatile (
+ "wrgsbase %0\n\t"
+ ".byte 0x65, 0x26\n\t" /* prefixes: GS + ES */
+ "movb $0, 0\n\t"
+ ".byte 0x65, 0x2E\n\t" /* prefixes: GS + CS */
+ "movb $0, 0\n\t"
+ ".byte 0x65, 0x36\n\t" /* prefixes: GS + SS */
+ "movb $0, 0\n\t"
+ ".byte 0x65, 0x3E\n\t" /* prefixes: GS + DS */
+ "movb $0, 0\n\t"
+ :
+ : "r" (&data)
+ : "memory"
+ );
+
+ return 0;
+}