【发布时间】:2024-04-28 11:05:03
【问题描述】:
我正在尝试使用 C 和 QEMU 实现键盘中断处理程序。但是当我执行程序时,我的处理程序只打印一个字符。之后,处理程序根本不起作用。
我的 IDT 设置:
struct IDT_entry {
unsigned short int offset_lowerbits;
unsigned short int selector;
unsigned char zero;
unsigned char type_attr;
unsigned short int offset_higherbits;
};
void setup_idt() {
struct IDT_entry IDT[256];
unsigned long keyboard_address;
unsigned long idt_address;
unsigned long idt_ptr[2];
keyboard_address = (unsigned long) keyboard_handler;
IDT[0x21].offset_lowerbits = keyboard_address & 0xffff;
IDT[0x21].selector = 0x8;
IDT[0x21].zero = 0;
IDT[0x21].type_attr = 0x8e;
IDT[0x21].offset_higherbits = (keyboard_address & 0xffff0000) >> 16;
/*
PIC1 PIC2
Commands 0x20 0xA0
Data 0x21 0xA1
*/
// ICW1 - init
outb(0x20, 0x11);
outb(0xA0, 0x11);
// ICW2 - reset offset address if IDT
// first 32 interrpts are reserved
outb(0x21, 0x20);
outb(0xA1, 0x28);
// ICW3 - setup cascading
outb(0x21, 0b0);
outb(0xA1, 0b0);
// ICW4 - env info
outb(0x21, 0b00000011);
outb(0xA1, 0b00000011);
// init finished
// disable IRQs except IRQ1
outb(0x21, 0xFD);
outb(0xA1, 0xff);
idt_address = (unsigned long)IDT;
idt_ptr[0] = (sizeof (struct IDT_entry) * 256) + ((idt_address & 0xffff) << 16);
idt_ptr[1] = idt_address >> 16;
__asm__ __volatile__("lidt %0" :: "m" (*idt_ptr));
__asm__ __volatile__("sti");
}
我的键盘处理程序:
// Variables for printing ==
unsigned int location = 0;
char* vga = (char*)0xb8000;
char letter;
// =========================
void keyboard_handler() {
if (inb(0x64) & 0x01 && (letter = inb(0x60)) > 0) {
vga[location] = keyboard_map[letter];
vga[location+1] = 0x4;
location += 2;
}
outb(0x20, 0x20);
// __asm__ __volatile__("iret");
}
主函数(它是从我的 asm 引导加载程序中执行的):
void kmain() {
setup_idt();
for (;;) {}
}
我认为问题出在“iret”指令中。没有它,我的内核至少会打印一些东西(只有一个字符,就像我之前说的那样)。但是当我执行 asm volatile("iret"); QEMU 打印一些垃圾,然后在每次击键后将其清除(“SeaBios ...”)。我需要做什么? 谢谢!
【问题讨论】:
-
在纯汇编中编写一个包装器,根据 C 调用约定调用您的处理程序。
-
@Jester,有什么区别?
-
与您的问题无关,但中断处理程序的更改 -
inb(0x64) & 0x01不需要从中断处理程序进行检查。您只需要在轮询键盘的中断处理程序之外执行此操作。
标签: c gcc assembly interrupt-handling osdev