[solved] Repeated bytes from PS/2 controller

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
zhiayang
Member
Member
Posts: 368
Joined: Tue Dec 27, 2011 7:57 am
Libera.chat IRC: zhiayang

[solved] Repeated bytes from PS/2 controller

Post by zhiayang »

Hello there.

I'm currently attempting some sort of microkernel-ish design, and the current situation puts me with a PS/2 driver in userspace. The way things are set up, the "control flow" is like this:

Code: Select all

irq_handler {
    sendEOI();
    signal_driver();
}

scheduler {
    if(driver_is_signalled) {
        switch_to_driver();
    }
}

driver {
    signal_handler {
        inb(0x60);
    }
}

I hope that was understandable; basically, when I get an IRQ, the handler sets up some stuff to signal the driver process, before sending the EOI to the interrupt controller and doing the IRET. Note that control flow doesn't jump to the driver immediately, that happens the next time the driver is scheduled. This puts some time latency between sending of the EOI/receiving the IRQ and actually reading the data from the io port.

Once the driver is scheduled, then it will read data from the PS/2 data port (0x60). The problem I am facing here is that I get repeated IRQs, and by extension repeated bytes when I read from the port. I'm not sure what to suspect here, but it might be related to reading the port very late after sending the EOI (i'll explain this suspicion below).

Basically, if I type something like "ok" in quick succession, I get the following IRQs and bytes (scancode set 2):

Code: Select all

0x44 (O - down) 
0x42 (K - down)
0xF0
0x44 (O - up)
0xF0
0x42 (K - up)
0x42 (??)
0x42 (??)
0x42 (??)
The last few bytes get stuck on -- the actual number of repeats seems completely arbitrary, sometimes I'll get a very long stream of the same repeated byte, sometimes just a handful. This does not happen if I type slowly -- only if I type quickly.

On to my suspicion: if, instead of waiting for the driver to read from the data byte, I read the byte inside the irq handler (before or after sending the EOI doesn't matter), it works completely fine, and I get no repeats. I don't really want to do this, since this couples the kernel with the driver...

More context: I'm running with an IOAPIC and LAPIC setup, but with only one CPU running. Of note is that if I use the "normal" PIC to handle stuff, instead of repeated bytes I get skipped bytes.

I have no clue what's going on here, and the nice people on IRC haven't been able to help either.
Last edited by zhiayang on Sat Jan 11, 2020 1:11 pm, edited 1 time in total.
Octocontrabass
Member
Member
Posts: 5578
Joined: Mon Mar 25, 2013 7:01 pm

Re: Repeated bytes from PS/2 controller

Post by Octocontrabass »

Instead of sending the EOI immediately after receiving the IRQ, send it when the driver acknowledges that it has handled the IRQ. This is required if you want to support PCI.

What kind of hardware (or emulator) are you running your OS on?

Does your IRQ handler call the scheduler? The unblocked driver might have a higher priority than the interrupted program.
User avatar
zhiayang
Member
Member
Posts: 368
Joined: Tue Dec 27, 2011 7:57 am
Libera.chat IRC: zhiayang

Re: Repeated bytes from PS/2 controller

Post by zhiayang »

Instead of sending the EOI immediately after receiving the IRQ, send it when the driver acknowledges that it has handled the IRQ. This is required if you want to support PCI.
I tried this, but because the timer irq is 0 and the keyboard irq is 1, they have the same priority; not sending the EOI stalls the entire system. Also, if I were to do this, how do I prevent the "irq round trip time" from ballooning? This takes a minimum of two context switches (kernel -> driver -> kernel) before any EOI is sent. And while the EOI is not sent, I may or may not be missing IRQs of the same priority from other devices?

Or am I thinking about this entirely wrongly?
What kind of hardware (or emulator) are you running your OS on?
Both QEMU and VirtualBox exhibit this behaviour, although slightly differently; QEMU always repeats the last byte only (like I wrote in the OP), while VBox sometimes repeats multiple bytes (eg. I type "jumped", I get "jujumped")
Does your IRQ handler call the scheduler? The unblocked driver might have a higher priority than the interrupted program.
No, the IRQ handler only sets up the driver process to get signalled the next time it is scheduled. There's no priority in my scheduler yet, it's just a simple round-robin. It shouldn't really depend on what the scheduler is doing, I think?
Octocontrabass
Member
Member
Posts: 5578
Joined: Mon Mar 25, 2013 7:01 pm

Re: Repeated bytes from PS/2 controller

Post by Octocontrabass »

zhiayang wrote:I tried this, but because the timer irq is 0 and the keyboard irq is 1, they have the same priority; not sending the EOI stalls the entire system.
Why doesn't the timer IRQ have a higher priority than the keyboard IRQ like it's supposed to?
zhiayang wrote:Also, if I were to do this, how do I prevent the "irq round trip time" from ballooning?
Your driver already has to perform a context switch to the kernel in order to yield. Combine the yield and the EOI into a single context switch.
zhiayang wrote:Both QEMU and VirtualBox exhibit this behaviour, although slightly differently; QEMU always repeats the last byte only (like I wrote in the OP), while VBox sometimes repeats multiple bytes (eg. I type "jumped", I get "jujumped")
You might be stumbling across bugs in both Qemu and VirtualBox. Especially the VirtualBox behavior: it's not possible for a real PS/2 controller to repeat multiple bytes like that. What happens when your OS runs on real hardware?
zhiayang wrote:No, the IRQ handler only sets up the driver process to get signalled the next time it is scheduled. There's no priority in my scheduler yet, it's just a simple round-robin.
Well, it doesn't make sense with no priorities, but once you have a better scheduler you'll want to call it in the IRQ handler. It's very likely that the unblocked driver will have a higher priority than whatever was interrupted.
User avatar
zhiayang
Member
Member
Posts: 368
Joined: Tue Dec 27, 2011 7:57 am
Libera.chat IRC: zhiayang

Re: Repeated bytes from PS/2 controller

Post by zhiayang »

Octocontrabass wrote: Why doesn't the timer IRQ have a higher priority than the keyboard IRQ like it's supposed to?
Well, it hasn't been an issue before, but this is my first time doing APIC stuff. I kinda forgot that the priority is only determined by the high 4 bits of the vector number, not the entire 8 bits.
Your driver already has to perform a context switch to the kernel in order to yield. Combine the yield and the EOI into a single context switch.
Right, so it's still 2 switches minimum, right? That should be fine.
You might be stumbling across bugs in both Qemu and VirtualBox. Especially the VirtualBox behavior: it's not possible for a real PS/2 controller to repeat multiple bytes like that. What happens when your OS runs on real hardware?
Hmm, interesting. I don't have a computer with a real PS/2 controller (or even an emulated one, I only have a macbook), so I can't test it on real hardware. I might dig around in QEMU's code to see if it's doing anything strange, but it's usually a safe bet that the problem lies on my end.
Well, it doesn't make sense with no priorities, but once you have a better scheduler you'll want to call it in the IRQ handler. It's very likely that the unblocked driver will have a higher priority than whatever was interrupted.
If I'm understanding you correctly, the IRQ handler would bump the driver proc/thread to the front of the queue when it receives the IRQ, right? Or are you saying that the IRQ handler should queue a schedule event at the next kernel tick and forfeit the timeslice of the interrupted process?


Anyway, I'll try to get the priority thing sorted out and report back if it works.
Octocontrabass
Member
Member
Posts: 5578
Joined: Mon Mar 25, 2013 7:01 pm

Re: Repeated bytes from PS/2 controller

Post by Octocontrabass »

zhiayang wrote:If I'm understanding you correctly, the IRQ handler would bump the driver proc/thread to the front of the queue when it receives the IRQ, right? Or are you saying that the IRQ handler should queue a schedule event at the next kernel tick and forfeit the timeslice of the interrupted process?
When the IRQ handler unblocks the driver, and the driver has a higher priority than the interrupted process, you should forefeit its time slice and immediately switch to the driver.

To keep that from being unfair, you might put the interrupted program at the beginning of the queue so it resumes as soon as the high-priority driver yields (or uses up its time slice). Or, have some kind of dynamic priority scheme where programs that haven't had their fair share of time get temporary priority boosts. It's your scheduler, so you get to decide how it should work.
User avatar
zhiayang
Member
Member
Posts: 368
Joined: Tue Dec 27, 2011 7:57 am
Libera.chat IRC: zhiayang

Re: Repeated bytes from PS/2 controller

Post by zhiayang »

Alright, that was solved pretty easily all things considered. There does appear to be some kind of issue if you read the data byte very late after sending the EOI, but I couldn't immediately identify a probable cause from looking at QEMU's code.

So, TL;DR:
Only send the EOI to your interrupt controller after reading from the data port. Also, make sure your timer interrupt is the highest priority, I guess.

Somewhat amusingly, I misremembered the priority order for LAPIC and thought that lower number = higher priority; of course it's the other way around.

EDIT: the latency is honestly quite bad, but I need to see if a sensible scheduling algorithm will fix that -- I sure hope so.

EDIT 2: using a proper scheduling algo with priorities works wonders for latency. For now I'm not forcing the next thread, I just give the driver thread an extra (large) bump so it's very likely to get picked next.
User avatar
eekee
Member
Member
Posts: 892
Joined: Mon May 22, 2017 5:56 am
Location: Kerbin
Discord: eekee
Contact:

Re: Repeated bytes from PS/2 controller

Post by eekee »

Octocontrabass wrote:You might be stumbling across bugs in both Qemu and VirtualBox.
Indeed. Several nice text editors for DOS have keyboard issues under Qemu, including key doubling, where they're fine under real hardware.
Kaph — a modular OS intended to be easy and fun to administer and code for.
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie
Post Reply