Page 1 of 3
PS/2 controller acting weird
Posted: Mon Mar 11, 2013 5:41 pm
by Sublimacija
I'm trying to write a keyboard driver. The interrupt is set up and I get to read scan codes perfectly fine. That's scan code set 1 though. I'd like to use set 2, but the controller clearly doesn't feel like it.
It is reacting abnormally to commands I send to port 0x64. Commands 0xAD (disable keyboard) and 0xAE (enable keyboard) work fine. 0xAA (test) returns 0x55 (good). If I send 0xFF (reset) or 0xEE (echo) status bit 0 won't set. Most importantly, if I send 0xF0 (get/set scan code) or 0xF2 (identify) my kernel starts executing some random garbage code (gdb says that eip = 0xfed9, while my kernel code is far bellow that). It is not clear to me how out could make a jump, but I see that changing outb(0x64, 0xEE); to outb(0x64, 0xF0); is all that is needed to reproduce the bug.
Note, I'm running this on qemu.
I'd appreciate any hints on how to tackle this nonsense.
Re: PS/2 controller acting weird
Posted: Mon Mar 11, 2013 9:24 pm
by Brendan
Hi,
Sublimacija wrote:It is reacting abnormally to commands I send to port 0x64. Commands 0xAD (disable keyboard) and 0xAE (enable keyboard) work fine. 0xAA (test) returns 0x55 (good). If I send 0xFF (reset) or 0xEE (echo) status bit 0 won't set. Most importantly, if I send 0xF0 (get/set scan code) or 0xF2 (identify) my kernel starts executing some random garbage code (gdb says that eip = 0xfed9, while my kernel code is far bellow that). It is not clear to me how out could make a jump, but I see that changing outb(0x64, 0xEE); to outb(0x64, 0xF0); is all that is needed to reproduce the bug.
There are 2 completely different pieces of hardware - the PS/2 controller itself, and the device/s attached to the PS/2 controller (e.g. the keyboard). To send commands to the PS/2 controller you "out" to IO port 0x64. To send commands to the device attached to the controller you "out" to IO port 0x60 (although
it's a bit more complicated than that).
Now; if you get things confused and send commands intended for the keyboard to the PS/2 controller itself, then the meaning of those commands changes completely. For example, sending 0xFF to the PS/2 controller tells the PS/2 controller to "pulse none of 4 output lines", and sending 0xF0 to the PS/2 controller tells it to "pulse all 4 output lines, including the line that should cause the computer to reset/reboot".
Of course if you accidentally reset the computer, the CPU will start executing the BIOS's power-on/reset code. This power-on/reset code is designed for real mode and is likely to be near then end of the 64 KiB segment at 0x000F0000 (e.g. and probably includes something at "0xF000:0xFED9", where GDB doesn't display CS and only says EIP = 0xFED9).
Cheers,
Brendan
Re: PS/2 controller acting weird
Posted: Tue Mar 12, 2013 12:54 am
by Antti
Now that this topic is current, I would like to mention that I have problems with the keyboard "Reset and start self-test" command. If I send a command
0xFF, is the "everything OK" response sequence
0xFA (command acknowledged) and
0xAA (self-test passed)?
My current code excerpt (not fully finished & tested) (
Full code):
Code: Select all
static int OutputWaitFull(); /* Return 1 if takes too long */
static int OutputWaitEmpty(); /* Return 1 if takes too long */
static int InputWaitEmpty(); /* Return 1 if takes too long */
int PS2_Keyboard_Reset()
{
int i;
int r = 1;
for (i = 0; i < PS2_KEYBOARD_RESETS; i++) {
if (OutputWaitEmpty()) return r; /* Discard buffer until empty */
if (InputWaitEmpty()) return r;
Port_Output8(PS2_CONTROLLER_DATA, 0xFF);
if (OutputWaitFull()) return r;
if (Port_Input8(PS2_CONTROLLER_DATA) == 0xFA) {
r = 0;
break;
}
}
OutputWaitEmpty();
InputWaitEmpty();
return r;
}
Currently PS2_Keyboard_Reset returns 1 (not OK) on one of my real test machine. As you can see, I do not even test more than "command acknowledged" just yet. However, this returns 0 (OK) on Virtualbox and on another test machine. I know that this whole PS/2 is emulated nowadays and I am heading to "full" USB implementation in the future. Of course I want to support PS/2 interface also. Am I doing something wrong or is the firmware just buggy?
Re: PS/2 controller acting weird
Posted: Tue Mar 12, 2013 1:06 am
by palk
The obvious question is: "which of those conditions is failing?" and the very likely followup: "how do you know you aren't waiting long enough?"
Emulated hardware (such as in qemu and virtualbox) doesn't often capture timing issues correctly.
Re: PS/2 controller acting weird
Posted: Tue Mar 12, 2013 1:29 am
by Brendan
Hi,
Antti wrote:Currently PS2_Keyboard_Reset returns 1
This might seem like a silly question, but how much time to you allow for the keyboard to reset?
From a copy of some IBM Technical Reference Manual pages I seem to have here:
Reset (Hex FF)
The system issues a Reset command to start a program reset and a keyboard internal self-test. The keyboard acknowledges the command with an 'acknowledge' signal (ACK) and ensures the system accepts that 'ACK' before executing the command. The system signals the acceptance of the 'ACK' by raising the clock and data for a minimum of 500 microseconds. The keyboard is disabled from the time it receives the Reset command until the 'ACK' is accepted or until another command overrides the previous one. Following acceptance of the 'ACK', the keyboard begins the reset operation, which is similar to a power-on reset. The keyboard clears the output buffer and sets up default values for typematic and delay rates.
From some other info from IBM (different document):
Power-On Reset (POR)
The keyboard logic generates a 'power-one reset' signal when power is first applied to the keyboard. A POR takes a minimum of 150 milliseconds and a maximum of 2.0 seconds form the time power is first applied to the keyboard.
Basic Assurance Test
The basic assurance test (BAT) consists of a keyboard process test, a checksum of read-only memory (ROM), and a random-access memory (RAM) test. During the BAT, activity on the 'clock' and 'data' lines is ignored. The LEDs are turned on at the beginning and off at the end of the BAT. The BAT takes a minimum of 300 milliseconds and a maximum of 500 milliseconds. This is in addition to the time required by the POR.
On satisfactory completion of the BAT, a completion code (hex AA) is sent to the system, and keyboard scanning begins. If a BAT failure occurs, the keyboard sends an error code to the system. The keyboard is then disabled pending command input. Completion codes are sent between 450 milliseconds and 2.5 seconds after the POR, and between 300 milliseconds and 500 milliseconds after a Reset command is acknowledged.
Immediately following a POR, the keyboard monitors the signals on the keyboard 'clock' and 'data' lines and sets the line protocol.
Most normal commands are meant to complete within 20 ms. Reading the above, "reset" can take up to 2.5 seconds, and the time-out for this is going to need to be a lot longer than the 20 ms timeout for normal commands.
Cheers,
Brendan
Re: PS/2 controller acting weird
Posted: Tue Mar 12, 2013 1:42 am
by Sublimacija
Thank you Brendan, it works well now. I can't believe it was that simple. Though I should have probably figured this out myself, seeing that there are different command sets listed in PS/2 Keyboard and PS/2 Controller wiki pages...
Re: PS/2 controller acting weird
Posted: Tue Mar 12, 2013 2:03 am
by Antti
Thank you Brendan. I have to think this through again and I actually might have similar kind of problem in the PS/2 controller initialize procedure. My OutputWaitFull() is not robust enough. If I made it simply poll until data is available, it would solve this. However, it could hang the system. Better watchdog timer must be implemented for this.
Re: PS/2 controller acting weird
Posted: Tue Mar 12, 2013 11:54 pm
by Antti
Last night I struggled with this problem. I now give it at least 3 seconds (I tested it with even more) to response. However, it does not matter because in this case the response came almost immediately anyway. Nevertheless, that timing issue was a very good thing to get fixed.
So what is the problem? I debugged this on real hardware (the one that fails) and the response byte for 0xFF (reset and self-test) is always 0xFE (resend). I have tried more than enough resends (also with seconds of delay between tries) but the response is always 0xFE. If I forget this whole reset thing, the PS/2 keyboard interface works well otherwise. I can get scan codes etc.
Now it seems that I cannot rely on that when determining whether the keyboard is available or not. Next I am going to try the echo command.
Re: PS/2 controller acting weird
Posted: Wed Mar 13, 2013 1:19 am
by gerryg400
Antti, instead of resending when you get the 0xfe, try ignoring that and simply continue polling. Like this (but with a way to break out of the 'do' loop)
Code: Select all
/* Try doing a reset on each port */
if (port_ok[0] == 1) {
ps2_data_write(0, 0xff);
/* Get the ack */
status = ps2_data_read();
/*
* Devices are supposed to ack with an 0xfa but many devices don't
* so we can't consider this an error
*/
if (status == 0xfa) {
syslog(0, "Reset 0, ACK was received\n");
}
else {
// return -1; Some devices don't reply with an ACK, so don't give up yet !!
}
/* Get the reset result */
syslog(0, "Kbd: Waiting for reset...\n");
while (status != 0xaa) {
status = ps2_data_read();
// We should break here after a few seconds
}
syslog(0, "Kbd: reset result was %02x\n", status);
}
[EDIT] Removed the "return -1" and added some c++ style comments.
[EDIT 2] Changed after combuster's review.
Re: PS/2 controller acting weird
Posted: Wed Mar 13, 2013 3:35 am
by Antti
Thanks you gerryg400 but I do not understand your code. First you say I should ignore the 0xFE and then you show a code snippet where you "return -1;" if the response is something else than the ACK (0xFA). However, I got the idea what you meant. Is it really a good idea?
Re: PS/2 controller acting weird
Posted: Wed Mar 13, 2013 4:27 am
by gerryg400
Antti, when you send a reset (0xff) you should receive an ACK (0xfa) almost immediately (i.e. in the normal time-frame). This happens before the reset.
After the reset, which could take several seconds, you should receive an 0xaa if all went well or a 0xfc for an error.
NOTE: that some devices don't send the ACK so actually the "return -1" should NOT be there. I have modified the code to reflect this.
Re: PS/2 controller acting weird
Posted: Wed Mar 13, 2013 4:58 am
by Combuster
Quick note on the current code: if the ACK actually goes missing, the current code simply discards the 0xaa/0xfc result byte as if it were the ACK, then goes looking for another one
Re: PS/2 controller acting weird
Posted: Wed Mar 13, 2013 5:01 am
by gerryg400
Excellent point combuster. Thanks for the review. I've never seen a device reply quicky enough to cause a problem but I will fix the code in any case.
[EDIT] I fixed the code above. Note that I have only tested it on one machine so far. Other testing welcome.
Re: PS/2 controller acting weird
Posted: Wed Mar 13, 2013 9:22 am
by rdos
My keyboard code doesn't do a RESET unless the combined keyboard & mouse driver is loaded, and the mouse doesn't work. That way, if the keyboard controller doesn't work properly, it is always possible to load the keyboard-only driver and use it in a way that minimize compability problems. When I do a RESET, I don't do any checking, but rather assume it will self-configure in a suitable way. Actually, it is the IRQ that does all the decoding of keyboard data and that is responsible for the keyboard interaction. There is no keyboard code that sends commands and waits for responses.
Re: PS/2 controller acting weird
Posted: Wed Mar 13, 2013 11:56 am
by Antti
It just does not work on this real machine. Even the echo fails. I cannot say for sure whether the keyboard is available or not. However, this is not a big problem.