jklmnn / base-linux-hw

GNU General Public License v3.0
1 stars 1 forks source link

Enable IRQ Session #7

Open jklmnn opened 6 years ago

jklmnn commented 6 years ago

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.

senier commented 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...

senier commented 6 years ago

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.

jklmnn commented 6 years ago

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.

senier commented 6 years ago

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()?

jklmnn commented 6 years ago

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.

senier commented 6 years ago

OK, I remember. Make it so.

We also discovered that we need explicit trapdoors then in favor of the address ranges.

jklmnn commented 6 years ago

This is not a problem as I have to change the private_data structure anyway.

jklmnn commented 6 years ago

https://github.com/jklmnn/hwiodev/commit/c445eb58daa6d29e9f779bf6ad4b00818fba6659 implements interrupts with a blocking read. A test is available at https://gist.github.com/jklmnn/4a30450a4b731cacdf1e06170bb46e61.

jklmnn commented 6 years ago

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.

jklmnn commented 6 years ago

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!

jklmnn commented 6 years ago

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.

jklmnn commented 6 years ago

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.

jklmnn commented 6 years ago

To be able to delay the irq handler to the next read, I have to use request_threaded_irq instead of request_irq.

senier commented 6 years ago

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?

jklmnn commented 6 years ago

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.

senier commented 6 years ago

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.

jklmnn commented 6 years ago

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).