如何解决在 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 举报,一经查实,本站将立刻删除。