PS/2 controller acting weird

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.
Sublimacija
Posts: 3
Joined: Mon Mar 11, 2013 4:45 pm

PS/2 controller acting weird

Post 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.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: PS/2 controller acting weird

Post 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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Antti
Member
Member
Posts: 923
Joined: Thu Jul 05, 2012 5:12 am
Location: Finland

Re: PS/2 controller acting weird

Post 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?
palk
Posts: 16
Joined: Mon Nov 15, 2010 8:30 pm

Re: PS/2 controller acting weird

Post 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.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: PS/2 controller acting weird

Post by Brendan »

Hi,
Antti wrote:

Code: Select all

/* Return 1 if takes too long */
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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Sublimacija
Posts: 3
Joined: Mon Mar 11, 2013 4:45 pm

Re: PS/2 controller acting weird

Post 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...
Antti
Member
Member
Posts: 923
Joined: Thu Jul 05, 2012 5:12 am
Location: Finland

Re: PS/2 controller acting weird

Post 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.
Antti
Member
Member
Posts: 923
Joined: Thu Jul 05, 2012 5:12 am
Location: Finland

Re: PS/2 controller acting weird

Post 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.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: PS/2 controller acting weird

Post 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.
Last edited by gerryg400 on Wed Mar 13, 2013 5:11 am, edited 2 times in total.
If a trainstation is where trains stop, what is a workstation ?
Antti
Member
Member
Posts: 923
Joined: Thu Jul 05, 2012 5:12 am
Location: Finland

Re: PS/2 controller acting weird

Post 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?
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: PS/2 controller acting weird

Post 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.
If a trainstation is where trains stop, what is a workstation ?
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: PS/2 controller acting weird

Post 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
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: PS/2 controller acting weird

Post 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.
If a trainstation is where trains stop, what is a workstation ?
rdos
Member
Member
Posts: 3306
Joined: Wed Oct 01, 2008 1:55 pm

Re: PS/2 controller acting weird

Post 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.
Antti
Member
Member
Posts: 923
Joined: Thu Jul 05, 2012 5:12 am
Location: Finland

Re: PS/2 controller acting weird

Post 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.
Post Reply