Kevin O'Connor wrote:
On Fri, Mar 12, 2010 at 11:24:27PM +0000, Jamie Lokier wrote:
The DOS coding method brought up in this thread, resulting in two reads of port 0x60, is quite common. It works on all real PCs, and correct emulation must handle it.
I'm not sure if reading port 0x60 is supposed to clear the status bit immediately or not. The problem might be QEMU's hardware emulation clearing the 8042 status bit too quickly, or it might be SeaBIOS should not check the status bit - in which case it probably fails on _real_ hardware too, when running these old DOS TSRs and similar programs.
It would be good if someone can check the behaviour of real hardware.
On my epia-cn, a read of port 0x60 immiediately clears the OBF flag of the status register.
Ok. As in like this, in rapid succession?
inb(0x64) -> OBF is set inb(0x60) -> keyboard byte inb(0x64) -> OBF is clear inb(0x60) -> same keyboard byte
That would mean SeaBIOS is broken - and should accept the byte on port 0x60 even if OBF is clear - even on real hardware.
The GHOST program which drops/corrupts keys on qemu seems to work fine on my epia-cn.
We'd expect that with any real PC running it's own BIOS. The interesting question is whether it works when running SeaBIOS on real hardware, which is hard to test without suitable hardware :-)
[...]
In other words, 8042 emulation _should_ permit port 0x60 to be read multiple times, but if sufficient time elapses without the irq being acknowledged, it should drop the byte and deliver the next one.
The ps2 port can use up to a 16.6Khz clock, and it takes 11 clock cycles to read a byte. The next keyboard byte only starts being transmitted after the first byte is dequeued, so a second read of the data port shouldn't return a new byte in less than 660us.
That's really helpful, thanks.
However, I don't see anything that would prevent a mouse data byte being read on the second read. So, this still seems very sloppy to me.
DOS - those were the days :-)
I'm guessing those programs don't expect the controller to be in mux mode. After all they typically just read port 0x60 and don't look at the status to determine which external port the byte came from. Many of them don't even check port 0x64 at all.
Unfortunately, in QEMU _guaranteeing_ that the guest has had some guest time to process the irq before the timeout is a bit tricky, if QEMU is delayed by host scheduling.
As a hack, I suppose qemu could check the time each inb(0x60) and return old data if a new irq hasn't been observed and 660us hasn't elapsed since the first read.
That's no mere hack: it's a good idea. But the 660us would have to be "at least 660us guest time", not qemu clock time. I'm not sure if qemu has the ability to guarantee holding something for a minimum guest CPU time.
The exact time almost certainly does not matter at all. I doubt very much if any DOS program times it.
All that matters, I expect, is that when these inb(0x60) sequences happen and they are within a few thousand instructions / emulated clock cycles of each other, the byte is not yet replaced.
From what you've said, SeaBIOS should be changed because it would fail
on real hardware too, and from others' reports, that's enough to make DOS int-intercepting programs work properly. The timeout is then needed to make DOS polling-in-a-loop-without-irqs programs work properly.
-- Jamie