[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Handling Timer Interrupts in Supervisor Mode (machine virt)

From: Alek Fröhlich
Subject: Handling Timer Interrupts in Supervisor Mode (machine virt)
Date: Mon, 5 Apr 2021 13:08:29 -0300

Hello all,

I am implementing a C++ Micro Kernel for RISCV, and I am having trouble to arrive at a good solution for the handling of timer interrupts.

I'd desire to run the entire system (after its setup phase) in supervisor/user mode, but, as it seems, there is no way to make the CLINT generate STI interrupt requests so that mideleg can automatically forward them to the S-mode handler pointed by stvec.

I took this conclusion based on two pieces of evidence:
  1. The RISCV privileged specification (version 1.10) lets it be understood that the bit MTI (on MIP) is hardwired to the comparison (mtime >= mtimecmp)?
  2. The QEMU implementation of Sifive's CLINT doesn't perform any tests (e.g., "am I configured to cause S-Mode IRQs"?) before issuing a MTI request (see this)
Then, the only solution I found was to always let the STI bit on SIP turned on and to let a M-mode handler turn the corresponding SIE bit (the S-mode handler is responsible for clearing this bit so as to avoid looping on STI IRQs).

This is not very satisfying; are there any other alternatives that would allow my kernel to have a preemptive scheduler without the need of ever switching back to M-mode?

After all, switching to M-mode after the setup has all kinds of unnecessary complications; to name one, consider the scenario where the M-mode handler has to save some of the process' context before being able to perform its task (this is currently the case; I've left a picture of my actual M-mode handler below). In this scenario, a stack must be used; but which stack? $sp, at the time the handler starts executing, points to a virtual address that, in my case, isn't even valid physical memory. Hence, one must also set aside a kernel stack for handling M-mode interrupts.

Of course, later when I have syscalls implemented, there will be another need for such kstack; however, that is only to illustrate my point.

[Handler; how would you even take advantage of __attribute__((interrupt)) if you had to fiddle with $sp before saving context?]

extern "C" [[gnu::interrupt, gnu::aligned(4)]] void _mmode_forward() {
Reg id = CPU::mcause();
Reg interrupt_id = 1 << ((id & IC::INT_MASK) - 2);
if(CPU::int_enabled() && (CPU::sie() & (interrupt_id)))

-machine virt -cpu rv32gcsu-v1.10.0 -smp $(CPUS) -m $(MEM_SIZE)k -serial mon:stdio -bios none -nographic -no-reboot -kernel

Where, for now, CPUS=1 and MEM_SIZE ends up totalling 128Mb.

Thanks very much for your attention,
Alek Frohlich.

ps: I was not sure if this was the correct medium to post this question; if it was not, I apologize.
ps2: If needed, I can attach the current version of the kernel I mentioned.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]