Results 1 to 7 of 7

Thread: KeGetCurrentIrql can't return HIGH_LEVEL

  1. #1

    KeGetCurrentIrql can't return HIGH_LEVEL

    I was playing with IRQL and spotted one interesting thing. If IRQL is raised to HIGH_LEVEL, then KeGetCurrentIrql will return wrong info about IRQL:

    .text:800123B8 ; __fastcall KfRaiseIrql(x)
    .text:800123B8                 public @KfRaiseIrql@4
    .text:800123B8 @KfRaiseIrql@4  proc near     
    .text:800123B8                 movzx   edx, cl
    .text:800123BB                 movzx   ecx, ds:_HalpIRQLtoTPR[edx]
    .text:800123C2                 mov     eax, ds:0FFFE0080h
    .text:800123C7                 mov     ds:0FFFE0080h, ecx
    .text:800123CD                 shr     eax, 4
    .text:800123D0                 movzx   eax, ds:_HalpVectorToIRQL[eax]
    .text:800123D7                 retn
    .text:800123D7 @KfRaiseIrql@4  endp
    Decode IRQL to Task Priority Register [APIC_base+0x80]

    .text:80012398 _HalpIRQLtoTPR  db   0h  <--- PASSIVE_LEVEL (0)
    .text:80012399                 db  3Dh  <--- APC_LEVEL  (1)
    .text:8001239A                 db  41h  <--- DISPATCH_LEVEL (2)
    .text:8001239B                 db  41h  
    .text:8001239C                 db  51h  
    .text:8001239D                 db  61h  <--- CMCI_LEVEL (5)
    .text:8001239E                 db  71h
    .text:8001239F                 db  81h 
    .text:800123A0                 db  91h
    .text:800123A1                 db 0A1h
    .text:800123A2                 db 0B1h 
    .text:800123A3                 db 0B1h 
    .text:800123A4                 db 0B1h 
    .text:800123A5                 db 0B1h 
    .text:800123A6                 db 0B1h
    .text:800123A7                 db 0B1h 
    .text:800123A8                 db 0B1h
    .text:800123A9                 db 0B1h 
    .text:800123AA                 db 0B1h
    .text:800123AB                 db 0B1h 
    .text:800123AC                 db 0B1h
    .text:800123AD                 db 0B1h 
    .text:800123AE                 db 0B1h
    .text:800123AF                 db 0B1h 
    .text:800123B0                 db 0B1h
    .text:800123B1                 db 0B1h 
    .text:800123B2                 db 0B1h
    .text:800123B3                 db 0C1h  <--- PROFILE_LEVEL (27)
    .text:800123B4                 db 0D1h  <--- CLOCK1/2_LEVEL (28)
    .text:800123B5                 db 0E1h  <--- IPI_LEVEL  (29)
    .text:800123B6                 db 0EFh  <--- POWER_LEVEL(30)
    .text:800123B7                 db 0FFh  <--- HIGH_LEVEL (31)
    Also there is a array used to decode Task Priority Register to IRQL:

    .data:8001D218 _HalpVectorToIRQL db   0h        <--- PASSIVE_IRQL                                       
    .data:8001D219                   db 0FFh
    .data:8001D21A                   db 0FFh
    .data:8001D21B                   db    1        <--- APC_LEVEL
    .data:8001D21C                   db    2        <--- DISPATCH_LEVEL
    .data:8001D21D                   db 0FFh
    .data:8001D21E                   db 0FFh
    .data:8001D21F                   db 0FFh
    .data:8001D220                   db 0FFh
    .data:8001D221                   db 0FFh
    .data:8001D222                   db 0FFh
    .data:8001D223                   db 0FFh
    .data:8001D224                   db  1Bh        PROFILE_LEVEL
    .data:8001D225                   db  1Ch        CLOCK1/2_LEVEL
    .data:8001D226                   db  1Dh        IPI_LEVEL and POWER LEVEL
                                                    are different in Task priority sub-class
                                                    (lower 8bits of Task Priority Register)     
    .data:8001D227                   db  1Eh        POWER_LEVEL
    Basically if we are running at HIGH_LEVEL, KeGetCurrentIrql will always return POWER_LEVEL. Calculaion is simple here, it uses Task Priority, upper 8 bits of TPR (Task Priority Register) as index into _HalpVectorToIRQL or better name would be _HalpTPRtoIRQL for this 2nd array.

    So are you sure that you are running at HIGH_IRQL? or POWER_LEVEL?

  2. #2
    Administrator dELTA's Avatar
    Join Date
    Oct 2000
    Ring -1
    Blog Entries
    Another gem for the archives.
    "Give a man a quote from the FAQ, and he'll ignore it. Print the FAQ, shove it up his ass, kick him in the balls, DDoS his ass and kick/ban him, and the point usually gets through eventually."

  3. #3
    Good find and thanks for sharing with our readers.


  4. #4
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Blog Entries
    You're always getting into the good stuff deroko

    That is weird. I confirmed the same thing programatically, when running at the 2 highest Irql levels, KeGetCurrentIrql returns one level lower. POWER_LEVEL returns IPI_LEVEL and HIGH_LEVEL returns POWER_LEVEL.

    At least one could always get the "true" irql as it's encoded in the TPR and make their own KeGetCurrentIrql function.

    KIRQL TPRVector;
    TPRVector = *(KIRQL*)0x0FFFE0080;

    It looks like that's just a way of dealing with the APIC architecture and HIGH_LEVEL is actually a Windows construct. If you look at Table7.1 in the Intel V.3 doc, the highest level listed is Priority Class 15, described as POWER_LEVEL.

  5. #5
    yup 15 disables delivery of all interupts on a given cpu. Funny is that even when you sstep KfRaiseIrq/lLowerIrql with sice, it always shows EF (power level, maybe irql at which sice is running) or it's just my machine

  6. #6
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Blog Entries
    I saw that behaviour in Sice as well. I think the EF level may be correct though. Back when I was making KDExtensions for Softice I naturally called KeGetCurrentIrql within a debugger extension itself to see the result. It returned IPI_LEVEL 29 (0x1D) (not being single stepped).

    If we take into account the fact that KeGetCurrentIrql returns one level lower, then the actual Irql level would have been POWER_LEVEL (0x1E), which corresponds correctly to the 0xEF TPR encoding.

    I might have guessed that Softice would run at HIGH_LEVEL, but from this osr thread it sounds like that is reserved for the debugger that is built into the NT kernel, and not a third party kernel debugger like Sice.

    Why Is The IRQL Always 0xFF When I Do !PCR?

  7. #7
    ah that explains it. when I think better it's quite logical softice should drop irql (I saw code in it where it modifies TPR directly) when executing instruction(single steping), but when it gains control again, after that instruction, it has to raise IRQL, and seems that there is no way to see current IRQL in sice by looking at FFFE0080, not sure if sice directly modifies PCR at the same time, but if it doesn't then there is stored real irql

    Also what I saw on mp machine is that softice doesn't list IRQL when cpu command is used, only lists priority from TPR

    CPU  PCR Base  IDT Base  GDT Base  Pri  TID  Process(ID)   CS:EIP
    0    FFDFF000  8003F400  8003F000   D1    0  Idle(0)       8:806E2F3D
    1    BAB40000  BAB44590  BAB44190   41    0  Idle(0)       8:805450D0

Similar Threads

  1. Does 'return' come back?
    By Hex Blog in forum Blogs Forum
    Replies: 0
    Last Post: November 14th, 2007, 00:35
  2. The return of HMEMCPY!!
    By disavowed in forum Off Topic
    Replies: 4
    Last Post: December 8th, 2005, 19:52
  3. return
    By frankmay in forum Off Topic
    Replies: 3
    Last Post: October 24th, 2003, 18:08
  4. GetModuleHandle return value
    By nino in forum The Newbie Forum
    Replies: 2
    Last Post: March 2nd, 2003, 09:04
  5. Softice - how do I return to calling code?
    By sync in forum Tools of Our Trade (TOT) Messageboard
    Replies: 5
    Last Post: August 20th, 2002, 00:16


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts