-
Part III
I’ll discuss how the OS realize IRQL with two examples: The process of ISR Synchronize Lock and interrupt
service routine.
1, ISR Synchronize Lock
SpinLocks have three types:
1, standard spin locks
2, ISR synchronization spin locks. Each type has its own IRQL associations
3, default ISR (Interrupt Service Request) spin locks
For “standard spin locks “, we’ve analyzed it at Part II. Now let’s anaylize the left two locks.
When developing a video miniport driver, I’ve ever met such an case: to protect some shared data between StartIO
and ISR. As we all know, IRQ runs at DIRQL, and we can not call the stand spinlocks.
I noticed that videoport supported an routine VideoPortAcquireDeviceLock. The ddk does not say more about the
limits. So I got BSOD when calling this routine in the ISR.
I disassembled it and found it that it used a dispatch synchronize object (Mutex). See the assembles codes below,
:u VideoPortAcquireDeviceLock
0008:EB095392 XOR EAX,EAX
0008:EB095394 PUSH EAX
0008:EB095395 PUSH EAX
0008:EB095396 PUSH EAX
0008:EB095397 PUSH EAX
0008:EB095398 MOV EAX,[ESP+14] //EAX = HwDeviceExtension
0008:EB09539C MOV EAX,[EAX-0228] // The Mutex maintained by VideoPort
0008:EB0953A2 ADD EAX,30
0008:EB0953A5 PUSH EAX
0008:EB0953A6 CALL [__imp__KeWaitForSingleObject]
0008:EB0953AC RET 0004
:u VideoPortReleaseDeviceLock
0008:EB0953B0 MOV EAX,[ESP+04]
0008:EB0953B4 PUSH 00
0008:EB0953B6 MOV EAX,[EAX-0228]
0008:EB0953BC ADD EAX,30
0008:EB0953BF PUSH EAX
0008:EB0953C0 CALL [__imp__KeReleaseMutex]
0008:EB0953C6 RET 0004
Luckly the videoport supports another mechanism of VideoPortSynchronizeExecution, which will call
KeSynchronizeExecution. So let us analyze KeSynchronizeExecution.
BOOLEAN
KeSynchronizeExecution(
IN PKINTERRUPT Interrupt,
IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
IN PVOID SynchronizeContext);
SynchronizeRoutine:
BOOLEAN
(*PKSYNCHRONIZE_ROUTINE) ( IN PVOID SynchronizeContext );
KeSynchronizeExecution will call KfRaiseIRQL to raise current processor’s IRQL to the InterruptObjects’s
SynchronzieIRQL and mask all the IRQs below the SynchronizeIRQL, then execute the SynchronizeRoutine which
will operate shared sensitive data, and call KfLowerIrql to do the restoring.at the end.
At the time SynchronizeRoutine is called, the interrupt specified by the interrupt object: interrupt will be masked. The
the protection of the access of the shared data is achieved.
Followings are the asm codes, from WinDbg.
kd> u nt!KeSynchronizeExecution
nt!KeSynchronizeExecution:
80468a70 55 push ebp
80468a71 8bec mov ebp,esp
80468a73 83ec04 sub esp,0x4
80468a76 53 push ebx
80468a77 56 push esi
//Raise Current IRQL to Interrupt->SynchronizeIrql
80468a78 8b5d08 mov ebx,[ebp+0x8] //ebx = Interrupt
80468a7b 8b4b29 mov ecx,[ebx+0x29] //cl = Interrupt->SynchronizeIrql
80468a7e ff15d8054080 call dword ptr [nt!_imp_KfRaiseIrql (804005d8)]
80468a84 8845fc mov [ebp-0x4],al// al = Old IRQL
80468a87 8b731c mov esi,[ebx+0x1c]
80468a8a 8b4510 mov eax,[ebp+0x10]
// Now call our SynchronizeRoutine
80468a8d 50 push eax
80468a8e ff550c call dword ptr [ebp+0xc] // SynchronizeRoutine
// Resotring …
80468a91 8bd8 mov ebx,eax
80468a93 8b4dfc mov ecx,[ebp-0x4] // Restore Old IRQL
80468a96 ff15dc054080 call dword ptr [nt!_imp_KfLowerIrql (804005dc)]
80468a9c 8bc3 mov eax,ebx
80468a9e 5e pop esi
80468a9f 5b pop ebx
80468aa0 c9 leave
80468aa1 c20c00 ret 0xc
kd> u hal!kfRaiseIrql
hal!KfRaiseIrql:
80062ea0 33c0 xor eax,eax
80062ea2 a024f0dfff mov al,[ffdff024] // Current IRQL
80062ea7 0fb6c9 movzx ecx,cl
80062eaa 80f902 cmp cl,0x2 // DISPATCH_LEVEL = 0x02
80062ead 7625 jbe hal!KfRaiseIrql+0x34 (80062ed4)
80062eaf 8bd0 mov edx,eax
80062eb1 9c pushfd
80062eb2 fa cli
// Change IRQL to new
80062eb3 880d24f0dfff mov [ffdff024],cl
// Besides changing current IRQL, it also mask all the IRQs below the SynchronizeIRQL
80062eb9 8b048dcc890680 mov eax,[hal!KiI8259MaskTable (800689cc)+ecx*4]
80062ec0 0b0530f0dfff or eax,[ffdff030]
80062ec6 e621 out 21,al // Mask I8259 – 1 (IMR1)
80062ec8 c1e808 shr eax,0x8
80062ecb e6a1 out 0xA1, al // Mask I8259 – 2 (IMR2)
80062ecd 9d popfd
80062ece 8bc2 mov eax,edx
80062ed0 c3 ret
80062ed1 8d4900 lea ecx,[ecx]
80062ed4 880d24f0dfff mov [ffdff024],cl
80062eda c3 ret
hal!KfLowerIrql:
80062f10 9c pushfd
80062f11 0fb6c9 movzx ecx,cl
80062f14 803d24f0dfff02 cmp byte ptr [ffdff024],0x2
80062f1b fa cli
80062f1c 7614 jbe hal!KfLowerIrql+0x22 (80062f32)
// Only need running when Current IRQL > DISPATCH_LEVEL
// Restore the 8259 settings
80062f1e 8b048dcc890680 mov eax,[hal!KiI8259MaskTable (800689cc)+ecx*4]
80062f25 0b0530f0dfff or eax,[ffdff030]
80062f2b e621 out 21,al
80062f2d c1e808 shr eax,0x8
80062f30 e6a1 out a1,al
// Restore current IRQL
80062f32 880d24f0dfff mov [ffdff024],cl
80062f38 a128f0dfff mov eax,[ffdff028]
80062f3d 8a80648a0680 mov al,[eax+0x80068a64]
80062f43 38c8 cmp al,cl
80062f45 7705 ja hal!KfLowerIrql+0x3c (80062f4c)
80062f47 9d popfd
80062f48 c3 ret
80062f49 8d4900 lea ecx,[ecx]
80062f4c ff14854c8a0680 call dword ptr [hal!SWInterruptHandlerTable (80068a4c)+eax*4]
80062f53 9d popfd
80062f54 c3 ret
2, Default ISR (Interrupt Service Request) spin locks
When an interrupt raises, cpu will be notified by a signal via the INTR pin, then the cpu will read the vector from the
data bus. After saving the current executing envrioment, cpu will get the entry of the interrupt from IDTR and execute
the ISR routine.
Here the ISR routine is not just the service routine supported by the specific driver when connecting the IRQ. It’s
hooked by Windows. Windows will decide whether the interrupt request is from the device. If it is surely form a
device, KiInterruptDispatch will be called to process the interrupt request.
KiInterruptDispatch will first call HalBeginSystemInterrupt to raise current IRQL and mask 8259A. Then call the
service routine at KINTERRUPT object offset 0x0C, which do the really work to perform the interrupt request. Then
KiInterruptDispatch calls HalDisableSystemInterrupt to do the restoring work. Then the response of an interrupt
request ends.
Here we will analyze the process of Vector 0x31 as example.
// Get the entry address of Vector 31 (IRQ 1)
:idt 31
Int Type Sel:Offset Attributes Symbol/Owner
0031 IntG32 0008:FF263444 DPL=0 P
kd> u 0008:FF263444
ff263444 54 push esp
ff263445 55 push ebp
ff263446 53 push ebx
ff263447 56 push esi
ff263448 57 push edi
ff263449 83ec54 sub esp,0x54
ff26344c 8bec mov ebp,esp
ff26344e 89442444 mov [esp+0x44],eax
ff263452 894c2440 mov [esp+0x40],ecx
ff263456 8954243c mov [esp+0x3c],edx
// Current Stack:
// ESP + 0: db * 0x54
// ESP + 54: edi
// ESP + 58: esi
// ESP + 5C: ebx
// ESP + 60: ebp
// ESP + 64: esp
// ESP + 68: Old EIP
// ESP + 6C: Old CS
// ESP + 70: Old Eflags
// Eflags bit 17 is VM bit, if VM = 1, it shows that the caller is from V86 mode,
// If the caller is from V86 mode, jump to ff26357b
ff26345a f744247000000200 test dword ptr [esp+0x70],0x20000
ff263462 0f8513010000 jne ff26357b
// For kernel space, CS = 0x08, it need not save the segments
// For user space (?), it will change current segments registers
ff263468 66837c246c08 cmp word ptr [esp+0x6c],0x8
ff26346e 7423 jz ff263493
ff263470 8c642450 mov [esp+0x50],fs
ff263474 8c5c2438 mov [esp+0x38],ds
ff263478 8c442434 mov [esp+0x34],es
ff26347c 8c6c2430 mov [esp+0x30],gs
ff263480 bb30000000 mov ebx,0x30
ff263485 b823000000 mov eax,0x23
ff26348a 668ee3 mov fs,bx
ff26348d 668ed8 mov ds,ax
ff263490 668ec0 mov es,ax
// ? Modify the exception record structure
ff263493 648b1d00000000 mov ebx,fs:[00000000]
ff26349a 64c70500000000ffffffff mov dword ptr fs:[00000000],0xffffffff
ff2634a5 895c244c mov [esp+0x4c],ebx
ff2634a9 81fc00000100 cmp esp,0x10000
ff2634af 0f829e000000 jb ff263553
ff2634b5 c744246400000000 mov dword ptr [esp+0x64],0x0
ff2634bd fc cld
ff2634be f60550f0dfffff test byte ptr [ffdff050],0xff
ff2634c5 750c jnz ff2634d3
ff2634c7 bf083426ff mov edi,0xff263408 // IntOBJ
ff2634cc e9cf562081 jmp nt!KiInterruptDispatch (80468ba0)
ff2634d1 8bff mov edi,edi
ff2634d3 f7457000000200 test dword ptr [ebp+0x70],0x20000
ff2634da 7509 jnz ff2634e5
ff2634dc f7456c01000000 test dword ptr [ebp+0x6c],0x1
ff2634e3 74e2 jz ff2634c7
ff2634e5 0f21c3 mov ebx,dr0
…
kd> u KiInterruptDispatch
nt!KiInterruptDispatch:
80468ba0 ff0560f5dfff inc dword ptr [ffdff560]
80468ba6 8bec mov ebp,esp
80468ba8 8b4724 mov eax,[edi+0x24]
80468bab 8b4f29 mov ecx,[edi+0x29]
80468bae 50 push eax
80468baf 83ec04 sub esp,0x4
// Initialize Current IRQL & 8259A
80468bb2 54 push esp
80468bb3 50 push eax
80468bb4 51 push ecx
80468bb5 ff1580054080 call dword ptr [nt!_imp__HalBeginSystemInterrupt (80400580)]
80468bbb 0bc0 or eax,eax
80468bbd 741a jz nt!KiInterruptDispatch+0x39 (80468bd9)
80468bbf 8b771c mov esi,[edi+0x1c]
80468bc2 8b4710 mov eax,[edi+0x10]
// Now call IntObj - ISR
80468bc5 50 push eax
80468bc6 57 push edi
80468bc7 ff570c call dword ptr [edi+0xc]
80468bca fa cli
// Restore …
80468bcb ff1584054080 call dword ptr [nt!_imp__HalEndSystemInterrupt (80400584)]
// Finish the process of the interrupt
80468bd1 e9e0c7ffff jmp nt!Kei386EoiHelper (804653b6)
80468bd6 83c408 add esp,0x8
80468bd9 83c408 add esp,0x8
80468bdc e9d5c7ffff jmp nt!Kei386EoiHelper (804653b6)
kd> u hal!HalBeginSystemInterrupt
hal!HalBeginSystemInterrupt:
80067ab8 0fb65c2408 movzx ebx,byte ptr [esp+0x8]
// Ebx = Vector Number, Ebx – 0x30 = IRQ number
80067abd 83eb30 sub ebx,0x30
//hal!HalpSpecialDismissTable = 80068a6c
80067ac0 ff249d6c8a0680 jmp dword ptr [hal!HalpSpecialDismissTable+ebx*4]
hal!HalBeginSystemInterrupt+3b:
// Entry of IRQ 1
80067af3 8b44240c mov eax,[esp+0xc]
// Save current IRQL, and change to new value from CL
80067af7 0fb70d24f0dfff movzx ecx,word ptr [ffdff024]
80067afe 8808 mov [eax],cl
80067b00 0fb6442404 movzx eax,byte ptr [esp+0x4]
80067b05 a224f0dfff mov [ffdff024],al // al = 0x1a
// Mask 8259A IRQs
80067b0a 8b0485cc890680 mov eax,[hal!KiI8259MaskTable (800689cc)+eax*4]
80067b11 0b0530f0dfff or eax,[ffdff030]
// eax = fffffefa [ffdff030] = 70 2c ff ff | Result: fffffefa
// Mask 8259A (IMR 1/2 (with Timer / Real Time exculed))
80067b17 e621 out 21,al
80067b19 c1e808 shr eax,0x8
80067b1c e6a1 out a1,al
80067b1e 8bc3 mov eax,ebx
80067b20 83f808 cmp eax,0x8
80067b23 7306 jnb hal!HalBeginSystemInterrupt+0x73 (80067b2b)
80067b25 0c60 or al,0x60
80067b27 e620 out 20,al
80067b29 eb08 jmp hal!HalBeginSystemInterrupt+0x7b (80067b33)
80067b2b b020 mov al,0x20
80067b2d e6a0 out a0,al
80067b2f b062 mov al,0x62
80067b31 e620 out 20,al
80067b33 e421 in al,21
80067b35 fb sti
80067b36 b801000000 mov eax,0x1
80067b3b c20c00 ret 0xc
// HalDisableSystemInterrupt is just reverse to HalBeginSystemInterrupt
hal!HalDisableSystemInterrupt:
80067b40 0fb64c2404 movzx ecx,byte ptr [esp+0x4]
80067b45 83e930 sub ecx,0x30
80067b48 ba01000000 mov edx,0x1
80067b4d d3e2 shl edx,cl
80067b4f fa cli
…
800630b7 e621 out 21,al
800630b9 c1e808 shr eax,0x8
800630bc e6a1 out a1,al
800630be 880d24f0dfff mov [ffdff024],cl
800630c4 a128f0dfff mov eax,[ffdff028]
800630c9 8a80648a0680 mov al,[eax+0x80068a64]
800630cf 38c8 cmp al,cl
800630d1 7703 ja hal!HalEndSystemInterrupt+0x3a (800630d6)
800630d3 c20800 ret 0x8
…
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
Bookmarks