因为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. 测试servlet学习笔记

    操作方法: 1.新建工程: File——>new——>Java Project——>TestServlet(工程名称)——>Finish. 2.加载servlet-api.ja ...

  2. 10套免费的 Photoshop UI 元素以及 PSD 素材

    免费的 PSD 用户界面工具包以及可以编辑 Photoshop PSD 文件,有你需要的设计漂亮的用户界面和惊人使用体验.这些用户界面工具包可有免费下载,可随意定制的,而且这些 PSD 分层素材文件组 ...

  3. ES6 Features系列:Template Strings & Tagged Template Strings

    1. Brief ES6(ECMAScript 6th edition)于2015年7月份发布,虽然各大浏览器仍未全面支持ES6,但我们可以在后端通过Node.js 0.12和io.js,而前端则通过 ...

  4. Android Studio快捷键每日一练(3)

    原文地址:http://www.developerphil.com/android-studio-tips-of-the-day-roundup-3/ 23.启停用断点 苹果:Cmd+F8    Wi ...

  5. 一对多关系domain Model中设置使用AutoMapper时出错

    在使用AutoMapper时,把数据从VO-PO时显示如下错误,错误提示说在一对多关系中已将集合设置为EntityCollection,那么这个是为什么呢. 看下action中的代码,我们可以发现这是 ...

  6. 【转载】lucene中Field.Index,Field.Store详解

    lucene在doc.add(new Field("content",curArt.getContent(),Field.Store.NO,Field.Index.TOKENIZE ...

  7. QQ--模拟登录

    QQ--模拟登录 使用PC端模拟登录,主要使用的QQ空间登录地址测试. 首先,QQHelper的创建. #region Helper /// <summary> /// Helper // ...

  8. Mac OS 的一点历史: Mac OS, Mac OSX 与Darwin

    作为收购 NeXT 公司的结果,苹果公司获得了 NeXTSTEP 架构中的 Mach 和 Objective-C 等设计.尽管 NeXTSTEP 本身已经不再发展了,但是其中的组件在 OS X 中获得 ...

  9. C#的变迁史 - C# 2.0篇

    在此重申一下,本文仅代表个人观点,如有不妥之处,还请自己辨别. 第一代的值类型装箱与拆箱的效率极其低下,特别是在集合中的表现,所以第二代C#重点解决了装箱的问题,加入了泛型.1. 泛型 - 珍惜生命, ...

  10. 15天玩转redis —— 第六篇 有序集合类型

    今天我们说一下Redis中最后一个数据类型 “有序集合类型”,回首之前学过的几个数据结构,不知道你会不会由衷感叹,开源的世界真好,写这 些代码的好心人真的要一生平安哈,不管我们想没想的到的东西,在这个 ...