Open jklmnn opened 6 years ago
Funnily there is an official way to receive signals through a file descriptor. See signalfd(2)
. I still don't think we should do it like this...
Have a look into the implementation of the signal(2) system call. Our ioctl would need to setup up a signal handler for calling processes in a similar way.
I've read through the IRQ session section in the Genode Foundations book. According to section 3.4.7 the IRQ session
provides an operation to wait for the next interrupt. Only while the IRQ client is waiting for an interrupt, core unmasks the interrupt at the interrupt controller. Once the interrupt occurs, core wakes up the IRQ client and masks the interrupt at the interrupt controller until the driver has acknowledged the completion of the IRQ handling and waits for the next interrupt.
If I understand this correctly there is a blocking wait the gets scheduled once the block is released. This could be a starting point for an interrupt session based on a Linux device.
The idea would be to configure a file descriptor on the device with ioctl to listen to a specific interrupt. The wait operation would then call a blocking read on this file descriptor and continue to run once this read returns. On the Linux side the read would return once the interrupt is triggered (the implementation would depend on whatever mechanisms the Linux kernel provides would fit best). The acknowledge would result in the read being called again (as the session waits for the next interrupt) which itself would acknowledge the interrupt to the kernel (if this is required).
A question is what would happen if the interrupts are handled to slow. The kernel module could either queue them and deliver once it has been acknowledged (depends on the behaviour of the Linux kernel if this is useful) or drop interrupts. Also a combination of both would be imaginable, for example to queue them up to a certain number and drop then.
The security would be achieved similary to the memory mapped IO with the configuration ioctl that traps and can be called once only.
I believe we settled on a implementation using a file descriptor and a blocking read() where interrupts are not queued by the kernel. Interrupts get unmasked only as long as the client is waiting in read(). Performing the next read() after an interrupt acknowledges the previous interrupt. There is a 1:1 mapping from file descriptor to IRQ.
The only concern I have is situation where an interrupt needs to be acknowledged without already waiting for the next interrupt. I don't know whether those situations exist in real-world scenarios, though. Let's assume this model is OK for now.
How did we say a mapping is established? ioctl()?
As far as I understand the Genode Book acknowledging the interrupt is defined as explicitly waiting for the next one do I don't see any reason to do it otherwise.
Only while the IRQ client is waiting for an interrupt, core unmasks the interrupt at the interrupt controller. Once the interrupt occurs, core wakes up the IRQ client and masks the interrupt at the interrupt controller until the driver has acknowledged the completion of the IRQ handling and waits for the next interrupt.
The idea was to extend the hwio device with another trapping ioctl that configures the file descriptor as an interrupt. Once it is configured it blocks on reading and returns when the interrupt has been triggered.
OK, I remember. Make it so.
We also discovered that we need explicit trapdoors then in favor of the address ranges.
This is not a problem as I have to change the private_data structure anyway.
https://github.com/jklmnn/hwiodev/commit/c445eb58daa6d29e9f779bf6ad4b00818fba6659 implements interrupts with a blocking read. A test is available at https://gist.github.com/jklmnn/4a30450a4b731cacdf1e06170bb46e61.
With the current concept, the IRQ in the Linux kernel is acked as soon as it has unlocked the read. Yet in Genode it could still be waiting for its acknowledgement. To snychronize this the write call could be implemented that acks the kernel IRQ when ack_irq is called in Genode.
With https://github.com/jklmnn/genode/commit/166075bdaf7e20546c856066a7024a557d4979ac and the latest hwio module I am able to successfully run the IRQ session and the test-input on Linux!
I added a demo that completely runs on base-linux and has usable input with ps2 input (https://github.com/jklmnn/base-linux-hw/commit/12761eceaa8c593ce0eb604faf5b5685371de1f1). Yet the interrupts seem to be horribly slow, at least on Qemu. I have not yet tested it on real hardware.
I tested the demo on the X260 and the mouse perfomance and usability is actually quite good. It sometimes might behave a little bit slow, but this is only personal feeling and nothing I can measure.
To be able to delay the irq handler to the next read, I have to use request_threaded_irq instead of request_irq.
Are you sure you need request_threaded_irq
? If I get it correctly, this is for performing long-running tasks which must not run in interrupt context. Don't we rather need a way to decouple interrupt handling from interrupt unmasking?
I did not find a way to mask an interrupt outside the interrupt handler. I also did not find a solution to delay the interrupt handler without using a threaded irq.
I don't think that this solves your issue. What prevents you from calling disable_irq()
in the interrupt handler and a corresponding enable_irq()
when handling the next read()
? Old sources imply that drivers for slow devices use this to reduce interrupt load.
I have implemented this with enable_irq()
and disable_irq()
but I could not spot any notable performance difference (https://github.com/jklmnn/hwiodev/commit/4a91173d628f8a7cdc23b85a19fc2563db3630cc).
The current idea is to send a signal to the process holding the file descriptor.
The
current
macro in the kernel seems to be the solution to get context information from the calling process. This could be used to determine the PID.