summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Mercl <0xjnml@gmail.com>2026-08-19 15:24:22 +0200
committerMichael Tokarev <mjt@tls.msk.ru>2026-08-21 13:05:17 +0300
commit9004e1cdabac80d9676efe224a61a868e871d94e (patch)
tree11dd4e7664393e577a65fc83ef1504e61a5a79ea
parentdcbe835ed0ac3d2b8896e79d135e327f56f57ad6 (diff)
downloadqemu-9004e1cdabac80d9676efe224a61a868e871d94e.tar.gz
qemu-9004e1cdabac80d9676efe224a61a868e871d94e.zip
target/loongarch: check FPE before reading fcc in bceqz/bcnez
gen_cz_bc() loads env->cf[cj] without CHECK_FPE, unlike every other translator that touches an fcc register (trans_fcmp.c.inc and trans_fmov.c.inc, for movcf2gr/movgr2cf/movcf2fr/movfr2cf/fsel). A guest that manages the FPU lazily -- Linux clears CSR.EUEN.FPE in lose_fpu() on every context switch -- relies on the next fcc access raising a Floating-Point-Disabled exception so the kernel can restore that task's fcc. Because bceqz and bcnez never raise it, they branch on the condition flag left behind by whichever task last owned the FPU. Real Loongson hardware does raise the exception, so this is TCG-only. It surfaces as Go binaries dying at startup in runtime.check() with "fatal error: float64nan1" -- roughly one process start in a thousand once the guest has more runnable tasks than vCPUs -- and in general as a conditional branch silently taking the wrong path. With four tasks each executing 5M bcnez on a 2-vCPU guest, master mispredicts 89 of 20000000. With this patch, 0 of 100000000 over five runs; a Loongson-3C5000 is likewise 0 of 600000000. CHECK_FPE is defined in trans_farith.c.inc, which translate.c includes before trans_branch.c.inc, so it is already in scope. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4209 Cc: qemu-stable@nongnu.org Signed-off-by: Jan Mercl <0xjnml@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-ID: <20260819132422.5164-1-0xjnml@gmail.com> Signed-off-by: Song Gao <gaosong@loongson.cn> (cherry picked from commit 215a4fc08f2aafce54c168cf41c64c79187430c1) Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
-rw-r--r--target/loongarch/tcg/insn_trans/trans_branch.c.inc2
1 files changed, 2 insertions, 0 deletions
diff --git a/target/loongarch/tcg/insn_trans/trans_branch.c.inc b/target/loongarch/tcg/insn_trans/trans_branch.c.inc
index f94c1f37ab..da07778658 100644
--- a/target/loongarch/tcg/insn_trans/trans_branch.c.inc
+++ b/target/loongarch/tcg/insn_trans/trans_branch.c.inc
@@ -66,6 +66,8 @@ static bool gen_cz_bc(DisasContext *ctx, arg_c_offs *a, TCGCond cond)
TCGv src1 = tcg_temp_new();
TCGv src2 = tcg_constant_tl(0);
+ CHECK_FPE;
+
tcg_gen_ld8u_tl(src1, tcg_env,
offsetof(CPULoongArchState, cf[a->cj]));
gen_bc(ctx, src1, src2, a->offs, cond);