操作系统开发系列—12.f.在内核中添加中断处理 ●
因为CPU只有一个,同一时刻要么是客户进程在运行,要么是操作系统在运行,如果实现进程,需要一种控制权转换机制,这种机制便是中断。
要做的工作有两项:设置8259A和建立IDT。
/*======================================================================*
init_8259A
*======================================================================*/
PUBLIC void init_8259A()
{
/* Master 8259, ICW1. */
out_byte(INT_M_CTL, 0x11);
/* Slave 8259, ICW1. */
out_byte(INT_S_CTL, 0x11);
/* Master 8259, ICW2. 设置 '主8259' 的中断入口地址为 0x20. */
out_byte(INT_M_CTLMASK, INT_VECTOR_IRQ0);
/* Slave 8259, ICW2. 设置 '从8259' 的中断入口地址为 0x28 */
out_byte(INT_S_CTLMASK, INT_VECTOR_IRQ8);
/* Master 8259, ICW3. IR2 对应 '从8259'. */
out_byte(INT_M_CTLMASK, 0x4);
/* Slave 8259, ICW3. 对应 '主8259' 的 IR2. */
out_byte(INT_S_CTLMASK, 0x2);
/* Master 8259, ICW4. */
out_byte(INT_M_CTLMASK, 0x1);
/* Slave 8259, ICW4. */
out_byte(INT_S_CTLMASK, 0x1);
/* Master 8259, OCW1. */
out_byte(INT_M_CTLMASK, 0xFF);
/* Slave 8259, OCW1. */
out_byte(INT_S_CTLMASK, 0xFF);
}
out_byte的函数体位于kliba.asm中
global out_byte
global in_byte ; ========================================================================
; void out_byte(u16 port, u8 value);
; ========================================================================
out_byte:
mov edx, [esp + 4] ; port
mov al, [esp + 4 + 4] ; value
out dx, al
nop ; 一点延迟
nop
ret ; ========================================================================
; u8 in_byte(u16 port);
; ========================================================================
in_byte:
mov edx, [esp + 4] ; port
xor eax, eax
in al, dx
nop ; 一点延迟
nop
ret
现在,该是把这些中断和异常的处理程序统统添加上的时候了。
global divide_error
global single_step_exception
global nmi
global breakpoint_exception
global overflow
global bounds_check
... lidt [idt_ptr] ...
; 中断和异常 -- 异常
divide_error:
push 0xFFFFFFFF ; no err code
push 0 ; vector_no = 0
jmp exception
single_step_exception:
push 0xFFFFFFFF ; no err code
push 1 ; vector_no = 1
jmp exception
nmi:
push 0xFFFFFFFF ; no err code
push 2 ; vector_no = 2
jmp exception
breakpoint_exception:
push 0xFFFFFFFF ; no err code
push 3 ; vector_no = 3
jmp exception
overflow:
push 0xFFFFFFFF ; no err code
push 4 ; vector_no = 4
jmp exception
...
exception:
call exception_handler
add esp, 4*2 ; 让栈顶指向 EIP,堆栈中从顶向下依次是:EIP、CS、EFLAGS
hlt
异常发生时堆栈的变化情况是,中断或异常发生时eflags、cs、eip已经被压栈,如果有错误码的话,错误码也已经被压栈。
所以我们对异常处理的总体思想是,如果有错误码,则直接把向量号压栈,然后执行一个函数exception_handler;如果没有错误码,则先在栈中压入一个0xFFFFFFFF,再把向量号压栈并随后执行exception_handler。
函数exception_hanlder()的原型是这样的:
void exception_handler(int vec_no,int err_code,int eip,int cs,int eflags);
由于C调用约定是调用者恢复堆栈,所以不用担心exception_handler会破坏堆栈中的eip、cs以及eflags。
现在我们已经有了异常处理函数,该是设置IDT的时候了。设置IDT的代码放进函数init_prot()中,它也位于protect.c中。protect.c通篇几乎只调用一个函数,就是init_idt_desc(),它用来初始化一个门描述符。其中用到的函数指针类型是这样定义的:
typedef void (*int_handler) ();
在init_prot()中,所有描述符都被初始化成中断门。DA_386IGate表示中断门。
Intel为我们准备了一个指令叫做ud2,能够产生一个#UD异常。
编译:
make image
运行结果如下:


【源码】
操作系统开发系列—12.f.在内核中添加中断处理 ●的更多相关文章
- 操作系统开发系列—12.g.在内核中设置键盘中断
8259A虽然已经设置完成,但是我们还没有真正开始使用它呢. 所有的中断都会触发一个函数spurious_irq(),这个函数的定义如下: PUBLIC void spurious_irq(int i ...
- 操作系统开发系列—12.d.扩充内核 ●
现在把esp.GDT等内容放进内核中,我们现在可以用C语言了,只要能用C,我们就避免用汇编. 下面看切换堆栈和GDT的关键代码: ; 导入函数 extern cstart ; 导入全局变量 exter ...
- 操作系统开发系列—12.c.从Loader加载ELF内核,顺便解释下函数调用过程 ●
实际上,我们要做的工作是根据内核的Program header table的信息进行类似下面这个C语言语句的内存复制: memcpy(p_vaddr, BaseOfLoaderPhyAddr+p_of ...
- 操作系统开发系列—12.a.从Loader到内核 ●
Loader要做两项工作,我们先来做第一项,把内核加载到内存: 1.加载内核到内存. 2.跳入保护模式. 首先编译无内核时: nasm boot.asm -o boot.bin nasm loader ...
- 操作系统开发系列—12.e.Makefile
先来看一个简单的Makefile,我们把它放在目录/boot下,可以用来编译boot.bin和loader.bin. # Makefile for boot # Programs, flags, et ...
- 操作系统开发系列—12.b.从Loader跳入保护模式
现在,内核已经被我们加载进内存了,该是跳入保护模式的时候了. 首先是GDT以及对应的选择子,我们只定义三个描述符,分别是一个0~4GB的可执行段.一个0~4GB的可读写段和一个指向显存开始地址的段: ...
- Windows下USB磁盘开发系列二:枚举系统中所有USB设备
上篇 <Windows下USB磁盘开发系列一:枚举系统中U盘的盘符>介绍了很简单的获取系统U盘盘符的办法,现在介绍下如何枚举系统中所有USB设备(不光是U盘). 主要调用的API如下: 1 ...
- Windows下USB磁盘开发系列三:枚举系统中U盘、并获取其设备信息
前面我们介绍了枚举系统中的U盘盘符(见<Windows下USB磁盘开发系列一:枚举系统中U盘的盘符>).以及获取USB设备的信息(见<Windows下USB磁盘开发系列二:枚举系统中 ...
- 向linux内核中添加外部中断驱动模块
本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内 ...
随机推荐
- Sql Server,如何去含有非数字的nvarchar,再转为为数值
菜鸟一枚,今天做项目时,突然遇到一个问题: 在数据库中中存放的nvarchar类型的“时间”,例如:‘08:00’,而我需要进行时间的范围比较,这时就想到了将nvarchar类型转化为int类型. 这 ...
- Auto Mapper02《demo》
学习这些基本上网上都有一些教程或者别人做的demo,我是按照这个方式去学习的.先做个demo,学会如何去使用它,接着去慢慢的了解它是如何的运行的,理解里面的一些基本的基础知识.我们不可以再像 ...
- CSS基础-插曲
CSS学习 1:通过css来设置边框的颜色 我们可以通过border:10px solid red;来统一的设置颜色,但是我们有的时候需要每个边框的颜色不一样,我们就需要通过各自设置的方法来设置边框的 ...
- IOS ID生成器
// // IdGenerator.m // Copyright (c) 2014年 青岛拓宇网络科技有限公司. All rights reserved. // #import "IdGen ...
- LINQ to SQL语句(3)之Count/Sum/Min/Max/Avg
适用场景:统计数据吧,比如统计一些数据的个数,求和,最小值,最大值,平均数. Count 说明:返回集合中的元素个数,返回INT类型:不延迟.生成SQL语句为:SELECT COUNT(*) FROM ...
- C# 读写App.config配置文件的方法
我们经常会希望在程序中写入一些配置信息,例如版本号,以及数据库的连接字符串等.你可能知道在WinForm应用程序中可以利用Properties.Settings来进行类似的工作,但这些其实都利用了Ap ...
- [Asp.net 5] Configuration-新一代的配置文件(ConfigurationSource的多种实现)
关于配置文件的目录:[Asp.net 5] Configuration-新一代的配置文件 在前面我们介绍了,系统中用IConfigurationSource表示不同配置文件的来源,起到读取.设置.加载 ...
- asp.net MVC4的执行流程
MVC在底层和传统的asp.net是一致的,在底层之上,相关流程如下: 1)Global.asax里,MvcApplication对象的Application_Start()事件中,调用 RouteC ...
- WinForm 简单蒙版实现控件遮盖
在Web上面要实现一个遮罩层或者说是蒙版吧,有了DIV那不算什么难事,只要给div定好位置和大小,把颜色的Alpha值设一下就有透明的效果.不过在Winform中实现起来就没那么简单了事.尝试过用一个 ...
- 分析.Net里线程同步机制
我 们知道并行编程模型两种:一种是基于消息式的,第二种是基于共享内存式的. 前段时间项目中遇到了第二种 使用多线程开发并行程序共享资源的问题 ,今天以实际案例出发对.net里的共享内存式的线程同步机制 ...