操作系统实现-外中断

博客网址:www.shicoder.top
微信:18223081347
欢迎加群聊天 :452380935

这次我们将解释中断中的外部中断,首先给出中断的分类并分配中断号。

[En]

This time we will explain the external interrupts in the interrupts, first give the classification of interrupts and assign the interrupt number.

操作系统实现-外中断

中断号 分类 0x0-0x20 异常和非屏蔽中断 0x20-0x30 I/O设备引发的可屏蔽中断,比如键盘、时钟等外中断 0x30-0xff 软中断,比如常说的int 80系统调用

前面解释了该异常,并解释了此外部中断。让我们以时钟中断为例。我们需要知道的第一件事是,时钟中断是由操作系统本身发生的。例如,当我们执行一段代码时,我们可能不知道它何时会触发时钟中断。为了反映触发的时钟中断,我们只打印了一句话。

[En]

The exception was explained earlier, and this external interruption was explained. Let’s take the clock interrupt as an example. the first thing we need to know is that the clock interrupt occurs by the operating system itself. for example, when we execute a piece of code, we may not know when it will trigger the clock interrupt. in order to reflect the triggered clock interrupt, we just print a sentence.

同样我们给每个外中断号定义一个入口函数

INTERRUPT_HANDLER 0x20, 0; clock 时钟中断
INTERRUPT_HANDLER 0x21, 0; 键盘中断
INTERRUPT_HANDLER 0x22, 0
INTERRUPT_HANDLER 0x23, 0
INTERRUPT_HANDLER 0x24, 0
INTERRUPT_HANDLER 0x25, 0
INTERRUPT_HANDLER 0x26, 0
INTERRUPT_HANDLER 0x27, 0
INTERRUPT_HANDLER 0x28, 0
INTERRUPT_HANDLER 0x29, 0
INTERRUPT_HANDLER 0x2a, 0
INTERRUPT_HANDLER 0x2b, 0
INTERRUPT_HANDLER 0x2c, 0
INTERRUPT_HANDLER 0x2d, 0
INTERRUPT_HANDLER 0x2e, 0
INTERRUPT_HANDLER 0x2f, 0

在这个函数中,同样设置一个具体的函数

void idt_init()
{
    // 初始化ENTRY_SIZE个中断处理函数
    for (size_t i = 0; i < ENTRY_SIZE; i++)
    {
        gate_t *gate = &idt[i];
        // gate->offset0 = (u32)interrupt_handler & 0xffff;
        // gate->offset1 = ((u32)interrupt_handler >> 16) & 0xffff;
        handler_t handler = handler_entry_table[i];

        gate->offset0 = (u32)handler & 0xffff;
        gate->offset1 = ((u32)handler >> 16) & 0xffff;
        gate->selector = 1 << 3; // 代码段
        gate->reserved = 0;      // 保留不用
        gate->type = 0b1110;     // 中断门
        gate->segment = 0;       // 系统段
        gate->DPL = 0;           // 内核态
        gate->present = 1;       // 有效
    }
    // 异常的具体处理函数
    for (size_t i = 0; i < 0x20; i++)
    {
        handler_table[i] = exception_handler;
    }
    // 外中断的具体处理函数
    for (size_t i = 0x20; i < ENTRY_SIZE; i++)
    {
        handler_table[i] = default_handler;
    }

    idt_ptr.base = (u32)idt;
    idt_ptr.limit = sizeof(idt) - 1;

    asm volatile("lidt idt_ptr\n");
}
void default_handler(int vector)
{
    send_eoi(vector);
    LOGK("[%d] default interrupt called %d...\n", vector, counter++);
}

注意我们有一个 send_eoi函数,这是发送结束中断的函数,因为我们比如时钟中断产生,那么首先是结束中断,然后才是对其进行处理,不然后续就不会再次发生中断,其代码如下

void send_eoi(int vector)
{
    if (vector >= 0x20 && vector < 0x28)
    {
        outb(PIC_M_CTRL, PIC_EOI);
    }
    if (vector >= 0x28 && vector < 0x30)
    {
        outb(PIC_M_CTRL, PIC_EOI);
        outb(PIC_S_CTRL, PIC_EOI);
    }
}

最后就是main函数的编写

void kernel_init()
{
    console_init();
    gdt_init();
    interrupt_init();

    // asm volatile(
    // "sti\n"
    // "movl %eax, %eax\n");

    asm volatile("sti");

    u32 counter = 0;
    while (true)
    {
        DEBUGK("looping in kernel init %d...\n", counter++);
        delay(100000000);
    }
}

其中最主要的就是 asm volatile("sti"),这行表示打开中断,否则不会触发,还有一个关键,怎么让cpu知道是时钟中断呢,这就要中断控制器进行设置,下面是设置代码

// 初始化中断控制器
void pic_init()
{
    outb(PIC_M_CTRL, 0b00010001); // ICW1: 边沿触发, 级联 8259, 需要ICW4.

    outb(PIC_M_DATA, 0x20);       // ICW2: 起始端口号 0x20
    outb(PIC_M_DATA, 0b00000100); // ICW3: IR2接从片.

    outb(PIC_M_DATA, 0b00000001); // ICW4: 8086模式, 正常EOI

    outb(PIC_S_CTRL, 0b00010001); // ICW1: 边沿触发, 级联 8259, 需要ICW4.

    outb(PIC_S_DATA, 0x28);       // ICW2: 起始端口号 0x28
    outb(PIC_S_DATA, 2);          // ICW3: 设置从片连接到主片的 IR2 引脚
    outb(PIC_S_DATA, 0b00000001); // ICW4: 8086模式, 正常EOI

    outb(PIC_M_DATA, 0b11111110); // 关闭所有中断,打开时钟中断
    outb(PIC_S_DATA, 0b11111111); // 关闭所有中断
}

主要看最后两行,设置打开哪些中断,下面是支持的中断图,可以看到有支持15个中断,上面的 outb(PIC_M_DATA, 0b11111110)表示打开时钟中断,当值为0,打开中断。

操作系统实现-外中断

下面是实验的结果图,第一张图是没有设置 send_eoi,可以看到只接收到了一次中断

操作系统实现-外中断

下面是设置了 send_eoi

操作系统实现-外中断

我们下面来尝试下键盘中断,将 outb(PIC_M_DATA, 0b11111110);设置为 outb(PIC_M_DATA, 0b11111101);,开启程序,我们按下键盘,可以看到,当按下键盘触发,但是我们再次按下,却发现没有用,这是因为针对键盘中断,我们要编写对应的处理函数,比如处理收到的字符,然后编写对应的中断结束函数,才能再次接受中断

操作系统实现-外中断

Original: https://www.cnblogs.com/shilinkun/p/16305628.html
Author: 小坤学习园
Title: 操作系统实现-外中断

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/158745/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

最近整理资源【免费获取】:   👉 程序员最新必读书单  | 👏 互联网各方向面试题下载 | ✌️计算机核心资源汇总