首先打开时钟中断:

	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. Android:StatFs类 获取系统/sdcard存储空间信息

    在存储文件时,为了保证有充足的存储空间大小,通常需要知道系统内部或者sdcard的剩余存储空间大小,这里就需要用到StatFs类. 1. 判断 SDCard 是否存在,并且是否具有可读写权限 /** ...

  2. 基于HT for Web 3D呈现Box2DJS物理引擎

    上篇我们基于HT for Web呈现了A* Search Algorithm的3D寻路效果,这篇我们将采用HT for Web 3D来呈现Box2DJS物理引擎的碰撞效果,同上篇其实Box2DJS只是 ...

  3. SQL Server时间粒度系列----第2节日期、周时间粒度详解

    本文目录列表: 1.从MySQL提供的TO_DAYS和FROM_DAYS这对函数说起2.SQL Server日期时间粒度3.SQL Server周有关时间粒度 4.总结语 5.参考清单列表   从My ...

  4. 使用MVVM-Sidekick开发Universal App(一)

    终于要迈进Universal的大坑了,还有点小激动呢. CurrencyExchanger 掌中汇率是我前几年发布在Windows Phone商店中的一个应用,当时是WP7版本,下载链接:http:/ ...

  5. 了解WP的传感器

    之前看到老大的一个QQ签名,说想写一个WP的程序,可是后来,后来就没有后来了.我去年打算学一下WP程序开发的,一年了也无任何进展,我可不想后来,后来就没有后来.于是抽时间来接触一下.虽然都是用CShs ...

  6. 【人在江湖飘,哪有不带刀】神器Jumony

    大神博客:http://www.cnblogs.com/Ivony/p/3447536.html 项目地址:https://github.com/Ivony/Jumony 1.安装Jumony包 在N ...

  7. webservice MaxReceivedMessageSize :已超过传入消息(65536)的最大消息大小配额

    在客户端的webconfig文件的webservice节点进行如下配置:(注:此处客户端为应用程序的config文件) <system.serviceModel> <bindings ...

  8. 紫橙绿蓝的jQuery幻灯片切换

      效果展示 http://hovertree.com/texiao/jquery/77/ 看惯了左右切换的幻灯片,何问起向您推荐一个新颖的,旋转切换,通过点击按钮的相应区域可以使幻灯片以旋转的方式来 ...

  9. MVP 2015社区大讲堂之:在ASP.NET应用中执行后台任务

    昨天下午,在微软的MVP 2015社区大讲堂上给大家分享了一个题目:在ASP.NET应用中执行后台任务.这是一点都不高大上,并且还有点土气的技术分享.不过我相信很多人都遇到过这样的问题. 虽然是一个很 ...

  10. Topshelf + ServiceModelEx + Nlog 从头构建WCF

    前言 Topshelf可以很方便的构建windows service,而且在本地开发时也可以构建Console宿主,因此很方便WCF的开发. ServiceModelEx则提供了很多便利的方法来配置w ...