Skip to content

Handle signals properly #529

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 30, 2024
Merged
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
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
Loading