首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >向ps2键盘发送启用中断(0xF4)命令会导致系统崩溃。OSDEV

向ps2键盘发送启用中断(0xF4)命令会导致系统崩溃。OSDEV
EN

Stack Overflow用户
提问于 2021-11-02 15:07:41
回答 1查看 203关注 0票数 0

我刚刚完成初始化IDT并启动了ps2内容。我得到了ps2控制器初始化器,现在我想在第一个ps2端口或键盘中启用中断。下面是初始化ps2控制器的代码:

代码语言:javascript
复制
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;
}

我遵循关于OSDev wiki的教程来初始化ps2控制器。

现在,我尝试使用0xf4命令在键盘上启用扫描:

代码语言:javascript
复制
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;
}

注意,writeToFirstPS2Port和其他ps2函数确实有一个正确的controllerWait函数,它确保数据端口是可写/可读的。

在加载idt之后,在执行sti之前调用以下代码:

代码语言:javascript
复制
    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");

这里还有我的IRQ处理程序:

代码语言:javascript
复制
void irq1_handler(interrupt_frame_t *frame)
{
    inb(0x60);
    default_irq_handler(frame);
}

我认为键盘控制器要求我在发送另一个中断之前读取0x60端口,所以我认为这可能会有所帮助。

有了这些代码,就会发生这样的事情。我成功地初始化了IDT,然后调用返回为0的initializePS2,这意味着它成功了。之后,我启动了initKeyboard调用,它甚至没有返回,更不用说成功了。当我将命令发送到键盘时,系统会崩溃。我使用qemu运行这个程序,我首先认为这是一个三重错误,所以我添加了-d int来查看引发了什么样的异常,但是似乎在系统关闭之前不会引发任何异常。

以下是指向该项目的github链接:

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

这些文件位于src/核/硬件/ps2和./硬件/键盘下。

IDT位于src/核/IDT之下。

任何帮助都是非常感谢的。谢谢。

EN

回答 1

Stack Overflow用户

发布于 2022-02-14 00:04:09

首先,在中断处理程序上添加中断属性:

代码语言:javascript
复制
 void __attribute__((interrupt)) Irq1Handler(interrupt_frame* frame);

这将导致编译器从堆栈中获取参数,而不是使用__cdecl调用约定获取参数。还执行iret (中断返回),而不是普通的ret (返回)。在编译中断文件“-mgeneral-regs”时,还向gcc添加一个参数。这将阻止编译器使用sse寄存器并生成有关该寄存器的警告。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69812627

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档