中断处理程序

前言

博客记录《操作系统真象还原》第七章实验的操作~

实验环境:ubuntu18.04+VMware , Bochs下载安装

实验内容

  1. 编写中断处理程序( 操作 8259A 打开中断)。
  2. 改进中断处理程序(在汇编版本的 intrXXentry 中调用 C 语言版本的中断处理函数)。
  3. 用计数器/定时器 8253 来设置时钟中断发生的频率。(给中断信号提速)。

前置知识

中断概念

中断处理(中断)的概念:由于 CPU 获知了计算机中发生的某些事,CPU 暂停正在执行的程序,转而去执行处理该事件的程序, 当这段程序执行完毕后,CPU 继续执行刚才的程序。整个过程称为中断处理,也称为中断。

OS 操作系统是中断驱动的。没有中断,操作系统几乎什么都做不了!

中断分类

中断可以分为以下2种类型。

  1. 外中断:来自 CPU 外部的中断就称为外部中断。
  2. 内中断:来自 CPU 内部的中断称为内部中断。

中断机制的本质:中断机制的本质是传入一个中断信号后,调用相应的中断处理程序。所以,CPU 将来自外部设备、内部指令的各种中断类型都归结为一种管理方式,即为每个中断信号分配一个整数,用此整数作为中断的 ID(整数即中断向量),然后用此 ID 作为中断描述符表中的索引,从而找到对应的表项,进而从中找到对应的中断处理程序。

外中断

外部中断是指来自 CPU 外部的中断,而这个外部的中断源一定是某个硬件。因此,外部中断又称为硬件中断。

外部硬件的中断是通过两根信号线通知 CPU 的,分别是INTR(INTeRrupt)和 NMI(Non Maskable Interrupt)。如下图所示

在这里插入图片描述

因为任务有轻重缓急,因此可以再细分位可屏蔽中断(maskable interrupt)和不可屏蔽中断(non-maskable interrupt,NMI)。

  • 可屏蔽中断
    概念:此外部设备发出的中断,CPU 可以不理会,因为它不会让系统宕机。
    【注】CPU也可以理会,把中断分为上半部和下半部分开处理。

  • 不可屏蔽中断
    概念:紧急的中断,严重可让让 CPU 宕机。
    中断处理流程:CPU 收到中断后,需要得知道发生了什么事情才能执行相应的处理办法。这是通过中断向量号进而查中断向量表或中断描述符表(中断向量表是实模式下的中断处理程序数组,在保护模式下已经被中断描述符表代替)来实现的。

内中断

内部中断可分为软中断和异常。

  • 软中断:软中断是指由软件主动发起的中断。(ex. “int 8 位立即数”)
  • 异常:异常是指令执行期间 CPU 内部产生的错误引起的。(ex. “int3”)

实验操作

实验一

开启中断流程

  1. init_all 函数用来初始化所有的设备及数据结构。
  2. init_all 调用 idt_init 初始化中断相关的内容。
  3. 初始化分为2个部分完成,分别是 pic_init 和 idt_desc_init。其中,pic_init (Programmable Interrupt Controller )用来初始化可编程中断控制器 8259A ,ide_desc_init 用来初始化中断描述符表 IDT。
  4. idt_init 完成,便加载 IDT 啦

在这里插入图片描述
实验1用汇编语言实现中断处理程序,该程序保存在 kernel.S 文件中。

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim kernel.S

完成了中断处理程序的编写,咱现在要把它们安装到中断描述符表中。即,创建中断描述符表 IDT,安装中断处理程序。该程序保存在 interrupt.c 文件中(文件 interrupt.c 包含目前有关中断的内容)。

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim interrupt.c

完成中断相关的数据准备,接下来需要设置中断代理 8259A ,这里用到内联汇编实现端口 I/O 函数。io.h 声明有关端口操作的函数定义。

(base) user@ubuntu:/home/cooiboi/bochs/lib/kernel$ sudo vim io.h

接着,需要定义初始化相关的工作的文件,即init_all。

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim init.c

init_all 是由 main.c 中的主函数 main 调用的,更新 main 函数。

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim  main.c

完成剩下文件的创建

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim global.h
(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim init.h
(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim interrupt.h

查看kernel下文件

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ ls
global.h  init.h       interrupt.h  kernel.S
init.c    interrupt.c  kernel.bin   main.c

新建 build 文件夹存放输出文件(将所有目标文件和编译后的内核文件)

(base) user@ubuntu:/home/cooiboi/bochs$ sudo mkdir build

完成基本文件创建工作后,现在进入到编译、链接、写入磁盘的步骤。

编译工作

sudo nasm -f elf -o build/print.o lib/kernel/print.S
sudo nasm -f elf -o build/kernel.o kernel/kernel.S
(base) user@ubuntu:/home/cooiboi/bochs$ sudo nasm -f elf -o build/print.o lib/kernel/print.S
(base) user@ubuntu:/home/cooiboi/bochs$ sudo nasm -f elf -o build/kernel.o kernel/kernel.S
sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/main.o kernel/main.c
sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/interrupt.o kernel/interrupt.c
sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/init.o kernel/init.c
(base) user@ubuntu:/home/cooiboi/bochs$ sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/main.o kernel/main.c
(base) user@ubuntu:/home/cooiboi/bochs$ sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/interrupt.o kernel/interrupt.c
(base) user@ubuntu:/home/cooiboi/bochs$ sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/init.o kernel/init.c

链接工作

这里注意新 kernel.bin 的目录,是在 build 目录下

sudo ld -m elf_i386 -Ttext 0xc0001500 -e main -o build/kernel.bin build/main.o build/init.o build/interrupt.o build/print.o build/kernel.o
(base) user@ubuntu:/home/cooiboi/bochs$ sudo ld -m elf_i386 -Ttext 0xc0001500 -e main -o build/kernel.bin build/main.o build/init.o build/interrupt.o build/print.o build/kernel.o

写入磁盘

sudo dd if=/home/cooiboi/bochs/build/kernel.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=200 seek=9 conv=notrunc
(base) user@ubuntu:/home/cooiboi/bochs$ sudo dd if=/home/cooiboi/bochs/build/kernel.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=200 seek=9 conv=notrunc
14+1 records in
14+1 records out
7236 bytes (7.2 kB, 7.1 KiB) copied, 0.00014881 s, 48.6 MB/s

如果硬盘内容存在问题可以删掉重新写入,下面是之前写入的内容(贴出来方便实现)

sudo dd if=/home/cooiboi/bochs/boot/mbr.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=1 conv=notrunc
sudo dd if=/home/cooiboi/bochs/boot/loader.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=3 seek=2 conv=notrunc

启动Bochs

sudo bin/bochs -f boot/bochsrc.disk
(base) user@ubuntu:/home/cooiboi/bochs$ sudo bin/bochs -f boot/bochsrc.disk

在这里插入图片描述

让我们看看安装后的中断描述符的样子八!命令:info idt

在这里插入图片描述

  • 第一列是中断门描述符的序号,共 0x20 个。
  • Interrupt Gate target 是门描述符中所指向的中断处理程序地址,用选择子:偏移量的形式表示。

假设查看某个中断门描述符,可以使用info idt 序号命令。【下图所示中断向量号 0x20 对应的中断门描述符】

在这里插入图片描述

实验二

改进中断处理程序,在汇编版本的 intrXXentry 中调用 C 语言版本的中断处理函数。

修改 interrupt.c 和 kernel.S 文件

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim interrupt.c
(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim  kernel.S 

之后的步骤和实验一的一模一样~

运行图中不断打印“int vector: 0x20”(只打开了时钟中断,并且时钟的中断向量号是 0x20)

在这里插入图片描述

实验三

新建device 目录下,存放设备代码。

(base) user@ubuntu:/home/cooiboi/bochs$ sudo mkdir  device

创建 timer.c 和 timer.h。

(base) user@ubuntu:/home/cooiboi/bochs/device$ sudo vim timer.c
(base) user@ubuntu:/home/cooiboi/bochs/device$ sudo vim timer.h

接下来,把 timer_init 函数加在文件 init.c 中

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim  init.c

完成基本文件创建工作后,现在进入到编译、链接、写入磁盘的步骤。

下面命令均在/home/cooiboi/bochs$下执行。

编译

sudo nasm -f elf -o build/print.o lib/kernel/print.S
sudo nasm -f elf -o build/kernel.o kernel/kernel.S
sudo gcc -m32 -I lib/kernel -c -o build/timer.o device/timer.c
sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/main.o kernel/main.c
sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/interrupt.o kernel/interrupt.c
sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/init.o kernel/init.c

链接工作

sudo ld -m elf_i386 -Ttext 0xc0001500 -e main -o build/kernel.bin build/main.o build/init.o build/interrupt.o build/print.o build/kernel.o build/timer.o

写入磁盘

sudo dd if=/home/cooiboi/bochs/build/kernel.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=200 seek=9 conv=notrunc

启动Bochs

sudo bin/bochs -f boot/bochsrc.disk

在这里插入图片描述
参考资料

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值