本论坛为只读模式,仅供查阅,不能注册新用户,不能发帖/回帖,有问题可发邮件 xikug.xp (^) gmail.com
查看: 7250|回复: 30

KfLowerIrql调用过程与平时的认识出入不小,请各位大牛解释一下!!! [复制链接]

Rank: 1

发表于 2011-6-23 12:15:05 |显示全部楼层
先附上KfLowerIrql的汇编和wrk源码:
汇编:hal!KfLowerIrql:
806d12d0 33c0 xor eax,eax
806d12d2 8ac1 mov al,cl
806d12d4 33c9 xor ecx,ecx
806d12d6 8a8858126d80 mov cl,byte ptr hal!HalpIRQLtoTPR (806d1258)[eax]
806d12dc 890d8000feff mov dword ptr ds:[0FFFE0080h],ecx
806d12e2 a18000feff mov eax,dword ptr ds:[FFFE0080h]
806d12e7 c3 ret
wrk源码:
VOID
FORCEINLINE
KfLowerIrql (
__in KIRQL NewIrql
)
{
ULONG tprValue;

ASSERT( NewIrql <= KeGetCurrentIrql() );

tprValue = HalpIRQLToTPR[NewIrql];
KeMemoryBarrier();
*APIC_TPR = tprValue;
*APIC_TPR;
KeMemoryBarrier();
}
有两个问题:
1、在KfLowerIrql中并未出现调用KiDispatchInterrupt的地方,未调用那么在降低Irql符合条件时,如何进行DPC调用和线程切换呢?
如果是对ds:[0FFFE0080h]下了一个写入断点引起HalpDispatchInterrupt并执行KiDispatchInterrupt,那么系统又是如何判断Irql符合条件呢?那么KfRaiseIrql 不是也有写入的动作,那不是也由可能引发中断吗,这不是不符合系统设计要求吗?这到底是怎么一回事呢?
2、wrk源码中进行了了当前与新的Irql级别的判断,而汇编中却没有这一步。事实上我做了实验,将Irql从PASSIVE_LEVEL用KfLowerIrql降到DISPATCH_LEVEL,结果并未引发任何问题,一切执行都通过了,这样不是对整个系统的设计提出了重大挑战了吗?从而不是影响了系统的同步及Irql的处理了吗?事实上到底是怎样的呀?
请各位大牛给点提示吧,多谢了!!!

Rank: 5Rank: 5

发表于 2011-6-23 15:24:33 |显示全部楼层
一切执行通过了,多美好啊~

Rank: 1

发表于 2011-6-23 16:32:47 |显示全部楼层
事实确实如此,最起码在这些代码的执行过程中没问题,你可以也试验一下,VMware加XP SP2。

Rank: 1

发表于 2011-6-24 02:15:26 |显示全部楼层
这个函数的实现依赖HAL,不同系统会有差异。
1, APIC 内部会对pending interrupt排队,你lower了priority, 先前被block的low priority interrupt在新的irql被允许执行 , interrupt就被CPU dispatch到对应的handler了。并非是你写TPR就触发中断。
2, 正确lower or raise IRQL是程序员的责任。

wrk的实现是最简单的, 你研究下vista/2k8的实现会发现真实的实现是非常复杂的,没必要
纠结这些细节。IRQL相关的概念被抽象出来就是为了屏蔽平台差异。

Rank: 1

发表于 2011-6-24 09:50:47 |显示全部楼层
多谢irp的回答,对于1我是否可以这样理解,这是APIC的硬件设计,针对不同的IRQL有着相应的interrupt priority,对于KfLowerIrql降低IRQL时相对应的也降低了priority,如果比较之后发现priprity级别符合条件,就被APIC所响应,从而被CPU dispatch到对应的handler,而APIC_TPR 处就代表着Priority。
对于2我理解是lower or raise IRQL是否正确,操作系统是不会检查的。那这样的话,系统不是健壮性差了吗,设置IRQL的目的不就打折扣了吗?
还有一点疑问就是,线程切换并非一个中断,比如KfLowerIrql在ReactOS中的实现就是KfLowerIrql调用发现新的IRQL低于Dispatch_level,就提升IRQL至Dispatch_level,然后调用KiDispatchInterrupt并调用KiSwapContext,并非一个中断,那为何会有interrupt priority的呢?
盼解答,多谢!

Rank: 1

发表于 2011-6-24 13:49:22 |显示全部楼层
我好奇为什么用了两次KeMemoryBarrier()呢?

Rank: 1

发表于 2011-6-24 20:25:53 |显示全部楼层
对于2,  下面是2K8 halmacpi.dll (MP ACPI  HAL) 的实现。

1: kd> uf /c /D hal!KeLowerIrql
hal!KeLowerIrql (825d3220)
  hal!KeLowerIrql+0x8 (825d3228):
    call to hal!KfLowerIrql (825d36a8)

1: kd> uf /c /D 0x825d36a8
hal!KfLowerIrql (825d36a8)
  hal!KfLowerIrql+0x4f (825d36f7):
    call to hal!DbgBreakPoint (825dcadc)
  hal!KfLowerIrql+0x56 (825d36fe):
    call to hal!HalpLowerIrqlHardwareInterrupts (825d34ac)
  hal!KfLowerIrql+0x5f (825d3707):
    call to hal!HalpCheckForSoftwareInterrupt (825d3604)

1: kd> uf 825d36a8
hal!KfLowerIrql:
825d36a8 8bff            mov     edi,edi
825d36aa 55              push    ebp
825d36ab 8bec            mov     ebp,esp
825d36ad 51              push    ecx
825d36ae 803dd55f5e8200  cmp     byte ptr [hal!HalpEnableIrqlAudit (825e5fd5)],0
825d36b5 53              push    ebx
825d36b6 8ad9            mov     bl,cl
825d36b8 7442            je      hal!KfLowerIrql+0x54 (825d36fc)

hal!KfLowerIrql+0x12:
825d36ba 648b0d20000000  mov     ecx,dword ptr fs:[20h]
825d36c1 81c17c030000    add     ecx,37Ch
825d36c7 9c              pushfd
825d36c8 58              pop     eax
825d36c9 8945fc          mov     dword ptr [ebp-4],eax
825d36cc 66f745fc0002    test    word ptr [ebp-4],200h
825d36d2 7528            jne     hal!KfLowerIrql+0x54 (825d36fc)

hal!KfLowerIrql+0x2c:
825d36d4 8a01            mov     al,byte ptr [ecx]
825d36d6 84c0            test    al,al
825d36d8 7622            jbe     hal!KfLowerIrql+0x54 (825d36fc)

hal!KfLowerIrql+0x32:
825d36da 0fb6c0          movzx   eax,al
825d36dd 8a0c08          mov     cl,byte ptr [eax+ecx]
825d36e0 803dd55f5e8200  cmp     byte ptr [hal!HalpEnableIrqlAudit (825e5fd5)],0
825d36e7 7413            je      hal!KfLowerIrql+0x54 (825d36fc)

hal!KfLowerIrql+0x41:
825d36e9 0fb6c1          movzx   eax,cl
825d36ec c1e804          shr     eax,4
825d36ef 3a98b0515e82    cmp     bl,byte ptr hal!HalpVectorToIRQL (825e51b0)[eax]
825d36f5 7305            jae     hal!KfLowerIrql+0x54 (825d36fc)

hal!KfLowerIrql+0x4f:
825d36f7 e8e0930000      call    hal!DbgBreakPoint (825dcadc)

hal!KfLowerIrql+0x54:
825d36fc 8acb            mov     cl,bl
825d36fe e8a9fdffff      call    hal!HalpLowerIrqlHardwareInterrupts (825d34ac)
825d3703 33d2            xor     edx,edx
825d3705 8acb            mov     cl,bl
825d3707 e8f8feffff      call    hal!HalpCheckForSoftwareInterrupt (825d3604)
825d370c 5b              pop     ebx
825d370d c9              leave
825d370e c3              ret

粗略看实现里面有检查,  注意到里面有个hal!HalpEnableIrqlAudit flag, 有个cmp, 然后 有个dbgbreakpoint.

1, 基本可以理解但是IRQL是个中断处理的抽象, 在x86上有APIC的interrupt priority来提供部分实现,这在其他平台也许不是这样的,两个概念有类似的方面但决不是一个概念。

3, reactos实现细节和windows差别还是很大的, 线程调度的部分工作以软件中断的方式来执行。

参考下jake oshins 怎么说的, 可见IRQL的设计目的有相当部分为了spinlock的安全处理。

-------- 原始信息 --------
主题:         Re:[nttalk] RE: IRQL
日期:         Sun, 24 Jan 2010 17:13:11 -0800
发件人:         Jake Oshins <jakeo@windows.microsoft.com>
回复地址:         Extended Discussions on System Software (particularly Windows) <nttalk@lists.osr.com>
收件人:         Extended Discussions on System Software (particularly Windows) <nttalk@lists.osr.com>
新闻组:         nttalk
引用:         <332@nttalk>


>
> In fact, I just don\'t see any benefit (which definitely does not mean that
> there are none) that
> the very concept of IRQL  adds to NT, in the first place......
>
>


Well I think that I can say what the people who invented it thought it would
provide.  Remember that was 25 or 30 years ago.  What it actually provides
depends on what year it is, specifically whether the relative speed of the
processor core so outstrips the speed of the Local APIC that doing it
software beats doing it in hardware.

IRQL as a concept is simply the following:

All the interrupts in the machine (hardware and software) are separated into
priority groups.  From lowest to highest priority;

Software interrupts that interrupt running threads - APC_LEVEL
Software interrupts that drive the scheduler (dispatcher) - DISPATCH_LEVEL
Hardware interrupts from devices - DISPATCH_LEVEL + 1 through CLOCK_LEVEL -
1
Clock interrupts - CLOCK_LEVEL
Inter-processor interrupts - IPI_LEVEL
Profile interrupts - PROFILE_LEVEL
No interrupts - HIGH_LEVEL

Every spinlock in the system has an associated IRQL.  (The DDK glosses over
this.  It makes it sound like all spinlocks are DISPATCH_LEVEL spinlocks,
except where it admits that there are a few exceptions, particularly around
device ISRs.)

The idea is that you raise IRQL to the level of the lock before attempting
to acquire the lock.  That way you can\'t have any priority inversion and
resulting deadlocks.  What\'s important to note here is that higher priority
interrupts can still occur both while the processor waiting to acquire the
lock and while it holds it.  Thus you don\'t defer (as an example) PTE
flushes (which come it at IPI level) while running your network DPC.

That\'s all there is to it.

(Queued spinlocks, which upset this nice orderly situation, came along
twenty years later.  If you want to know the story on those, type my name
and queued locks into a search engine and I\'m sure that you\'ll find the
archives.)



--
Jake Oshins
Hyper-V I/O Architect
Windows Kernel Group

This post implies no warranties and confers no rights.

Rank: 1

发表于 2011-6-24 20:28:00 |显示全部楼层
[quote=\"majinxin2003\"]我好奇为什么用了两次KeMemoryBarrier()呢?[/quote]

可能是因为FORCEINLINE, 这段代码会被内联,所以要追加后面一个barrier.

Rank: 1

发表于 2011-6-25 01:10:02 |显示全部楼层
多谢irp的详细解答,十分感谢。这段代码在XP SP2上运行没问题,可能是在Vista和2008上ms做了检查吧,但是在Xp sp2上确实是没有的。还有一点还想烦请irp讲解一下,就是能否把线程调度这个软中断的具体实现和处理说明一下,它是如何作为一个中断出现在APIC的记录之中的呢?

Rank: 1

发表于 2011-6-25 02:48:00 |显示全部楼层
当thread的时间片结束时候,kernel会调用hal!HalRequestSoftwareInterrupt来issue一个
DISPATCH_LEVEL的软件中断,HalRequestSoftwareInterrup往APIC的ICR(interrupt command register) 写,就注册了一个中断。这个中断在合适的时候被cpu dispatch到
hal!HalpDispatchInterrupt (IDT handler for XP) 这个函数调用KiDispatchInterrupt, 这是XP的情况。

Rank: 1

发表于 2011-6-25 12:39:23 |显示全部楼层
多谢irp的详细耐心解答,衷心感谢。我有点爱较真,还想再问一下HalRequestSoftwareInterrupt这个函数是在那里被调用的呢,是在时钟中断中吗?因为在ReactOS中,线程时间片结束的检查是在KiDispatchInterrupt中的,那么在XP中时间片结束的检查又是在哪里进行的,然后又调用HalRequestSoftwareInterrupt的呢?
另:关于“Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?”问题我已将相关源码和截图传了上来,烦请您再关注一下吧,万分感谢!

Rank: 1

发表于 2011-6-25 14:45:45 |显示全部楼层
http://book.51cto.com/art/201011/235775.htm

Rank: 1

发表于 2011-6-25 14:59:38 |显示全部楼层
参考WRK  的 KeUpdateRunTime, 时钟中断调用它。

Rank: 1

发表于 2011-6-25 15:07:40 |显示全部楼层
KeWaitForSingleObject 可以在DISPATCH_LEVEL调用,不过有限制条件,参考DDK文档。
可以想见如果某个thread在DISPATCH_LEVEL上等待,并且这个thread有APC发生,那么
当线程再次被调度(cpu irql会被恢复到DISPATCH_LEVEL) APC不会得到执行。

Rank: 1

发表于 2011-6-25 16:17:24 |显示全部楼层
多谢irp的耐心和热情,十分感谢!您说得十分清晰!
如果不考虑系统功能的实现,只考虑仅保证系统不出错的话,那么就算是把Irql提到Dispatch_level之上,在xp sp2系统中,KeWaitForSingleObject函数首先将Irql提至Dispatch_level级上,用的是KeRaiseIrqlToDpcLevel,而在xp sp2系统中Irql是不进行级别检查的,那么这一步也就通过了,剩下就是调用KiSwapThread切换线程,而在这个过程中不会再进行任何有关Irql的操作,那么这样的话不是就算在Dispatch_level级之上的硬件中断级上等待对象了吗?请irp大哥再帮忙解释一下吧,多谢了!

Rank: 1

发表于 2011-6-25 16:25:41 |显示全部楼层
KiSwapThread之后,current cpu已经运行new thread了,不存在等待的意思,仅仅是要等的
object处于non-signal状态, object signal后,如果old thread适合运行,会被切回来继续,
KeWaitForSingleObject就返回了。你参考下wrk, 仔细结合KD来多体会。

Rank: 1

发表于 2011-6-25 16:53:52 |显示全部楼层
WRK的KeWaitForSingleObject 没有raise irql, 期间的irql操作都是dispatcher database相关的,为了spinlock同步。waitirql 是保存在thread object中,thread 被调度,irql会被从waitirql中恢复,你仔细看看wrk的代码。

Rank: 1

发表于 2011-6-25 17:12:25 |显示全部楼层
多谢irp大哥,您太好了,解决了我许多疑惑。
我看了一下wrk的代码,他和ReactOs中等待函数的代码差不多。但是我用Windbg观察了等待函数的过程,它就是先提升irql再调用KiSwapThread的。
再一个我还是不太理解wrk中代码关于等待函数利用dispatcher database操作irql从而对irql的隐含限制作用在哪里,也就是他是如何隐含的限制了调用等待函数时的irql的级别的?
多谢您的回答!

Rank: 1

发表于 2011-6-25 17:45:17 |显示全部楼层
在单cpu系统,  raise irql 相当于acquire spinlock. 实质还是spinlock,  spinlock 都有对应的irql.

Rank: 1

发表于 2011-6-25 17:54:40 |显示全部楼层
wait函数的irql主要要考虑的是<是否能够顺利完成scheduler的工作>, 我个人的理解,
如果timeout值有效,scheduler会 用timer来定时,timer 是以dpc形式完成的,这隐含了
irql啊。
您需要登录后才可以回帖 登录 | 立即加入

Archiver|手机版|第8个男人 - 论坛为只读模式,仅供查阅

GMT+8, 2019-7-16 15:01 , Processed in 0.036686 second(s), 8 queries .

Design by pvo.cn

© 2011 Pvo Inc.

回顶部