c语言中断处理Word下载.docx

上传人:b****5 文档编号:18613835 上传时间:2022-12-29 格式:DOCX 页数:10 大小:25.55KB
下载 相关 举报
c语言中断处理Word下载.docx_第1页
第1页 / 共10页
c语言中断处理Word下载.docx_第2页
第2页 / 共10页
c语言中断处理Word下载.docx_第3页
第3页 / 共10页
c语言中断处理Word下载.docx_第4页
第4页 / 共10页
c语言中断处理Word下载.docx_第5页
第5页 / 共10页
点击查看更多>>
下载资源
资源描述

c语言中断处理Word下载.docx

《c语言中断处理Word下载.docx》由会员分享,可在线阅读,更多相关《c语言中断处理Word下载.docx(10页珍藏版)》请在冰豆网上搜索。

c语言中断处理Word下载.docx

这里要用到setvect 

)和getvect 

)函数。

setvect 

)有两个参数:

中断号和函数的入口地址,其功能是将指定的函数安装到指定的中断向量中,getvect 

)函数有一个参数:

中断号,返回值是该中断的入口地址。

在安装中断以前,最好用disable 

)函数关闭中断,以防止在安装过程中又产生新的中断而导致程序运行混乱,待安装完成后,再用enable 

)函数开放中断,使程序正常运行。

现在我们可以把上面的例子再丰富一下:

/*例2:

中断服务程序的编写、安装和使用*/ 

#include 

<

dos.h>

stdio.h>

#ifdef 

__cplusplus 

#define 

__ARGU 

... 

#else 

#endif 

int60 

(__ARGU) 

/*中断服务函数*/ 

install 

(void 

(*fadd)(__ARGU),int 

num) 

/*安装中断*/ 

disable();

/*关闭中断*/ 

setvect(num, 

fadd);

/*设置中断*/ 

enable();

/*开放中断*/ 

main() 

(int60,0x60);

/*将int60函数安装到0x60中断*/ 

geninterrupt 

(0x60);

/*人为产生0x60号中断*/ 

有一定经验的读者很容易得到该程序的执行结果:

在屏幕上显示“This 

example!

”。

编写、安装中断服务程序的方法就介绍这些。

下面再浅谈一下内存驻留程序(TSR)的编写和使用。

在C语言中,可以用keep 

)函数将程序驻留内存。

这个函数有两个参数:

status和size。

size为驻留内存长度,可以用size=_SS+_SP/16-_psp得到,当然这也是一种估算的方法,并不是精确值。

函数执行完以后,出口状态信息保存在status中。

比如,对于上面的例子,将“geninterrupt 

”改写成“keep(0,_SS+_SP/16-_psp);

”后再执行程序,这一段程序就被驻留,此后在其它的任何软件或程序设计中,只要用到了60H号中断,就会在屏幕上显示“This 

”的字样。

要恢复系统对60H号中断的定义,只能重新启动计算机。

像上面的例子其实还很不完善,它没有考虑DOS系统环境的状态、没有考虑程序是否已经驻留内存、没有考虑退出内存驻留等问题。

对于第二个问题还是很容易解决的:

执行程序一开始就读取某一函数中断入口地址(如63H号中断)判断是否为空(NULL),如果为空就先将该地址置为非空再驻留内存,若为非空则表示已经驻留并退出程序。

这一步判断非常重要,否则将会因为重复驻留占用过多内存空间而最后造成系统崩溃。

至于其它两个问题,在此不多作说明,有兴趣的读者可以参考一些有关书籍。

不仅如此,我们还可以通过在DOS下使用热键(Hotkey)来调用内存驻留程序。

比如将《希望汉字系统》自带的《希望词典》驻留内存后,在任意时刻按下Ctrl+F11键,就能激活程序,出现词典界面。

微机的键盘中有一个微处理芯片,用来扫描和检测每个按键的按下和释放状态。

大多数按键都有一个扫描码,告知CPU当前的状态,但一些特殊的键如PrintScreen、Ctrl+Break等不会产生扫描码,而直接产生中断。

正因为如此,我们可以将Ctrl+Break产生的中断号指向我们自己写好的程序入口地址,那么当按下Ctrl+Break后,系统就会调用我们自己的程序去执行,这实际上也就是修改了Ctrl+Break的中断向量。

至于其它按键激活程序则可以利用9H号键盘中断捕获的扫描码来实现,在此不多作说明。

例如,执行下面的程序后,退回DOS系统,在任意的时候按下Ctrl+Break后,屏幕的底色就会变成红色。

/*例3:

中断服务程序编写、安装和使用,内存驻留*/ 

conio.h>

newint(__ARGU);

/*函数声明*/ 

(*fadd)(__ARGU), 

int 

num);

(newint,0x1b);

/*Ctrl+Break中断号:

1BH*/ 

keep(0,_SS+(_SP/16)-_psp);

/*驻留程序*/ 

return 

0;

newint(__ARGU) 

textbackground(4);

/*设置屏幕底色为红色*/ 

clrscr();

/*清除屏幕*/ 

setvect(num,fadd);

由于13H号中断是BIOS提供的磁盘中断服务程序,对于DOS下的应用程序,它们的存盘、读盘功能都是通过调用这一中断来实现的。

有许多DOS下的病毒就喜欢修改13H号中断来破坏系统,例如,修改13H号中断服务程序,将其改成:

/*例4:

病毒体程序伪代码*/ 

new13(__ARGU) 

if 

(病毒发作条件成熟) 

修改入口参数指向病毒程序入口地址;

执行病毒代码;

调用原来的13H中断;

只要当任一软件(如EDIT.COM等)对磁盘有操作并且病毒发作条件成熟时,病毒就被激活。

当然,这样做会导致可用内存空

Linux中断编程

在 

Linux 

下,硬件中断被称为 

IRQs 

[Interrupt 

Requests 

(这是Linux起源的Intel 

架构上的标准术语。

)的缩写]。

有两种 

IRQs,短的和长的。

一个短的 

IRQ 

预期占用 

非常短的一段时间,在那期间,机器的剩余部分被阻塞,没有其他的中断将被处理。

长的 

占用的时间长些,在那期间其他中断有可能发生(但不能是来自同一设备)。

只要是可能的,声明一个长中断是较好的。

   

当 

CPU 

接收到一个中断,它停止它正在做的任何事情(除非它正在处理一个更重要的中断,在那种情况下,它将处理完那个中断后才来处理现在的这个),在堆栈中保存某些参数并调用中断处理程序。

这意味着在中断处理程序自身中有些东西是不能允许的,因为系统处于一种未知的状态。

解决的办法是中断处理程序马上做完需要做的,通常是从硬件里面读什么或向硬件发送什么然后安排处理稍后的新信息(这被称为‘bottom 

half’)并返回。

然后内核保证只要可能就调用bottom 

half 

--当这在运行,内核模块中允许做的所有事情将被允许。

实现这个办法是当接收到相关的IRQ(在 

Intel 

平台下有16个)时去调用 

request_irq 

以使中断处理程序被调用。

这个函数接收IRQ 

号,函数名,标志, 

/proc/interrupts 

中的名字及一个传送给中断处理程序的参数作为其参数。

标志可以包括 

SA_SHIRQ 

以指明你愿意和其他的中断处理程序分享那个IRQ(通常因为几个硬件设备在同一IRQ)以及 

SA_INTERRUPT 

以指明这是一个快速中断。

这个函数只在那个IRQ上没有处理程序的情况下成功,或者你愿意两者共享。

然后从中断处理程序中我们和硬件通信,联合tq_immediate使用 

queue_task_irq 

和 

mark_bh(BH_IMMEDIATE) 

调度 

bottom 

half。

我们在 

2.0 

版中不使用标准的queue_task 

的原因是中断有可能在其他人的 

queue_task(queue_task_irq 

从这被一个全局锁保护 

-- 

在 

2.2 

版中没有queue_task_irq 

而 

queue_task 

被一个锁保护。

)中发生。

我们需要 

mark_bh 

是因为Linux 

的早期版本只能有32个 

half,而现在它们中的一个(BH_IMMEDIATE) 

用于还没有得到bottom 

half入口的驱动程序的bottom 

half连接表。

Intel 

架构键盘 

警告:

这章剩下的内容都特别指定为完全的 

基于Intel 

架构。

如果你不是在这个平台下运行,它没有用。

甚至不要试图去编译这里的代码。

在为这章写范例代码的时候我有一个问题。

一方面,对于一个有用的范例,它应该运行于每个人的计算机上且有意味深长的结果。

另一方面,内核已经包含了所有的通用设备的驱动程序,并且那些设备驱动程序不能和我将要写的共存。

我发现的结果是写一些键盘中断的东西并且先关闭通常的键盘的中断句柄。

因为在内核源文件(明确的, 

drivers/char/keyboard.c)中它被定义为静态符号,所以没有办法恢复它。

如果你重视你的文件系统,在 

insmod 

这些代码前,在另一个终端上sleep 

120 

;

reboot 

这个代码将自己绑定为 

1,这是Intel 

架构下的键盘控制器的IRQ(中断请求)。

然后当它收到键盘中断时它就读键盘的状态( 

那就是inb(0x64)的目的)和扫描代码,该代码即是键盘的返回值。

然后,内核一认为它是可行的它就运行给出键所使用的代码(扫描代码的前7位)和它是被按下(第8位为0)还是被释放(第8位为1)的got_char函数。

范例 

intrpt.c 

/* 

中断句柄 

*/ 

Copyright 

(C) 

1998 

by 

Ori 

Pomerantz 

必要头文件 

标准头文件 

#include 

/* 

内核工作 

明确指定是模块 

处理 

CONFIG_MODVERSIONS 

#if 

CONFIG_MODVERSIONS==1 

#define 

MODVERSIONS 

#endif 

我们想中断 

2.2.3 

版/usr/include/linux/version.h 

中包含这个宏, 

但 

2.0.35 

版不包含-因此在这加入以被需要 

#ifndef 

KERNEL_VERSION 

KERNEL_VERSION(a,b,c) 

((a)*65536+(b)*256+(c)) 

Bottom 

Half 

一旦内核模块认为它做任何事都是安全的时候这将被内核调用。

static 

got_char(void 

*scancode) 

printk("

Scan 

Code 

%x 

%s.n"

 

(int) 

*((char 

*) 

scancode) 

&

0x7F, 

*((char 

0x80 

?

"

Released"

:

Pressed"

这个函数为键盘中断服务。

它读取来自键盘的相关信息然后安排当内核认为bottom 

half安全的时候让它运行 

void 

irq_handler(int 

irq, 

*dev_id, 

struct 

pt_regs 

*regs) 

这些变量是静态的,因为它们需要对 

可见(通过指针)。

unsigned 

char 

scancode;

struct 

tq_struct 

task 

{NULL, 

0, 

got_char, 

scancode};

unsigned 

status;

Read 

keyboard 

status 

status 

inb(0x64);

scancode 

inb(0x60);

安排 

运行 

LINUX_VERSION_CODE 

>

KERNEL_VERSION(2,2,0) 

queue_task(&

task, 

tq_immediate);

#else 

queue_task_irq(&

mark_bh(IMMEDIATE_BH);

初始化模块--登记 

句柄 

int 

init_module() 

既然键盘的句柄不能和我们的共存,在我们做事情前我们不得不关闭它(释放它的 

IRQ)。

因为我们不知道它在哪儿,所以以后没有办法恢复它--因此当我们做完时计算机将被重新启动。

*/ 

free_irq(1, 

NULL);

请求 

1,键盘的 

IRQ,指向我们的 

irq_handler。

return 

request_irq( 

1, 

PC上的键盘的 

号 

irq_handler, 

我们的句柄 

SA_SHIRQ, 

意味着我们将另一个句柄用于这个 

IRQ。

能使句柄为一个快速中断。

"

test_keyboard_irq_handler"

清除 

cleanup_module() 

它在这儿只是为了完全。

它是完全不相关的,因为我们没有办法恢复通常的键盘中断因此计算机完全没用 

了,需要被重新启动。

}

Windows中断编程

中断机制 

(1)实模式中断 

为了便于理解,我们先回顾实模式中断。

在实模式下,中断向量表IVT起到相当重要的作用。

无论来自外部硬件的中断或是内部的软中断INTn,在CPU中都产生同样的响应。

①CPU将当前的指令指针寄存器(IP)、代码段寄存器(CS)、标志寄存器压入堆栈。

②然后CPU使用 

n值作为指向中断向量表IVT的索引,在IVT中找出服务例程的远地址。

②CPU将此远地垃装入CS:

IP寄存器中,并开始执行服务例程。

④中断例程总以IRET指令结束。

此指令使存在堆栈中的三个值弹出并填入CS、IP和标志寄存器,CPU继续执行原来的指令。

(2)保护模式中断 

保护模式中断过程与实模式中断过程类似,但它不再使用中断向量表IVT,而使用中断描述符表(IDT)。

值得一提的是,Windows运行时IVT还存在,应用程序并不使用它,Windows仍然使用,但含义已不同‘ 

(1)IVT结构:

IVT在RAM的 

0000:

0000之上,占据开始的1024字节。

它仍然由 

BIOS启动例程设置,由DOS填充到RAM中。

②IDT中断描述符表:

保护模式下,Windows操作系统为实现中断机制而建立的一个特殊表,即中断描述符表IDT。

该表被用来保存中断服务例程的线性地址,它们是真正的24位或32位地址,没有段:

偏移值结构。

中断描述器表最多可含有256个例 

程说明,详细说明请见[3]。

IDT结构见图2。

②当中断或异常发生时,处理过程与实模式类丁当前的CS;

IP值和标志寄存器值被存储。

保存的内容还包括CPU其他内部寄存器的值,以及目 

前正在被执行的任务的有关信息(若必须发生任务切换的话)。

CPU设法获取中断向量后,以它为索引值查找IDT中的服务例程远地址,接着将控制转移到该处的服务例程。

这是与实模式转移到IVT的不同所在。

保护模式使用IDTR寄存器分配和定位内存中的IDT中断描述符表。

IDT在内存中是可移动的,与IVT固定在内存中刚好相反。

IDT中断描述符表在 

Windows中起决定性的作用。

理解了windows保护模式的中断机制。

有助于我们理解中断服务程序的设计,它的关键就在于如何将服务例程的地址放入IDT中断描述符表中。

当中断发生时,如何将断点地址及CPU各寄存器值保护起来,中断结束时,如何将保护的值恢复。

windows系统本身并不提供实现上述功能的API,而DOS保护模式接口DPMI正具备了上述的功能。

下面我们首先介绍DPMI接口,然后基于它实现Windows下中断服务程序的设计。

四、DOS保护模式接口 

DMPI 

Windows除了标准服务外,还支持一组特殊的DOS服务,称为DOS保护模式接口 

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1