实验10.实现中断处理

简介

实验.实现中断处理

中断的流程

    1.外设发出中断信号给8259A芯片
    2.8259A芯片处理信号,并向CPU发送中断向量号
    3.CPU根据中断向量号,在IDT表中找到对应的中断门描述符
    4.从中断门描述符找到中断服务程序入口地址,跳转到服务程序
    5.返回

主要代码

引导

省略

内核

main.c

// 文件: main.c
// 时间: 2024-07-19
// 来自: ccj
// 描述: 内核从此处开始


#include "print.h"
#include "init.h"

int main(void) {
    put_str("I am kernel\n");
    init_all();

    asm volatile("sti");  // 将eflags寄存器的IF位置为1 IF位1,表示不屏蔽可屏蔽外部中断
    while (1);
}

init.c

// 文件: interrupt.c
// 时间: 2024-07-22
// 来自: ccj
// 描述: 中断,硬件初始化,初始化中断门描述符表

/// @brief 完成有关中断的所有初始化工作
void idt_init() {
    put_str("[int] init start\n");

    idt_desc_init();  // 初始化中断描述符表

    pic_init();  // 初始化8259A

    // 加载中断描述符表 Load Interrupt Descriptor Table
    // lidt 2字节中断描述符偏移限制 4字节中断描述表的基地址
    // (sizeof(idt) - 1) 为 263
    uint64_t idt_operand = ((sizeof(idt) - 1) | ((uint64_t)(uint32_t)idt << 16));
    asm volatile("lidt %0" : : "m"(idt_operand));

    put_str("[int] init done\n");
}


/// @brief 可编程中断控制器8259A
/// @param
static void pic_init(void) {
   ...
}

/// @brief 把中断服务程序地址绑定到中断门描述符
/// @param p_gdesc
/// @param attr 属性
/// @param function 中断服务程序
static void make_idt_desc(struct gate_desc* p_gdesc, uint8_t attr, intr_handler function) {
    p_gdesc->func_offset_low_word = (uint32_t)function & 0x0000FFFF;
    p_gdesc->selector = SELECTOR_K_CODE;
    p_gdesc->dcount = 0;
    p_gdesc->attribute = attr;
    p_gdesc->func_offset_high_word = ((uint32_t)function & 0xFFFF0000) >> 16;
}

/// @brief 把kernel.s的中断服务程序地址写入到中断描述符中
/// @param
static void idt_desc_init(void) {
    for (int i = 0; i < IDT_DESC_CNT; i++) {
        make_idt_desc(&idt[i], IDT_DESC_ATTR_DPL0, intr_entry_table[i]);
    }
    /* 单独处理系统调用,系统调用对应的中断门dpl为3,
     * 中断处理程序为单独的syscall_handler */

    put_str("[int] init int_desc_table done\n");
}

kernel.s

; 文件: kernel.s
; 时间: 2024-07-22
; 来自: ccj
; 描述: 产生33个中断服务程序, 构建中断服务程序入口地址表

[bits 32]

; 相当于 #define ZERO (push 0)
%define ERROR_CODE nop
%define ZERO       push 0

extern put_str          ; 引入外部打印字符串函数

section .data
intr_str db "interrupt occur!", 0xa, 0

; 重要! 中断服务程序入口地址表 [intr01entry, intr1entry, ..., intr32entry]
global intr_entry_table 
intr_entry_table:

;---宏定义 VECTOR 接收2个参数 begin---
%macro VECTOR 2
    ;---text节 start---
section .text
intr%1entry:            ; 中断入口

    %2                  ; 如果有错误码,错误码入栈

    push intr_str;      ; 中断字符串入栈
    call put_str;       ; 调用打印中断字符串
    add esp, 4;         ; 中断字符串出栈

    ; 如果是从片上进入的中断, 除了往从片上发送EOI外 ,还要往主片上发送EOI 
    mov al,0x20         ; 0x20 = EOI
    out 0xa0,al         ; 向从片发送
    out 0x20,al         ; 向主片发送

    add esp, 4          ; 错误码出栈
    iret                ; 中断的返回
    ;---text节 end---

    ;---data节 begin---
section .data
   dd    intr%1entry    ; 中断入口地址
    ;---data节 end---
%endmacro
;---宏定义 VECTOR 接收2个参数 end---


;---创建中断处理函数 begin---
VECTOR 0x00,ZERO
VECTOR 0x01,ZERO
VECTOR 0x02,ZERO
VECTOR 0x03,ZERO
VECTOR 0x04,ZERO
VECTOR 0x05,ZERO
VECTOR 0x06,ZERO
VECTOR 0x07,ZERO
VECTOR 0x08,ERROR_CODE
VECTOR 0x09,ZERO
VECTOR 0x0a,ERROR_CODE
VECTOR 0x0b,ERROR_CODE
VECTOR 0x0c,ZERO
VECTOR 0x0d,ERROR_CODE
VECTOR 0x0e,ERROR_CODE
VECTOR 0x0f,ZERO 
VECTOR 0x10,ZERO
VECTOR 0x11,ERROR_CODE
VECTOR 0x12,ZERO
VECTOR 0x13,ZERO
VECTOR 0x14,ZERO
VECTOR 0x15,ZERO
VECTOR 0x16,ZERO
VECTOR 0x17,ZERO
VECTOR 0x18,ERROR_CODE
VECTOR 0x19,ZERO
VECTOR 0x1a,ERROR_CODE
VECTOR 0x1b,ERROR_CODE
VECTOR 0x1c,ZERO
VECTOR 0x1d,ERROR_CODE
VECTOR 0x1e,ERROR_CODE
VECTOR 0x1f,ZERO
VECTOR 0x20,ZERO
;---创建中断处理函数 end---

编译

省略

运行

start.sh

#/bin/bash
# 文件: start.sh
# 描述: 启动bochs
# 时间: 2024-07-19
# 来自: ccj


set -x

bin/bochs -f bochsrc.disk

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值