Reputation: 475
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
Reputation: 475
virt
RISC-V machineChanging 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.
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