首先打开时钟中断:

	out_byte(INT_M_CTLMASK,	0xFE);	// Master 8259, OCW1.
out_byte(INT_S_CTLMASK, 0xFF); // Slave 8259, OCW1.

为了让时钟中断可以不停地发生而不是只发生一次,还需要设置EOI:

hwint00:		; Interrupt routine for irq 0 (the clock).
mov al, EOI ; `. reenable
out INT_M_CTL, al ; / master 8259
iretd

运行后发现结果和原来没有任何区别,因为我们只是可以继续接受中断而已,其余并没有做什么。

中断现在已经被打开,于是就存在ring0和ring1之间频繁的切换。两个层级之间的切换包含两方面,一是代码的跳转,还有一个不容忽视的方面,就是堆栈也在切换。

代码如下:

hwint00:		; Interrupt routine for irq 0 (the clock).
sub esp,4
pushad ; `.
push ds ; |
push es ; | 保存原寄存器值
push fs ; |
push gs ; /
mov dx, ss
mov ds, dx
mov es, dx inc byte [gs:0] ; 改变屏幕第 0 行, 第 0 列的字符 mov al, EOI ; `. reenable
out INT_M_CTL, al ; / master 8259 lea eax, [esp + P_STACKTOP]
mov dword [tss + TSS3_S_SP0], eax pop gs ; `.
pop fs ; |
pop es ; | 恢复原寄存器值
pop ds ; |
popad ; /
add esp,4 iretd

你可以看到,sub/add esp这两句代码实际上是跳过了4字节,结合进程表的定义知道,被跳过的这4字节实际上就是那个retaddr,我们还是先不管这个值。

我们曾经提到过内核栈的问题,如今这个问题真的出现了。现在esp指向的是进程表,如果此时我们要执行复杂的进程调度程序呢?最简单的例子是如果我们想调用一个函数,这时一定会用到堆栈操作,那么我们的进程表立刻会被破坏掉。所以我们需要切换堆栈,将esp指向另外的位置。

hwint00:		; Interrupt routine for irq 0 (the clock).
sub esp, 4
pushad ; `.
push ds ; |
push es ; | 保存原寄存器值
push fs ; |
push gs ; /
mov dx, ss
mov ds, dx
mov es, dx mov esp, StackTop ; 切到内核栈 inc byte [gs:0] ; 改变屏幕第 0 行, 第 0 列的字符 mov al, EOI ; `. reenable
out INT_M_CTL, al ; / master 8259 mov esp, [p_proc_ready] ; 离开内核栈 lea eax, [esp + P_STACKTOP]
mov dword [tss + TSS3_S_SP0], eax pop gs ; `.
pop fs ; |
pop es ; | 恢复原寄存器值
pop ds ; |
popad ; /
add esp, 4 iretd

切到内核栈和重新将esp切到进程表都很简单,一个mov语句就够了,但是它却非常关键。如果没有这个简单的mov,随着中断例程越来越大,出错的时候,你可能都不知道错在哪里。

在这里我们尽可能地把代码放在使用内核栈的过程中来执行,只留下跳回进程所必需的代码。我们在这里试一下,把这段打印字符的代码替换成使用DispStr这个函数:

extern	disp_str

[SECTION .data]
clock_int_msg db "^", 0 hwint00: ; Interrupt routine for irq 0 (the clock).
sub esp, 4
pushad ; `.
push ds ; |
push es ; | 保存原寄存器值
push fs ; |
push gs ; /
mov dx, ss
mov ds, dx
mov es, dx mov esp, StackTop ; 切到内核栈 inc byte [gs:0] ; 改变屏幕第 0 行, 第 0 列的字符 mov al, EOI ; `. reenable
out INT_M_CTL, al ; / master 8259 push clock_int_msg
call disp_str
add esp, 4 mov esp, [p_proc_ready] ; 离开内核栈 lea eax, [esp + P_STACKTOP]
mov dword [tss + TSS3_S_SP0], eax pop gs ; `.
pop fs ; |
pop es ; | 恢复原寄存器值
pop ds ; |
popad ; /
add esp, 4 iretd

运行结果如下,我们看到不断出现的字符“^”,说明函数disp_str运行正常,而且没有影响到中断处理的其他部分以及进程A,之所以在两次字符A的打印中间有多个“^”,是因为我们的进程执行体中加入了delay()函数,在此函数的执行过程中发生了多次中断:

源码

操作系统开发系列—13.b.进程之丰富中断处理程序的更多相关文章

  1. 操作系统开发系列—13.c.进程之中断重入

    现在又出现了另外一个的问题,在中断处理过程中是否应该允许下一个中断发生? 让我们修改一下代码,以便让系统可以在时钟中断的处理过程中接受下一个时钟中断.这听起来不是个很好的主意,但是可以借此来做个试验. ...

  2. 操作系统开发系列—13.a.进程 ●

    进程的切换及调度等内容是和保护模式的相关技术紧密相连的,这些代码量可能并不多,但却至关重要. 我们需要一个数据结构记录一个进程的状态,在进程要被挂起的时候,进程信息就被写入这个数据结构,等到进程重新启 ...

  3. 操作系统开发系列—13.d.多进程 ●

    进程此时不仅是在运行而已,它可以随时被中断,可以在中断处理程序完成之后被恢复.进程此时已经有了两种状态:运行和睡眠.我们已经具备了处理多个进程的能力,只需要让其中一个进程处在运行态,其余进程处在睡眠态 ...

  4. 操作系统开发系列—13.e.三进程

    我们再来添加一个任务,首先添加一个进程体: void TestC() { int i = 0x2000; while(1){ disp_str("C"); disp_int(i++ ...

  5. 操作系统开发系列—13.g.操作系统的系统调用 ●

    在我们的操作系统中,已经存在的3个进程是运行在ring1上的,它们已经不能任意地使用某些指令,不能访问某些权限更高的内存区域,但如果一项任务需要这些使用指令或者内存区域时,只能通过系统调用来实现,它是 ...

  6. 操作系统开发系列—13.i.进程调度 ●

    上面的三个进程都是延迟相同的时间,让我们修改一下,尝试让它们延迟不同的时间. void TestA() { int i = 0; while (1) { disp_str("A." ...

  7. 操作系统开发系列—13.h.延时操作

    计数器的工作原理是这样的:它有一个输入频率,在PC上是1193180HZ.在每一个时钟周期(CLK cycle),计数器值会减1,当减到0时,就会触发一个输出.由于计数器是16位的,所以最大值是655 ...

  8. 微信公众号开发系列-13、基于RDIFramework.NET框架整合微信开发应用效果展示

    1.前言 通过前面一系列文章的学习,我们对微信公众号开发已经有了一个比较深入和全面的了解. 微信公众号开发为企业解决那些问题呢? 我们经常看到微信公众号定制开发.微信公众平台定制开发,都不知道这些能给 ...

  9. 操作系统开发系列—12.f.在内核中添加中断处理 ●

    因为CPU只有一个,同一时刻要么是客户进程在运行,要么是操作系统在运行,如果实现进程,需要一种控制权转换机制,这种机制便是中断. 要做的工作有两项:设置8259A和建立IDT. /*========= ...

随机推荐

  1. Windows Azure Web Site (9) Web Site公网IP地址

    <Windows Azure Platform 系列文章目录> 本文会同时介绍国内由世纪互联运维的Azure China和海外Azure Global. 熟悉Windows Azure平台 ...

  2. 帮助你提高排版技巧的18个 PS 文字特效教程

    Photoshop 文字特效教程对于学习基础的和高级的排版思维有很大的帮助.在这篇文章中,你会发现一组最新发布的文字效果教程.这些高品质的 Photoshop 教程可以帮助你设计出惊人的2D,3D,木 ...

  3. REOBJECT 结构

    REOBJECT 结构   包含有关 rich edit 控件中的 OLE 或图像对象的信息. 语法 typedef struct _reobject { DWORD           cbStru ...

  4. LINQ的Any方法

    返回布尔值,判断集合中是否有元素满足某一条件. source code: IEnumerable<string> str = new List<string> { " ...

  5. Rebalance Customer Balances Utility的使用

    用户不管是打开A/R Posted Transactions Detail还是A/R Posted Transactions Summary 窗口,均显示如下一个警示: 打开Currency Code ...

  6. C#反射技术概念作用和要点

    反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类.结构.委托.接口和枚举等)的成员,包括方法.属性.事件,以及构造函数等.还可以获得每个成员的 ...

  7. SQL Server XML转Table

    前言 在SQL Server中有时候我们需要传人一个Table过去,然后可以在存储过程中批量更新,批量的获取相应数据. 但存储过程的参数是固定,所以这里我们可以变通的传人xml类型的参数,然后在存储过 ...

  8. 速战速决 (3) - PHP: 函数基础, 函数参数, 函数返回值, 可变函数, 匿名函数, 闭包函数, 回调函数

    [源码下载] 速战速决 (3) - PHP: 函数基础, 函数参数, 函数返回值, 可变函数, 匿名函数, 闭包函数, 回调函数 作者:webabcd 介绍速战速决 之 PHP 函数基础 函数参数 函 ...

  9. 最新微信公众平台js sdk整合PHP版

    由于没有持续关注微信公众平台相关的开发,所以看到这个东西时,都没有耐心看完开发文档,或者不知道重点. 重点在哪呢?重点在示例代码:http://mp.weixin.qq.com/wiki/7/aaa1 ...

  10. Time series database

    https://en.wikipedia.org/wiki/Time_series_database https://influxdb.com/docs/v0.9/introduction/getti ...