mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-05 20:35:44 +00:00
linux-user/nios2: Properly emulate EXCP_TRAP
The real kernel has to load the instruction and extract the imm5 field; for qemu, modify the translator to do this. The use of R_AT for this in cpu_loop was a bug. Handle the other trap numbers as per the kernel's trap_table. Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Laurent Vivier <laurent@vivier.eu> Message-Id: <20211221025012.1057923-2-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
This commit is contained in:
parent
e13685a6e5
commit
87d7bfdba1
3 changed files with 39 additions and 20 deletions
|
@ -26,7 +26,6 @@
|
||||||
void cpu_loop(CPUNios2State *env)
|
void cpu_loop(CPUNios2State *env)
|
||||||
{
|
{
|
||||||
CPUState *cs = env_cpu(env);
|
CPUState *cs = env_cpu(env);
|
||||||
Nios2CPU *cpu = NIOS2_CPU(cs);
|
|
||||||
target_siginfo_t info;
|
target_siginfo_t info;
|
||||||
int trapnr, ret;
|
int trapnr, ret;
|
||||||
|
|
||||||
|
@ -39,9 +38,10 @@ void cpu_loop(CPUNios2State *env)
|
||||||
case EXCP_INTERRUPT:
|
case EXCP_INTERRUPT:
|
||||||
/* just indicate that signals should be handled asap */
|
/* just indicate that signals should be handled asap */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXCP_TRAP:
|
case EXCP_TRAP:
|
||||||
if (env->regs[R_AT] == 0) {
|
switch (env->error_code) {
|
||||||
abi_long ret;
|
case 0:
|
||||||
qemu_log_mask(CPU_LOG_INT, "\nSyscall\n");
|
qemu_log_mask(CPU_LOG_INT, "\nSyscall\n");
|
||||||
|
|
||||||
ret = do_syscall(env, env->regs[2],
|
ret = do_syscall(env, env->regs[2],
|
||||||
|
@ -55,26 +55,30 @@ void cpu_loop(CPUNios2State *env)
|
||||||
|
|
||||||
env->regs[2] = abs(ret);
|
env->regs[2] = abs(ret);
|
||||||
/* Return value is 0..4096 */
|
/* Return value is 0..4096 */
|
||||||
env->regs[7] = (ret > 0xfffffffffffff000ULL);
|
env->regs[7] = ret > 0xfffff000u;
|
||||||
env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
|
|
||||||
env->regs[CR_STATUS] &= ~0x3;
|
|
||||||
env->regs[R_EA] = env->regs[R_PC] + 4;
|
|
||||||
env->regs[R_PC] += 4;
|
env->regs[R_PC] += 4;
|
||||||
break;
|
break;
|
||||||
} else {
|
|
||||||
qemu_log_mask(CPU_LOG_INT, "\nTrap\n");
|
|
||||||
|
|
||||||
env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
|
case 1:
|
||||||
env->regs[CR_STATUS] &= ~0x3;
|
qemu_log_mask(CPU_LOG_INT, "\nTrap 1\n");
|
||||||
env->regs[R_EA] = env->regs[R_PC] + 4;
|
force_sig_fault(TARGET_SIGUSR1, 0, env->regs[R_PC]);
|
||||||
env->regs[R_PC] = cpu->exception_addr;
|
break;
|
||||||
|
case 2:
|
||||||
info.si_signo = TARGET_SIGTRAP;
|
qemu_log_mask(CPU_LOG_INT, "\nTrap 2\n");
|
||||||
info.si_errno = 0;
|
force_sig_fault(TARGET_SIGUSR2, 0, env->regs[R_PC]);
|
||||||
info.si_code = TARGET_TRAP_BRKPT;
|
break;
|
||||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
case 31:
|
||||||
|
qemu_log_mask(CPU_LOG_INT, "\nTrap 31\n");
|
||||||
|
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->regs[R_PC]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qemu_log_mask(CPU_LOG_INT, "\nTrap %d\n", env->error_code);
|
||||||
|
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLTRP,
|
||||||
|
env->regs[R_PC]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case EXCP_DEBUG:
|
case EXCP_DEBUG:
|
||||||
info.si_signo = TARGET_SIGTRAP;
|
info.si_signo = TARGET_SIGTRAP;
|
||||||
info.si_errno = 0;
|
info.si_errno = 0;
|
||||||
|
|
|
@ -160,9 +160,9 @@ struct CPUNios2State {
|
||||||
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
Nios2MMU mmu;
|
Nios2MMU mmu;
|
||||||
|
|
||||||
uint32_t irq_pending;
|
uint32_t irq_pending;
|
||||||
#endif
|
#endif
|
||||||
|
int error_code;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -636,6 +636,21 @@ static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
|
||||||
tcg_temp_free(t0);
|
tcg_temp_free(t0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void trap(DisasContext *dc, uint32_t code, uint32_t flags)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
/*
|
||||||
|
* The imm5 field is not stored anywhere on real hw; the kernel
|
||||||
|
* has to load the insn and extract the field. But we can make
|
||||||
|
* things easier for cpu_loop if we pop this into env->error_code.
|
||||||
|
*/
|
||||||
|
R_TYPE(instr, code);
|
||||||
|
tcg_gen_st_i32(tcg_constant_i32(instr.imm5), cpu_env,
|
||||||
|
offsetof(CPUNios2State, error_code));
|
||||||
|
#endif
|
||||||
|
t_gen_helper_raise_exception(dc, EXCP_TRAP);
|
||||||
|
}
|
||||||
|
|
||||||
static const Nios2Instruction r_type_instructions[] = {
|
static const Nios2Instruction r_type_instructions[] = {
|
||||||
INSTRUCTION_ILLEGAL(),
|
INSTRUCTION_ILLEGAL(),
|
||||||
INSTRUCTION(eret), /* eret */
|
INSTRUCTION(eret), /* eret */
|
||||||
|
@ -682,7 +697,7 @@ static const Nios2Instruction r_type_instructions[] = {
|
||||||
INSTRUCTION_ILLEGAL(),
|
INSTRUCTION_ILLEGAL(),
|
||||||
INSTRUCTION_ILLEGAL(),
|
INSTRUCTION_ILLEGAL(),
|
||||||
INSTRUCTION_ILLEGAL(),
|
INSTRUCTION_ILLEGAL(),
|
||||||
INSTRUCTION_FLG(gen_excp, EXCP_TRAP), /* trap */
|
INSTRUCTION(trap), /* trap */
|
||||||
INSTRUCTION(wrctl), /* wrctl */
|
INSTRUCTION(wrctl), /* wrctl */
|
||||||
INSTRUCTION_ILLEGAL(),
|
INSTRUCTION_ILLEGAL(),
|
||||||
INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU), /* cmpltu */
|
INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU), /* cmpltu */
|
||||||
|
|
Loading…
Reference in a new issue