键盘中断处理程序在系统iso中不起作用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了键盘中断处理程序在系统iso中不起作用相关的知识,希望对你有一定的参考价值。

我正在尝试使用OSDev和其他人编写操作系统。现在,我被困在制作键盘中断处理程序。当我编译我的操作系统并使用qemu-system-i386 -kernel kernel/myos.kernel运行内核时,一切都很完美。当我将所有内容都放入ISO映像并尝试使用qemu-system-i386 -cdrom myos.iso运行时,当我按下某个键时它会重新启动。我认为这是由我的中断处理程序中的一些问题或IDT条目错误引起的。

我的键盘处理程序(AT&T语法):

.globl   keyboard_handler
.align   4

keyboard_handler:

    pushal
    cld 
    call keyboard_handler_main
    popal
    iret

我在C中的主要处理程序:

void keyboard_handler_main(void) {
    unsigned char status;
  char keycode;
    /* write EOI */
    write_port(0x20, 0x20);

    status = read_port(KEYBOARD_STATUS_PORT);
    /* Lowest bit of status will be set if buffer is not empty */
    if (status & 0x01) {
        keycode = read_port(KEYBOARD_DATA_PORT);
        if(keycode < 0)
            return;

        if(keycode == ENTER_KEY_CODE) {
            printf("
");
            return;
        }
        printf("%c", keyboard_map[(unsigned char) keycode]);
    }
}

我用来加载的C函数:

void idt_init(void)
{
    //unsigned long keyboard_address;
    unsigned long idt_address;
    unsigned long idt_ptr[2];

    auto keyboard_address = (*keyboard_handler);

    IDT[0x21].offset_lowerbits = keyboard_address & 0xffff;
    IDT[0x21].selector = KERNEL_CODE_SEGMENT_OFFSET;
    IDT[0x21].zero = 0;
    IDT[0x21].type_attr = INTERRUPT_GATE;
    IDT[0x21].offset_higherbits = (keyboard_address & 0xffff0000) >> 16;

    /*     Ports
    *    PIC1   PIC2
    *Command 0x20   0xA0
    *Data    0x21   0xA1
    */

    write_port(0x20 , 0x11);
    write_port(0xA0 , 0x11);

    write_port(0x21 , 0x20);
    write_port(0xA1 , 0x28);

    write_port(0x21 , 0x00);
    write_port(0xA1 , 0x00);

    write_port(0x21 , 0x01);
    write_port(0xA1 , 0x01);

    write_port(0x21 , 0xff);
    write_port(0xA1 , 0xff);

    idt_address = (unsigned long)IDT ;
    idt_ptr[0] = (sizeof (struct IDT_entry) * IDT_SIZE) + ((idt_address & 0xffff) << 16);
    idt_ptr[1] = idt_address >> 16 ;

    load_idt(idt_ptr);

    printf("%s
", "loadd");
}

文件的组织方式与OSDev's Meaty Skeleton相同。我有一个不同的bootloader。

答案

根据经验,我认为这个问题与GDT没有建立有关。通常当有人说中断使用QEMU的-kernel选项而不是GRUB的真实版本时,通常与内核开发人员无法创建和加载他们自己的GDT有关。 Mulitboot Specification说:

‘GDTR’即使段寄存器如上所述设置,'GDTR'也可能无效,因此OS映像不能加载任何段寄存器(甚至只是重新加载相同的值!),直到它建立自己的'GDT'。

当使用带有-kernel选项的QEMU时,GDTR通常是有效的,但不能保证这样。当使用真实版本的GRUB(安装到硬盘驱动器,虚拟映像,ISO等)来启动时,您可能会发现GDTR实际上并不有效。第一次尝试使用选择器重新加载任何段寄存器时(即使它是相同的值),它可能会出错。使用中断时,将修改代码段(CS),这可能导致三重故障并重新启动。

同样,多引导规范也没有说明哪些选择器指向代码或数据描述符。由于GDT条目的布局不为Multiboot规范所知或保证,因此填写IDT条目会产生问题。每个IDT条目都需要指定指向代码段的特定选择器。

OSDev上的Meaty Skeleton教程没有设置中断,也没有修改任何段寄存器,因此代码可能适用于QEMU的-kernel选项和GRUB的真实版本。在基础教程之上添加IDT和中断代码可能会导致您在使用GRUB启动时看到的失败。该教程应该更清楚地说明您应该设置自己的GDT而不是依赖于Multiboot加载器设置的GDT。

以上是关于键盘中断处理程序在系统iso中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

java代码在片段活动中不起作用

按钮在片段中不起作用

wpf 虚拟键盘在安装过程中不起作用

Javascript代码片段在drupal中不起作用

片段隐藏在Android中不起作用

AlertDialog 在片段中不起作用