* [PATCH v2 01/10] target/i386: fix INVD vmexit
2023-06-20 15:16 [PATCH v2 00/10] target/i386: add a few simple features Paolo Bonzini
@ 2023-06-20 15:16 ` Paolo Bonzini
2023-06-20 15:16 ` [PATCH v2 02/10] target/i386: TCG supports 3DNow! prefetch(w) Paolo Bonzini
` (8 subsequent siblings)
9 siblings, 0 replies; 19+ messages in thread
From: Paolo Bonzini @ 2023-06-20 15:16 UTC (permalink / raw)
To: qemu-devel; +Cc: richard.henderson
Due to a typo or perhaps a brain fart, the INVD vmexit was never generated.
Fix it (but not that fixing just the typo would break both INVD and WBINVD,
due to a case of two wrongs making a right).
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
target/i386/tcg/translate.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 5cf14311a60..0ef4d98ce79 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -6119,7 +6119,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
case 0x108: /* invd */
case 0x109: /* wbinvd */
if (check_cpl0(s)) {
- gen_svm_check_intercept(s, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD);
+ gen_svm_check_intercept(s, (b & 1) ? SVM_EXIT_WBINVD : SVM_EXIT_INVD);
/* nothing to do */
}
break;
--
2.40.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 02/10] target/i386: TCG supports 3DNow! prefetch(w)
2023-06-20 15:16 [PATCH v2 00/10] target/i386: add a few simple features Paolo Bonzini
2023-06-20 15:16 ` [PATCH v2 01/10] target/i386: fix INVD vmexit Paolo Bonzini
@ 2023-06-20 15:16 ` Paolo Bonzini
2023-06-20 15:16 ` [PATCH v2 03/10] target/i386: TCG supports RDSEED Paolo Bonzini
` (7 subsequent siblings)
9 siblings, 0 replies; 19+ messages in thread
From: Paolo Bonzini @ 2023-06-20 15:16 UTC (permalink / raw)
To: qemu-devel; +Cc: richard.henderson
The AMD prefetch(w) instructions have not been deprecated together with the rest
of 3DNow!, and in fact are even supported by newer Intel processor. Mark them
as supported by TCG, as it supports all of 3DNow!.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
target/i386/cpu.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 1242bd541a5..ff3dcd02dcb 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -647,7 +647,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_PDPE1GB | \
TCG_EXT2_X86_64_FEATURES)
#define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \
- CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A)
+ CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | \
+ CPUID_EXT3_3DNOWPREFETCH)
#define TCG_EXT4_FEATURES 0
#define TCG_SVM_FEATURES (CPUID_SVM_NPT | CPUID_SVM_VGIF | \
CPUID_SVM_SVME_ADDR_CHK)
--
2.40.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 03/10] target/i386: TCG supports RDSEED
2023-06-20 15:16 [PATCH v2 00/10] target/i386: add a few simple features Paolo Bonzini
2023-06-20 15:16 ` [PATCH v2 01/10] target/i386: fix INVD vmexit Paolo Bonzini
2023-06-20 15:16 ` [PATCH v2 02/10] target/i386: TCG supports 3DNow! prefetch(w) Paolo Bonzini
@ 2023-06-20 15:16 ` Paolo Bonzini
2023-06-20 16:24 ` Richard Henderson
2023-06-20 15:16 ` [PATCH v2 04/10] target/i386: TCG supports XSAVEERPTR Paolo Bonzini
` (6 subsequent siblings)
9 siblings, 1 reply; 19+ messages in thread
From: Paolo Bonzini @ 2023-06-20 15:16 UTC (permalink / raw)
To: qemu-devel; +Cc: richard.henderson
TCG implements RDSEED, and in fact uses qcrypto_random_bytes which is
secure enough to match hardware behavior. Expose it to guests.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
target/i386/cpu.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index ff3dcd02dcb..fc4246223d4 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -657,11 +657,10 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \
CPUID_7_0_EBX_PCOMMIT | CPUID_7_0_EBX_CLFLUSHOPT | \
CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_FSGSBASE | \
- CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_AVX2)
+ CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_RDSEED)
/* missing:
CPUID_7_0_EBX_HLE
- CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
- CPUID_7_0_EBX_RDSEED */
+ CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM */
#define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | \
/* CPUID_7_0_ECX_OSPKE is dynamic */ \
CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES)
--
2.40.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v2 03/10] target/i386: TCG supports RDSEED
2023-06-20 15:16 ` [PATCH v2 03/10] target/i386: TCG supports RDSEED Paolo Bonzini
@ 2023-06-20 16:24 ` Richard Henderson
2023-06-21 5:46 ` Paolo Bonzini
0 siblings, 1 reply; 19+ messages in thread
From: Richard Henderson @ 2023-06-20 16:24 UTC (permalink / raw)
To: Paolo Bonzini, qemu-devel
On 6/20/23 17:16, Paolo Bonzini wrote:
> TCG implements RDSEED, and in fact uses qcrypto_random_bytes which is
> secure enough to match hardware behavior. Expose it to guests.
>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
> target/i386/cpu.c | 5 ++---
> 1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/target/i386/cpu.c b/target/i386/cpu.c
> index ff3dcd02dcb..fc4246223d4 100644
> --- a/target/i386/cpu.c
> +++ b/target/i386/cpu.c
> @@ -657,11 +657,10 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
> CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \
> CPUID_7_0_EBX_PCOMMIT | CPUID_7_0_EBX_CLFLUSHOPT | \
> CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_FSGSBASE | \
> - CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_AVX2)
> + CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_RDSEED)
> /* missing:
> CPUID_7_0_EBX_HLE
> - CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
> - CPUID_7_0_EBX_RDSEED */
> + CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM */
> #define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | \
> /* CPUID_7_0_ECX_OSPKE is dynamic */ \
> CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES)
Still missing the check for CPUID_7_0_EBX_RDSEED at the RDSEED insn.
r~
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 03/10] target/i386: TCG supports RDSEED
2023-06-20 16:24 ` Richard Henderson
@ 2023-06-21 5:46 ` Paolo Bonzini
0 siblings, 0 replies; 19+ messages in thread
From: Paolo Bonzini @ 2023-06-21 5:46 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 1718 bytes --]
Il mar 20 giu 2023, 18:24 Richard Henderson <richard.henderson@linaro.org>
ha scritto:
> On 6/20/23 17:16, Paolo Bonzini wrote:
> > TCG implements RDSEED, and in fact uses qcrypto_random_bytes which is
> > secure enough to match hardware behavior. Expose it to guests.
> >
> > Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> > Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> > ---
> > target/i386/cpu.c | 5 ++---
> > 1 file changed, 2 insertions(+), 3 deletions(-)
> >
> > diff --git a/target/i386/cpu.c b/target/i386/cpu.c
> > index ff3dcd02dcb..fc4246223d4 100644
> > --- a/target/i386/cpu.c
> > +++ b/target/i386/cpu.c
> > @@ -657,11 +657,10 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t
> vendor1,
> > CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX
> | \
> > CPUID_7_0_EBX_PCOMMIT | CPUID_7_0_EBX_CLFLUSHOPT |
> \
> > CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX |
> CPUID_7_0_EBX_FSGSBASE | \
> > - CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_AVX2)
> > + CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_AVX2 |
> CPUID_7_0_EBX_RDSEED)
> > /* missing:
> > CPUID_7_0_EBX_HLE
> > - CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
> > - CPUID_7_0_EBX_RDSEED */
> > + CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM */
> > #define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU |
> \
> > /* CPUID_7_0_ECX_OSPKE is dynamic */ \
> > CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES)
>
> Still missing the check for CPUID_7_0_EBX_RDSEED at the RDSEED insn.
>
Sorry, I 6kissed that remain. It's more of a separate patch IMO, I will add
it.
Paolo
> r~
>
>
[-- Attachment #2: Type: text/html, Size: 2729 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 04/10] target/i386: TCG supports XSAVEERPTR
2023-06-20 15:16 [PATCH v2 00/10] target/i386: add a few simple features Paolo Bonzini
` (2 preceding siblings ...)
2023-06-20 15:16 ` [PATCH v2 03/10] target/i386: TCG supports RDSEED Paolo Bonzini
@ 2023-06-20 15:16 ` Paolo Bonzini
2023-06-20 15:16 ` [PATCH v2 05/10] target/i386: TCG supports WBNOINVD Paolo Bonzini
` (5 subsequent siblings)
9 siblings, 0 replies; 19+ messages in thread
From: Paolo Bonzini @ 2023-06-20 15:16 UTC (permalink / raw)
To: qemu-devel; +Cc: richard.henderson
XSAVEERPTR is actually a fix for an errata; TCG does not have the issue.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
target/i386/cpu.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index fc4246223d4..bce0cb73e85 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -678,6 +678,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
#define TCG_SGX_12_0_EBX_FEATURES 0
#define TCG_SGX_12_1_EAX_FEATURES 0
+#define TCG_8000_0008_EBX CPUID_8000_0008_EBX_XSAVEERPTR
+
FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
[FEAT_1_EDX] = {
.type = CPUID_FEATURE_WORD,
@@ -939,7 +941,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
"amd-psfd", NULL, NULL, NULL,
},
.cpuid = { .eax = 0x80000008, .reg = R_EBX, },
- .tcg_features = 0,
+ .tcg_features = TCG_8000_0008_EBX,
.unmigratable_flags = 0,
},
[FEAT_8000_0021_EAX] = {
--
2.40.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 05/10] target/i386: TCG supports WBNOINVD
2023-06-20 15:16 [PATCH v2 00/10] target/i386: add a few simple features Paolo Bonzini
` (3 preceding siblings ...)
2023-06-20 15:16 ` [PATCH v2 04/10] target/i386: TCG supports XSAVEERPTR Paolo Bonzini
@ 2023-06-20 15:16 ` Paolo Bonzini
2023-06-20 15:16 ` [PATCH v2 06/10] target/i386: Intel only supports SYSCALL in long mode Paolo Bonzini
` (4 subsequent siblings)
9 siblings, 0 replies; 19+ messages in thread
From: Paolo Bonzini @ 2023-06-20 15:16 UTC (permalink / raw)
To: qemu-devel; +Cc: richard.henderson
WBNOINVD is the same as INVD or WBINVD as far as TCG is concerned,
since there is no cache in TCG and therefore no invalidation side effect
in WBNOINVD.
With respect to SVM emulation, processors that do not support WBNOINVD
will ignore the prefix and treat it as WBINVD, while those that support
it will generate exactly the same vmexit.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
target/i386/cpu.c | 3 ++-
target/i386/tcg/translate.c | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index bce0cb73e85..695e01582bf 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -678,7 +678,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
#define TCG_SGX_12_0_EBX_FEATURES 0
#define TCG_SGX_12_1_EAX_FEATURES 0
-#define TCG_8000_0008_EBX CPUID_8000_0008_EBX_XSAVEERPTR
+#define TCG_8000_0008_EBX (CPUID_8000_0008_EBX_XSAVEERPTR | \
+ CPUID_8000_0008_EBX_WBNOINVD)
FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
[FEAT_1_EDX] = {
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 0ef4d98ce79..89df7bb528a 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -6117,7 +6117,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
break;
case 0x108: /* invd */
- case 0x109: /* wbinvd */
+ case 0x109: /* wbinvd; wbnoinvd with REPZ prefix */
if (check_cpl0(s)) {
gen_svm_check_intercept(s, (b & 1) ? SVM_EXIT_WBINVD : SVM_EXIT_INVD);
/* nothing to do */
--
2.40.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 06/10] target/i386: Intel only supports SYSCALL in long mode
2023-06-20 15:16 [PATCH v2 00/10] target/i386: add a few simple features Paolo Bonzini
` (4 preceding siblings ...)
2023-06-20 15:16 ` [PATCH v2 05/10] target/i386: TCG supports WBNOINVD Paolo Bonzini
@ 2023-06-20 15:16 ` Paolo Bonzini
2023-06-20 15:57 ` Richard Henderson
2023-06-20 15:16 ` [PATCH v2 07/10] target/i386: sysret and sysexit are privileged Paolo Bonzini
` (3 subsequent siblings)
9 siblings, 1 reply; 19+ messages in thread
From: Paolo Bonzini @ 2023-06-20 15:16 UTC (permalink / raw)
To: qemu-devel; +Cc: richard.henderson
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
target/i386/cpu.c | 4 ++++
target/i386/tcg/translate.c | 5 ++++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 695e01582bf..978d24b5ec7 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6238,6 +6238,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ecx |= 1 << 1; /* CmpLegacy bit */
}
}
+ if (tcg_enabled() && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 &&
+ !(env->hflags & HF_LMA_MASK)) {
+ *edx &= ~CPUID_EXT2_SYSCALL;
+ }
break;
case 0x80000002:
case 0x80000003:
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 89df7bb528a..9aec7ec8288 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -5684,7 +5684,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
break;
#ifdef TARGET_X86_64
case 0x105: /* syscall */
- /* XXX: is it usable in real mode ? */
+ /* For Intel SYSCALL is only valid in long mode */
+ if (!LMA(s) && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1) {
+ goto illegal_op;
+ }
gen_update_cc_op(s);
gen_update_eip_cur(s);
gen_helper_syscall(cpu_env, cur_insn_len_i32(s));
--
2.40.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 07/10] target/i386: sysret and sysexit are privileged
2023-06-20 15:16 [PATCH v2 00/10] target/i386: add a few simple features Paolo Bonzini
` (5 preceding siblings ...)
2023-06-20 15:16 ` [PATCH v2 06/10] target/i386: Intel only supports SYSCALL in long mode Paolo Bonzini
@ 2023-06-20 15:16 ` Paolo Bonzini
2023-06-20 15:58 ` Richard Henderson
2023-06-20 15:16 ` [PATCH v2 08/10] target/i386: implement 32-bit SYSCALL for linux-user Paolo Bonzini
` (2 subsequent siblings)
9 siblings, 1 reply; 19+ messages in thread
From: Paolo Bonzini @ 2023-06-20 15:16 UTC (permalink / raw)
To: qemu-devel; +Cc: richard.henderson
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
target/i386/tcg/translate.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 9aec7ec8288..c58f5f24ab3 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -5675,7 +5675,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
/* For Intel SYSEXIT is valid on 64-bit */
if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
goto illegal_op;
- if (!PE(s)) {
+ if (!PE(s) || CPL(s) != 0) {
gen_exception_gpf(s);
} else {
gen_helper_sysexit(cpu_env, tcg_constant_i32(dflag - 1));
@@ -5697,7 +5697,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
gen_eob_worker(s, false, true);
break;
case 0x107: /* sysret */
- if (!PE(s)) {
+ if (!PE(s) || CPL(s) != 0) {
gen_exception_gpf(s);
} else {
gen_helper_sysret(cpu_env, tcg_constant_i32(dflag - 1));
--
2.40.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 08/10] target/i386: implement 32-bit SYSCALL for linux-user
2023-06-20 15:16 [PATCH v2 00/10] target/i386: add a few simple features Paolo Bonzini
` (6 preceding siblings ...)
2023-06-20 15:16 ` [PATCH v2 07/10] target/i386: sysret and sysexit are privileged Paolo Bonzini
@ 2023-06-20 15:16 ` Paolo Bonzini
2023-06-20 16:10 ` Richard Henderson
2023-06-20 15:16 ` [PATCH v2 09/10] target/i386: implement 32-bit SYSENTER " Paolo Bonzini
2023-06-20 15:16 ` [PATCH v2 10/10] target/i386: implement RDPID in TCG Paolo Bonzini
9 siblings, 1 reply; 19+ messages in thread
From: Paolo Bonzini @ 2023-06-20 15:16 UTC (permalink / raw)
To: qemu-devel; +Cc: richard.henderson
TCG supports both 32-bit and 64-bit SYSCALL, but the linux-user
code only exposes it for 64-bit. The ABI is the same as "int $80",
so expose it even for 32-bit emulators, where it can be used if the
vendor is specified as AMD.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
linux-user/i386/cpu_loop.c | 3 +++
target/i386/cpu.c | 8 +++++++-
target/i386/helper.h | 2 +-
target/i386/tcg/translate.c | 2 +-
target/i386/tcg/user/seg_helper.c | 2 --
5 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c
index 2d0918a93ff..6908bad14aa 100644
--- a/linux-user/i386/cpu_loop.c
+++ b/linux-user/i386/cpu_loop.c
@@ -211,6 +211,9 @@ void cpu_loop(CPUX86State *env)
switch(trapnr) {
case 0x80:
+#ifdef TARGET_ABI32
+ case EXCP_SYSCALL:
+#endif
/* linux syscall from int $0x80 */
ret = do_syscall(env,
env->regs[R_EAX],
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 978d24b5ec7..934360e4091 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -642,10 +642,16 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
#define TCG_EXT2_X86_64_FEATURES 0
#endif
+#if defined CONFIG_SOFTMMU || defined CONFIG_LINUX_USER
+#define TCG_EXT2_NOBSD_FEATURES CPUID_EXT2_SYSCALL
+#else
+#define TCG_EXT2_NOBSD_FEATURES 0
+#endif
+
#define TCG_EXT2_FEATURES ((TCG_FEATURES & CPUID_EXT2_AMD_ALIASES) | \
CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_RDTSCP | \
CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_PDPE1GB | \
- TCG_EXT2_X86_64_FEATURES)
+ TCG_EXT2_NOBSD_FEATURES | TCG_EXT2_X86_64_FEATURES)
#define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \
CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | \
CPUID_EXT3_3DNOWPREFETCH)
diff --git a/target/i386/helper.h b/target/i386/helper.h
index e627a931073..c2e86c6119c 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -51,8 +51,8 @@ DEF_HELPER_FLAGS_2(get_dr, TCG_CALL_NO_WG, tl, env, int)
DEF_HELPER_1(sysenter, void, env)
DEF_HELPER_2(sysexit, void, env, int)
-#ifdef TARGET_X86_64
DEF_HELPER_2(syscall, void, env, int)
+#ifdef TARGET_X86_64
DEF_HELPER_2(sysret, void, env, int)
#endif
DEF_HELPER_FLAGS_2(pause, TCG_CALL_NO_WG, noreturn, env, int)
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index c58f5f24ab3..0ddb689444e 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -5682,7 +5682,6 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
s->base.is_jmp = DISAS_EOB_ONLY;
}
break;
-#ifdef TARGET_X86_64
case 0x105: /* syscall */
/* For Intel SYSCALL is only valid in 64-bit */
if (!LMA(s) && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1) {
@@ -5696,6 +5695,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
generated after one has entered CPL0 if TF is set in FMASK. */
gen_eob_worker(s, false, true);
break;
+#ifdef TARGET_X86_64
case 0x107: /* sysret */
if (!PE(s) || CPL(s) != 0) {
gen_exception_gpf(s);
diff --git a/target/i386/tcg/user/seg_helper.c b/target/i386/tcg/user/seg_helper.c
index 67481b0aa8e..c45f2ac2ba6 100644
--- a/target/i386/tcg/user/seg_helper.c
+++ b/target/i386/tcg/user/seg_helper.c
@@ -26,7 +26,6 @@
#include "tcg/helper-tcg.h"
#include "tcg/seg_helper.h"
-#ifdef TARGET_X86_64
void helper_syscall(CPUX86State *env, int next_eip_addend)
{
CPUState *cs = env_cpu(env);
@@ -36,7 +35,6 @@ void helper_syscall(CPUX86State *env, int next_eip_addend)
env->exception_next_eip = env->eip + next_eip_addend;
cpu_loop_exit(cs);
}
-#endif /* TARGET_X86_64 */
/*
* fake user mode interrupt. is_int is TRUE if coming from the int
--
2.40.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v2 08/10] target/i386: implement 32-bit SYSCALL for linux-user
2023-06-20 15:16 ` [PATCH v2 08/10] target/i386: implement 32-bit SYSCALL for linux-user Paolo Bonzini
@ 2023-06-20 16:10 ` Richard Henderson
0 siblings, 0 replies; 19+ messages in thread
From: Richard Henderson @ 2023-06-20 16:10 UTC (permalink / raw)
To: Paolo Bonzini, qemu-devel, Warner Losh
On 6/20/23 17:16, Paolo Bonzini wrote:
> @@ -211,6 +211,9 @@ void cpu_loop(CPUX86State *env)
>
> switch(trapnr) {
> case 0x80:
> +#ifdef TARGET_ABI32
> + case EXCP_SYSCALL:
> +#endif
> /* linux syscall from int $0x80 */
ABI32 includes x32.
I think you want TARGET_I386.
> +#if defined CONFIG_SOFTMMU || defined CONFIG_LINUX_USER
> +#define TCG_EXT2_NOBSD_FEATURES CPUID_EXT2_SYSCALL
> +#else
> +#define TCG_EXT2_NOBSD_FEATURES 0
> +#endif
Missing TARGET_I386 test per above.
Better named TCG_EXT2_USERONLY_FEATURES.
Warner, if I'm reading freebsd-src correctly, sys/x86 (aka 32-bit) does not use
sysenter/sysret? I only see that under sys/amd64 (where fast_syscall32 is a cya nop).
r~
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 09/10] target/i386: implement 32-bit SYSENTER for linux-user
2023-06-20 15:16 [PATCH v2 00/10] target/i386: add a few simple features Paolo Bonzini
` (7 preceding siblings ...)
2023-06-20 15:16 ` [PATCH v2 08/10] target/i386: implement 32-bit SYSCALL for linux-user Paolo Bonzini
@ 2023-06-20 15:16 ` Paolo Bonzini
2023-06-20 16:22 ` Richard Henderson
2023-06-20 15:16 ` [PATCH v2 10/10] target/i386: implement RDPID in TCG Paolo Bonzini
9 siblings, 1 reply; 19+ messages in thread
From: Paolo Bonzini @ 2023-06-20 15:16 UTC (permalink / raw)
To: qemu-devel; +Cc: richard.henderson
TCG reports the SEP feature (SYSENTER/SYSEXIT) in user mode emulation,
but does not plumb it into the linux-user run loop. Split the helper into
system emulation and user-mode emulation cases and implement the latter.
SYSENTER does not have the best design for a kernel-mode entry
instruction, and therefore Linux always makes it return to the
vsyscall page. Because QEMU does not provide the _contents_ of
the vsyscall page, the instructions executed after SYSEXIT have
to be emulated by hand until the first RET.
Some corner cases, such as restarting the system call after the
system call has rewritten the SYSENTER instruction, are not emulated
correctly. On Linux, the system call restart uses the SYSENTER
call in the vsyscall page, while on QEMU it uses the emulated
program's instruction.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
linux-user/i386/cpu_loop.c | 51 +++++++++++++++++++++++++++--
target/i386/cpu.c | 9 ++++-
target/i386/cpu.h | 1 +
target/i386/helper.h | 2 +-
target/i386/tcg/seg_helper.c | 33 -------------------
target/i386/tcg/sysemu/seg_helper.c | 33 +++++++++++++++++++
target/i386/tcg/translate.c | 2 +-
target/i386/tcg/user/seg_helper.c | 16 +++++++++
8 files changed, 109 insertions(+), 38 deletions(-)
diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c
index 6908bad14aa..690d9a42ee0 100644
--- a/linux-user/i386/cpu_loop.c
+++ b/linux-user/i386/cpu_loop.c
@@ -197,6 +197,41 @@ static bool maybe_handle_vm86_trap(CPUX86State *env, int trapnr)
return false;
}
+static void emulate_vsyscall_sysexit(CPUX86State *env)
+{
+ /*
+ * Emulate the pop and ret instructions after the sysenter instruction
+ * in the vsyscall page. Any sysenter returns there, because sysenter
+ * does not save the old EIP!
+ */
+ abi_ulong word;
+ if (get_user_ual(word, env->regs[R_ESP])) {
+ goto segv;
+ }
+ env->regs[R_EBP] = word;
+ env->regs[R_ESP] += sizeof(target_ulong);
+ if (get_user_ual(word, env->regs[R_ESP])) {
+ goto segv;
+ }
+ env->regs[R_EDX] = word;
+ env->regs[R_ESP] += sizeof(target_ulong);
+ if (get_user_ual(word, env->regs[R_ESP])) {
+ goto segv;
+ }
+ env->regs[R_ECX] = word;
+ env->regs[R_ESP] += sizeof(target_ulong);
+ if (get_user_ual(word, env->regs[R_ESP])) {
+ goto segv;
+ }
+ env->eip = word;
+ env->regs[R_ESP] += sizeof(target_ulong);
+ return;
+
+segv:
+ env->error_code = PG_ERROR_W_MASK | PG_ERROR_U_MASK;
+ force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->regs[R_ESP]);
+}
+
void cpu_loop(CPUX86State *env)
{
CPUState *cs = env_cpu(env);
@@ -213,6 +248,7 @@ void cpu_loop(CPUX86State *env)
case 0x80:
#ifdef TARGET_ABI32
case EXCP_SYSCALL:
+ case EXCP_SYSENTER:
#endif
/* linux syscall from int $0x80 */
ret = do_syscall(env,
@@ -226,12 +262,18 @@ void cpu_loop(CPUX86State *env)
0, 0);
if (ret == -QEMU_ERESTARTSYS) {
env->eip -= 2;
- } else if (ret != -QEMU_ESIGRETURN) {
+ break;
+ }
+ if (ret != -QEMU_ESIGRETURN) {
env->regs[R_EAX] = ret;
}
+ if (trapnr == EXCP_SYSENTER) {
+ emulate_vsyscall_sysexit(env);
+ }
break;
#ifndef TARGET_ABI32
case EXCP_SYSCALL:
+ case EXCP_SYSENTER:
/* linux syscall from syscall instruction */
ret = do_syscall(env,
env->regs[R_EAX],
@@ -244,9 +286,14 @@ void cpu_loop(CPUX86State *env)
0, 0);
if (ret == -QEMU_ERESTARTSYS) {
env->eip -= 2;
- } else if (ret != -QEMU_ESIGRETURN) {
+ break;
+ }
+ if (ret != -QEMU_ESIGRETURN) {
env->regs[R_EAX] = ret;
}
+ if (trapnr == EXCP_SYSENTER) {
+ emulate_vsyscall_sysexit(env);
+ }
break;
#endif
#ifdef TARGET_X86_64
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 934360e4091..2c71c3ea32b 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -614,11 +614,18 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \
CPUID_PAE | CPUID_SEP | CPUID_APIC)
+#if defined CONFIG_SOFTMMU || defined CONFIG_LINUX_USER
+#define TCG_NOBSD_FEATURES CPUID_SEP
+#else
+#define TCG_NOBSD_FEATURES 0
+#endif
+
#define TCG_FEATURES (CPUID_FP87 | CPUID_PSE | CPUID_TSC | CPUID_MSR | \
CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | CPUID_SEP | \
CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \
CPUID_PSE36 | CPUID_CLFLUSH | CPUID_ACPI | CPUID_MMX | \
- CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS | CPUID_DE)
+ CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS | CPUID_DE | \
+ TCG_NOBSD_FEATURES)
/* partly implemented:
CPUID_MTRR, CPUID_MCA, CPUID_CLFLUSH (needed for Win64) */
/* missing:
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 7201a71de86..bc7d10bf863 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1185,6 +1185,7 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w,
#define EXCP_VMEXIT 0x100 /* only for system emulation */
#define EXCP_SYSCALL 0x101 /* only for user emulation */
#define EXCP_VSYSCALL 0x102 /* only for user emulation */
+#define EXCP_SYSENTER 0x103 /* only for user emulation */
/* i386-specific interrupt pending bits. */
#define CPU_INTERRUPT_POLL CPU_INTERRUPT_TGT_EXT_1
diff --git a/target/i386/helper.h b/target/i386/helper.h
index c2e86c6119c..49d2f537557 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -49,7 +49,7 @@ DEF_HELPER_FLAGS_3(set_dr, TCG_CALL_NO_WG, void, env, int, tl)
DEF_HELPER_FLAGS_2(get_dr, TCG_CALL_NO_WG, tl, env, int)
#endif /* !CONFIG_USER_ONLY */
-DEF_HELPER_1(sysenter, void, env)
+DEF_HELPER_2(sysenter, void, env, int)
DEF_HELPER_2(sysexit, void, env, int)
DEF_HELPER_2(syscall, void, env, int)
#ifdef TARGET_X86_64
diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c
index 03b58e94a2d..6899b8f6890 100644
--- a/target/i386/tcg/seg_helper.c
+++ b/target/i386/tcg/seg_helper.c
@@ -2147,39 +2147,6 @@ void helper_lret_protected(CPUX86State *env, int shift, int addend)
helper_ret_protected(env, shift, 0, addend, GETPC());
}
-void helper_sysenter(CPUX86State *env)
-{
- if (env->sysenter_cs == 0) {
- raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
- }
- env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
-
-#ifdef TARGET_X86_64
- if (env->hflags & HF_LMA_MASK) {
- cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK |
- DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
- DESC_L_MASK);
- } else
-#endif
- {
- cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK |
- DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
- }
- cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK |
- DESC_W_MASK | DESC_A_MASK);
- env->regs[R_ESP] = env->sysenter_esp;
- env->eip = env->sysenter_eip;
-}
-
void helper_sysexit(CPUX86State *env, int dflag)
{
int cpl;
diff --git a/target/i386/tcg/sysemu/seg_helper.c b/target/i386/tcg/sysemu/seg_helper.c
index 2c9bd007adb..967882b6c69 100644
--- a/target/i386/tcg/sysemu/seg_helper.c
+++ b/target/i386/tcg/sysemu/seg_helper.c
@@ -215,3 +215,36 @@ void helper_check_io(CPUX86State *env, uint32_t addr, uint32_t size)
raise_exception_err_ra(env, EXCP0D_GPF, 0, retaddr);
}
}
+
+void helper_sysenter(CPUX86State *env, int next_eip_addend)
+{
+ if (env->sysenter_cs == 0) {
+ raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
+ }
+ env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
+
+#ifdef TARGET_X86_64
+ if (env->hflags & HF_LMA_MASK) {
+ cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
+ 0, 0xffffffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+ DESC_S_MASK |
+ DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
+ DESC_L_MASK);
+ } else
+#endif
+ {
+ cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
+ 0, 0xffffffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+ DESC_S_MASK |
+ DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+ }
+ cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
+ 0, 0xffffffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+ DESC_S_MASK |
+ DESC_W_MASK | DESC_A_MASK);
+ env->regs[R_ESP] = env->sysenter_esp;
+ env->eip = env->sysenter_eip;
+}
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 0ddb689444e..af74c842f96 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -5667,7 +5667,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
if (!PE(s)) {
gen_exception_gpf(s);
} else {
- gen_helper_sysenter(cpu_env);
+ gen_helper_sysenter(cpu_env, cur_insn_len_i32(s));
s->base.is_jmp = DISAS_EOB_ONLY;
}
break;
diff --git a/target/i386/tcg/user/seg_helper.c b/target/i386/tcg/user/seg_helper.c
index c45f2ac2ba6..1ac3ee39b5b 100644
--- a/target/i386/tcg/user/seg_helper.c
+++ b/target/i386/tcg/user/seg_helper.c
@@ -36,6 +36,22 @@ void helper_syscall(CPUX86State *env, int next_eip_addend)
cpu_loop_exit(cs);
}
+void helper_sysenter(CPUX86State *env, int next_eip_addend)
+{
+ CPUState *cs = env_cpu(env);
+
+ /*
+ * sysenter returns to the landing pad of the vDSO, which pops
+ * ebp/edx/ecx before executing a "ret".
+ */
+ cs->exception_index = EXCP_SYSENTER;
+ env->exception_is_int = 0;
+
+ /* Used for ERESTARTSYS. */
+ env->exception_next_eip = env->eip + next_eip_addend;
+ cpu_loop_exit(cs);
+}
+
/*
* fake user mode interrupt. is_int is TRUE if coming from the int
* instruction. next_eip is the env->eip value AFTER the interrupt
--
2.40.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v2 09/10] target/i386: implement 32-bit SYSENTER for linux-user
2023-06-20 15:16 ` [PATCH v2 09/10] target/i386: implement 32-bit SYSENTER " Paolo Bonzini
@ 2023-06-20 16:22 ` Richard Henderson
2023-06-20 16:27 ` Paolo Bonzini
0 siblings, 1 reply; 19+ messages in thread
From: Richard Henderson @ 2023-06-20 16:22 UTC (permalink / raw)
To: Paolo Bonzini, qemu-devel
On 6/20/23 17:16, Paolo Bonzini wrote:
> TCG reports the SEP feature (SYSENTER/SYSEXIT) in user mode emulation,
> but does not plumb it into the linux-user run loop. Split the helper into
> system emulation and user-mode emulation cases and implement the latter.
>
> SYSENTER does not have the best design for a kernel-mode entry
> instruction, and therefore Linux always makes it return to the
> vsyscall page. Because QEMU does not provide the_contents_ of
> the vsyscall page, the instructions executed after SYSEXIT have
> to be emulated by hand until the first RET.
>
> Some corner cases, such as restarting the system call after the
> system call has rewritten the SYSENTER instruction, are not emulated
> correctly. On Linux, the system call restart uses the SYSENTER
> call in the vsyscall page, while on QEMU it uses the emulated
> program's instruction.
>
> Signed-off-by: Paolo Bonzini<pbonzini@redhat.com>
> ---
> linux-user/i386/cpu_loop.c | 51 +++++++++++++++++++++++++++--
> target/i386/cpu.c | 9 ++++-
> target/i386/cpu.h | 1 +
> target/i386/helper.h | 2 +-
> target/i386/tcg/seg_helper.c | 33 -------------------
> target/i386/tcg/sysemu/seg_helper.c | 33 +++++++++++++++++++
> target/i386/tcg/translate.c | 2 +-
> target/i386/tcg/user/seg_helper.c | 16 +++++++++
> 8 files changed, 109 insertions(+), 38 deletions(-)
I'm not keen on this.
This belongs with the rest of the vdso (see patches posted years ago; committing binary
blobs rejected, still waiting on a decent way to invoke cross-compilers to build them).
Further, this shouldn't ever be reachable, because AT_SYSINFO won't be present to give the
guest libc the location of the vdso routine to call.
r~
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 09/10] target/i386: implement 32-bit SYSENTER for linux-user
2023-06-20 16:22 ` Richard Henderson
@ 2023-06-20 16:27 ` Paolo Bonzini
0 siblings, 0 replies; 19+ messages in thread
From: Paolo Bonzini @ 2023-06-20 16:27 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel
On Tue, Jun 20, 2023 at 6:23 PM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 6/20/23 17:16, Paolo Bonzini wrote:
> > TCG reports the SEP feature (SYSENTER/SYSEXIT) in user mode emulation,
> > but does not plumb it into the linux-user run loop. Split the helper into
> > system emulation and user-mode emulation cases and implement the latter.
>
> I'm not keen on this.
>
> This belongs with the rest of the vdso (see patches posted years ago; committing binary
> blobs rejected, still waiting on a decent way to invoke cross-compilers to build them).
As we discussed in Dublin, that should be doable by reusing the
tests/tcg logic in configure (though we would likely commit the binary
blobs as well). You could do it in your sleep. ;)
> Further, this shouldn't ever be reachable, because AT_SYSINFO won't be present to give the
> guest libc the location of the vdso routine to call.
Even without AT_SYSINFO the program should be able to do SYSENTER and
'trust" the kernel not to change the epilog of the routine.
To be honest I don't like it particularly either; but I also didn't
like that SEP is reported but doesn't work (and the purpose of these
patches is to allow using named CPU models in linux-user)... I can
certainly drop the patch since it's been like this for ages.
Paolo
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 10/10] target/i386: implement RDPID in TCG
2023-06-20 15:16 [PATCH v2 00/10] target/i386: add a few simple features Paolo Bonzini
` (8 preceding siblings ...)
2023-06-20 15:16 ` [PATCH v2 09/10] target/i386: implement 32-bit SYSENTER " Paolo Bonzini
@ 2023-06-20 15:16 ` Paolo Bonzini
2023-06-20 16:23 ` Richard Henderson
9 siblings, 1 reply; 19+ messages in thread
From: Paolo Bonzini @ 2023-06-20 15:16 UTC (permalink / raw)
To: qemu-devel; +Cc: richard.henderson
RDPID corresponds to a RDMSR(TSC_AUX); however, it is unprivileged
so for user-mode emulation we must provide the value that the kernel
places in the MSR. For Linux, it is a combination of the current CPU
and the current NUMA node, both of which can be retrieved with getcpu(2).
For BSD, just return 0.
RDTSCP is reimplemented as RDTSC + RDPID ECX; the differences in terms
of serializability are not relevant to QEMU.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
meson.build | 1 +
target/i386/cpu.c | 10 +++++++++-
target/i386/helper.h | 2 +-
target/i386/tcg/misc_helper.c | 23 +++++++++++++++++------
target/i386/tcg/translate.c | 15 +++++++++++++--
5 files changed, 41 insertions(+), 10 deletions(-)
diff --git a/meson.build b/meson.build
index 34306a6205b..0f6c5a70333 100644
--- a/meson.build
+++ b/meson.build
@@ -2230,6 +2230,7 @@ config_host_data.set('CONFIG_CLOCK_ADJTIME', cc.has_function('clock_adjtime'))
config_host_data.set('CONFIG_DUP3', cc.has_function('dup3'))
config_host_data.set('CONFIG_FALLOCATE', cc.has_function('fallocate'))
config_host_data.set('CONFIG_POSIX_FALLOCATE', cc.has_function('posix_fallocate'))
+config_host_data.set('CONFIG_GETCPU', cc.has_function('getcpu', prefix: gnu_source_prefix))
# Note that we need to specify prefix: here to avoid incorrectly
# thinking that Windows has posix_memalign()
config_host_data.set('CONFIG_POSIX_MEMALIGN', cc.has_function('posix_memalign', prefix: '#include <stdlib.h>'))
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 2c71c3ea32b..974e2eb46d7 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -674,9 +674,17 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
/* missing:
CPUID_7_0_EBX_HLE
CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM */
+
+#if defined CONFIG_SOFTMMU || defined CONFIG_LINUX
+#define TCG_7_0_ECX_RDPID CPUID_7_0_ECX_RDPID
+#else
+#define TCG_7_0_ECX_RDPID 0
+#endif
#define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | \
/* CPUID_7_0_ECX_OSPKE is dynamic */ \
- CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES)
+ CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES | \
+ TCG_7_0_ECX_RDPID)
+
#define TCG_7_0_EDX_FEATURES CPUID_7_0_EDX_FSRM
#define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \
CPUID_7_1_EAX_FSRC)
diff --git a/target/i386/helper.h b/target/i386/helper.h
index 49d2f537557..d796f0d2f70 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -69,8 +69,8 @@ DEF_HELPER_2(into, void, env, int)
DEF_HELPER_FLAGS_1(single_step, TCG_CALL_NO_WG, noreturn, env)
DEF_HELPER_1(rechecking_single_step, void, env)
DEF_HELPER_1(cpuid, void, env)
+DEF_HELPER_FLAGS_1(rdpid, TCG_CALL_NO_WG, tl, env)
DEF_HELPER_1(rdtsc, void, env)
-DEF_HELPER_1(rdtscp, void, env)
DEF_HELPER_FLAGS_1(rdpmc, TCG_CALL_NO_WG, noreturn, env)
#ifndef CONFIG_USER_ONLY
diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c
index 5f7a3061ca5..66d6bbfcb40 100644
--- a/target/i386/tcg/misc_helper.c
+++ b/target/i386/tcg/misc_helper.c
@@ -75,12 +79,6 @@ void helper_rdtsc(CPUX86State *env)
env->regs[R_EDX] = (uint32_t)(val >> 32);
}
-void helper_rdtscp(CPUX86State *env)
-{
- helper_rdtsc(env);
- env->regs[R_ECX] = (uint32_t)(env->tsc_aux);
-}
-
G_NORETURN void helper_rdpmc(CPUX86State *env)
{
if (((env->cr[4] & CR4_PCE_MASK) == 0 ) &&
@@ -137,3 +135,16 @@ void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val)
env->pkru = val;
tlb_flush(cs);
}
+
+target_ulong HELPER(rdpid)(CPUX86State *env)
+{
+#if defined CONFIG_SOFTMMU
+ return env->tsc_aux;
+#elif defined CONFIG_LINUX && defined CONFIG_GETCPU
+ unsigned cpu, node;
+ getcpu(&cpu, &node);
+ return (node << 12) | (cpu & 0xfff);
+#else
+ return 0;
+#endif
+}
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index af74c842f96..a803bcb96b3 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -3924,7 +3924,16 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
gen_cmpxchg8b(s, env, modrm);
break;
- case 7: /* RDSEED */
+ case 7: /* RDSEED, RDPID with f3 prefix */
+ if (mod == 3 && !(s->prefix & PREFIX_LOCK) &&
+ (s->prefix & PREFIX_REPZ) &&
+ (s->cpuid_ext_features & CPUID_7_0_ECX_RDPID)) {
+ gen_helper_rdpid(s->T0, cpu_env);
+ rm = (modrm & 7) | REX_B(s);
+ gen_op_mov_reg_v(s, dflag, rm, s->T0);
+ break;
+ }
+ /* fallthrough */
case 6: /* RDRAND */
if (mod != 3 ||
(s->prefix & (PREFIX_LOCK | PREFIX_REPZ | PREFIX_REPNZ)) ||
@@ -6111,7 +6120,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
gen_update_cc_op(s);
gen_update_eip_cur(s);
translator_io_start(&s->base);
- gen_helper_rdtscp(cpu_env);
+ gen_helper_rdtsc(cpu_env);
+ gen_helper_rdpid(s->T0, cpu_env);
+ gen_op_mov_reg_v(s, dflag, R_ECX, s->T0);
break;
default:
--
2.40.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v2 10/10] target/i386: implement RDPID in TCG
2023-06-20 15:16 ` [PATCH v2 10/10] target/i386: implement RDPID in TCG Paolo Bonzini
@ 2023-06-20 16:23 ` Richard Henderson
0 siblings, 0 replies; 19+ messages in thread
From: Richard Henderson @ 2023-06-20 16:23 UTC (permalink / raw)
To: Paolo Bonzini, qemu-devel
On 6/20/23 17:16, Paolo Bonzini wrote:
> RDPID corresponds to a RDMSR(TSC_AUX); however, it is unprivileged
> so for user-mode emulation we must provide the value that the kernel
> places in the MSR. For Linux, it is a combination of the current CPU
> and the current NUMA node, both of which can be retrieved with getcpu(2).
> For BSD, just return 0.
>
> RDTSCP is reimplemented as RDTSC + RDPID ECX; the differences in terms
> of serializability are not relevant to QEMU.
>
> Signed-off-by: Paolo Bonzini<pbonzini@redhat.com>
> ---
> meson.build | 1 +
> target/i386/cpu.c | 10 +++++++++-
> target/i386/helper.h | 2 +-
> target/i386/tcg/misc_helper.c | 23 +++++++++++++++++------
> target/i386/tcg/translate.c | 15 +++++++++++++--
> 5 files changed, 41 insertions(+), 10 deletions(-)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 19+ messages in thread