Multi-Processors and KdVersionBlock

Tomorrow, I’ll publish a bugfix for win32dd about the following problem: on multi-processors computers a BSOD occurs when user try to generate a Microsoft Crash dump file through the -d option.

The problem is located inside KdGetDebuggerDataBlock function, when the function try to read KdVersionBlock field an invalid pointer is returned because this field is only valid in the 1st processor KPCR.

lkd> dt nt!_KPCR ffdff000
   +0x000 NtTib            : _NT_TIB
   +0x01c SelfPcr          : 0xffdff000 _KPCR
   +0x020 Prcb             : 0xffdff120 _KPRCB
   +0x024 Irql             : 0 ''
   +0x028 IRR              : 0
   +0x02c IrrActive        : 0
   +0x030 IDR              : 0xffffffff
   +0x034 KdVersionBlock   : 0x805562b8 
   +0x038 IDT              : 0x8003f400 _KIDTENTRY
   +0x03c GDT              : 0x8003f000 _KGDTENTRY
   +0x040 TSS              : 0x80042000 _KTSS
   +0x044 MajorVersion     : 1
   +0x046 MinorVersion     : 1
   +0x048 SetMember        : 1
   +0x04c StallScaleFactor : 0x6bb
   +0x050 DebugActive      : 0 ''
   +0x051 Number           : 0 ''
   +0x052 Spare0           : 0 ''
   +0x053 SecondLevelCacheAssociativity : 0x10 ''
   +0x054 VdmAlert         : 0
   +0x058 KernelReserved   : [14] 0
   +0x090 SecondLevelCacheSize : 0x80000
   +0x094 HalReserved      : [16] 0
   +0x0d4 InterruptMode    : 0
   +0x0d8 Spare1           : 0 ''
   +0x0dc KernelReserved2  : [17] 0
   +0x120 PrcbData         : _KPRCB
lkd> dt nt!_KPCR f9c2c000
   +0x000 NtTib            : _NT_TIB
   +0x01c SelfPcr          : 0xf9c2c000 _KPCR
   +0x020 Prcb             : 0xf9c2c120 _KPRCB
   +0x024 Irql             : 0 ''
   +0x028 IRR              : 0
   +0x02c IrrActive        : 0
   +0x030 IDR              : 0xffffffff
   +0x034 KdVersionBlock   : (null)
   +0x038 IDT              : 0xf9c30590 _KIDTENTRY
   +0x03c GDT              : 0xf9c30190 _KGDTENTRY
   +0x040 TSS              : 0xf9c2cd70 _KTSS
   +0x044 MajorVersion     : 1
   +0x046 MinorVersion     : 1
   +0x048 SetMember        : 2
   +0x04c StallScaleFactor : 0x650
   +0x050 DebugActive      : 0 ''
   +0x051 Number           : 0x1 ''
   +0x052 Spare0           : 0 ''
   +0x053 SecondLevelCacheAssociativity : 0x10 ''
   +0x054 VdmAlert         : 0
   +0x058 KernelReserved   : [14] 0
   +0x090 SecondLevelCacheSize : 0x80000
   +0x094 HalReserved      : [16] 1
   +0x0d4 InterruptMode    : 0
   +0x0d8 Spare1           : 0 ''
   +0x0dc KernelReserved2  : [17] 0
   +0x120 PrcbData         : _KPRCB

This piece of code is your friend if you are also experiencing some problem with it.

    //
    // Multi Processors (MP)
    // To ensure that it's running on a specific processor.
    //
    KeSetSystemAffinityThread(1);
    _asm {
       mov eax, fs:[0x1C]  // SelfPCR
       mov eax, [eax + 0x34] // KdVersionBlock
       mov KdVersionBlock, eax
   }
    //
    // Go back to default affinity.
    //
    KeRevertToUserAffinityThread();

MSDN documentation suggests to Windows Vista and later developpers to use KeSetSystemAffinityThreadEx instead of KeSetSystemAffinityThread and to use KeRevertToUserAffinityThreadEx instead of KeRevertToUserAffinityThread.

Even if there is no entry for KeRevertToUserAffinityThread inside the MSDN there is a blogpost from Windows Driver Kit (WDK) Documentation Blog about Windows Kernel Routine Name Conventions that says

Suffix – Ex – indicates that this is a new version of KeRevertToUserAffinityThread. “Ex” is an abbreviation for extension. It is a common Windows naming convention for new versions of a routine.

Thanks to Sebastien and Martim for reporting the bug.

One thought on “Multi-Processors and KdVersionBlock

  1. My pleasure Matthieu,

    You know me, always ready to do something stupid in order to help a friend ;-)

    Have a nice one and happy New Year.

Comments are closed.