interrupt webservice是什么 routine是什么意思,中断服务例程翻译

service_routine
石油英语词汇(S3) ... service road 辅助道路 service routine 服务程序 service sector 服务业.
- 基于826个网页
实用例行程序
service regulator,气源减压器service routine,服务程序;实用例行程序service speed,工作转速
- 基于164个网页
服务子程序
VAX / VMS interrupt service routine that is activated by a software interrupt at a fork interrupt priority level ( IPL ) .VAX/VMS的一种中断服务子程序,在分叉中断优先级(PL)软件中断激活。
- 基于16个网页
interrupt service routine
中断服务程序   (2)中断服务程序(Interrupt Service Routine)不能被其他进程抢占。   2.2 基于优先级的调度算法   在Linux 2.6中,采用了O(1)调度算法。
- 基于1016个网页
service routines
服务例行程序 a comprehensive collection of control program options , language processors , I / O supports , application programs , and service routines , designed to meet the needs of users who require the extensive facilities of a large operating system .控制程序选件、语言处理程
- 基于1个网页
routine servicing
日常养护 routine sequential of tests 常规系列试验routine servicing 日常养护routine test 常规试验
- 基于15个网页
routine service
例行保养 设备管理英文术语 - 豆丁网 ... 磨损性故障 wearout failure · 例行保养(例保) routine service · 密封点 sealed point &#183.
- 基于2个网页Interrupt-service-routine 设计单片机中断T0 服务程序,作为子 随时调用 SCM 开发 238万源代码下载-
&文件名称: Interrupt-service-routine
& & & & &&]
&&所属分类:
&&开发工具: Visual C++
&&文件大小: 3 KB
&&上传时间:
&&下载次数: 0
&&提 供 者:
&详细说明:设计单片机中断T0中断服务程序,作为子程序随时调用-Design microcontroller interrupt T0 interrupt service routine, as a subroutine called at any time
文件列表(点击判断是否您需要的文件,如果是垃圾请在下面评价投诉):
&&Interrupt service routine.doc
&输入关键字,在本站238万海量源码库中尽情搜索:所谓中断是指当CPU正在处理某件事情的时候,外部发生的某一事件(如一个电平的变化,一个脉冲沿的发生或计数溢出等)请求CPU迅速去处理,于是CPU暂时中止当前的工作,转去处理所发生的事件。中断服务处理完该事件以后,再回到原来被中止的地方继续原来的工作。
中断是一种硬件机制,用于通知CPU有个异步事件发生了。中断一旦被系统识别,CPU则保存部分(或全部)现场(context),即部分(或全部)的值,跳转到专门的,称为(ISR)。做事件处理,处理完成后执行任务调度,程序回到就绪态优先级最高的任务开始运行(对于可剥夺型内核)。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:106153次
积分:1911
积分:1911
排名:第11362名
转载:519篇
(1)(13)(14)(1)(27)(16)(14)(3)(46)(29)(35)(23)(58)(9)(7)(34)(2)(8)(6)(1)(2)(2)(28)(33)(71)(39)(2)interrupt service routine的用法和样例:
Unable to register the interrupt service routine.
无法注册中断服务例程。
The address of an interrupt service routine.
中断服务程序所在的地址。
The automatic clear reduces the operations required by the interrupt service routine entry code to reading the AIC_IVR.
这个)自动清除(动作)减少了中断服务程序入口代码读取AIC_IVR(寄存器)所需的操作.
The amount of time between the assertion of an interrupt and the start of the associated interrupt service routine.
在中断发生和相关的中断服务程序运行之间的时间长短。
Later on, your device might generate an interrupt, whereupon your interrupt service routine will be called at DIRQL.
稍后,你的设备可能发生一个中断,因此你的中断服务程序将要在DIRQL上被调用。
VAX/ VMS interrupt service routine that is activated by a software interrupt at a fork interrupt priority level ( IPL).
VMS的一种中断服务子程序,在分叉中断优先级(PL)软件中断激活。
interrupt service routine的海词问答与网友补充:
interrupt service routine的相关资料:
相关词典网站:深入理解 x86/x64 的中断体系
深入理解 x86/x64 的中断体系
1. 实模式下的中断机制
x86 processor 在加电后被初始化为 real mode 也称为 real-address mode,关于实模式请详见文章:
processor 执行的第一条指针在 0xFFFFFFF0 处,这个地址经过 North Bridge(北桥)和 South ridge(南桥)芯片配合解码,最终会访问到固化的 ROM 块,同时,经过别名机制映射在地址空间低端,实际上等于 ROM 被映射到地址空间最高端和低端位置。
此时在系统的内存里其实并不存在 BIOS 代码,ROM BIOS 的一部分职责是负责安装 BIOS 代码进入系统内存。
jmp far f000:e05b
典型是这条指令就是 0xFFFFFFF0 处的 ROM BIOS 指令,执行后它将跳到 0x000FE05B 处,这条指令的作用很大:
更新 CS.base 使 processor 变成纯正的 real mode
跳转到低端内存,使之进入 1M 低端区域
前面说过,此时内存中也不存在 BIOS,也就是说 IVT(中断向量表)也是不存在的,中断系统此时是不可用的,那么由 ROM BIOS 设置 IVT 。
1.1 中断向量表(IVT)
IDTR.base 被初始化为 0,ROM BIOS 将不会对 IDTR.base 进行更改,因此如果实模式 OS 不更改 IDTR.base 的值,这意味着 IVT 在 0 的位置上,典型的如: DOS 操作系统。
在保护模式下 IDTR.base 将向不再是中断向量表,而是中断描述符表。不再称为 IVT 而是 IDT。那是因为:
在实模式下,DITR.base 指向的表格项直接给出中断服务例程(Interrupt Service Routine)的入口地址。
在保护模式下,并不直接给出入口地址,而是门描述符(Interrupt/Trap/Task gate),从这些门描述符间接取得中断服务例程入口。
在 x86/x64 体系中允许有 256 个中断存在,中断号从 0x00 - 0xff,共 256 个中断,如图:
上面这个图是实模式下的 IVT 表,每个向量占据 4 个字节,中断服务例程入口是以 segment:offset 形式提供的,offset 在低端,segment 在高端,整个 IVT 表从地址 0x0 - 0x3FF,占据了 1024 个字节,即 1K bytes
1.2 改变中断向量表地址
事实上,我们完全可以在实模式下更改 IVT 的地址,下面的代码作为示例:
; ****************************************************************; * boot.asm for interrupt demo(real mode) on x86&&&&&&&&&&&&&&& *; *&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& * ; * Copyright (c) &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *; * All rights reserved.&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *; * mik&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *; * visit web site : &&&&&&&&&&&&&&&&&&&&&&&&&&&& *; * bug send email : &&&&&&&&&&&&&&&&&&&&&&&&&&&& *; *&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *; *&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *; * version 0.01 by mik&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *& ; ***************************************************************
BOOT_SEG&&&&&&& equ 0x7c00&&&&&&& ; boot module load into BOOT_SEG
;----------------------------------------------------------; Now, the processor is real mode ;----------------------------------------------------------
&&&&&&& bits 16
&&&&&&& org BOOT_SEG&&&&&&&&&&&&&&&&&& ; for int 19&&&&&&& start:&&&&&&& mov ax, cs&&&&&&& mov ds, ax&&&&&&& mov es, ax&&&&&&& mov ss, ax&&&&&&& mov sp, BOOT_SEG&&&&&&& &&&&&&& mov si, msg1&&&&&&& call printmsg
&&&&&&& sidt [old_IVT]&&&&&&&&&&&&&&&&&&&&&&& ; save old IVT
&&&&&&& mov cx, [old_IVT]&&&&&&& mov [new_IVT], cx&&&&&&&&&&&&&&& ; limit of new IVT
&&&&&&& mov dword [new_IVT+2], 0x8000&&&&&&& ; base of new IVT
&&&&&&& mov si, [old_IVT+2]&&&&&&& mov di, [new_IVT+2]
&&&&&&& rep movsb&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&& lidt [new_IVT]&&&&&&&&&&&&&&&&&&&&&&& ; set new IVT&&&&&&& &&&&&&& mov si, msg2&&&&&&& call printmsg
&&&&&&& jmp $
;-----------------------------------; printmsg() - print message;-----------------------------------printmsg:&&&&&&& mov ah, 0x0e&&&&&&& xor bh, bh
print_loop:&&&&&&& lodsb&&&&&&& test al,al&&&&&&& jz done&&&&&&& int 0x10&&&&&&& jmp print_loop
done:&&&&&&& &&&&&&& ret
old_IVT&&&&&&&& dw 0&&&&&&&&&&&&&&&&&&&&&&& ; limit of IVT&&&&&&&&&&&&&&& dd 0&&&&&&&&&&&&&&&&&&&&&&& ; base of IVT
new_IVT&&&&&&&& dw 0&&&&&&&&&&&&&&&&&&&&&&& ; limit of IVT&&&&&&&&&&&&&&& dd 0&&&&&&&&&&&&&&&&&&&&&&& ; base of IVT
&&&&&&& msg1&&&&&&&&&&& db 'Hi, print message with old IVT', 10,13, 0msg2&&&&&&&&&&& db 'Now,pirnt message with new IVT', 13, 10, 0
&&&&&&& times 510-($-$$) db 0&&&&&&& &&&&&&& dw 0xaa55&&&&&&& ; end of boot.asm
在 vmware 上这段代码的执行结果如图:
这段代码在实模式下将 IVT 表复制到 0x8000 位置上,然后将 IVT 地址设为 0x8000 上,这样完全可以正常工作。正如代码上看到的,我做:
使用 sidt 指令取得 IDTR 寄存器的值,即 IVT 的 limit 和 base 值,保存在 old_IVT 里
设置 new_IVT 值,limit 等于 old_IVT 的 limit,base 设为 0x8000
将 IVT 表复制到 0x8000 处
使用 lidt 指令加载 IDTR 寄存器,即设 IVT 表在 0x8000 处
1.3 设置自己的中断服务例程
在中断向量表里还有许多空 vector 是未使用的,我们可以在这些空白的向量里设置自己的中断服务例程,典型的如: DOS 操作系统中使用了 0x21 号向量作为 DOS 提供给用户的系统调用!
在这里我将展示,使用 0x40 向量作为自己的中断服务例程向量,我所需要做的是:
写一个自己的中断服务例程,在本例中的 my_isr
设置向量 0x40 的 segment 和 offset 值
调用 int 0x40 进行测试
中断服务例程 my_isr 很简单,仅仅是打印信息:
;------------------------------------------------; our Interrupt Service Routine: vector 0x40;-------------------------------------------------my_isr:&&&&&&& mov si, msg3&&&&&&& call printmsg&&&&&&& iret
接下来设置 vector 0x40 的 segment 和 offset:
&&&&&&& mov ax, cs&&&&&&& mov bx, [new_IVT+2]&&; base of IVT&&&&&&& mov dword [bx+0x40*4], my_isr&; set offset 0f my_isr
&&&&&&& mov [bx+0x40*4+2], ax&&; set segmet of my_isr
记住 segment 在高位,offset 在低位,这个 segment 是我们当前的 CS,offset 是我们的 ISR 地址,直接写入 IVT 表中就可以了
现在我们可以测试了:
&&&&&&& int 0x40
结果如下:
我们的 ISR 能正常工作了,我提供了完整的示例源码和磁盘映像下载:
2. 保护模式下的中断机制
引入保护模式后,情形变得复杂多了,实施了权限控制机制,为了支持权限的控制增添了几个重要的数据结构,下面是与中断相关的结构:
gate descriptor(门描述符):用于描述和控制 Interrupt Service Routine 的访问,中断可使用的 gate 包括:
Interrupt-gate descriptor(中断门描述符)
Trap-gate descriptor(陷井门描述符)
Task-gate descriptor(任务门描述符)-- 在 64 位模式下无效
interrupt descriptor table(中断描述符表):用于存在 gate descriptor 的表格
在 32 位保护模式下,每个 gate descriptor 是 8 bytes 宽,在 64 位模式下 gate descriptor 被扩充为 16 bytes, 同时 64 位模式下不存在 task gate descriptor,因此在 64 位下的 IDT 只允许存放 interrupt/trap gate descriptor。
当我们执行调用中断时,processor 会在 IDT 表中寻找相应的 descriptor,并通过了权限检查转入相应的 interrupt service routine(大多数时候被称为 interrupt handler),在中断体系里分为两种引发方式:
由硬件引发请求
由软件执行调用
然而软件上发起的中断调用还可分为:
引发 exception(异常) 执行 interrupt handler
软件请求执行 system service(系统服务),而执行 interrupt handler
硬件引发的中断请求还可分为:
maskable interrupt(可屏蔽中断)
non-maskable interrupt(不可屏蔽中断)
无论何种方式,进入 interrupt handler 的途径都是一样的。
2.1 查找 interrupt handler 入口
在发生中断时,processor 在 IDTR.base 里可以获取 IDT 的地址,根据中断号在 IDT 表里读取 descriptor,descriptor 的职责是给出 interrupt handler 的入口地址,processor 会检查中断号(vector)是否超越 IDT 的 limit 值。
上图是 interrupt handler 的定位查找图。在 32 位模式下的过程是:
从 IDTR.base 得到 IDT 表地址
从 IDTR.base + vector * 8(每个 descriptor 为 8 bytes)处读取 8 bytes 宽的 escriptor
对 descriptor 进行分析检查,包括:
descriptor 类型的检查
IDT limit 的检查
访问权限的检查
从 gate descriptor 里读取 selector
判断 code segment descriptor 是存放在 GDT 表还是 LDT 表
使用 selector 从 descriptor table 读取 code segment descriptor,当然这里也要经过对 code segment descriptor 的检查
descriptor 类型检查
GDT limit 检查
访问权限的检查
从 code segment descriptor 中读取 code segment base 值
从 gate descriptor 里读取 interrupt handler 的 offset 值
得取 interrupt handler 的入口地址:base + offset,转入执行 interrupt handler
它的逻辑用 C 描述,类似下面:
long IDT_&&&&&&&&&&&&&&&&&&&&&&&&&&&& /* address of IDT */long DT_&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /* GDT or LDT */DESCRIPTOR gate_&&&&&&&&&&&&&&&&&& /* gate descriptor */DESCRIPTOR code_&&&&&&&&&&&&&&&&&& /* code segment descriptor */&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /* code segment selector */
IDT_address = IDTR.&&&&&&&&&&&&&&&&&&&&& /* get address of IDT */gate_descriptor = IDT_address + vector * 8;&& /* get descriptor */
selector = gate_descriptor.
DT_address = selector.TI ? LDTR.base : GDTR.&&&&&&&&&&&&&&&&&&&&& /* address of GDT or LDT */
code_descriptor = GDT_address + selector * 8;&&&&&&&&&&&&&&&&&&&&&&&&& /* get code segment descriptor */
interrupt_handler = code_descriptor.base + gate_descripotr.&&&& /* interrupt handler entry */
((*(void))interrupt_handler)();&&&&&&&&&&&&&&&&& /* do interrupt_handler() */
上面的 C 代码显示了 processor 定位 interrupt handler 的逻辑过程,为了清楚展示这个过程,这里省略了各种的检查机制!
2.2 IDT 表中 descriptor 类型的检查
processor 会对 IDT 表中的 descriptor 类型进行检查,这个检查发生在:
当读取 IDT 表中的 descriptor 时
在 IDT 中的 descriptor 类型要属于:
S = 0:属于 system 类 descriptor
descriptor 的 type 域应属于:
1110:32-bit interrupt gate
1111:32-bit trap gate
0101:task gate
0110:16-bit interrupt gate
0111:16-bit trap gate
非上述所说的类型,都将会产生 #GP 异常。当 descriptor 的 S 标志为 1 时,表示这是个 user 的 descriptor,它们是:code/data segment descriptor。可以看到在 32 位保护模式下 IDT 允许存在 interrupt/trap gate 以及 task gate
2.3 使用 16-bit gate descriptor
在 32 位保护模式下 interrupt handler 也能使用 16-bit gate descriptor,包括:
16-bit interrupt gate
16-bit trap gate
这是一个比较特别的现象,假如使用 16-bit gate 来构建中断调用机制,实际上等于 interrupt handler 会从 32-bit 模式切换到 16-bit 模式执行。只要构建环境要素正确这样切换执行当然是没问题的。
这个执行环境要素需要注意的是:当使用 16-bit gate 时,也要相应使用 16-bit code segment descriptor。也就是在 gate descriptor 中的 selector 要使用 16-bit code segment selector。下面我写了个使用 16-bit gate 构建 interrupt 调用的例子:
; set IDT vector&&&&&&& mov eax, BP_handler&&&&&&& mov [IDT+3*8], ax&&&&&&&&&&&&&&&&&&&&&& ; set offset 15-0&&&&&&& mov word [IDT+3*8+2], code16_sel&&&&&&& ; 16-bit code selector
&&&&&&& mov word [IDT+3*8+4], 0xc600&&&&&&&&&&& ; DPL=3, 16-bit interrupt gate
&&&&&&& shr eax, 16&&&&&&& mov [IDT+3*8+8], ax&&&&&&&&&&&&&&&&&&&& ; offset 31-16
上面这段代码将 vector 3 设置为使用 16-bit interrupt gate,并且使用了 16-bit selector
下面是我的 interrupt handler 代码:
&&&&&&& bits 16
;-----------------------------------------------------; INT3 BreakPoint handler for 16-bit interrupt gate;-----------------------------------------------------BP_handler:&&&&&& jmp do_BP_handlerBP_msg&&&& db 'I am a 16-bit breakpoint handler on 32-bit proected mode',0
do_BP_handler:&&&&&& mov edi, 10&&&&&& mov esi, BP_msg&&&&&& call printmsg16
&&&&&& iret
这个 interrupt handler 很简单,只是打印一条信息而已,值得注意的是,这里需要使用 bits 16 来指示编译为 16 位代码。
那么这样我们就可以使用 int3 指令来调用这个 16-bit 的 interrupt handler,执行结果如图:
完整的源代码和软盘映像下载:
2.4 IDT 表的 limit 检查
在 IDT 表中查找索引 gate descriptor 时,processor 也会对 IDT 表的 limit 进行检查,这个检查的逻辑是:
gate_descriptor = IDTR.base + vector * 8;&&&&&&&&&&&&&&&&& /* get gate descriptor */
if ((gate_descriptor + sizeof(DESCRIPTOR) - 1) & (IDTR.base + IDTR.limit))
{&&&&&&& /* failure: #GP exception */}
我们看看下面这个图:
IDTR.base = 0x10000
IDTR.limit = 0x1f
那么 IDT 表的有效地址范围是:0x10000 - 0x1001f,也就是:IDTR.base + IDTR.limit 这表示:
vector 0:0x10000 - 0x10007
vector 1:0x10008 - 0x1000f
vector 2: 0x10010 - 0x10017
vector 3: 0x10018 - 0x1001f
上面是这 4 个 vector 的有效范围,因此:当设 IDTR.limit = 0x1e 时,如果访问 vector 3 时(调用中断3)processor 检测到访问 IDT 越界而出错!
因此:访问的 vector 地址在 IDTR.base 到 IDTR.base + IDTR.limit(含)之外,将会产生 #GP 异常。
2.5 请求访问 interrupt handler 时的权限检查
访问权限的检查是 x86/x64 体系中保护措施中非常重要的一环,它控制着访问者是否有权限进行访问,在访问 interrupt handler 过程权限控制中涉及 3 个权限类别:
CPL:当前 processor 所处的权限级别
DPLg:代表 DPL of gate,也就是 IDT 中 gate descriptor 所要求的访问权限级别
DPLs:代表 DPL of code segment,也就是 interrupt handler 的目标 code segment 所要求的访问权限级别
CPL 权限级别代表着访问者的权限,也就是说当前正在执行代码的权限,要理解权限控制的逻辑,你需要明白下面两点:
要调用 interrupt handler 那么首先你必须要有权限去访问 IDT 表中的 gate,这表示:CPL 的权限必须不低于 DPLg (gate 所要求的权限),这样你才有权限去访问 gate
interrupt handler 会在高权限级别里执行,也就是说 interrupt handler 会在特权级别里运行。这表示:interrupt handler 里的权限至少不低于访问者的权限
在调用 interrupt handler 中并不使用 selector 来访问 gate 而是使用使用 vector 来访问 gate,因此中断权限控制中并不使用 RPL 权限类别,我们可以得知中断访问权限控制的要素:
CPL &= DPLg
CPL &= DPLs
需同时满足上面的两个式子,在比较表达式中数字高的权限低,数字低的权限高!用 C 描述为:
DPLg = gate_descriptor.DPL;&&&&&&&&&&&&&& /* DPL of gate */DPLs = code_descriptor.DPL;&&&&&&&&&&&&&& /* DPL of code segment */
if ((CPL &= DPLg) && (CPL &= CPLs))
{&&&& /* pass */} else {&&&& /* failure: #GP exception */}
2.5.1 gate 的权限设置
对于 gate 的权设置,我们应考虑 interrupt handler 调用上的两个原则:
interrupt handler 开放给用户调用
interrupt handler 在系统内部使用
由这两个原则产生了 gate 权根设置的两个设计方案:
gate 的权限设置为 3 级:这样可以给用户代码有足够的权限去访问 gate
gate 的权限设置为 0 级:只允许内核代码访问,用户无权通过这个 gate 去访问 interrupt handler
这是现代操作系统典型的 gate 权限设置思路,绝大部分的 gate 都设置为高权限,仅有小部分允许用户访问。很明显:系统服务例程的调用入口应该设置为 3 级,以供用户调用。
下面是很典型的设计:
#BP 异常:BreakPoint(断点)异常的 gate 应该设置为 3 级,使得用户程序能够使用断点调试程序。
系统调用:系统调用是 OS 提供给用户访问 OS 服务的接口,因此 gate 必须设置为 3 级。
系统调用在每个 OS 实现上可能是不同的,#BP 异常必定是 vector 3,因此对于 vector 3 所使用的 gate 必须使用 3 级权限。
下面是在 windows 7 x64 操作系统上的 IDT 表的设置:
&bochs:2& info idtInterrupt Descriptor Table (base=0xfffff80004fea080, limit=4095):IDT[0x00]=64-Bit Interrupt Gate target=0x0010:fffff80003abac40, DPL=0IDT[0x01]=64-Bit Interrupt Gate target=0x0010:fffff80003abad40, DPL=0IDT[0x02]=64-Bit Interrupt Gate target=0x0010:fffff80003abaf00, DPL=0
IDT[0x03]=64-Bit Interrupt Gate target=0x0010:fffff80003abb280, DPL=3
IDT[0x04]=64-Bit Interrupt Gate target=0x0010:fffff80003abb380, DPL=3IDT[0x05]=64-Bit Interrupt Gate target=0x0010:fffff80003abb480, DPL=0
IDT[0x29]=64-Bit Interrupt Gate target=0x0010:fffff8, DPL=0IDT[0x2a]=64-Bit Interrupt Gate target=0x0010:fffff8, DPL=0IDT[0x2b]=64-Bit Interrupt Gate target=0x0010:fffff8, DPL=0
IDT[0x2c]=64-Bit Interrupt Gate target=0x0010:fffff80003abca00, DPL=3
IDT[0x2d]=64-Bit Interrupt Gate target=0x0010:fffff80003abcb00, DPL=3
IDT[0x2e]=64-Bit Interrupt Gate target=0x0010:fffff8, DPL=0IDT[0x2f]=64-Bit Interrupt Gate target=0x0010:fffff, DPL=0IDT[0x30]=64-Bit Interrupt Gate target=0x0010:fffff8, DPL=0
上面的粗体显示 interrupt gate 被设置为 3 级,在 windows 7 x64 下 vector 0x2c 和 0x2d 被设置为系统调用接口。实际上这两个 vector 的入口虽然不同,但是代码是一样的。你可以通过 int 0x2c 和 int 0x2d 请求系统调用。
那么对于系统内部使用的 gate 我们应该保持与用户的隔离,绝大部分 interrupt handler 的 gate 权限都是设置为 0 级的。
2.5.2 interrupt handler 的 code segment 权限设置
前面说过:interrupt handler 的执行权限应该至少不低于调用者的权限,意味着 interrupt handler 需要在高权限级别下运行。无论是系统提供给用户的系统服务例程还是系统内部使用的 interrupt handler 我们都应该将 interrupt handler 设置为 0 级别的运行权限(最高权限),这样才能保证 interrupt handler 能访问系统的全部资源。
在权限检查方面,要求 DPLs 权限(interrupt handler 的执行权限)要高于或等于调用者的权限,也就是 CPL 权限,当数字上 DPLs 要小于等于 CPL(DPLs <= CPL)。
2.6 使用 interrupt gate
使用 interrupt gate 来构造中断调用机制的,当 processor 进入 interrupt handler 执行前,processor 会将 eflags 值压入栈中保存并且会清 eflags.IF 标志位,这意味着进入中断后不允许响应 makeable 中断(可屏蔽中断)。它的逻辑 C 描述为:
*(--esp) =&&&&&&&&&&&&&&&&&&&&&&&&&& /* push eflags */
if (gate_descriptor.type == INTERRUPT_GATE)
&&&&&&& eflags.IF = 0;&&&&&&&&&&&&&&&&&&&&&& /* clear eflags.IF */
interrupt handler 使用 iret 指令返回时,会将栈中 eflags 值出栈以恢复原来的 eflags 值。
下面是 interrupt gate 的结构图:
可以看到 interrupt gate 和 trap gate 的结构是完全一样的,除了以 type 来区分 gate 外,interrupt gate 的类型是:
1110:32-bit interrupt gate
0110:16-bit interrupt gate
32 位的 offset 值提供了 interrupt handler 的入口偏移地址,这个偏移量是基于 code segment 的 base 值,selector 域提供了目标 code segment 的 selector,用来在 GDT 或 LDT 进行查找 code segment descriptor。这些域的使用描述为:
if (gate_descriptor.selector.TI == 0)&&&&&&& code_descriptor = GDTR.base + gate_descriptor.selector * 8;&&&&&&& /* GDT */else&&&&&&& code_descriptor = LDTR.base + gate_descriptor.selector * 8;&&&&&&& /* LDT */
interrupt_handler = code_descriptor.base + gate_descriptor.offset;&&&&&&&& /* interrupt handler entry */
注得注意的是:在 interrupt gate 和 trap gate 中的 selector 它的 RPL 是不起作用的,这个 selector.RPL 将被忽略。
在 OS 的实现中大部分的 interrupt handler 都是使用 interrupt gate 进行构建的。在 windows 7 x64 系统上全部都使用 interrupt gate 并没有使用 trap gate
2.7 使用 trap gate
trap gate 在结构上与 interrupt gate 是完全一样的,参见节 2.6 的那图,trap gate 与 interrupt gate 不同的一点是:使用 trap gate 的,processor 进入 interrupt handler 前并不改变 eflags.IF 标志,这意味着在 interrupt handler 里将允许可屏蔽中断的响应。
*(--esp) =&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /* push eflags */
if (gate_descriptor.type == TRAP_GATE) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /* skip: do nothing */} else if (gate_descriptor.type == INTERRUPT_GATE){&&&&&&&& eflags.IF = 0;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /* clear eflags.IF */&&&&&& } else if (gate_descriptor.type == TASK_GATE) {&&&&&&&& ... ...}
2.8 使用 task gate
在使用 task gate 的情形下变得异常复杂,你需要为 new task 准备一个 task 信息的 TSS,然而你必须事先要设置好当前的 TSS 块,也就是说,系统中应该有两个 TSS 块:
current TSS
TSS of new task
当前的 TSS 是系统初始化设置好的,这个 TSS 的作用是:当发生 task 切换时保存当前 processor 的状态信(当前进程的 context 环境),新任务的 TSS 是通过 task gete 进行切换时使用的 TSS 块,这个 TSS 是存放新任务的入口信息。
tss_desc&&&&&&& dw 0x67&&&&&&&&&&&&&&& ; seletor.SI = 3&&&&&&&&&&&&&&& dw TSS&&&&&&&&&&&&&&& dd 0x
tss_gate_desc&& dw 0x67&&&&&&&&&&&&&&& ; selector.SI = 4&&&&&&&&&&&&&&& dw TSS_TASKGATE&&&&&&& &&&&&&&&&&&&&&&& dd 0x
在上面的示例代码中,设置了两个 TSS descriptor,一个供系统初始化使用(tss_desc),另一个是为新任务而设置(tss_task_gate),代码中必须设置两个 TSS 块:
TSS_TASKGATE
TSS 块的内容是什么在这个示例中无关紧要,然而 TSS_TASKGATE 块中应该设置新任务的入口信息,其中包括:eip 和 cs 值,以后必要的 DS 与 SS 寄存器值,还有 eflags 和 GPRs 值,下面的代码正是做这项工作:
; set TSS for task-gate&&&&&&&& mov dword [TSS_TASKGATE+0x20], BP_handler32&&&&&&&&&&&&&&& ; tss.EIP&&&&&&&& mov dword [TSS_TASKGATE+0x4C], code32_sel&&&&&&&&&&&&&&&&& ; cs&&&&&&&& mov dword [TSS_TASKGATE+0x50], data32_sel&&&&&&&&&&&&&&&&& ; ss&&&&&&&& mov dword [TSS_TASKGATE+0x54], data32_sel&&&&&&&&&&&&&&&&& ; ds&&&&&&&& mov dword [TSS_TASKGATE+0x38], esp&&&&&&&&&&&&&&&&&&&&&&&& ; esp&&&&&&&& pushf&&&&&&&& pop eax&&&&&&&& mov dword [TSS_TASKGATE+0x24], eax&&&&&&&&&&&&&&&&&&&&&&&& ; eflags
我将新任务的入口点设为 BP_handler32(),这个是 #BP 断点异常处理程序,保存当前的 eflags 值作为新任务的 eflags 值。
我们必须为 task gate 设置相应的 IDT 表项,正如下面的示例代码:
; set IDT vector: It's a& #BP handler
&&&&&&&& mov word [IDT+3*8+2], tss_taskgate_sel&&&&&&&&&&&&&&&&& ; tss selector&&&&&&&& mov dword [IDT+3*8+4], 0xe500&&&&&&&&&&&&&&&&&&&&&&&&&& ; type = task gate
示例代码中,我为 vector 3(#BP handler)设置为 task-gate descirptor,当发生 #BP 异常时,就会通过 task-gate 进行任务切换到我们的新任务(BP_handler32)。
; load IDT into IDTR&&&&&&&& lidt [IDT_POINTER]
; load TSS&&&&&&&& mov ax, tss_sel&&&&&&&& ltr ax
当然我们应该先设置好 IDT 表和加载当前的 TSS 块,这个 TSS 块就是我们所定义的第1个 TSS descirptor (tss_desc),这个 TSS 块里什么内容都没有,设置它的目的是为切换到新任务时,保存当前任务的 context 环境,以便执行完新任务后切换回到原来的任务。
&&&&&&& db 0xcc&&&&&&&&&&&&&&&&&&&&&&&& ; throw BreakPoint
现在我们就可以测试我们的 BP_handler32(),通过 INT3 指令引发 #BP 异常,这个异常通过 task-gate 进行切换。
我们的 BP_handler32 代码是这样的:
;-----------------------------------------------------; INT3 BreakPoint handler for 32-bit interrupt gate;-----------------------------------------------------BP_handler32:&&&&&& jmp do_BP_handler32BP_msg32&&& db 'I am a 32-bit breakpoint handler with task-gate on 32-bit proected mode',0
do_BP_handler32:
&&&&&& mov edi, 10&&&&&& mov esi, BP_msg32&&&&&& call printmsg
&&&&&& clts&&&&&&&&&&&&&&&&&& ; clear CR0.TS flag
&&&&&& iret
它只是简单的显示一条信息,在这个 BP_handler32 中,我们应该要清 CR0.TS 标志位,这个标志位是通过 TSS 进行任务切换时,processor 自动设置的,然而 processsor 不会清 CR0.TS 标志位,需要代码中清除。
2.8.1 任务切换的情形
在本例中,我们来看看当进行任务切换时发生了什么,processor 会设置一些标志位:
置 CR0.TS = 1
置 eflags.NT = 1
设置 CR0.TS 标志位表示当前发生过任务切换,processor 只会置位,而不会清位,事实上,你应该使用 clts 指令进行清位工作。设置 eflags.NT 标志位表示当前任务是在嵌套层内,它指示当进行中断返回时,需切换回原来的任务,因此,请注意:
当执行 iret 指令时,processor 会检查 eflags.NT 标志是否置位
当 eflags.NT 被置位时,processor 执行另一个任务切换工作,从 TSS 块的 link 域中取出原来的 TSS selector 从而切换回原来的任务。这不像 ret 指令,它不会检查 eflags.NT 标志位。
processor 也会对 TSS descriptor 做一些设置标志,当进入新任务时,processor 会设置 new task 的 TSS descriptor 为 busy,当切换回原任务时,会置回这个任务的 TSS descriptor 为 available,同时 processor 会检查 TSS 中的 link 域的 TSS selector(原任务的 TSS)是否为 busy,如果不为 busy 则会抛出 #TS 异常。
当然发生切换时 processor 会保存当前的 context 到 current TSS 块中,因此:
切换到目标任务时,processor 会保存当前的任务 context 到 TSS,读取目标任务的 TSS,加载相应的信息,然后进入目标任务
目标任务执行完后,切换回原任务时,processor 会保存目标任务的 context 到目标任务的 TSS 中,从目标任务的 TSS 块读取 link(原任务的 TSS selector),加载相应的信息,返回到原任务
当从目标任务返回时,processor 会清目标任务的 eflags.NT = 0,如前所述目标任务的 TSS descriptor 也会被置为 available
版权 mik 所有,转载请注明出处}

我要回帖

更多关于 atci service是什么 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信