文章目录
- 前言
- 前置知识
- 中断概念
- 中断分类
- 实验操作
- 实验一
- 实验二
- 实验三
前言
博客记录《操作系统真象还原》第七章实验的操作~
实验环境:ubuntu18.04+VMware , Bochs下载安装
实验内容:
- 编写中断处理程序( 操作 8259A 打开中断)。
- 改进中断处理程序(在汇编版本的 intrXXentry 中调用 C 语言版本的中断处理函数)。
- 用计数器/定时器 8253 来设置时钟中断发生的频率。(给中断信号提速)。
前置知识
中断概念
中断处理(中断)的概念:由于 CPU 获知了计算机中发生的某些事,CPU 暂停正在执行的程序,转而去执行处理该事件的程序, 当这段程序执行完毕后,CPU 继续执行刚才的程序。整个过程称为中断处理,也称为中断。
OS 操作系统是中断驱动的。没有中断,操作系统几乎什么都做不了!
中断分类
中断可以分为以下2种类型。
- 外中断:来自 CPU 外部的中断就称为外部中断。
- 内中断:来自 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”)
实验操作
实验一
开启中断流程
- init_all 函数用来初始化所有的设备及数据结构。
- init_all 调用 idt_init 初始化中断相关的内容。
- 初始化分为2个部分完成,分别是 pic_init 和 idt_desc_init。其中,pic_init (Programmable Interrupt Controller )用来初始化可编程中断控制器 8259A ,ide_desc_init 用来初始化中断描述符表 IDT。
- 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
参考资料
- 《操作系统真象还原》
- 《操作系统真象还原》第七章 ---- 终进入中断处理拳打脚踢 操作系统日渐成熟 目前所有代码总览