Skip to content

Commit

Permalink
Merge pull request #529 from ChinYikMing/handle-signal
Browse files Browse the repository at this point in the history
Handle signals properly
  • Loading branch information
jserv authored Dec 30, 2024
2 parents e89e613 + 8e08387 commit 5a04f3a
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 8 deletions.
12 changes: 10 additions & 2 deletions src/emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ static bool need_clear_block_map = false;
static uint32_t reloc_enable_mmu_jalr_addr;
static bool reloc_enable_mmu = false;
bool need_retranslate = false;
bool need_handle_signal = false;
#endif

static void rv_trap_default_handler(riscv_t *rv)
Expand Down Expand Up @@ -379,8 +380,12 @@ static uint32_t peripheral_update_ctr = 64;
{ \
IIF(RV32_HAS(SYSTEM))(ctr++;, ) cycle++; \
code; \
nextop: \
PC += __rv_insn_##inst##_len; \
IIF(RV32_HAS(SYSTEM)) \
( \
if (need_handle_signal) { \
need_handle_signal = false; \
return true; \
}, ) nextop : PC += __rv_insn_##inst##_len; \
IIF(RV32_HAS(SYSTEM)) \
(IIF(RV32_HAS(JIT))( \
, if (unlikely(need_clear_block_map)) { \
Expand Down Expand Up @@ -1219,6 +1224,9 @@ static void _trap_handler(riscv_t *rv)
mode = rv->csr_stvec & 0x3;
cause = rv->csr_scause;
rv->csr_sepc = rv->PC;
#if RV32_HAS(SYSTEM)
rv->last_csr_sepc = rv->csr_sepc;
#endif
} else { /* machine */
const uint32_t mstatus_mie =
(rv->csr_mstatus & MSTATUS_MIE) >> MSTATUS_MIE_SHIFT;
Expand Down
6 changes: 6 additions & 0 deletions src/riscv_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,12 @@ struct riscv_internal {
#if RV32_HAS(SYSTEM)
/* The flag is used to indicate the current emulation is in a trap */
bool is_trapped;

/*
* The flag that stores the SEPC CSR at the trap point for corectly
* executing signal handler.
*/
uint32_t last_csr_sepc;
#endif
};

Expand Down
59 changes: 53 additions & 6 deletions src/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ void emu_update_uart_interrupts(riscv_t *rv)
plic_update_interrupts(attr->plic);
}

/*
* Linux kernel might create signal frame when returning from trap
* handling, which modifies the SEPC CSR. Thus, the fault instruction
* cannot always redo. For example, invalid memory access causes SIGSEGV.
*/
extern bool need_handle_signal;
#define CHECK_PENDING_SIGNAL(rv, signal_flag) \
do { \
signal_flag = (rv->csr_sepc != rv->last_csr_sepc); \
} while (0)

#define MMIO_R 1
#define MMIO_W 0

Expand Down Expand Up @@ -297,8 +308,14 @@ static uint32_t mmu_read_w(riscv_t *rv, const uint32_t addr)
uint32_t level;
pte_t *pte = mmu_walk(rv, addr, &level);
bool ok = MMU_FAULT_CHECK(read, rv, pte, addr, PTE_R);
if (unlikely(!ok))
if (unlikely(!ok)) {
#if RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER)
CHECK_PENDING_SIGNAL(rv, need_handle_signal);
if (need_handle_signal)
return 0;
#endif
pte = mmu_walk(rv, addr, &level);
}

{
get_ppn_and_offset();
Expand All @@ -323,8 +340,14 @@ static uint16_t mmu_read_s(riscv_t *rv, const uint32_t addr)
uint32_t level;
pte_t *pte = mmu_walk(rv, addr, &level);
bool ok = MMU_FAULT_CHECK(read, rv, pte, addr, PTE_R);
if (unlikely(!ok))
if (unlikely(!ok)) {
#if RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER)
CHECK_PENDING_SIGNAL(rv, need_handle_signal);
if (need_handle_signal)
return 0;
#endif
pte = mmu_walk(rv, addr, &level);
}

get_ppn_and_offset();
return memory_read_s(ppn | offset);
Expand All @@ -338,8 +361,14 @@ static uint8_t mmu_read_b(riscv_t *rv, const uint32_t addr)
uint32_t level;
pte_t *pte = mmu_walk(rv, addr, &level);
bool ok = MMU_FAULT_CHECK(read, rv, pte, addr, PTE_R);
if (unlikely(!ok))
if (unlikely(!ok)) {
#if RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER)
CHECK_PENDING_SIGNAL(rv, need_handle_signal);
if (need_handle_signal)
return 0;
#endif
pte = mmu_walk(rv, addr, &level);
}

{
get_ppn_and_offset();
Expand All @@ -364,8 +393,14 @@ static void mmu_write_w(riscv_t *rv, const uint32_t addr, const uint32_t val)
uint32_t level;
pte_t *pte = mmu_walk(rv, addr, &level);
bool ok = MMU_FAULT_CHECK(write, rv, pte, addr, PTE_W);
if (unlikely(!ok))
if (unlikely(!ok)) {
#if RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER)
CHECK_PENDING_SIGNAL(rv, need_handle_signal);
if (need_handle_signal)
return;
#endif
pte = mmu_walk(rv, addr, &level);
}

{
get_ppn_and_offset();
Expand All @@ -390,8 +425,14 @@ static void mmu_write_s(riscv_t *rv, const uint32_t addr, const uint16_t val)
uint32_t level;
pte_t *pte = mmu_walk(rv, addr, &level);
bool ok = MMU_FAULT_CHECK(write, rv, pte, addr, PTE_W);
if (unlikely(!ok))
if (unlikely(!ok)) {
#if RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER)
CHECK_PENDING_SIGNAL(rv, need_handle_signal);
if (need_handle_signal)
return;
#endif
pte = mmu_walk(rv, addr, &level);
}

get_ppn_and_offset();
memory_write_s(ppn | offset, (uint8_t *) &val);
Expand All @@ -405,8 +446,14 @@ static void mmu_write_b(riscv_t *rv, const uint32_t addr, const uint8_t val)
uint32_t level;
pte_t *pte = mmu_walk(rv, addr, &level);
bool ok = MMU_FAULT_CHECK(write, rv, pte, addr, PTE_W);
if (unlikely(!ok))
if (unlikely(!ok)) {
#if RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER)
CHECK_PENDING_SIGNAL(rv, need_handle_signal);
if (need_handle_signal)
return;
#endif
pte = mmu_walk(rv, addr, &level);
}

{
get_ppn_and_offset();
Expand Down

0 comments on commit 5a04f3a

Please sign in to comment.