【发布时间】:2018-06-30 10:28:49
【问题描述】:
我正在尝试使用 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("\n");
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\n", "loadd");
}
文件的组织方式与OSDev's Meaty Skeleton 相同。我确实有不同的引导加载程序。
【问题讨论】:
-
您在中断处理程序中使用 printf()?
-
我有自己的 printf 实现。我不应该吗?
-
应该吗?它似乎有点……奇怪。您的 printf 可以安全地中断并从中断状态重新进入吗?
-
您没有向我们展示所有代码,但请考虑这一点 - Multiboot 规范要求您设置自己的 GDT。 Multibootloader 设置了自己的,但在规范中它说 GDTR 应该假定为无效,您应该在重新加载任何段寄存器之前建立自己的。使用中断需要更改段寄存器。在使用 QEMU(带有
-kernel选项)时会发生这种情况,GDTR 通常是有效的,但是当通过真正的 GRUB(在 ISO 上)完成时,它不是。 -
看起来多肉的骨架没有设置 GDT。可能是因为他们不使用中断并且不设置任何段寄存器。如果您在多肉骨架上添加了 IDT 代码而没有添加代码来设置 GDT,那么很有可能就是这里出了问题。但是如果没有你所有的代码,我会做出最好的教育猜测
标签: c assembly x86 interrupt-handling osdev