gcc OSDev. __attribute__((中断))无法完全工作

abithluo  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(212)

我正在写一个操作系统。我想使用__attribute__((interrupt))来做一些中断支持(我从PonchoOS复制了一堆代码来开始)。但是,只有页面故障检测和双重故障检测是有效的,其他中断不起作用(如键盘和定时器)。
这是标题:

#ifndef _KERNEL_INTERRUPTS_H_
#define _KERNEL_INTERRUPTS_H_
#include <stdint.h>

#define GP_FAULT 0xD
#define PAGE_FAULT 0xE
#define TIME_INTR 0x20
#define KERYBOARD_INTR 0x21
#define MOUSE_INTR 0x2C
#define PI_INTR 0x20
#define SOFT_INTR 0x80
#define DOUBLE_PAGE_FAULT 0x08

#define IDT_InterruptGate    0x8e
#define IDT_CallGate         0x8c
#define IDT_TrapGate         0x8f

#define PIC1_COMMAND 0x20
#define PIC1_DATA 0x21
#define PIC2_COMMAND 0xA0
#define PIC2_DATA 0xA1
#define PIC_EOI 0x20

#define ICW1_INIT 0x10
#define ICW1_ICW4 0x01
#define ICW4_8086 0x01

typedef struct _idtr {
    uint16_t limit;
    uint64_t offset;
} __attribute__((packed)) IDTR;

typedef struct _idt {
    uint16_t offset0;
    uint16_t selector;
    uint8_t zero;
    uint8_t type;
    uint16_t offset1;
    uint32_t offset2;
    uint32_t reserved;
} __attribute__((packed)) IDT;

void setIDTOffset(IDT* _idt, uint64_t offset);
uint64_t getIDTOffset(IDT* _idt);
void initializeInterrupts(void);
void setIRQ(uint8_t iqrn, void* handler, uint8_t typeAttributes, uint8_t selector);
void initializePIC(void);
void picEnd(void);

struct InterruptFrame;
__attribute__((interrupt)) void pageFaultHandler(struct InterruptFrame* Frame);
__attribute__((interrupt)) void timerHandler(struct InterruptFrame* Frame);
__attribute__((interrupt)) void doubleFaultHandler(struct InterruptFrame* Frame);
__attribute__((interrupt)) void gpFaultHandler(struct InterruptFrame* Frame);
__attribute__((interrupt)) void keyboardIntHandler(struct InterruptFrame* Frame);
__attribute__((interrupt)) void mouseIntHandler(struct InterruptFrame* Frame);
__attribute__((interrupt)) void pitIntHandler(struct InterruptFrame* Frame);

#endif /* _KERNEL_INTERRUPTS_H_ */

这是实现:

#include <interrupts.h>
#include <graphics.h>
#include <io.h>

IDT idt[256];
IDTR idtr;

void setIDTOffset(IDT* _idt, uint64_t offset) {
    _idt->offset0 = (uint16_t)(offset & 0xffff);
    _idt->offset1 = (uint16_t)((offset & 0xffff0000) >> 16);
    _idt->offset2 = (uint32_t)((offset & 0xffffffff00000000) >> 32);
}

uint64_t getIDTOffset(IDT* _idt) {
    uint64_t offset = 0;
    offset |= (uint64_t)_idt->offset0;
    offset |= (uint64_t)_idt->offset1 << 16;
    offset |= (uint64_t)_idt->offset2 << 32;
    return offset;
}

void initializeInterrupts(void) {
    idtr.limit = sizeof(IDT) * 256 - 1;
    idtr.offset = (uint64_t)idt;

    asm volatile("cli");
    setIRQ(PAGE_FAULT, (void*)pageFaultHandler, IDT_InterruptGate, 0x8);
    setIRQ(TIME_INTR, (void*)timerHandler, IDT_InterruptGate, 0x8);
    setIRQ(KERYBOARD_INTR, (void*)keyboardIntHandler, IDT_InterruptGate, 0x8);
    setIRQ(DOUBLE_PAGE_FAULT, (void*)doubleFaultHandler, IDT_InterruptGate, 0x8);
    setIRQ(GP_FAULT, (void*)gpFaultHandler, IDT_InterruptGate, 0x8);
    setIRQ(MOUSE_INTR, (void*)mouseIntHandler, IDT_InterruptGate, 0x8);
    setIRQ(PI_INTR, (void*)pitIntHandler, IDT_InterruptGate, 0x8);
    asm ("lidt %0" : : "m" (idtr));
    asm volatile("sti");
    initializePIC();
}

void setIRQ(uint8_t iqrn, void* handler, uint8_t typeAttributes, uint8_t selector) {
    setIDTOffset(&idt[iqrn], (uint64_t)handler);
    idt[iqrn].type = typeAttributes;
    idt[iqrn].selector = selector;
    idt[iqrn].zero = 0;
    idt[iqrn].reserved = 0;
}

void initializePIC(void) {
    uint8_t a1, a2;
    a1 = inb(PIC1_DATA);
    ioWait();
    a2 = inb(PIC2_DATA);
    ioWait();

    outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
    ioWait();
    outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
    ioWait;

    outb(PIC1_DATA, 0x20);
    ioWait();
    outb(PIC2_DATA, 0x28);
    ioWait();

    outb(PIC1_DATA, 4);
    ioWait();
    outb(PIC2_DATA, 2);
    ioWait();

    outb(PIC1_DATA, ICW4_8086);
    ioWait();
    outb(PIC2_DATA, ICW4_8086);
    ioWait();

    outb(PIC1_DATA, a1);
    ioWait();
    outb(PIC2_DATA, a2);
}

void picEnd(void){
    outb(PIC2_COMMAND, PIC_EOI);
    outb(PIC1_COMMAND, PIC_EOI);
}

__attribute__((interrupt)) void pageFaultHandler(struct InterruptFrame* Frame) {
    clear();
    debugPrint("Page Fault Detected");
    while(1);
}

__attribute__((interrupt)) void timerHandler(struct InterruptFrame* Frame) {
    debugPrint("timer\n");
    picEnd();
}

__attribute__((interrupt)) void doubleFaultHandler(struct InterruptFrame* Frame) {
    clear();
    debugPrint("Double Fault Detected");
    while(1);
}

__attribute__((interrupt)) void gpFaultHandler(struct InterruptFrame* Frame) {
    clear();
    debugPrint("General Protection Fault Detected");
    while(1);
}

__attribute__((interrupt)) void keyboardIntHandler(struct InterruptFrame* Frame) {
    clear();
    debugPrint("Pressed");
    uint8_t scanCode = inb(0x60);
    picEnd();
}

__attribute__((interrupt)) void mouseIntHandler(struct InterruptFrame* Frame) {

}

__attribute__((interrupt)) void pitIntHandler(struct InterruptFrame* Frame) {

}

这是我的github
我使用“asm(“int $0x21“)”手动触发键盘中断。数据可以通过端口0x 60读取。
我正在使用x86_64-elf-gcc来构建内核,使用QEMU来运行内核。如何解决这个问题?有什么建议吗?

gab6jxml

gab6jxml1#

谢谢你的回复。只要打开所有的中断。

outb(PIC1_DATA, 0x0); // enable all interrupt
ioWait();
outb(PIC2_DATA, 0x0);
ioWait();

相关问题