tcg: Add EXCP_ATOMIC
When we cannot emulate an atomic operation within a parallel context, this exception allows us to stop the world and try again in a serial context. Reviewed-by: Emilio G. Cota <cota@braap.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
parent
1edaeee095
commit
fdbc2b5722
@ -77,3 +77,9 @@ void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc)
|
|||||||
}
|
}
|
||||||
siglongjmp(cpu->jmp_env, 1);
|
siglongjmp(cpu->jmp_env, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc)
|
||||||
|
{
|
||||||
|
cpu->exception_index = EXCP_ATOMIC;
|
||||||
|
cpu_loop_exit_restore(cpu, pc);
|
||||||
|
}
|
||||||
|
30
cpu-exec.c
30
cpu-exec.c
@ -222,6 +222,36 @@ static void cpu_exec_nocache(CPUState *cpu, int max_cycles,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void cpu_exec_step(CPUState *cpu)
|
||||||
|
{
|
||||||
|
CPUArchState *env = (CPUArchState *)cpu->env_ptr;
|
||||||
|
TranslationBlock *tb;
|
||||||
|
target_ulong cs_base, pc;
|
||||||
|
uint32_t flags;
|
||||||
|
|
||||||
|
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
||||||
|
tb = tb_gen_code(cpu, pc, cs_base, flags,
|
||||||
|
1 | CF_NOCACHE | CF_IGNORE_ICOUNT);
|
||||||
|
tb->orig_tb = NULL;
|
||||||
|
/* execute the generated code */
|
||||||
|
trace_exec_tb_nocache(tb, pc);
|
||||||
|
cpu_tb_exec(cpu, tb);
|
||||||
|
tb_phys_invalidate(tb, -1);
|
||||||
|
tb_free(tb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_exec_step_atomic(CPUState *cpu)
|
||||||
|
{
|
||||||
|
start_exclusive();
|
||||||
|
|
||||||
|
/* Since we got here, we know that parallel_cpus must be true. */
|
||||||
|
parallel_cpus = false;
|
||||||
|
cpu_exec_step(cpu);
|
||||||
|
parallel_cpus = true;
|
||||||
|
|
||||||
|
end_exclusive();
|
||||||
|
}
|
||||||
|
|
||||||
struct tb_desc {
|
struct tb_desc {
|
||||||
target_ulong pc;
|
target_ulong pc;
|
||||||
target_ulong cs_base;
|
target_ulong cs_base;
|
||||||
|
2
cpus.c
2
cpus.c
@ -1497,6 +1497,8 @@ static void tcg_exec_all(void)
|
|||||||
if (r == EXCP_DEBUG) {
|
if (r == EXCP_DEBUG) {
|
||||||
cpu_handle_guest_debug(cpu);
|
cpu_handle_guest_debug(cpu);
|
||||||
break;
|
break;
|
||||||
|
} else if (r == EXCP_ATOMIC) {
|
||||||
|
cpu_exec_step_atomic(cpu);
|
||||||
}
|
}
|
||||||
} else if (cpu->stop || cpu->stopped) {
|
} else if (cpu->stop || cpu->stopped) {
|
||||||
if (cpu->unplug) {
|
if (cpu->unplug) {
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
|
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
|
||||||
#define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */
|
#define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */
|
||||||
#define EXCP_YIELD 0x10004 /* cpu wants to yield timeslice to another */
|
#define EXCP_YIELD 0x10004 /* cpu wants to yield timeslice to another */
|
||||||
|
#define EXCP_ATOMIC 0x10005 /* stop-the-world and emulate atomic */
|
||||||
|
|
||||||
/* some important defines:
|
/* some important defines:
|
||||||
*
|
*
|
||||||
|
@ -59,6 +59,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
|||||||
|
|
||||||
void QEMU_NORETURN cpu_loop_exit(CPUState *cpu);
|
void QEMU_NORETURN cpu_loop_exit(CPUState *cpu);
|
||||||
void QEMU_NORETURN cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc);
|
void QEMU_NORETURN cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc);
|
||||||
|
void QEMU_NORETURN cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc);
|
||||||
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
void cpu_reloading_memory_map(void);
|
void cpu_reloading_memory_map(void);
|
||||||
|
@ -80,6 +80,7 @@ void tcg_exec_init(unsigned long tb_size);
|
|||||||
bool tcg_enabled(void);
|
bool tcg_enabled(void);
|
||||||
|
|
||||||
void cpu_exec_init_all(void);
|
void cpu_exec_init_all(void);
|
||||||
|
void cpu_exec_step_atomic(CPUState *cpu);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set_preferred_target_page_bits:
|
* set_preferred_target_page_bits:
|
||||||
|
@ -354,6 +354,9 @@ void cpu_loop(CPUX86State *env)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case EXCP_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
pc = env->segs[R_CS].base + env->eip;
|
pc = env->segs[R_CS].base + env->eip;
|
||||||
EXCP_DUMP(env, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
|
EXCP_DUMP(env, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
|
||||||
@ -851,6 +854,9 @@ void cpu_loop(CPUARMState *env)
|
|||||||
case EXCP_YIELD:
|
case EXCP_YIELD:
|
||||||
/* nothing to do here for user-mode, just resume guest code */
|
/* nothing to do here for user-mode, just resume guest code */
|
||||||
break;
|
break;
|
||||||
|
case EXCP_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error:
|
error:
|
||||||
EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
|
EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
|
||||||
@ -1051,6 +1057,9 @@ void cpu_loop(CPUARMState *env)
|
|||||||
case EXCP_YIELD:
|
case EXCP_YIELD:
|
||||||
/* nothing to do here for user-mode, just resume guest code */
|
/* nothing to do here for user-mode, just resume guest code */
|
||||||
break;
|
break;
|
||||||
|
case EXCP_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
|
EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
|
||||||
abort();
|
abort();
|
||||||
@ -1142,6 +1151,9 @@ void cpu_loop(CPUUniCore32State *env)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case EXCP_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -1415,6 +1427,9 @@ void cpu_loop (CPUSPARCState *env)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case EXCP_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf ("Unhandled trap: 0x%x\n", trapnr);
|
printf ("Unhandled trap: 0x%x\n", trapnr);
|
||||||
cpu_dump_state(cs, stderr, fprintf, 0);
|
cpu_dump_state(cs, stderr, fprintf, 0);
|
||||||
@ -1954,6 +1969,9 @@ void cpu_loop(CPUPPCState *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_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
cpu_abort(cs, "Unknown exception 0x%x. Aborting\n", trapnr);
|
cpu_abort(cs, "Unknown exception 0x%x. Aborting\n", trapnr);
|
||||||
break;
|
break;
|
||||||
@ -2649,6 +2667,9 @@ done_syscall:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case EXCP_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error:
|
error:
|
||||||
EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
|
EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
|
||||||
@ -2736,6 +2757,9 @@ void cpu_loop(CPUOpenRISCState *env)
|
|||||||
case EXCP_NR:
|
case EXCP_NR:
|
||||||
qemu_log_mask(CPU_LOG_INT, "\nNR\n");
|
qemu_log_mask(CPU_LOG_INT, "\nNR\n");
|
||||||
break;
|
break;
|
||||||
|
case EXCP_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
|
EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
|
||||||
trapnr);
|
trapnr);
|
||||||
@ -2812,6 +2836,9 @@ void cpu_loop(CPUSH4State *env)
|
|||||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EXCP_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf ("Unhandled trap: 0x%x\n", trapnr);
|
printf ("Unhandled trap: 0x%x\n", trapnr);
|
||||||
cpu_dump_state(cs, stderr, fprintf, 0);
|
cpu_dump_state(cs, stderr, fprintf, 0);
|
||||||
@ -2879,6 +2906,9 @@ void cpu_loop(CPUCRISState *env)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case EXCP_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf ("Unhandled trap: 0x%x\n", trapnr);
|
printf ("Unhandled trap: 0x%x\n", trapnr);
|
||||||
cpu_dump_state(cs, stderr, fprintf, 0);
|
cpu_dump_state(cs, stderr, fprintf, 0);
|
||||||
@ -2995,6 +3025,9 @@ void cpu_loop(CPUMBState *env)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case EXCP_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf ("Unhandled trap: 0x%x\n", trapnr);
|
printf ("Unhandled trap: 0x%x\n", trapnr);
|
||||||
cpu_dump_state(cs, stderr, fprintf, 0);
|
cpu_dump_state(cs, stderr, fprintf, 0);
|
||||||
@ -3098,6 +3131,9 @@ void cpu_loop(CPUM68KState *env)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case EXCP_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
|
EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
|
||||||
abort();
|
abort();
|
||||||
@ -3334,6 +3370,9 @@ void cpu_loop(CPUAlphaState *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_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf ("Unhandled trap: 0x%x\n", trapnr);
|
printf ("Unhandled trap: 0x%x\n", trapnr);
|
||||||
cpu_dump_state(cs, stderr, fprintf, 0);
|
cpu_dump_state(cs, stderr, fprintf, 0);
|
||||||
@ -3463,6 +3502,9 @@ void cpu_loop(CPUS390XState *env)
|
|||||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EXCP_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
|
fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
|
||||||
cpu_dump_state(cs, stderr, fprintf, 0);
|
cpu_dump_state(cs, stderr, fprintf, 0);
|
||||||
@ -3717,6 +3759,9 @@ void cpu_loop(CPUTLGState *env)
|
|||||||
case TILEGX_EXCP_REG_UDN_ACCESS:
|
case TILEGX_EXCP_REG_UDN_ACCESS:
|
||||||
gen_sigill_reg(env);
|
gen_sigill_reg(env);
|
||||||
break;
|
break;
|
||||||
|
case EXCP_ATOMIC:
|
||||||
|
cpu_exec_step_atomic(cs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "trapnr is %d[0x%x].\n", trapnr, trapnr);
|
fprintf(stderr, "trapnr is %d[0x%x].\n", trapnr, trapnr);
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
|
@ -704,6 +704,7 @@ struct TCGContext {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern TCGContext tcg_ctx;
|
extern TCGContext tcg_ctx;
|
||||||
|
extern bool parallel_cpus;
|
||||||
|
|
||||||
static inline void tcg_set_insn_param(int op_idx, int arg, TCGArg v)
|
static inline void tcg_set_insn_param(int op_idx, int arg, TCGArg v)
|
||||||
{
|
{
|
||||||
|
@ -118,6 +118,7 @@ static void *l1_map[V_L1_MAX_SIZE];
|
|||||||
|
|
||||||
/* code generation context */
|
/* code generation context */
|
||||||
TCGContext tcg_ctx;
|
TCGContext tcg_ctx;
|
||||||
|
bool parallel_cpus;
|
||||||
|
|
||||||
/* translation block context */
|
/* translation block context */
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
Loading…
Reference in New Issue
Block a user