0

I have just finished initializing the IDT and started the ps2 stuff. I got the ps2 controller initializer and now I want to enable the interrupts in the first ps2 port or the keyboard. Here is my code for initializing the ps2 controller:


uint8_t initPS2()
{
    // Start by disabling devices

    disableFirstPS2Port();
    disableSecondPS2Port();

    // Flush the input buffer

    inb(PS2DATA);

    // Set the state of the status register.

    outb(PS2COMMAND, 0x20);
    uint8_t status = inb(PS2DATA);
    uint8_t dual0 = status & 0b00100000 == 0b00100000; // if dual = 0, there is no second channel
    status |= 0b01000011;
    outb(PS2COMMAND, 0x60);
    outb(PS2DATA, status);

    // Perform self test

    outb(PS2COMMAND, 0xAA);
    uint8_t response = inb(PS2DATA);
    if (response == 0xFC)
        return 0xFC;
    outb(PS2COMMAND, 0x60);
    outb(PS2DATA, status);

    // test dual channel controller
    uint8_t dual = 0xFF;

    if (dual0 == 1)
    {
        outb(PS2COMMAND, 0xAE);
        outb(PS2COMMAND, 0x20);
        status = inb(PS2DATA);
        uint8_t dual1 = status & 0b00100000 == 0b00100000;
        // if dual1 == 0, dual channel exists
        outb(PS2COMMAND, 0xAD);
        dual = !dual1;
    }
    else
    {
        dual = 0;
    }

    // Perform interface tests

    outb(PS2COMMAND, 0xAB);
    uint8_t responseIT1 = inb(PS2DATA);
    uint8_t responseIT2;
    if (dual == 1)
    {
        outb(PS2COMMAND, 0xA9);
        responseIT2 = inb(PS2DATA);
    }

    if (responseIT1 != 0x0)
        return responseIT1;
    if (responseIT2 != 0x0 && dual == 1)
        return responseIT2;

    // Enable devices

    enableFirstPS2Port();
    if (dual == 1)
        enableSecondPS2Port();

    writeToFirstPS2Port(0xFF);
    response = readPS2DataPort();
    if (response == 0xFC)
        return 0xFC;
    writeToSecondPS2Port(0xFF);
    response = readPS2DataPort();
    if (response == 0xFC)
        return 0xFC;

        return 0;
}

I follow the tutorial on OSDev wiki for initializing the ps2 controller.

Now I try to enable scanning on the keyboard with the 0xf4 command:

uint8_t commandKeyboard(unsigned char byt)
{

    writeToFirstPS2Port(byt);
    uint8_t response = readPS2DataPort();

    if (response == 0xFE)
    {
        writeToFirstPS2Port(byt);
        response = readPS2DataPort();

        if (response == 0xFE)
        {
            writeToFirstPS2Port(byt);
            response = readPS2DataPort();
        }
    }

    return response;
}

uint8_t initKeyboard()
{
    uint8_t res = commandKeyboard(0xF4);
    return res;
}

Note that the writeToFirstPS2Port and likewise other ps2 function do have a proper controllerWait function which makes sure that the data port is writable/readable.

I call this code before doing sti after I load my idt:

    idt_flush(&currentIDT);

    uint8_t ps2init = initPS2();
    printk("PS2 Initalized, returned with 0x%x\n", ps2init);
    while (1)
        ;
    uint8_t keyboardinit = initKeyboard();
    printk("PS2 Initalized, returned with 0x%x\n", keyboardinit);

    outb(PIC1_DATA, 0);
    outb(PIC2_DATA, 0);

    //int d = 5 / 0;
    asm volatile("sti");

Also here is my IRQ Handler:

void irq1_handler(interrupt_frame_t *frame)
{
    inb(0x60);
    default_irq_handler(frame);
}

I think the keyboard controller required for me to read 0x60 port before sending another interrupt so I thought that may help.

With this code here is what happens. I successfully initialize the IDT and then call the initializePS2 which returns with 0, meaning it succeeded. After that I start the initKeyboard call which doesn't even return let alone succeed. When I send the command to the keyboard, the system crashes. I am running this using qemu and I first thought this was a triple fault so I added -d int to see what kind of exceptions were raised but it seems that no exception is raised before the system closes itself.

Here is the github link to the project:

https://github.com/Danyy427/NEWOSDEV/tree/master/new%2064%20bit

The files are under src/Kernel/Hardware/PS2 and .../Hardware/Keyboard

The IDT is under src/Kernel/IDT

Any help is appreciated. Thank you.

  • If you aren't already, it may help to run qemu with the `-no-reboot` and `-no-shutdown` options so you can examine the state at the point the machine stops running, either with gdb or the qemu monitor (e.g. `-monitor stdio`). – sj95126 Nov 02 '21 at 15:35
  • @sj95126 oh sorry forgot to mention that. I do run it with ```-no-reboot``` and that's how I learned that there is no exception whatsoever from ```-d int```. I didn't know about ```-no-shutdown```. – Özgür Güzeldereli Nov 02 '21 at 17:20

1 Answers1

0

First add the interrupt attribute on your interrupt handler :

 void __attribute__((interrupt)) Irq1Handler(interrupt_frame* frame);

This will cause the compiler to get parameters from stack rather than getting them using __cdecl calling convention. And also performing an iret (Interrupt Return) rather than a normal ret (Return). Also add a parameter to gcc when compiling your interrupts file "-mgeneral-regs-only". This will prevent the compiler from using sse registers and generating a warning about that.