浅议APC
0x01 APC中断请求级别
在Intel x86体系结构中,外部硬件中断是通过处理器上的"中断管脚"或者一个称为"本地APIC(local APIC)"的内置模块来发生的。本地APIC可以接收的中断源包括:
1处理器管脚(LINT0和LINT1)
2本地APIC定时器(timer)
3性能监视计数器中断
4热传感器中断
5 APIC内部错误中断
APIC这个硬件中断设备是有优先级的,它使用了一个可编程阵列硬件来实现,并且在系统初始化的时候就完成了,Intel x86定义了256个中断向量号(Interrupt Vector Number),也称为中断向量,从0~255。这就对应了IDT中断描述符表,IDT的表项数目就是256,也就是说,APIC定义的是IDT中的中断例程的优先级
对于一个处理器,它一旦被中断(可能来自内部,可能来自外部,可能是硬中断,可能是软中断),则某个预设的"中断服务例程"便被执行。而系统软件(操作系统)要做的事情就是,提供这些例程,并将它们设定到处理器的硬件中断向量表(即IDT)中。
然而尽管APIC中断控制器已经提供了中断优先级支持,windows还是自己定义了一套优先级方案,称为"中断请求级别(IRPL Interrupt Request Level)"。在Intel x86系统中,windows使用了0~31来表示优先级,数值越大,优先级越高。内核为软件中断定义了一组标准的IRQL,而HAL则将硬件中断号映射为IRQL。
IRQL的宏定义:
#define PASSIVE_LEVEL 0 //Passive release level(被动级别)
#define LOW_LEVEL 0 //Lowest interrupt level
#define APC_LEVEL 1 //APC interrupt level
#define DISPATCH_LEVEL 2 //Dispatcher level
#define PROFILE_LEVEL 27 //Timer used for profiling
#define CLOCK1_LEVEL 28 //Interval clock 1 level
#define CLOCK2_LEVEL 28 //Interval clock 2 level
#define IPI_LEVEL 29 //Interprocessor interrupt level
#define POWER_LEVEL 30 //Power failure level
#define HIGH_LEVEL 31 //Highest interrupt level
对于IRQL,PASSIVE_LEVEL(被动级别)代表了最低的IRQL,那既然你最低,运行在PASSIVE_LEVEL的线程可以被任何更高的IRQL(从LOW_LEVEL开始都可以)的事情打断,所有的的用户模式代码都运行在PASSIVE_LEVEL(被动模式)上。而APC_LEVEL(APC级别)比PASSIVE_LEVEL高,这也正是在一个线程中插入一个APC可以打断该线程(如果被插入的这个线程正在PASSIVE_LEVEL上运行)的原因(APC注入的原理)。
APC_LEVEL位于PASSIVE_LEVEL和DISPATCH_LEVEL之间,这是"专门"为另一种称为APC(异步过程调用 Asynchronous Procedure Call)的"软件中断"而保留的IRQL。每个APC都是在特定的线程环境中执行的,从而也一定在特定的进程环境中执行。APC是针对线程的,每个线程都有自己特有的APC链表。同一个线程的APC也是被排队执行的(思考线程的IRP对清队列,我们的IO请求要被排队执行,APC作为IRP请求的一种也不例外)。
由于APC的IRQL高于PASSIVE_LEVEL,所以,它优先于普通的"线程代码"。当一个线程获得控制时,它的APC进程会立刻被执行(即执行APC队列中的IRP请求)。这一特性使得APC非常适合于实现各种异步通知事件。例如,I/O完成通知可以用APC来实现。
(详细内容见《windows内核原理与实现》第5章2.6节)
0x02 APC结构
APC是与线程相关的,在描述线程的结构KTHREAD中,可以看到很多带APC字眼的成员。
win7 32: kd> dt _kthread
dtx is unsupported for this scenario. It only recognizes dtx [<type>] [<address>] with -a, -h, and -r. Reverting to dt.
ntdll!_KTHREAD
+0x000 Header : _DISPATCHER_HEADER
+0x010 CycleTime : Uint8B
+0x018 HighCycleTime : Uint4B
+0x020 QuantumTarget : Uint8B
+0x028 InitialStack : Ptr32 Void
+0x02c StackLimit : Ptr32 Void
+0x030 KernelStack : Ptr32 Void
+0x034 ThreadLock : Uint4B
+0x038 WaitRegister : _KWAIT_STATUS_REGISTER
+0x039 Running : UChar
+0x03a Alerted : [2] UChar
+0x03c KernelStackResident : Pos 0, 1 Bit
+0x03c ReadyTransition : Pos 1, 1 Bit
+0x03c ProcessReadyQueue : Pos 2, 1 Bit
+0x03c WaitNext : Pos 3, 1 Bit
+0x03c SystemAffinityActive : Pos 4, 1 Bit
+0x03c Alertable : Pos 5, 1 Bit
……
+0x040 ApcState : _KAPC_STATE
……
+0x168 ApcStatePointer : [2] Ptr32 _KAPC_STATE
+0x170 SavedApcState : _KAPC_STATE
……
可以看到在win7的32位下,与kthread偏移为0x40和0x170处,有两个成员:ApcState和SavedApcState,这两个成员指向两个不同的_KAPC_STATE结构:
typedef struct _KAPC_STATE {
LIST_ENTRY ApcListHead[MaximumMode]; //线程的apc链表 只有两个 内核态和用户态
struct _KPROCESS *Process; //当前线程的进程体 PsGetCurrentProcess()
BOOLEAN KernelApcInProgress; //内核APC正在执行
BOOLEAN KernelApcPending; //内核APC正在等待执行
BOOLEAN UserApcPending; //用户APC正在等待执行
} KAPC_STATE, *PKAPC_STATE, *PRKAPC_STATE;
在_KAPC_STATE结构中,第一个成员为ApcListHead[2],第一个成员指向一个用户模式APC链表,而第二个成员指向内核模式APC链表。如果注意观察,可以看出特殊内核模式APC都排在普通内核模式APC之前。
(图片源自危险漫步:http://www.weixianmanbu.com/article/33.html)
APC结构:
//win7 32
kd> dt _kapc
dtx is unsupported for this scenario. It only recognizes dtx [<type>] [<address>] with -a, -h, and -r. Reverting to dt.
ntdll!_KAPC
+0x000 Type : UChar
+0x001 SpareByte0 : UChar
+0x002 Size : UChar
+0x003 SpareByte1 : UChar
+0x004 SpareLong0 : Uint4B
+0x008 Thread : Ptr64 _KTHREAD
+0x010 ApcListEntry : _LIST_ENTRY
+0x020 KernelRoutine : Ptr64 void
+0x028 RundownRoutine : Ptr64 void
+0x030 NormalRoutine : Ptr64 void
+0x038 NormalContext : Ptr64 Void
+0x040 SystemArgument1 : Ptr64 Void
+0x048 SystemArgument2 : Ptr64 Void
+0x050 ApcStateIndex : Char
+0x051 ApcMode : Char
+0x052 Inserted : UChar
在 KAPC 结 构 中 , Type 域 应 为 KOBJECTS 枚 举 类 型 的 ApcObJect; Size 域 等 于 KAPC结 构 的 大 小 ; Thread 域 指 向 此 APC 对 象 所 在 的 线 程 KTHREAD 对 象 ; ApcListEntry 域 是APC 对 象 被 加 人 到 线 程 APC 链 表 中 的 节 点 对 象 ; KernelRoutine 域 是 一 个函 数 指 针 , 该 函数 将 在 内 核 模 式 的 APC-LEVEL 上 被 执 行 ; RundownRoutine 域 也 是 一 个 函 数 指 针 , 当 一个 线 程 终 止 时 如 果 它 的 APC 链 表 中 还 有 APC 对 象 , 那 么 , 若 成 员 非 空 ,则 调 用 它 所 指 的 函 数 。 № rmalRoutine 域 指 向 一 个 在 PASSIVE-LEVEL 上 执 行 的 函 数 。 在
这 三 个 函 数 指 针 成 员 中 , 只 有 KernelRoutine 是 必 需 的 , RundownRoutine 和 NormalRoutine都 是 可 选 的 。 而 且 , 如 果 NormalRoutine 为 空 的 话 , 则 其 后 的 Norma ℃ ontext 和 ApcMode域 也 将 被 忽 略 , 本 节 稍 后 会 解 释 这 三 个 域 的 关 系 。 SystemArgumentl 和 SystemArgument2是 两 个 提 供 给 KernelRoutine 或 NormalRoutine 函 数 的 参 数 。 ApcStateIndex 域 说 明 了 APC对 象 的 环 境 状 态 , 它 是 KAPC ENVIRONMENT 枚 举 类 型 的 成 员 , 一 旦 APC 对 象 被 插 人到 线 程 的 APC 链 表 中 , 则 ApcStatelndex 域 指 示 了 它 位 于 线 程 KTHREAD 对 象 的 哪 个 APC链 表 中 。 最 后 , 布 尔 类 型 Inserted 域 指 示 该 APC 对 象 是 否 已 被 插 人 到 线 程 的 APC 链 表 中。
提炼几点关键:
1.如果mode为UserMode,但是NormalRoutine为NULL,那么实际的模式变为Kernelmode,因为没有用户空间的APC例程可以使用;
2.每种APC都有内核模式的例程;
3.特殊的内核模式APC与普通的内核模式APC区别在于Normalroutine是否为空;
4.当普通的内核模式APC例程被执行时,先执行KernelRoutine例程,再执行NormalRoutine例程(除非执行过KernelRoutine例程后,NormalRoutine例程被清除为NULL)。
APC可以分成三种:用户模式APC、普通的内核模式APC,特殊的内核模式APC
(图片源自危险漫步:http://www.weixianmanbu.com/article/33.html)
浅议APC的更多相关文章
- 网络语音视频技术浅议(附多个demo源码下载)
我们在开发实践中常常会涉及到网络语音视频技术.诸如即时通讯.视频会议.远程医疗.远程教育.网络监控等等,这些网络多媒体应用系统都离不开网络语音视频技术.本人才疏学浅,对于网络语音视频技术也仅仅是略知皮 ...
- 浅议Delphi中的Windows API调用(举的两个例子分别是String和API,都不错,挺具有代表性)
浅议Delphi中的Windows API调用http://tech.163.com/school • 2005-08-15 10:57:41 • 来源: 天极网为了能在Windows下快速开发应用程 ...
- 浅议Grpc传输机制和WCF中的回调机制的代码迁移
浅议Grpc传输机制和WCF中的回调机制的代码迁移 一.引子 如您所知,gRPC是目前比较常见的rpc框架,可以方便的作为服务与服务之间的通信基础设施,为构建微服务体系提供非常强有力的支持. 而基于. ...
- 浅议NetMQ常见模式和消息加密机制
浅议NetMQ常见模式和消息加密机制 概述 在传统企业级开发中,消息队列机制已经成为一种非常常见的技术实现手段,而基于NetMQ则看起来有点像一朵"奇葩",看起来从名字似乎是一个消 ...
- 浅议.NET遗留应用改造
浅议.NET遗留应用改造 TLDR:本文介绍了遗留应用改造中的一些常见问题,并对改造所能开展的目标.原则.策略进行了概述. 一.背景概述 1.概述 或许仅"遗留应用"这个标题就比较 ...
- 浅议SNMP安全、SNMP协议、网络管理学习
相关学习资料 tcp-ip详解卷1:协议.pdf(重点看25章SNMP部分) http://www.rfc-editor.org/rfc/rfc1213.txt http://www.rfc-edit ...
- 网络语音视频技术浅议 Visual Studio 2010(转)
我们在开发实践中常常会涉及到网络语音视频技术.诸如即时通讯.视频会议.远程医疗.远程教育.网络监控等等,这些网络多媒体应用系统都离不开网络语音视频技术.本人才疏学浅,对于网络语音视频技术也仅仅是略知皮 ...
- Oracle 数据库表同步方法浅议
总结一下Oracle数据库表级别的复制同步 一.通过触发器进行表的复制 原理,是监听表上都某一字段进行的DML操作,然后得到DML操作的数据,重新在另一个表上执行DML操作. 优点: 简单,编写一个触 ...
- DNS安全浅议、域名A记录(ANAME),MX记录,CNAME记录
相关学习资料 http://baike.baidu.com/link?url=77B3BYIuVsB3MpK1nOQXI-JbS-AP5MvREzSnnedU7F9_G8l_Kvbkt_O2gKqFw ...
随机推荐
- 如何抓取Amazon大图
https://www.douban.com/note/277033391/ 進入到日本Amazon看到某些商品有預覽圖可以放大欣賞,當你想要右鍵下載卻發現只得到空白圖或白邊圖.縮圖.切割圖,究竟原圖 ...
- android--------自定义控件 之 组合控件篇
上篇介绍了自定义控件的自定义属性篇,地址:http://www.cnblogs.com/zhangqie/p/8969163.html 这篇博文主要来说说 自定义控件的组合控件来提高布局的复用 使用自 ...
- spring boot(八)RabbitMQ使用
RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用. 消息中间件在互联网公司的使用中越来越多,刚才还看到新闻阿里将RocketMQ捐献给了apa ...
- 有一个问题关于stl函数中的算法问题
是不是stl中的算法函数中参数只要是和函数相关的就是函数对象和谓词?
- 自定义alert弹框,title不显示域名
问题: 系统默认的alert弹框的title会默认显示网页域名 解决办法: (修改弹框样式) (function() { window.alert = function(name) { $(" ...
- JQ 实现监测input中值的变化并绑定到另个input
$('#input').bind('input propertychange', function () { $('#myDiv ...
- ajax请求二进制流图片并渲染到html中img标签
日常显示图片都诸如这种形式:直接使用img的src属性 <img src="图片路径.地址" alt="" /> 以上方法无法在获取图片请求中设置请 ...
- 十九、Spring框架(注解方式测试)
一.注解方式测试 1.注解方式测试使用junit.使用junit-4.12.jar和hamcrest-all-1.3.jar(单元测试包) 把这两个jar包,导入到lib文件夹下. 2.TestSpr ...
- 一个典型的多表参与连接的复杂SQL调优(SQL TUNING)引发的思考
今天在看崔华老师所著SQL优化一书时,看到他解决SQL性能问题的一个案例,崔华老师成功定位问题并进行了解决.这里,在崔华老师分析定位的基础上,做进一步分析和推理,以便大家一起研究探讨,下面简述该案例场 ...
- java 类变量初始化顺序
假定有一个类定义如下: package com.zhang; public final class Girl { // static代码块1 private static String sex = & ...