Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/uc_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ struct uc_struct {
TargetPageBits *init_target_page;
int target_bits; // User defined page bits by uc_ctl
int cpu_model;
bool architectural_exceptions;
BounceBuffer bounce; // qemu/cpu-exec.c
volatile sig_atomic_t exit_request; // qemu/cpu-exec.c
/* qemu/accel/tcg/cpu-exec-common.c */
Expand Down
9 changes: 9 additions & 0 deletions include/unicorn/unicorn.h
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,11 @@ typedef enum uc_control_type {
// controle if context_save/restore should work with snapshots
// Write: @args = (int)
UC_CTL_CONTEXT_MODE,
// Let the target CPU perform architectural exception entry before
// UC_HOOK_INTR is invoked. Disabled by default for compatibility.
// Write: @args = (int)
// Read: @args = (int*)
UC_CTL_UC_ARCHITECTURAL_EXCEPTIONS,
} uc_control_type;

/*
Expand Down Expand Up @@ -688,6 +693,10 @@ See sample_ctl.c for a detailed example.
uc_ctl(uc, UC_CTL_WRITE(UC_CTL_TCG_BUFFER_SIZE, 1), (size))
#define uc_ctl_context_mode(uc, mode) \
uc_ctl(uc, UC_CTL_WRITE(UC_CTL_CONTEXT_MODE, 1), (mode))
#define uc_ctl_get_architectural_exceptions(uc, enabled) \
uc_ctl(uc, UC_CTL_READ(UC_CTL_UC_ARCHITECTURAL_EXCEPTIONS, 1), (enabled))
#define uc_ctl_set_architectural_exceptions(uc, enabled) \
uc_ctl(uc, UC_CTL_WRITE(UC_CTL_UC_ARCHITECTURAL_EXCEPTIONS, 1), (enabled))

// Opaque storage for CPU context, used with uc_context_*()
struct uc_context;
Expand Down
10 changes: 8 additions & 2 deletions qemu/accel/tcg/cpu-exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
cpu->exception_index = -1;
return true;
} else {
int hook_exception = cpu->exception_index;
#if defined(TARGET_X86_64)
CPUArchState *env = cpu->env_ptr;
if (env->exception_is_int) {
Expand All @@ -392,7 +393,11 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
#endif
#if defined(TARGET_RISCV)
CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env);
env->pc += 4;
if (uc->architectural_exceptions) {
riscv_cpu_do_interrupt(cpu);
} else {
env->pc += 4;
}
#endif
#if defined(TARGET_SPARC)
CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env);
Expand All @@ -409,7 +414,8 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
if (hook->to_delete) {
continue;
}
JIT_CALLBACK_GUARD(((uc_cb_hookintr_t)hook->callback)(uc, cpu->exception_index, hook->user_data));
JIT_CALLBACK_GUARD(((uc_cb_hookintr_t)hook->callback)(
uc, hook_exception, hook->user_data));
catched = true;
}
// Unicorn: If un-catched interrupt, stop executions.
Expand Down
32 changes: 32 additions & 0 deletions tests/unit/test_riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,36 @@ static void test_riscv64_ecall(void)
OK(uc_close(uc));
}

static void test_riscv32_architectural_exception_entry(void)
{
uc_engine *uc;
char code[] = "\x73\x00\x00\x00"; // ecall
uint32_t mtvec = 0x1800;
uint32_t pc, mepc, mcause, priv;
int enabled = 0;
uc_hook h;

uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV32, code,
sizeof(code) - 1);
OK(uc_reg_write(uc, UC_RISCV_REG_MTVEC, &mtvec));
OK(uc_ctl_set_architectural_exceptions(uc, 1));
OK(uc_ctl_get_architectural_exceptions(uc, &enabled));
TEST_CHECK(enabled == 1);
OK(uc_hook_add(uc, &h, UC_HOOK_INTR, test_riscv64_ecall_cb, NULL, 1, 0));
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));

OK(uc_reg_read(uc, UC_RISCV_REG_PC, &pc));
OK(uc_reg_read(uc, UC_RISCV_REG_MEPC, &mepc));
OK(uc_reg_read(uc, UC_RISCV_REG_MCAUSE, &mcause));
OK(uc_reg_read(uc, UC_RISCV_REG_PRIV, &priv));
TEST_CHECK(pc == mtvec);
TEST_CHECK(mepc == code_start);
TEST_CHECK(mcause == 11); // machine-mode ecall
TEST_CHECK(priv == 3); // machine mode

OK(uc_close(uc));
}

static uint64_t test_riscv32_mmio_map_read_cb(uc_engine *uc, uint64_t offset,
unsigned size, void *data)
{
Expand Down Expand Up @@ -810,6 +840,8 @@ TEST_LIST = {
test_riscv64_fp_move_from_int_reg_write},
{"test_riscv64_fp_move_to_int", test_riscv64_fp_move_to_int},
{"test_riscv64_ecall", test_riscv64_ecall},
{"test_riscv32_architectural_exception_entry",
test_riscv32_architectural_exception_entry},
{"test_riscv32_mmio_map", test_riscv32_mmio_map},
{"test_riscv64_mmio_map", test_riscv64_mmio_map},
{"test_riscv32_map", test_riscv32_map},
Expand Down
13 changes: 13 additions & 0 deletions uc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2632,6 +2632,19 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...)
va_start(args, control);

switch (type) {
case UC_CTL_UC_ARCHITECTURAL_EXCEPTIONS: {
if (uc->arch != UC_ARCH_RISCV) {
err = UC_ERR_ARCH;
} else if (rw == UC_CTL_IO_READ) {
int *enabled = va_arg(args, int *);
*enabled = uc->architectural_exceptions;
} else if (rw == UC_CTL_IO_WRITE) {
uc->architectural_exceptions = !!va_arg(args, int);
} else {
err = UC_ERR_ARG;
}
break;
}
case UC_CTL_UC_MODE: {
if (rw == UC_CTL_IO_READ) {
int *pmode = va_arg(args, int *);
Expand Down