因为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.在内核中添加中断处理 ●的更多相关文章

  1. 操作系统开发系列—12.g.在内核中设置键盘中断

    8259A虽然已经设置完成,但是我们还没有真正开始使用它呢. 所有的中断都会触发一个函数spurious_irq(),这个函数的定义如下: PUBLIC void spurious_irq(int i ...

  2. 操作系统开发系列—12.d.扩充内核 ●

    现在把esp.GDT等内容放进内核中,我们现在可以用C语言了,只要能用C,我们就避免用汇编. 下面看切换堆栈和GDT的关键代码: ; 导入函数 extern cstart ; 导入全局变量 exter ...

  3. 操作系统开发系列—12.c.从Loader加载ELF内核,顺便解释下函数调用过程 ●

    实际上,我们要做的工作是根据内核的Program header table的信息进行类似下面这个C语言语句的内存复制: memcpy(p_vaddr, BaseOfLoaderPhyAddr+p_of ...

  4. 操作系统开发系列—12.a.从Loader到内核 ●

    Loader要做两项工作,我们先来做第一项,把内核加载到内存: 1.加载内核到内存. 2.跳入保护模式. 首先编译无内核时: nasm boot.asm -o boot.bin nasm loader ...

  5. 操作系统开发系列—12.e.Makefile

    先来看一个简单的Makefile,我们把它放在目录/boot下,可以用来编译boot.bin和loader.bin. # Makefile for boot # Programs, flags, et ...

  6. 操作系统开发系列—12.b.从Loader跳入保护模式

    现在,内核已经被我们加载进内存了,该是跳入保护模式的时候了. 首先是GDT以及对应的选择子,我们只定义三个描述符,分别是一个0~4GB的可执行段.一个0~4GB的可读写段和一个指向显存开始地址的段: ...

  7. Windows下USB磁盘开发系列二:枚举系统中所有USB设备

    上篇 <Windows下USB磁盘开发系列一:枚举系统中U盘的盘符>介绍了很简单的获取系统U盘盘符的办法,现在介绍下如何枚举系统中所有USB设备(不光是U盘). 主要调用的API如下: 1 ...

  8. Windows下USB磁盘开发系列三:枚举系统中U盘、并获取其设备信息

    前面我们介绍了枚举系统中的U盘盘符(见<Windows下USB磁盘开发系列一:枚举系统中U盘的盘符>).以及获取USB设备的信息(见<Windows下USB磁盘开发系列二:枚举系统中 ...

  9. 向linux内核中添加外部中断驱动模块

    本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内 ...

随机推荐

  1. [New Portal]Windows Azure Virtual Machine (12) 在本地使用Hyper-V制作虚拟机模板,并上传至Azure (2)

    <Windows Azure Platform 系列文章目录> 本章介绍的内容是将本地Hyper-V的VHD,上传到Azure数据中心,作为自定义的虚拟机模板. 注意:因为在制作VHD的最 ...

  2. Windows 8.1 系统ISO镜像下载或自Win8应用商店升级方法

    1)下载 -- 面向全体用户的Win8.1预览版ISO镜像下载(28日开放): 安装时请输入微软官方提供给大家的产品密钥:NTTX3-RV7VB-T7X7F-WQYYY-9Y92F. 64位简体中文版 ...

  3. mysql的timeout

    mysql的timeout 很多时候我们连接mysql会在timeout这里跌倒,这里明确下mysql的timeout: 下面是获取timeout的变量: mysql> show global ...

  4. IOS从视频中获取截图

    从视频中获取截图: NSString *movpath =[[NSBundle mainBundle] pathForResource:@”iosxcode4″ ofType:@”mov”]; mpv ...

  5. [AngularJS] AngularJS系列(1) 基础篇

    目录 什么是AngularJS? 为什么使用/ng特性 Hello World 内置指令 内置过滤器 模块化开发 一年前开始使用AngularJS(以后简称ng),如今ng已经出2了.虽说2已完全变样 ...

  6. IOS 通用颜色快速生成代码

    通常情况下我们是直接使用类似于#EE1289这样的代码来直接表示RGB颜色的.但是在IOS语言中,它的颜色表示方式比较另类,他是使用一个0-1的小数来表示颜色值的.这样的实现,或许能够表示更多的颜色值 ...

  7. 二维码详解(QR Code)

    作者:王子旭链接:https://zhuanlan.zhihu.com/p/21463650来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 2016.7.5 更新:长文 ...

  8. 在WCF数据访问中使用缓存提高Winform字段中文显示速度

    在我们开发基于WCF访问方式的Winform程序的时候,一般情况下需要对界面显示的字段进行中文显示的解析.如果是硬编码进行中文显示,那么除了不方便调整及代码臃肿外,性能上没有什么问题,但是不建议这样处 ...

  9. 全动态Portlet点击后选中样式

    1  背景概述 在配置公司云平台的帮助信息过程中,由于使用的全动态portlet的数据URL获取到的是静态数据,没有办法在后台做选中的逻辑判断,所以需要在前台来控制选中列表的样式,这里将对前台选中列表 ...

  10. 只用CSS实现容器内图片上下左右居中

    一直以来,大家都知道,DIV容器内设置 text-align:center 即可让图片居中,但是DIV内默认的图片是上对齐,不会上下居中,如果想要实现这样的效果,JS判断是比较麻烦的,因为DIV容器内 ...