Search code examples
interruptinterrupt-handlingriscv

In RISC-V CLINT vector mode, does the synchronous exception handler is same with the ID=0 interrupt handler(User software interrupt)?


In RISC-V Manual Volume II, it said:

When MODE=Vectored, all synchronous exceptions into machine mode cause the pc to be set to the address in the BASE field, whereas interrupts cause the pc to be set to the address in the BASE field plus four times the interrupt cause number.

Does the synchronous exception handler is same with the ID=0 interrupt handler(User software interrupt) ? And I try to solve my question on qemu-system-riscv64 virt, and my steps following, I try to test exception, user software interrupt and machine timer interrupt:

# boot:
la t0, __vector_table
xor t0, t0, 1 # vector mode
csrw mtvec, t0

# vector table
__vector_table:
IRQ_0:
        j trap_handler_entry 
IRQ_1:
        j trap_handler_entry
             ...
IRQ_7:
        j timer_interrupt_vector_handler

# handler at vector table index 0
trap_handler_entry:
    SAVE_REGISTER
    j trap_handler # trap_handler is the handler 
                   # I used to handle all trap in direct mode
    RESTORE_REGISTER
    mret
# timer handler
void __atrributr__ ((interrupt)) timer_interrupt_vector_handler { 
    add new value in mtimecmp
}

At this point I test ecall and timer interrupt, when timer interrupt and ecall happens it surely go to the function in vector table, ecall -> INDEX=0, timer -> INDEX=7 And then I try to trigger a user software interrupt, like:

# Test function
while(1) {
    if (odd round) { ecall }
    else {
        set_csr(mip, USIP);
        /* Test func in M mode, enable USIE in MIE, 
         * and other interrupts works well */
    }
}

But there no user software interrupt happens, the manual saids:

Each lower privilege level has a separate software interrupt-pending bit (SSIP, USIP), which can be both read and written by CSR accesses from code running on the local hart at the associated or any higher privilege level.

And I'm sure I can get Supervisor Software Interrupt by set MIP_SSIP. And I check the interrupt raise function in Spike, I found that there is no user softeware interrupt ... The manual also said:

If user-level interrupts are not supported, USIP and USIE are hardwired to zero.

So I print the mie to ckeck it:

# config in mie and mstatus
write_csr(mie, read_csr(mie) | MIP_MTIP | MIP_MSIP | MIP_SSIP | MIP_USIP);
write_csr(mstatus, (read_csr(mstatus) | MSTATUS_MIE | MSTATUS_SIE | MSTATUS_UIE));
# Set mie and mip in test func
set_csr(mie, MIP_USIP);
set_csr(mip, MIP_USIP);
# Result before and after set
MIE >> 000000000000008a # before
MIP >> 0000000000000000
MIE >> 000000000000008a # after
MIP >> 0000000000000000

The USIP and USIE are hardwired to zero ! So, maybe there is no USI right now ? But depends on the first try, I think synchronous exception actully using the ID=0 interrupt handler(User software interrupt). It seems may the answer of my question is yes ... And the conflict is avoid by no user software interrupt ? Is this right? Does there any conflict ?


Solution

  • USIP and USIE hardwired to zero is an implementation detail. The Volume II: RISC-V Privileged Architectures V1.10 states:

    When vectored interrupts are enabled, interrupt cause 0, which corresponds to user-mode soft- ware interrupts, are vectored to the same location as synchronous exceptions. This ambiguity does not arise in practice, since user-mode software interrupts are either disabled or delegated to a less-privileged mode.

    So basically the anser is yes, the synchronous exception handler is same as the user software interrupt interrupt handler.