从零开始操作系统-04:Interruption

这一节主要是装载中断。

所需要的文件在Github:https://github.com/yongkangluo/Ubuntu20.04OS/tree/main/Files/Lec4-Interrupts

1. 中断相关知识

中断: 分为两种:非屏蔽中断(Non-Maskable Interrupts); 可屏蔽中断(Maskable Interrupts)。

如何让CPU忽略中断,使用的就是 EFLAGS(Program status and control)寄存器。
在这里插入图片描述
IF(bit 9) [Interrupt enable flag] 该标志用于控制处理器对可屏蔽中断请求(maskable interrupt requests)的响应。置1以响应可屏蔽中断,反之则禁止可屏蔽中断。

Interrupt Descriptor Table (IDT) 中断向量描述表
在这里插入图片描述

为了让系统找到 IDT需要一个 IDTR 即 IDT 寄存器
其与 GDT 非常相似。

在这里插入图片描述
可以使用基地址访问IDT。
在这里插入图片描述
下面就是 IDT 和 Interrupt Vector 的关系:IDT 中的中断向量,包括了偏移地址和段选择器,就可以根据利用这些去GDT中查询到相应的中断处理程序(ISP)。
在这里插入图片描述

2. 中断向量表代码实现
// idt.c
#define IDT_ENTRY 32

uint64_t _idt[IDT_ENTRY];
uint16_t _idt_limit = sizeof(_idt) - 1;

void _set_idt_entry(uint32_t vector, uint16_t seg_selector, void (*isr)(), uint8_t dpl){
    uintptr_t offset = (uintptr_t) isr;
    _idt[vector] = ((offset & 0xffff0000) | IDT_ATTR(dpl));
    _idt[vector] <<= 32;
    _idt[vector] |= seg_selector << 16 | (offset & 0x0000ffff);

}
void _init_idt(){
    _set_idt_entry(FAULT_DIVISION_ERROR, 0x08, _asm_isr0, 0);
    // 其中 _asm_isr0 就是中断程序的入口
}

之后将 idt 加载进 lidt 寄存器;

//boot.S
        movl $_idt, 2(%esp)
        movw _idt_limit, %ax
        movw %ax, (%esp) 
        lidt (%esp)
3. ISR(Interrupt Service Routine) 实现

Interrupt handler 设计:
存在一个问题,无法利用C语言设计一个形如这种的 interrupt handler:

/* How NOT to write an interrupt handler */
void interrupt_handler(void)
{
    asm("pushad"); /* Save registers. */
    /* do something */
    asm("popad");  /* Restore registers. */
    asm("iret");   /* This will triple-fault! */
}

编译器不明白发生了什么。它不明白,寄存器和堆栈必须保留在 asm 语句之间; 优化器可能会破坏函数。此外,编译器在函数之前和之后添加堆栈处理代码,这与 iret 结果类似于下面的汇编代码:

push   %ebp
mov    %esp,%ebp
sub    $<size of local variables>,%esp
pushad
# C code comes here
popad
iret
# 'leave' if you use local variables, 'pop %ebp' otherwise.
leave
ret

解决方法:使用汇编语言写!
新建一个.S 文件

//interrupts.S
// 宏定义
.macro isr_template vector, no_error_code = 1
    .global _asm_isr\vector
    .type _asm_isr\vector, @function
    _asm_isr\vector:
        .if \no_error_code
            pushl $0x0
        .endif
        pushl $\vector
        jmp interrupt_wrapper
.endm

.section .text
    isr_template 0

    interrupt_wrapper:
    
        movl %esp, %eax
        andl $0xfffffff0, %esp
        subl $16, %esp
        movl %eax, (%esp)

        call interrupt_handler
        pop %eax
        movl %eax, %esp
        addl $8, %esp

        iret

关于ISR的参数
在这里插入图片描述

方法主要跟着B站Up主做的,B站视频链接在:https://www.bilibili.com/video/BV1jL4y1s7X6/?spm_id_from=333.788&vd_source=72ce864f895f9fbf22b81450817f2875

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值