linux-user/loongarch64/cpu_loop.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
Handle specific LoongArch BRK break codes in user-mode emulation
to deliver accurate floating-point exception signals. Specifically,
BRK_OVERFLOW (6) triggers TARGET_FPE_INTOVF, and BRK_DIVZERO (7)
triggers TARGET_FPE_INTDIV. Other BRK codes fall back to a generic
SIGTRAP.
This improves correctness for programs that rely on BRK to signal
overflow or divide-by-zero conditions.
Signed-off-by: WANG Rui <wangrui@loongson.cn>
---
linux-user/loongarch64/cpu_loop.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c
index 0614d3de22..ec8a06c88c 100644
--- a/linux-user/loongarch64/cpu_loop.c
+++ b/linux-user/loongarch64/cpu_loop.c
@@ -11,6 +11,12 @@
#include "user/cpu_loop.h"
#include "signal-common.h"
+/* Break codes */
+enum {
+ BRK_OVERFLOW = 6,
+ BRK_DIVZERO = 7
+};
+
void cpu_loop(CPULoongArchState *env)
{
CPUState *cs = env_cpu(env);
@@ -66,9 +72,26 @@ void cpu_loop(CPULoongArchState *env)
force_sig_fault(TARGET_SIGFPE, si_code, env->pc);
break;
case EXCP_DEBUG:
- case EXCCODE_BRK:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
break;
+ case EXCCODE_BRK:
+ {
+ unsigned int opcode;
+
+ get_user_u32(opcode, env->pc);
+
+ switch (opcode & 0x7fff) {
+ case BRK_OVERFLOW:
+ force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->pc);
+ break;
+ case BRK_DIVZERO:
+ force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc);
+ break;
+ default:
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
+ }
+ }
+ break;
case EXCCODE_BCE:
force_sig_fault(TARGET_SIGSYS, TARGET_SI_KERNEL, env->pc);
break;
--
2.49.0
在 2025/4/14 下午3:49, WANG Rui 写道: > Handle specific LoongArch BRK break codes in user-mode emulation > to deliver accurate floating-point exception signals. Specifically, > BRK_OVERFLOW (6) triggers TARGET_FPE_INTOVF, and BRK_DIVZERO (7) > triggers TARGET_FPE_INTDIV. Other BRK codes fall back to a generic > SIGTRAP. > > This improves correctness for programs that rely on BRK to signal > overflow or divide-by-zero conditions. > > Signed-off-by: WANG Rui <wangrui@loongson.cn> > --- > linux-user/loongarch64/cpu_loop.c | 25 ++++++++++++++++++++++++- > 1 file changed, 24 insertions(+), 1 deletion(-) Acked-by: Song Gao <gaosong@loongson.cn> thanks. Song Gao > diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c > index 0614d3de22..ec8a06c88c 100644 > --- a/linux-user/loongarch64/cpu_loop.c > +++ b/linux-user/loongarch64/cpu_loop.c > @@ -11,6 +11,12 @@ > #include "user/cpu_loop.h" > #include "signal-common.h" > > +/* Break codes */ > +enum { > + BRK_OVERFLOW = 6, > + BRK_DIVZERO = 7 > +}; > + > void cpu_loop(CPULoongArchState *env) > { > CPUState *cs = env_cpu(env); > @@ -66,9 +72,26 @@ void cpu_loop(CPULoongArchState *env) > force_sig_fault(TARGET_SIGFPE, si_code, env->pc); > break; > case EXCP_DEBUG: > - case EXCCODE_BRK: > force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); > break; > + case EXCCODE_BRK: > + { > + unsigned int opcode; > + > + get_user_u32(opcode, env->pc); > + > + switch (opcode & 0x7fff) { > + case BRK_OVERFLOW: > + force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->pc); > + break; > + case BRK_DIVZERO: > + force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc); > + break; > + default: > + force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); > + } > + } > + break; > case EXCCODE_BCE: > force_sig_fault(TARGET_SIGSYS, TARGET_SI_KERNEL, env->pc); > break;
© 2016 - 2025 Red Hat, Inc.