Lilymonade
Lilymonade

Reputation: 475

External interrupt does not trigger when in Supervisor mode

I am writing a toy kernel to learn about operating systems. I am targeting a RISC-V machine (virt in qemu). I try to delegate interrupts to Supervisor mode, but I don't know why it does not work.

From what I read in the privileged architecture manual, I need to enable exceptions for supervisor in the mie CSR, and set bits from the exceptions I want to delegate in the mideleg and medeleg CSRs. But doing so does not raise any exception when having an external interrupt pending.

Software interrupts work, they are triggered and taken in S-mode, but External interrupts are not even triggering (not even in M-mode).

To understand what happens, I tried using gdb and watch for the mip register to change. I trigger the interrupt with the UART0 port of the machine (by pressing a key on my keyboard) and here is what happen.

Pressing a key sets a bit in mip which pauses the execution. And here is the state of the relevant CSR:

(gdb) p /x $sip
$3 = 0x200
(gdb) p /x $sie
$4 = 0x222
(gdb) p /x $mstatus
$5 = 0xaa
(gdb) p /x $mideleg
$6 = 0x666
(gdb) p /x $medeleg
$7 = 0xb0bfff
(gdb) p /x $scause
$8 = 0x0
(gdb) p /x $stval
$9 = 0x0

So the SEIP (supervisor external interrupt pending) bit is set, but nothing triggers. If I then continue execution I eventually trigger a Page Fault or an Illegal Instruction as these are software interrupts and are taken.

If I try to run a wfi instruction in supervisor mode, the same thing happens, and thuss the machine will be stuck at the wfi instruction.

Am I doing something wrong or is it virt ? If this question lacks details, please tell me, I will modify it.

Edit: it seems like the board on which the virt machine is based has for Hart 0 a SiFive E51 processor which does not support supervisor mode at all and of course I was using this hart for my bootloader.

But still, why does the simulator allow supervisor mode on this hart even though the documentation explicitely tells it implements only M and U modes ? And why are the synchronous exceptions still delegated into S-mode ?

Thank you

Upvotes: 2

Views: 937

Answers (1)

Lilymonade
Lilymonade

Reputation: 475

Precisions about the virt RISC-V machine

Changing from Hart 0 to Hart 1 as my main core did not change the problem.

By printing the misa and mimp CSRs, I can now tell that all cores of the virt machine have the same misa and implement Supervisor mode. So the machine is not based on the FU53 platform architecture, it just uses the same kind of global interruption system with a PLIC.

But the PLIC memory map is not the same as the FU53 which has no S-mode global interrupt memory mapped registers for Hart 0. Because of that, the addresses I used to enable S-mode global interruption were not the good ones.

In this file: qemu/virt.h at master · qemu/qemu you can find constants to use to compute the right PLIC addresses to use when setting it up.

I still don't fully understand why the pending bit in mip was set, but now it works.

tl;dr

So here is the state which made it work when going into S-mode. The PLIC addresses were the culprit.

mstatus: MPIE = 1, SIE = 1, MPP = 01
mie    : MEIE = MTIE = MSIE = SEIE = STIE = SSIE = 1 (mie=0xaaa)
mideleg: 0x222
medeleg: 0xb0bfff (which is set when writing 0xffffffff to it)

PLIC:
  - *0x0C00_2080 (Hart 0 S-mode enable) = 0x400 (enable UART0)
  - *0x0C00_0028 (Interrupt number 10 priority) = 1
  - *0x0C20_1000 (Hart 0 S-mode threshold) = 0

Upvotes: 3

Related Questions