Skip to content

Commit ed1b582

Browse files
committed
riscv: add optional architectural trap entry
1 parent 7c5db94 commit ed1b582

5 files changed

Lines changed: 68 additions & 2 deletions

File tree

include/uc_priv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ struct uc_struct {
335335
TargetPageBits *init_target_page;
336336
int target_bits; // User defined page bits by uc_ctl
337337
int cpu_model;
338+
bool architectural_exceptions;
338339
BounceBuffer bounce; // qemu/cpu-exec.c
339340
volatile sig_atomic_t exit_request; // qemu/cpu-exec.c
340341
/* qemu/accel/tcg/cpu-exec-common.c */

include/unicorn/unicorn.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,11 @@ typedef enum uc_control_type {
605605
// controle if context_save/restore should work with snapshots
606606
// Write: @args = (int)
607607
UC_CTL_CONTEXT_MODE,
608+
// Let the target CPU perform architectural exception entry before
609+
// UC_HOOK_INTR is invoked. Disabled by default for compatibility.
610+
// Write: @args = (int)
611+
// Read: @args = (int*)
612+
UC_CTL_UC_ARCHITECTURAL_EXCEPTIONS,
608613
} uc_control_type;
609614

610615
/*
@@ -688,6 +693,10 @@ See sample_ctl.c for a detailed example.
688693
uc_ctl(uc, UC_CTL_WRITE(UC_CTL_TCG_BUFFER_SIZE, 1), (size))
689694
#define uc_ctl_context_mode(uc, mode) \
690695
uc_ctl(uc, UC_CTL_WRITE(UC_CTL_CONTEXT_MODE, 1), (mode))
696+
#define uc_ctl_get_architectural_exceptions(uc, enabled) \
697+
uc_ctl(uc, UC_CTL_READ(UC_CTL_UC_ARCHITECTURAL_EXCEPTIONS, 1), (enabled))
698+
#define uc_ctl_set_architectural_exceptions(uc, enabled) \
699+
uc_ctl(uc, UC_CTL_WRITE(UC_CTL_UC_ARCHITECTURAL_EXCEPTIONS, 1), (enabled))
691700

692701
// Opaque storage for CPU context, used with uc_context_*()
693702
struct uc_context;

qemu/accel/tcg/cpu-exec.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,12 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
392392
#endif
393393
#if defined(TARGET_RISCV)
394394
CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env);
395-
env->pc += 4;
395+
int riscv_hook_exception = cpu->exception_index;
396+
if (uc->architectural_exceptions) {
397+
riscv_cpu_do_interrupt(cpu);
398+
} else {
399+
env->pc += 4;
400+
}
396401
#endif
397402
#if defined(TARGET_SPARC)
398403
CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env);
@@ -409,7 +414,13 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
409414
if (hook->to_delete) {
410415
continue;
411416
}
412-
JIT_CALLBACK_GUARD(((uc_cb_hookintr_t)hook->callback)(uc, cpu->exception_index, hook->user_data));
417+
JIT_CALLBACK_GUARD(((uc_cb_hookintr_t)hook->callback)(uc,
418+
#if defined(TARGET_RISCV)
419+
riscv_hook_exception,
420+
#else
421+
cpu->exception_index,
422+
#endif
423+
hook->user_data));
413424
catched = true;
414425
}
415426
// Unicorn: If un-catched interrupt, stop executions.

tests/unit/test_riscv.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,36 @@ static void test_riscv64_ecall(void)
459459
OK(uc_close(uc));
460460
}
461461

462+
static void test_riscv32_architectural_exception_entry(void)
463+
{
464+
uc_engine *uc;
465+
char code[] = "\x73\x00\x00\x00"; // ecall
466+
uint32_t mtvec = 0x1800;
467+
uint32_t pc, mepc, mcause, priv;
468+
int enabled = 0;
469+
uc_hook h;
470+
471+
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV32, code,
472+
sizeof(code) - 1);
473+
OK(uc_reg_write(uc, UC_RISCV_REG_MTVEC, &mtvec));
474+
OK(uc_ctl_set_architectural_exceptions(uc, 1));
475+
OK(uc_ctl_get_architectural_exceptions(uc, &enabled));
476+
TEST_CHECK(enabled == 1);
477+
OK(uc_hook_add(uc, &h, UC_HOOK_INTR, test_riscv64_ecall_cb, NULL, 1, 0));
478+
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
479+
480+
OK(uc_reg_read(uc, UC_RISCV_REG_PC, &pc));
481+
OK(uc_reg_read(uc, UC_RISCV_REG_MEPC, &mepc));
482+
OK(uc_reg_read(uc, UC_RISCV_REG_MCAUSE, &mcause));
483+
OK(uc_reg_read(uc, UC_RISCV_REG_PRIV, &priv));
484+
TEST_CHECK(pc == mtvec);
485+
TEST_CHECK(mepc == code_start);
486+
TEST_CHECK(mcause == 11); // machine-mode ecall
487+
TEST_CHECK(priv == 3); // machine mode
488+
489+
OK(uc_close(uc));
490+
}
491+
462492
static uint64_t test_riscv32_mmio_map_read_cb(uc_engine *uc, uint64_t offset,
463493
unsigned size, void *data)
464494
{
@@ -810,6 +840,8 @@ TEST_LIST = {
810840
test_riscv64_fp_move_from_int_reg_write},
811841
{"test_riscv64_fp_move_to_int", test_riscv64_fp_move_to_int},
812842
{"test_riscv64_ecall", test_riscv64_ecall},
843+
{"test_riscv32_architectural_exception_entry",
844+
test_riscv32_architectural_exception_entry},
813845
{"test_riscv32_mmio_map", test_riscv32_mmio_map},
814846
{"test_riscv64_mmio_map", test_riscv64_mmio_map},
815847
{"test_riscv32_map", test_riscv32_map},

uc.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2632,6 +2632,19 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...)
26322632
va_start(args, control);
26332633

26342634
switch (type) {
2635+
case UC_CTL_UC_ARCHITECTURAL_EXCEPTIONS: {
2636+
if (uc->arch != UC_ARCH_RISCV) {
2637+
err = UC_ERR_ARCH;
2638+
} else if (rw == UC_CTL_IO_READ) {
2639+
int *enabled = va_arg(args, int *);
2640+
*enabled = uc->architectural_exceptions;
2641+
} else if (rw == UC_CTL_IO_WRITE) {
2642+
uc->architectural_exceptions = !!va_arg(args, int);
2643+
} else {
2644+
err = UC_ERR_ARG;
2645+
}
2646+
break;
2647+
}
26352648
case UC_CTL_UC_MODE: {
26362649
if (rw == UC_CTL_IO_READ) {
26372650
int *pmode = va_arg(args, int *);

0 commit comments

Comments
 (0)