简介
实验.实现中断处理
中断的流程
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
、