微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 x86_64 程序集中打开中断会在 QEMU

如何解决在 x86_64 程序集中打开中断会在 QEMU

我认为我的问题是我的一个愚蠢的错误,但我一直在寻找 OSDev wiki 和其他资源一段时间,但仍然迷路了。

我正在使用 x86_64 程序集和 C 制作一个小型操作系统,并且我正在尝试添加键盘支持以构建外壳。一切都在 QEMU 中使用 multiboot 在长模式下启动,直到我在 IDT 加载程序中添加 sti 命令,在那里我的操作系统在启动时继续三重故障(我很确定)。我知道其他人也遇到过类似的问题,但我还没有找到适合我的解决方案。

以下是 64 位程序集文件

global keyboard_handler
global read_port
global write_port
global load_idt
global long_mode_start

extern kernel_main
extern keyboard_handler_main

section .text
bits 64
read_port:
    mov edx,[esp + 4]
    in al,dx   ; al is the lower 8 bits of eax; dx is the lower 16 bits of edx
    ret

write_port:
    mov   edx,[esp + 4]
    mov   al,[esp + 8]
    out   dx,al
    ret

load_idt:
    mov edx,[esp + 6]
    lidt [edx]
    ;sti      ; turn on interrupts
    ret

keyboard_handler:
    call    keyboard_handler_main
    iretd

long_mode_start:
  ; Load NULL into all data registers

  mov ax,0
  mov ss,ax
  mov ds,ax
  mov es,ax
  mov fs,ax
  mov gs,ax

  call kernel_main
  hlt

这是我在 sti 中取消注释 load_idt 后的故障跟踪摘录(在 QEMU 中使用 -d int):

check_exception old: 0xffffffff new 0xd
     0: v=0d e=0800 i=0 cpl=0 IP=0008:0000000000100c7d pc=0000000000100c7d SP=0000:0000000000108fb8 env->regs[R_EAX]=0000000000108fc0
RAX=0000000000108fc0 RBX=0000000000000000 RCX=0000000000000036 RDX=0000000000000000
RSI=000000000000000a RDI=0000000000108fc0 RBP=0000000000108fe0 RSP=0000000000108fb8
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=0000000000100c7d RFL=00000206 [-----P-] CPL=0 II=1 A20=1 SMM=0 HLT=0
ES =0000 0000000000000000 00000000 00000000
CS =0008 0000000000000000 00000000 00209a00 dpl=0 CS64 [-R-]
SS =0000 0000000000000000 00000000 00000000
DS =0000 0000000000000000 00000000 00000000
FS =0000 0000000000000000 00000000 00000000
GS =0000 0000000000000000 00000000 00000000
LDT=0000 0000000000000000 0000ffff 00008200 dpl=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 dpl=0 TSS64-busy
GDT=     00000000001001b8 0000000f
IDT=     e2c3f000ff53f000 0000ff53
CR0=80000011 CR2=0000000000000000 CR3=0000000000102000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000001 CCD=0000000000000006 CCO=ADDQ    
EFER=0000000000000500
check_exception old: 0xd new 0xd
     1: v=08 e=0000 i=0 cpl=0 IP=0008:0000000000100c7d pc=0000000000100c7d SP=0000:0000000000108fb8 env->regs[R_EAX]=0000000000108fc0
RAX=0000000000108fc0 RBX=0000000000000000 RCX=0000000000000036 RDX=0000000000000000
RSI=000000000000000a RDI=0000000000108fc0 RBP=0000000000108fe0 RSP=0000000000108fb8
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=0000000000100c7d RFL=00000206 [-----P-] CPL=0 II=1 A20=1 SMM=0 HLT=0
ES =0000 0000000000000000 00000000 00000000
CS =0008 0000000000000000 00000000 00209a00 dpl=0 CS64 [-R-]
SS =0000 0000000000000000 00000000 00000000
DS =0000 0000000000000000 00000000 00000000
FS =0000 0000000000000000 00000000 00000000
GS =0000 0000000000000000 00000000 00000000
LDT=0000 0000000000000000 0000ffff 00008200 dpl=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 dpl=0 TSS64-busy
GDT=     00000000001001b8 0000000f
IDT=     e2c3f000ff53f000 0000ff53
CR0=80000011 CR2=0000000000000000 CR3=0000000000102000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000001 CCD=0000000000000006 CCO=ADDQ    
EFER=0000000000000500
check_exception old: 0x8 new 0xd
     2: v=03 e=0000 i=1 cpl=0 IP=0008:00000000000f1203 pc=00000000000f1203 SP=0010:0000000000000fb4 env->regs[R_EAX]=00000000000f6006

我检查了我的 OI 处理和 ISR 描述符,我认为它们很好。我想我只是在 load_idt 中用我的记忆运动做了一些愚蠢的事情,但任何建议都将不胜感激。我很乐意提供更多代码/解释。谢谢。

编辑:这里是调用 load_idt 的地方(CAPS 中的变量都是通常的值)。我已经给出了 IDT 的 32 位和 64 位(注释)初始化。有人指出我的读/写端口可能无法正常工作,这可以解释一些事情:

#include "keyboard.h"
#include "print.h"

unsigned char keyboard_map[128] =
{
    0,27,'1','2','3','4','5','6','7','8',/* 9 */
  '9','0','-','=','\b',/* Backspace */
  '\t',/* Tab */
  'q','w','e','r',/* 19 */
  't','y','u','i','o','p','[',']','\n',/* Enter key */
    0,/* 29   - Control */
  'a','s','d','f','g','h','j','k','l',';',/* 39 */
 '\'','`',/* Left shift */
 '\\','z','x','c','v','b','n',/* 49 */
  'm',','.','/',/* Right shift */
  '*',/* Alt */
  ' ',/* Space bar */
    0,/* Caps lock */
    0,/* 59 - F1 key ... > */
    0,/* < ... F10 */
    0,/* 69 - Num lock*/
    0,/* Scroll Lock */
    0,/* Home key */
    0,/* Up Arrow */
    0,/* Page Up */
  '-',/* Left Arrow */
    0,/* Right Arrow */
  '+',/* 79 - End key*/
    0,/* Down Arrow */
    0,/* Page Down */
    0,/* Insert Key */
    0,/* Delete Key */
    0,/* F11 Key */
    0,/* F12 Key */
    0,/* All other keys are undefined */
};


/* current cursor location */
unsigned int current_loc = 0;
/* video memory begins at address 0xb8000 */
char *vidptr = (char*)0xb8000;

struct IDT_entry {
    unsigned short int offset_lowerbits;
    unsigned short int selector;
    unsigned char zero;
    unsigned char type_attr;
    unsigned short int offset_higherbits;
};

struct IDT_entry_64 { // Will possibly use later
    unsigned short int offset_lowerbits;
    unsigned short int selector;
    unsigned char ist;
    unsigned char type_attr;
    unsigned short int offset_middlebits;
    unsigned long int offset_higherbits;
    unsigned long int zero;
};

struct IDT_entry IDT[IDT_SIZE];

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

    /* populate IDT entry of keyboard's interrupt */
    keyboard_address = (unsigned long)keyboard_handler;
    print_str( " Keyboard address: " );
    print_int( keyboard_address );
    print_newline();
    IDT[0x21].offset_lowerbits = keyboard_address & 0x0000ffff;
    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;

  // IDT[0x21].offset_lowerbits = keyboard_address & 0x000000000000ffff;
  // IDT[0x21].offset_middlebits = (keyboard_address & 0x00000000ffff0000) >> 16;
  // IDT[0x21].offset_higherbits = (keyboard_address & 0xffffffff00000000) >> 32;
    // IDT[0x21].selector = KERNEL_CODE_SEGMENT_OFFSET;
    // IDT[0x21].ist = 0;
    // IDT[0x21].type_attr = INTERRUPT_GATE;
  // IDT[0x21].zero = 0;


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

    /* ICW1 - begin initialization */
    write_port(0x20,0x11);
    write_port(0xA0,0x11);

    /* ICW2 - remap offset address of IDT */
    /*
    * In x86 protected mode,we have to remap the PICs beyond 0x20 because
    * Intel have designated the first 32 interrupts as "reserved" for cpu exceptions
    */
    write_port(0x21,0x20);
    write_port(0xA1,0x28);

    /* ICW3 - setup cascading */
    write_port(0x21,0x00);
    write_port(0xA1,0x00);

    /* ICW4 - environment info */
    write_port(0x21,0x01);
    write_port(0xA1,0x01);
    /* Initialization finished */

    /* mask interrupts */
    write_port(0x21,0xfd);
    write_port(0xA1,0xff);

    /* fill the IDT descriptor */
    idt_address = (unsigned long)IDT;
    print_str( " IDT address: " );
    print_int( idt_address );
    print_newline();
    print_str( " Pre-assignment IDT pointers: " );
    print_int( idt_ptr[0] );
    print_str( "," );
    print_int( idt_ptr[1] );
    print_newline();
    idt_ptr[0] = (sizeof (struct IDT_entry) * IDT_SIZE) + ((idt_address & 0x00000000ffffffff) << 32);
    idt_ptr[1] = idt_address >> 16;

    print_str( " Post-assignment IDT pointers: " );
    print_int( idt_ptr[0] );
    print_str( "," );
    print_int( idt_ptr[1] );
    print_newline();

    load_idt(idt_ptr);
}

void keyboard_init(void) {
    /* 0xFD is 11111101 - enables only IRQ1 (keyboard)*/
    write_port(0x21,0xFD);
}

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 ) {
      print_str( " pressed enter" );
            print_newline();
            return;
        }

        vidptr[current_loc++] = keyboard_map[(unsigned char) keycode];
        vidptr[current_loc++] = 0x07;
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。