实验11.实现中断处理 2

简介

实验.实现中断处理, 在kernel.s中的中断服务程序中调用在interrupt.c定义的中断函数,并调快时钟

中断的流程

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

主要代码

引导

省略

内核

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

// 文件: init.c
// 时间: 2024-07-22
// 来自: ccj
// 描述: 内核所有初始化操作

#include "init.h"
#include "print.h"
#include "interrupt.h"
#include "timer.h"

/// @brief 内核所有初始化
void init_all() {
    put_str("init all\n");

    idt_init();    // 初始化中断
    timer_init();  // 调快时钟
}

interrupt.c

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

// 中断描述符表,每个表项叫做一个门描述符(gate descriptor) 门的含义是当中断发生时必须先通过这些门
static struct gate_desc idt[IDT_DESC_CNT];

// 用于保存中断的名字
char* intr_name[IDT_DESC_CNT];

// 声明引用定义在kernel.S中的中断处理函数入口数组
extern intr_handler intr_entry_table[IDT_DESC_CNT];

// 中断处理函数 kernel.S中的中断处理函数入口里调用的这里的函数
intr_handler idt_table[IDT_DESC_CNT];

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

    idt_desc_init();   // 初始化中断描述符表
    exception_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) {
    ...
}

/// @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");
}

/// @brief 默认中断处理函数
/// @param vec_nr
static void general_intr_handler(uint8_t vec_nr) {
    ...
}

/// @brief 给每一个中断一个中断名、默认的处理函数
/// @param
static void exception_init(void) {
    // 先初始化每一个中断
    for (int i = 0; i < IDT_DESC_CNT; i++) {
        idt_table[i] = general_intr_handler;
        intr_name[i] = "unknown";
    }

    // 给每一个中断命名
    intr_name[0] = "#DE Divide Error";
    ...
    intr_name[19] = "#XF SIMD Floating-Point Exception";
}

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          ; 引入外部打印字符串函数
extern idt_table        ; 引入在interrupt.c中定义的中断处理函数

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

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

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

    ; 保存上下文环境
    push ds
    push es
    push fs
    push gs
    pushad              ; PUSHAD指令压入32位寄存器,其入栈顺序是: EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI

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

    push %1                     ; 中断向量号入栈
    call [idt_table + %1 * 4]   ; 调用interrupt.c的中断处理函数表中向量号的中断处理函数
    jmp intr_exit               ; 中断执行完成
    ;---text节 end---

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

section .text
global intr_exit
intr_exit:
    add esp, 4          ; 中断号出栈

    ; 恢复上下文环境
    popad
    pop gs
    pop fs
    pop es
    pop ds

    add esp, 4          ; 错误码出栈
    iretd


;---创建中断处理函数 begin---
VECTOR 0x00,ZERO
...
VECTOR 0x20,ZERO
;---创建中断处理函数 end---


timer.c

配置硬件,忽略

编译

省略

运行

start.sh

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


set -x

bin/bochs -f bochsrc.disk

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值