CURRENT WORK ITEM - PREVIEW ONLY

KPRCB (amd64)

The name KPRCB stands for (Kernel) Processor Control Block. The kernel keeps one KPRCB for each logical processor, embedded in the same processor’s KPCR. The KPRCB holds most of what the kernel needs ready access to while managing a processor and while managing resources that are themselves managed more simply (and quickly) per processor. Neither of these structures is formally documented. Both are highly specific to the processor architecture. This page concerns itself only with the KPRCB in 64-bit Windows for the processor architecture that’s variously named amd64 or x64.

Access

Kernel-mode code can easily find the KPRCB for whichever processor it’s executing on, by finding the current KPCR first. The latter is well-known to be accessible through the gs register. Its CurrentPrcb member points to the KPRCB without depending on it to be embedded in the KPCR. Given a C-language definition of the KPCR, getting the current processor’s KPRCB can be conveniently wrapped into one inline function:

FORCEINLINE
KPRCB *KeGetCurrentPrcb (VOID)
{
    return (KPRCB *) __readgsqword (FIELD_OFFSET (KPCR, CurrentPrcb));
}

which, less some dressing, is mostly how Microsoft’s own programmers have been doing it, apparently all along, as confirmed by the NTOSP.H that has recently been disclosed in a Windows Driver Kit (WDK) for Windows 10.

The part of the KPCR that’s ahead of the embedded KPRCB is highly stable, notably so that the offset of the CurrentPrcb member is reliable over all Windows versions, as is the offset of the KPRCB within the KPCR. Members of the KPRCB are sometimes accessed through offsets from the KPCR. For some members, this is even the most usual access. Notably, the KeGetCurrentThread function is implemented very like

KTHREAD *KeGetCurrentThread (VOID)
{
    return (KTHREAD *) __readgsqword (FIELD_OFFSET (KPCR, Prcb.CurrentThread));
}

both as exported and when inlined throughout the kernel. Indeed, this particular offset is so stable and reliable that NTOSP.H doesn’t compute it symbolically but hard-codes it (to 0x0188). More generally, access to KPRCB members as nested in the KPCR is formalised in Microsoft’s assembly-language header KSAMD64.INC through such definitions as PcCurrentThread for the preceding.

In many typical cases, including that of KeGetCurrentThread, kernel-mode code does much better to access a KPRCB member via the fs register and an offset from the KPCR. This is because the address that some such routine as KeGetCurrentPrcb obtains is merely the address of the KPRCB for the processor that the current thread was being run on at the time. It remains the address of the current KPRCB only while the thread can ensure it is not switched to another processor. Often, it can’t be—at least in the circumstances that have the kernel itself access the KPRCB. But often is not always, even for the kernel’s own use. How much trouble has been caused by unsynchronised access to a KPRCB for some processor that the thread is no longer running on, whether in the kernel and from outside, is not known.

Other Processors

Finding the KPRCB for an arbitrary processor is easy too in 64-bit Windows. Its kernel exports a function, named KeQueryPrcbAddress, that returns the address of the KPRCB for the processor that is represented by a given processor index.

Variability

The KPRCB is highly variable. The layout changes not just from one version to another but even between builds of version 6.0. Where this article refers to early and late builds of version 6.0, early means before Windows Vista SP1, and late means Windows Vista SP1 or higher.

Names, types and offsets are from Microsoft’s symbol files for the kernel. Some symbol files, e.g., those for the HAL in Windows 7 and higher, define a smaller KPRCB that is just an “architecturally defined section” at the structure’s start. This term is long established from comments in C-language definitions of a partial KPRCB for other processor architectures all the way back to the NTDDK.H from the Device Driver Kit (DDK) for Windows NT 3.51. Microsoft’s first known disclosure of a C-language definition of the KPRCB for the amd64 architecture—though still only of the architecturally defined section—is in the NTOSP.H from the WDK for Windows 10.

Architecturally Defined Section

The very start of the 64-bit KPRCB is relatively stable. When the processor Number was widened in place for Windows Vista, the NestingLevel moved further on. When Number was widened even further for Windows 7, it too moved further on, and the space it occupied was renamed, presumably so that it is never reassigned.

Offset Definition Applicable Versions Remarks
0x00
ULONG MxCsr;
all  
0x04
UCHAR Number;
5.2 only  
USHORT Number;
6.0 only next at offset 0x24
UCHAR LegacyNumber;
6.1 and higher  
0x05
UCHAR NestingLevel;
5.2 only next at offset 0x20
UCHAR ReservedMustBeZero;
6.1 and higher  
0x06
BOOLEAN InterruptRequest;
all  
0x07
BOOLEAN IdleHalt;
all  
0x08
KTHREAD *CurrentThread;
all  
0x10
KTHREAD *NextThread;
all  
0x18
KTHREAD *IdleThread;
all  

Shifting the processor Number from offset 0x04 to widen it to 32 bits had special implications for compatibility because of the vast amounts of kernel-mode code, not only written by Microsoft, that accesses the 8-bit Number through the inline function KeGetCurrentProcessorNumber as defined for seemingly general use in the NTDDK.H from driver kits for versions before Windows 7 (and still defined if targetting those versions). This routine gets Number via the gs register, relying not only on its offset within the KPRCB but the offset of the KPRCB within the KPCR, the sum (0x0184) being hard-coded in the definition. Its replacement, KeGetCurrentProcessorIndex, is similarly hard-coded but to access the 32-bit Number at its new location. The kernel must maintain the LegacyNumber for as long as the old routine remains in use by drivers that might ever get loaded.

The other inline function that is declared in NTDDK.H for general use and which has a hard-coded offset from gs to a KPRCB member is KeGetCurrentThread. It, of course, reads CurrentThread.

There the hard constraints on moving members seem to end. The very next member even got moved out. Space left by moving the 8-byte UserRsp to the KPCR in Windows Vista got reused little by little in each later version. The byte at offset 0x21 even got reused, unused and re-reused. All 8 bytes are in use as of Windows 10.

Offset Definition Applicable Versions Remarks
0x20
ULONG64 UserRsp;
5.2 only next at 0x10 in KPCR
UCHAR NestingLevel;
6.0 and higher previously at 0x05
0x21
UCHAR Group;
6.0 only next as USHORT at 0x0658 (6.1 to 6.2)
UCHAR PrcbPad00 [3];
6.1 only  
BOOLEAN ClockOwner;
6.2 and higher  
0x22
UCHAR PrcbPad00 [6];
6.0 only  
UCHAR PendingTick;
6.2 only  
union {
    UCHAR PendingTickFlags;
    struct {
        UCHAR PendingTick : 1;          // 0x01
        UCHAR PendingBackupTick : 1;    // 0x02
    };
};
6.3 and higher  
0x23
UCHAR PrcbPad00 [1];
6.2 to 6.3  
UCHAR IdleState;
10.0 and higher  
0x24
ULONG Number;
6.1 and higher previously USHORT at 0x04

Much of the rest of the architecturally defined section has been very nearly stable.

Offset Definition Applicable Versions Remarks
0x28
ULONG64 RspBase;
all  
0x30
KSPIN_LOCK PrcbLock;
all  
0x38
KAFFINITY SetMember;
5.2 to 6.0  
ULONG64 PrcbPad01;
6.1 to 6.2  
CHAR *PriorityState;
6.3 and higher  
0x40
KPROCESSOR_STATE ProcessorState;
all  
0x05F0
CHAR CpuType;
all  
0x05F1
CHAR CpuID;
all  
0x05F2
USHORT CpuStep;
5.2 only  
union {
    USHORT CpuStep;
    struct {
        UCHAR CpuStepping;
        UCHAR CpuModel;
    };
};
6.0 and higher  
0x05F4
ULONG MHz;
all  
0x05F8
ULONG64 HalReserved [8];
all  
0x0638
USHORT MinorVersion;
all  
0x063A
USHORT MajorVersion;
all  
0x063C
UCHAR BuildType;
all  
0x063D
UCHAR CpuVendor;
all  
0x063E
UCHAR InitialApicId;
5.2 only next as ULONG at 0x0650
UCHAR CoresPerPhysicalProcessor;
6.0 and higher  
0x063F
UCHAR LogicalProcessorsPerPhysicalProcessor;
5.2 only  
UCHAR LogicalProcessorsPerCore;
6.0 and higher  

The remainder of the architecturally defined section got so heavily reworked for Windows 8.1 that it seems better to present before and after layouts. The development before Windows 8.1 is straightforward enough:

Offset Definition Applicable Versions Remarks
0x0640 (5.2 to 6.2)
ULONG ApicMask;
5.2 to 6.2 next at 0x0654
0x0644 (5.2 to 6.2)
UCHAR CFlushSize;
5.2 only  
ULONG CFlushSize;
6.0 to 6.2 next at 0x0658
0x0645 (5.2)
UCHAR PrcbPad0x [3];
5.2 only  
0x0648 (5.2 to 6.2)
PVOID AcpiReserved;
5.2 to 6.2 next at 0x0660
0x0650 (5.2 to 6.2)
ULONG64 PrcbPad00 [4];
5.2 only  
ULONG InitialApicId;
6.0 to 6.2 previously UCHAR at 0x063E;
next at 0x0668
0x0654 (6.0 to 6.2)
ULONG Stride;
6.0 to 6.2  
0x0658 (6.0 to 6.2)
ULONG64 PrcbPad01 [3];
6.0 only  
USHORT Group;
6.1 to 6.2 previously UCHAR at 0x21;
next as UCHAR at 0x0650
0x0660 (6.1 to 6.2)
KAFFINITY GroupSetMember;
6.1 to 6.2 next at 0x0648
0x0668 (6.1 to 6.2)
UCHAR GroupIndex;
6.1 to 6.2 next at 0x0651

An initially 8-bit CFlushSize was followed by padding that formally accounts for the next member’s alignment requirement and which went away when CFlushSize was widened in place. As an initial 32 bytes of padding (as PrcbPad00) was brought into use, it shifted and shrank (as PrcbPad01), until it was no longer needed (assuming 8-byte alignment of whatever follows). Note the will to preserve that the architecturally defined section ends at offset 0x0670 in all versions.

For Windows 8.1 and Windows 10 to bring ParentNode and ScbOffset from much further into the structure without pushing anything beyond offset 0x0670, the inefficient packing of Group and GroupIndex had to be reorganised. But there was more than enough space to achieve this by moving only GroupIndex. Why Windows 10 reorders ApicMask, CFlushSize and InitialApicId is anyone’s guess.

Offset Definition Applicable Versions Remarks
0x0640
KNODE *ParentNode;
6.3 and higher previously at 0x5338
0x0648
KAFFINITY GroupSetMember;
6.3 and higher previously at 0x0660
0x0650
UCHAR Group;
6.3 and higher previously USHORT at 0x0658
0x0651
UCHAR GroupIndex;
6.3 and higher previously at 0x0668
0x0652
UCHAR PrcbPad05 [2];
6.3 and higher  
0x0654
ULONG InitialApicId;
10.0 and higher previously at 0x0668
0x0658
ULONG ScbOffset;
10.0 and higher previously at 0x0531C
0x0654 (6.3);
0x065C
ULONG ApicMask;
6.3 and higher previously at 0x0640
0x0658 (6.3)
ULONG CFlushSize;
6.3 only previously at 0x0644;
next at 0x0668
0x0660
PVOID AcpiReserved;
6.3 and higher previously at 0x0648
0x0668 (6.3)
ULONG InitialApicId;
6.3 only previously at 0x0650;
next at 0x0654
0x0668
ULONG CFlushSize;
10.0 and higher previously at 0x0658
0x066C
ULONG PrcbPad10;
10.0 and higher  

Note that NTOSP.H from the WDK for Windows 10 has a C_ASSERT to enforce at compile-time that AcpiReserved is at offset 0x0660, and then the comment “Do not move field”. Was the offset changed despite the comment or was the comment added after changing the offset?

Non-Achitectural

From here onwards, the KPRCB does indeed seem to be private to the kernel. In contrast to 32-bit Windows, not even the HAL is known to use anything beyond the architecturally defined section.

Spin Lock Queues

Functions such as KeAcquireQueuedSpinLock that operate on the per-processor spin lock queues are exported from the HAL (originally) in 32-bit Windows but have always been kernel exports in 64-bit Windows. Another difference from 32-bit Windows is that the LockQueue is outside the architecturally defined section: the kernel itself accesses the LockQueue via the LockArray pointer in the KPCR.

Offset Definition Applicable Versions
0x0670
KSPIN_LOCK_QUEUE LockQueue [0x21];
5.2 to early 6.0
KSPIN_LOCK_QUEUE LockQueue [0x31];
late 6.0
KSPIN_LOCK_QUEUE LockQueue [0x11];
6.1 and higher

As with 32-bit Windows, the LockQueue array is positioned such that its second element is cache-aligned. This is plainly by design. Caching is plainly important to the 64-bit implementation, whose KeReleaseQueuedSpinLock has always prefetched its selected element. Why the first element should be in its own cache line is not known.

The array is indexed by members of the enumeration KSPIN_LOCK_QUEUE_NUMBER, which is defined first in NTDDK.H and then in WDM.H (starting with the WDK for Windows Vista).

Lookaside Lists

Broadly speaking, there are two separate types of per-processor lookaside lists. First come the system lookaside lists.

Offset Definition Applicable Versions
0x0880 (5.2 to early 6.0);
0x0980 (late 6.0);
0x0780
PP_LOOKASIDE_LIST PPLookasideList [0x10];
all

The PPLookasideList array is indexed by the undocumented enumeration PP_NPAGED_LOOKASIDE_NUMBER. Its different values represent lookaside lists that cache very different fixed-size structures that each have a very specific purpose.

The undocumented PP_LOOKASIDE_LIST structure is a pair of pointers, P and L, to the actual lookaside lists. Ideally, they point to separate lists: the first just for the processor; the second shared. Allocations are sought first from the per-processor list, for speed, else from the shared. Allocations are freed to the per-processor list for easy re-allocation, except that if that list has reached its capacity the allocation is instead freed to the shared list.

The remaining arrays help with the efficiency of small allocations from various types of pool (NonPagedPool, PagedPool and, in version 6.2 and higher, NonPagedPoolNx). The purpose of the allocation is arbitrary. What matters is just the size: successive lists in the array are for successively larger sizes of allocation, from 0x10 to 0x0200, in increments of 0x10.

Offset Definition Applicable Versions
0x0880
GENERAL_LOOKASIDE_POOL PPNxPagedLookasideList [0x20];
6.2 and higher
0x0980 (5.2 to early 6.0);
0x0A80 (late 6.0);
0x0880 (6.1);
0x1480
PP_LOOKASIDE_LIST PPNPagedLookasideList [0x20];
5.2 only
GENERAL_LOOKASIDE_POOL PPNPagedLookasideList [0x20];
6.0 and higher
0x0B80 (5.2);
0x1580 (early 6.0);
0x1680 (late 6.0);
0x1480 (6.1);
0x2080
PP_LOOKASIDE_LIST PPPagedLookasideList [0x20];
5.2 only
GENERAL_LOOKASIDE_POOL PPPagedLookasideList [0x20];
6.0 and higher

Mostly Counters

Offset Definition Applicable Versions Remarks
0x0D80 (5.2);
0x2180 (early 6.0);
0x2280 (late 6.0);
0x2080 (6.1);
0x2C80
ULONG64 volatile PacketBarrier;
5.2 to 6.1 next as LONG volatile at 0x2D00
ULONG64 PrcbPad20;
6.2 and higher  
0x0D88 (5.2);
0x2188 (early 6.0);
0x2288 (late 6.0);
0x2088 (6.1);
0x2C88
SINGLE_LIST_ENTRY DeferredReadyListHead;
all  
0x0D90 (5.2);
0x2190 (early 6.0);
0x2290 (late 6.0);
0x2090 (6.1);
0x2C90
LONG volatile MmPageFaultCount;
all  
0x0D94 (5.2);
0x2194 (early 6.0);
0x2294 (late 6.0);
0x2094 (6.1);
0x2C94
LONG volatile MmCopyOnWriteCount;
all  
0x0D98 (5.2);
0x2198 (early 6.0);
0x2298 (late 6.0);
0x2098 (6.1);
0x2C98
LONG volatile MmTransitionCount;
all  
0x0D9C (5.2)
LONG volatile MmCacheTransitionCount;
5.2 only next as ULONG at 0x3768
0x0DA0 (5.2);
0x219C (early 6.0);
0x229C (late 6.0);
0x209C (6.1);
0x2C9C
LONG volatile MmDemandZeroCount;
all  
0x0DA4 (5.2);
0x21A0 (early 6.0);
0x22A0 (late 6.0);
0x20A0 (6.1);
0x2CA0
LONG volatile MmPageReadCount;
all  
0x0DA8 (5.2);
0x21A4 (early 6.0);
0x22A4 (late 6.0);
0x20A4 (6.1);
0x2CA4
LONG volatile MmPageReadIoCount;
all  
0x0DAC (5.2)
LONG volatile MmCacheReadCount;
5.2 only next as ULONG at 0x376C
0x0DB0 (5.2)
LONG volatile MmCacheIoCount;
5.2 only next as ULONG at 0x3770
0x0DB4 (5.2);
0x21A8 (early 6.0);
0x22A8 (late 6.0);
0x20A8(6.1);
0x2CA8 
LONG volatile MmDirtyPagesWriteCount;
all  
0x0DB8 (5.2);
0x21AC (early 6.0);
0x22AC (late 6.0);
0x20AC (6.1);
0x2CAC
LONG volatile MmDirtyWriteIoCount;
all  
0x0DBC (5.2);
0x21B0 (early 6.0);
0x22B0 (late 6.0);
0x20B0 (6.1);
0x2CB0
LONG volatile MmMappedPagesWriteCount;
all  
0x0DC0 (5.2);
0x21B4 (early 6.0);
0x22B4 (late 6.0);
0x20B4 (6.1);
0x2CB4
LONG volatile MmMappedWriteIoCount;
all  
0x0DC4 (5.2)
LONG LookasideIrpFloat;
5.2 only next at 0x21D8
0x0DC8 (5.2);
0x21B8 (early 6.0);
0x22B8 (late 6.0);
0x20B8 (6.1);
0x2CB8
ULONG KeSystemCalls;
all  
0x21BC (early 6.0);
0x22BC (late 6.0);
0x20BC (6.1);
0x2CBC
ULONG KeContextSwitches;
6.0 and higher previously at 0x0DF0
0x2CC0
USHORT LdtSelector;
6.3 and higher  
0x2CC2
USHORT PrcbPad40;
6.3 and higher  
0x21C0 (early 6.0);
0x22C0 (late 6.0);
0x20C0 (6.1);
0x2CC0 (6.2);
0x2CC4
ULONG CcFastReadNoWait;
6.0 and higher previously at 0x2280
0x21C4 (early 6.0);
0x22C4 (late 6.0);
0x20C4 (6.1);
0x2CC4 (6.2);
0x2CC8
ULONG CcFastReadWait;
6.0 and higher previously at 0x2284
0x21C8 (early 6.0);
0x22C8 (late 6.0);
0x20C8 (6.1);
0x2CC8 (6.2);
0x2CCC
ULONG CcFastReadNotPossible;
6.0 and higher previously at 0x2288
0x21CC (early 6.0);
0x22CC (late 6.0);
0x20CC (6.1);
0x2CCC (6.2);
0x2CD0
ULONG CcCopyReadNoWait;
6.0 and higher previously at 0x228C
0x21D0 (early 6.0);
0x22D0 (late 6.0);
0x20D0 (6.1);
0x2CD0 (6.2);
0x2CD4
ULONG CcCopyReadWait;
6.0 and higher previously at 0x2290
0x21D4 (early 6.0);
0x22D4 (late 6.0);
0x20D4 (6.1);
0x2CD4 (6.2);
0x2CD8
ULONG CcCopyReadNoWaitMiss;
6.0 and higher previously at 0x2294
0x21D8 (early 6.0);
0x22D8 (late 6.0);
0x20D8 (6.1);
0x2CD8 (6.2)
LONG LookasideIrpFloat;
6.0 to 6.2 previously at 0x0DC4;
next at 0x2D1C
0x0DCC (5.2);
0x21DC (early 6.0);
0x22DC (late 6.0);
0x20DC (6.1);
0x2CDC
LONG volatile IoReadOperationCount;
all  
0x0DD0 (5.2);
0x21E0 (early 6.0);
0x22E0 (late 6.0);
0x20E0 (6.1);
0x2CE0
LONG volatile IoWriteOperationCount;
all  
0x0DD4 (5.2);
0x21E4 (early 6.0);
0x22E4 (late 6.0);
0x20E4 (6.1);
0x2CE4
LONG volatile IoOtherOperationCount;
all  
0x0DD8 (5.2);
0x21E8 (early 6.0);
0x22E8 (late 6.0);
0x20E8 (6.1);
0x2CE8
LARGE_INTEGER IoReadTransferCount;
all  
0x0DE0 (5.2);
0x21F0 (early 6.0);
0x22F0 (late 6.0);
0x20F0 (6.1);
0x2CF0
LARGE_INTEGER IoWriteTransferCount;
all  
0x0DE8 (5.2);
0x21F8 (early 6.0);
0x22F8 (late 6.0);
0x20F8 (6.1);
0x2CF8
LARGE_INTEGER IoOtherTransferCount;
all  
0x0DF0 (5.2)
ULONG KeContextSwitches;
5.2 only next at 0x21BC
0x0DF4 (5.2)
UCHAR PrcbPad2 [0x0C];
5.2 only  

Cache-alignment again seeems deliberate, at least in version 5.2.

Inter-Processor Interrupts

Offset Definition Applicable Versions Remarks
0x2D00
LONG volatile PacketBarrier;
6.2 and higher previously ULONG64 volatile at 0x2080
0x0E00 (5.2);
0x2200 (early 6.0);
0x2300 (late 6.0);
0x2100 (6.1);
0x2D04
ULONG64 volatile TargetSet;
5.2 to 6.0  
LONG volatile TargetCount;
6.1 and higher  
0x0E08 (5.2);
0x2208 (early 6.0);
0x2308 (late 6.0);
0x2104 (6.1);
0x2D08
ULONG volatile IpiFrozen;
all  

A substantial amount of padding, not just to the next cache line but the one after, gets put to use in Windows 8.1:

Offset Definition Applicable Versions Remarks
0x0E0C (5.2);
0x220C (early 6.0);
0x230C (late 6.0);
0x2D0C (6.2)
UCHAR PrcbPad3 [0x74];
5.2 to 6.0  
ULONG PrcbPad40 [0x1D];
6.2 only  
0x2D10
PVOID IsrDpcStats;
6.3 and higher  
0x2D18
ULONG DeviceInterrupts;
6.3 and higher  
0x2D1C
LONG LookasideIrpFloat;
6.3 and higher previously at 0x2CD8
0x2D20
ULONG InterruptLastCount;
6.3 and higher previously at 0x2DF8
0x2D24
ULONG InterruptRate;
6.3 and higher previously at 0x2DFC
0x2D28
ULONG PrcbPad41 [0x16];
6.3 and higher  

Early versions have a REQUEST_MAILBOX for each of 64 possible processors. For Windows 7 to support more, the array was moved to the end.

Offset Definition Applicable Versions Remarks
0x0E80 (5.2);
0x2280 (early 6.0);
0x2380 (late 6.0)
REQUEST_MAILBOX RequestMailbox [0x40];
5.2 to 6.0 next at 0x4C80
0x1E80 (5.2);
0x3280 (early 6.0);
0x3380 (late 6.0)
ULONG64 volatile SenderSummary;
5.2 to 6.0  
0x1E88 (5.2);
0x3288 (early 6.0);
0x3388 (late 6.0)
UCHAR PrcbPad4 [0x78];
5.2 to 6.0  

Deferred Procedure Calls And Timing

Offset Definition Applicable Versions Remarks
0x1F00 (5.2);
0x3300 (early 6.0);
0x3400 (late 6.0);
0x2180 (6.1);
0x2D80
KDPC_DATA DpcData [2];
all  
0x1F40 (5.2);
0x3340 (early 6.0);
0x3440 (late 6.0);
0x21C0 (6.1);
0x2DC0 (6.2);
0x2DD0
PVOID DpcStack;
all  
0x1F48 (5.2);
0x3348 (early 6.0);
0x3448 (late 6.0)
PVOID SavedRsp;
5.2 to early 6.0  
PVOID SparePtr0;
late 6.0 only  
0x1F50 (5.2);
0x3350 (early 6.0);
0x3450 (late 6.0);
0x21C8 (6.1);
0x2DC8 (6.2);
0x2DD8
LONG MaximumDpcQueueDepth;
all  
0x1F54 (5.2);
0x3354 (early 6.0);
0x3454 (late 6.0);
0x21CC (6.1);
0x2DCC (6.2);
0x2DDC
ULONG DpcRequestRate;
all  
0x1F58 (5.2);
0x3358 (early 6.0);
0x3458 (late 6.0);
0x21D0 (6.1);
0x2DD0 (6.2);
0x2DE0
ULONG MinimumDpcRate;
all  
0x1F5C (5.2);
0x335C (early 6.0);
0x345C (late 6.0)
BOOLEAN volatile DpcInterruptRequested;
5.2 to 6.0  
0x1F5D (5.2);
0x335D (early 6.0);
0x345D (late 6.0)
BOOLEAN volatile DpcThreadRequested;
5.2 to 6.0 next as bit at 0x21DC
0x1F5E (5.2);
0x335E (early 6.0);
0x345E (late 6.0)
BOOLEAN volatile DpcRoutineActive;
5.2 to 6.0 next at 0x21DA
0x1F5F (5.2);
0x335F (early 6.0);
0x345F (late 6.0)
BOOLEAN volatile DpcThreadActive;
5.2 to 6.0 next as bit at 0x21DC
0x1F60 (5.2);
0x3360 (early 6.0);
0x3460 (late 6.0)
union {
    ULONG64 volatile TimerHand;
    ULONG64 volatile TimerRequest;
};
5.2 to 6.0 next as ULONG volatile at 0x21E0
0x1F68 (5.2);
0x3368 (early 6.0);
0x3468 (late 6.0)
LONG TickOffset;
5.2 to 6.0 next as ULONG64 at 0x4470
0x1F6C (5.2);
0x336C (early 6.0);
0x346C (late 6.0)
LONG MasterOffset;
5.2 to 6.0 next at 0x21E4
0x1F70 (5.2);
0x3370 (early 6.0);
0x3470 (late 6.0);
0x21D4 (6.1);
0x2DD4 (6.2);
0x2DE4
ULONG DpcLastCount;
all  
0x1F74 (5.2);
0x3374 (early 6.0);
0x3474 (late 6.0);
0x21D8 (6.1);
0x2DD8 (6.2);
0x2DE8
UCHAR ThreadDpcEnabled;
all  
0x1F75 (5.2);
0x3375 (early 6.0);
0x3475 (late 6.0);
0x21D9 (6.1);
0x2DD9 (6.2);
0x2DE9
UCHAR volatile QuantumEnd;
all  
0x1F76 (5.2);
0x3376 (early 6.0);
0x3476 (late 6.0);
0x21DA (6.1);
0x2DDA (6.2);
0x2DEA
UCHAR PrcbPad50;
5.2 to 6.0  
BOOLEAN volatile DpcRoutineActive;
6.1 and higher previously at 0x345E
0x1F77 (5.2);
0x3377 (early 6.0);
0x3477 (late 6.0);
0x21DB (6.1);
0x2DDB (6.2);
0x2DEB
UCHAR volatile IdleSchedule;
all  

Windows 7 introduced, but did not completely formalise, a set of bit flags for DPC management: DpcThreadActive and DpcThreadRequested were previously BOOLEAN volatile at offsets 0x345F and 0x345D (late 6.0).

Offset Definition Applicable Versions
0x1F78 (5.2);
0x3378 (early 6.0);
0x3478 (late 6.0);
0x21DC (6.1);
0x2DDC (6.2);
0x2DEC
LONG DpcSetEventRequest;
5.2 to 6.0
union {
    LONG volatile DpcRequestSummary;
    SHORT DpcRequestSlot [2];
    struct {
        SHORT NormalDpcState;
        union {
            USHORT volatile DpcThreadActive : 1;        // 0x0001
            SHORT ThreadDpcState;
        };
    };
};
6.1 only
union {
    LONG volatile DpcRequestSummary;
    SHORT DpcRequestSlot [2];
    struct {
        SHORT NormalDpcState;
        SHORT ThreadDpcState;
    };
    struct {
        ULONG DpcNormalProcessingActive : 1;            // 0x00000001
        ULONG DpcNormalProcessingRequested : 1;         // 0x00000002
        ULONG DpcNormalThreadSignal : 1;                // 0x00000004
        ULONG DpcNormalTimerExpiration : 1;             // 0x00000008
        ULONG DpcNormalDpcPresent : 1;                  // 0x00000010
        ULONG DpcNormalLocalInterrupt : 1;              // 0x00000020
        ULONG DpcNormalSpare : 10;
        ULONG DpcThreadActive : 1;                      // 0x00010000
        ULONG DpcThreadRequested : 1;                   // 0x00020000
        ULONG DpcThreadSpare : 14;
    };
};
6.2 and higher

Miscellany

Offset Definition Applicable Versions Remarks
0x1F7C (5.2);
0x337C (early 6.0);
0x347C (late 6.0);
0x21E0 (6.1);
0x2DE0 (6.2);
0x2DF0
LONG PrcbPad40;
5.2 only  
ULONG KeExceptionDispatchCount;
6.0 only previously at 0x22A0;
next at 0x4734
ULONG volatile TimerHand;
6.1 only previously ULONG64 volatile in union at 0x3460
ULONG LastTimerHand;
6.2 and higher  
0x1F80 (5.2)
PVOID DpcThread;
5.2 only  
0x1F88 (5.2);
0x3380 (early 6.0);
0x3480 (late 6.0);
0x21E4 (6.1)
KEVENT DpcEvent;
5.2 to 6.0  
LONG MasterOffset;
6.1 only previously at 0x346C
0x21E8 (6.1);
0x2DE4 (6.2);
0x2DF4
ULONG LastTick;
6.1 and higher  
0x21EC (6.1)
ULONG UnusedPad;
6.1 only  
0x21F0 (6.1);
0x2DE8 (6.2);
0x2DF8
ULONG64 PrcbPad50 [2];
6.1 only  
ULONG ClockInterrupts;
6.2 and higher  
0x2DEC (6.2);
0x2DFC
ULONG ReadyScanTick;
6.2 and higher  
0x2DF0 (6.2)
UCHAR BalanceState;
6.2 only  
0x2DF1 (6.2)
UCHAR PrcbPad50 [7];
6.2 only  
0x2DF8 (6.2)
ULONG InterruptLastCount;
6.2 only next at 0x2D20
0x2DFC (6.2)
ULONG InterruptRate;
6.2 only next at 0x2D24
0x2E00
PVOID InterruptObject [0x0100];
10.0 and higher  
0x2200 (6.1);
0x2E00 (6.2 to 6.3);
0x3600
KTIMER_TABLE TimerTable;
6.1 and higher  
0x4400 (6.1);
0x5000 (6.2 to 6.3);
0x5800
KGATE DpcGate;
6.1 and higher  
0x3398 (early 6.0);
0x3498 (late 6.0);
0x4418 (6.1);
0x5018 (6.2 to 6.3);
0x5818
PVOID PrcbPad51;
6.0 only  
PVOID PrcbPad52;
6.1 and higher  
0x1FA0 (5.2);
0x33A0 (early 6.0);
0x34A0 (late 6.0);
0x4420 (6.1);
0x5020 (6.2 to 6.3);
0x5820
KDPC CallDpc;
all  

Padding to the next cache line is still not completely put to use.

Offset Definition Applicable Versions Remarks
0x1FE0 (5.2);
0x33E0 (early 6.0);
0x34E0 (late 6.0);
0x4460 (6.1);
0x5060 (6.2 to 6.3);
0x5860
ULONG64 PrcbPad7 [4];
5.2 only  
LONG ClockKeepAlive;
6.0 and higher  
0x33E4 (early 6.0);
0x34E4 (late 6.0);
0x4464 (6.1);
0x5064 (6.2 to 6.3);
0x5864
UCHAR ClockCheckSlot;
6.0 to 6.1  
UCHAR PrcbPad60 [2];
6.2 and higher  
0x33E5 (early 6.0);
0x34E5 (late 6.0);
0x4465 (6.0 to 6.1)
UCHAR ClockPollCycle;
6.0 to 6.1  
0x33E6 (early 6.0);
0x34E6 (late 6.0);
0x4466 (6.1);
0x5066 (6.2 to 6.3);
0x5866
UCHAR PrcbPad6 [2];
6.0 only  
USHORT NmiActive;
6.1 and higher  
0x33E8 (early 6.0);
0x34E8 (late 6.0);
0x4468 (6.1);
0x5068 (6.2 to 6.3);
0x5868
LONG DpcWatchdogPeriod;
6.0 and higher  
0x33EC (early 6.0);
0x34EC (late 6.0);
0x446C (6.1);
0x506C (6.2 to 6.3);
0x586C
LONG DpcWatchdogCount;
6.0 and higher  
0x4470 (6.0)
ULONG64 TickOffset;
6.1 only previously LONG at 0x3468
0x4478 (6.1);
0x5070 (6.2 to 6.3);
0x5870
LONG volatile KeSpinLockOrdering;
6.1 and higher  
0x33F0 (early 6.0);
0x34F0 (late 6.0);
0x447C (6.1);
0x5074 (6.2 to 6.3);
0x5874
ULONG64 PrcbPad70 [2];
6.0 only  
ULONG PrcbPad70;
6.1 only  
ULONG PrcbPad70 [1];
6.2 and higher  
0x5078 (6.2 to 6.3);
0x5878
PVOID CachedPtes;
6.2 and higher  

Scheduling

Offset Definition Applicable Versions Remarks
0x2000 (5.2);
0x3400 (early 6.0);
0x3500 (late 6.0);
0x4480 (6.1);
0x5080 (6.2 to 6.3);
0x5880
LIST_ENTRY WaitListHead;
all  
0x3410 (early 6.0);
0x3510 (late 6.0);
0x4490 (6.1);
0x5090 (6.2 to 6.3);
0x5890
KSPIN_LOCK WaitLock;
6.0 and higher  
0x2010 (5.2);
0x3418 (early 6.0);
0x3518 (late 6.0);
0x4498 (6.1);
0x5098 (6.2 to 6.3);
0x5898
ULONG ReadySummary;
all  
0x509C (6.3);
0x589C
LONG AffinitizedSelectionMask;
6.3 and higher  
0x2014 (5.2);
0x341C (early 6.0);
0x351C (late 6.0);
0x449C (6.1);
0x509C (6.2);
0x50A0 (6.3);
0x58A0
ULONG QueueIndex;
all  
0x50A0 (6.2)
ULONG ReadyQueueWeight;
6.2 only  
0x50A4 (6.3);
0x58A4
ULONG PrcbPad75;
6.2 only  
ULONG PrcbPad75 [3];
6.3 and higher  
0x44A0 (6.1);
0x50A8 (6.2);
0x50B0 (6.3);
0x58B0
KDPC TimerExpirationDpc;
6.1 and higher  
0x3420 (early 6.0);
0x3520 (late 6.0);
0x44E0 (6.1);
0x50E8 (6.2)
ULONG64 PrcbPad71 [0x0C];
6.0 only  
ULONG64 PrcbPad72 [4];
6.1 only  
KPRCB *BuddyPrcb;
6.2 only  
0x50F0 (6.2 to 6.3);
0x58F0
RTL_RB_TREE ScbQueue;
6.2 and higher  
0x2018 (5.2);
0x3480 (early 6.0);
0x3580 (late 6.0);
0x4500 (6.1);
0x5100 (6.2 to 6.3);
0x5900
LIST_ENTRY DispatcherReadyListHead [0x20];
all  
0x2218 (5.2);
0x3680 (early 6.0);
0x3780 (late 6.0);
0x4700 (6.1);
0x5300 (6.2 to 6.3);
0x5B00
ULONG InterruptCount;
all  
0x221C (5.2);
0x3684 (early 6.0);
0x3784 (late 6.0);
0x4704 (6.1);
0x5304 (6.2 to 6.3);
0x5B04
ULONG KernelTime;
all  
0x2220 (5.2);
0x3688 (early 6.0);
0x3788 (late 6.0);
0x4708 (6.1);
0x5308 (6.2 to 6.3);
0x5B08
ULONG UserTime;
all  
0x2224 (5.2);
0x368C (early 6.0);
0x378C (late 6.0);
0x470C (6.1);
0x530C (6.2 to 6.3);
0x5B0C
ULONG DpcTime;
all  
0x2228 (5.2);
0x3690 (early 6.0);
0x3790 (late 6.0);
0x4710 (6.1);
0x5310 (6.2 to 6.3);
0x5B10
ULONG InterruptTime;
all  
0x222C (5.2);
0x3694 (early 6.0);
0x3794 (late 6.0);
0x4714 (6.1);
0x5314 (6.2 to 6.3);
0x5B14
ULONG AdjustDpcThreshold;
all  
0x2230 (5.2);
0x3698 (early 6.0);
0x3798 (late 6.0)
UCHAR SkipTick;
5.2 to 6.0  
0x2231 (5.2);
0x3699 (early 6.0);
0x3799 (late 6.0);
0x4718 (6.1);
0x5318 (6.2 to 6.3);
0x5B18
UCHAR DebuggerSavedIRQL;
all  
0x2232 (5.2);
0x369A (early 6.0);
0x379A (late 6.0)
UCHAR PollSlot;
5.2 to 6.0  
0x2233 (5.2);
0x369B (early 6.0);
0x379B (late 6.0);
0x4719 (6.1);
0x5319 (6.2 to 6.3);
0x5B19
UCHAR PrcbPad8 [0x0D];
5.2 only  
UCHAR PrcbPad80 [5];
6.0 only  
UCHAR PrcbPad80 [7];
6.1 only  
BOOLEAN GroupSchedulingOverQuota;
6.2 and higher  
0x531A (6.2 to 6.3);
0x5B1A
BOOLEAN volatile DeepSleep;
6.2 and higher  
0x531B (6.2 to 6.3);
0x5B1B
UCHAR PrcbPad80 [1];
6.2 to 6.3  
UCHAR PrcbPad80 [5];
10.0 and higher  
0x531C (6.2 to 6.3)
ULONG ScbOffset;
6.2 to 6.3 next at 0x0658
0x36A0 (early 6.0);
0x37A0 (late 6.0);
0x4720 (6.1);
0x5320 (6.2 to 6.3);
0x5B20
ULONG DpcTimeCount;
6.0 and higher  
0x36A4 (early 6.0);
0x37A4 (late 6.0);
0x4724 (6.1);
0x5324 (6.2 to 6.3);
0x5B24
ULONG DpcTimeLimit;
6.0 and higher  
0x36A8 (early 6.0);
0x37A8 (late 6.0);
0x4728 (6.1);
0x5328 (6.2 to 6.3);
0x5B28
ULONG PeriodicCount;
6.0 and higher  
0x36AC (early 6.0);
0x37AC (late 6.0);
0x472C (6.1);
0x532C (6.2 to 6.3);
0x5B2C
ULONG PeriodicBias;
6.0 and higher  
0x36B0 (early 6.0);
0x37B0 (late 6.0);
0x4730 (6.1);
0x5330 (6.2 to 6.3);
0x5B30
ULONG64 PrcbPad81 [2];
6.0 only  
ULONG AvailableTime;
6.1 and higher  
0x4734 (6.1);
0x5334 (6.2 to 6.3);
0x5B34
ULONG KeExceptionDispatchCount;
6.1 and higher previously at 0x347C
0x2240 (5.2);
0x36C0 (early 6.0);
0x37C0 (late 6.0);
0x4738 (6.1);
0x5338 (6.2)
KNODE *ParentNode;
5.2 to 6.2 next at 0x0640
0x2248 (5.2);
0x26C8 (early 6.0);
0x37C8 (late 6.0)
ULONG64 MultiThreadProcesserSet;
5.2 to 6.0  
0x2250 (5.2);
0x36D0 (early 6.0);
0x37D0 (late 6.0)
KPRCB *MultiThreadSetMaster;
5.2 to 6.0  
0x2258 (5.2)
LONG Sleeping;
5.2 only next at 0x36F4
0x36D8 (early 6.0);
0x37D8 (late 6.0);
0x4740 (6.1);
0x5340 (6.2);
0x5338 (6.3);
0x5B38
ULONG64 StartCycles;
6.0 and higher  
0x5B40
ULONG64 TaggedCyclesStart;
10.0 and higher  
0x5B48
ULONG64 TaggedCycles [2];
10.0 and higher  
0x4748 (6.1);
0x5348 (6.2);
0x5340 (6.3);
0x5B58
ULONG64 PrcbPad82 [3];
6.1 only  
ULONG64 GenerationTarget;
6.2 and higher  
0x5350 (6.2);
0x5348 (6.3);
0x5B60
ULONG64 AffinitizedCycles;
6.2 and higher  
0x5358 (6.2);
0x5350 (6.3);
0x5B68
ULONG64 PrcbPad81;
6.2 only  
ULONG64 PrcbPad81 [2];
6.3 only  
ULONG PrcbPad81 [0x1D];
10.0 and higher  
0x225C (5.2)
ULONG PrcbPad90 [1];
5.2 only  
0x2260 (5.2)
ULONG DebugDpcTime;
5.2 only  
0x36E0 (early 6.0);
0x37E0 (late 6.0);
0x4760 (6.1);
0x5360 (6.2 to 6.3);
0x5BDC
LONG volatile MmSpinLockOrdering;
6.0 and higher  
0x2264 (5.2);
0x36E4 (early 6.0);
0x37E4 (late 6.0);
0x4764 (6.1);
0x5364 (6.2 to 6.3);
0x5BE0
ULONG PageColor;
all  
0x2268 (5.2);
0x36E8 (early 6.0);
0x37E8 (late 6.0);
0x4768 (6.1);
0x5368 (6.2 to 6.3);
0x5BE4
ULONG NodeColor;
all  
0x226C (5.2);
0x36EC (early 6.0);
0x37EC (late 6.0);
0x476C (6.1);
0x536C (6.2 to 6.3);
0x5BE8
ULONG NodeShiftedColor;
all  
0x2270 (5.2);
0x36F0 (early 6.0);
0x37F0 (late 6.0);
0x4770 (6.1);
0x5370 (6.2 to 6.3);
0x5BEC
ULONG SecondaryColorMask;
all  
0x2274 (5.2);
0x36F4 (early 6.0);
0x37F4 (late 6.0);
0x4774 (6.1);
0x5374 (6.2 to 6.3);
0x5BF0
UCHAR PrcbPad9 [0x0C];
5.2 only  
LONG Sleeping;
6.0 only previously at 0x2258
ULONG PrcbPad83;
6.1 and higher  
0x36F8 (early 6.0);
0x37F8 (late 6.0);
0x4778 (6.1);
0x5378 (6.2 to 6.3);
0x5BF8
ULONG64 CycleTime;
6.0 and higher  
0x5C40
ULONG PrcbPad84 [0x10];
10.0 and higher  

Counters

Windows Vista added numerous counters, mostly to do with caching by the file system, to an original handful. For some reason, the originals were moved to another area of counters nearer the start.

Offset Definition Applicable Versions Remarks
0x2280 (5.2)
ULONG CcFastReadNoWait;
5.2 only next at 0x21C0
0x2284 (5.2)
ULONG CcFastReadWait;
5.2 only next at 0x21C4
0x2288 (5.2)
ULONG CcFastReadNotPossible;
5.2 only next at 0x21C8
0x228C (5.2)
ULONG CcCopyReadNoWait;
5.2 only next at 0x21CC
0x2290 (5.2)
ULONG CcCopyReadWait;
5.2 only next at 0x21D0
0x2294 (5.2)
ULONG CcCopyReadNoWaitMiss;
5.2 only next at 0x21D4
0x3700 (early 6.0);
0x3800 (late 6.0);
0x4780 (6.1);
0x5380 (6.2 to 6.3);
0x5C80
ULONG CcFastMdlReadNoWait;
6.0 and higher  
0x3704 (early 6.0);
0x3804 (late 6.0);
0x4784 (6.1);
0x5384 (6.2 to 6.3);
0x5C84
ULONG CcFastMdlReadWait;
6.0 and higher  
0x3708 (early 6.0);
0x3808 (late 6.0);
0x4788 (6.1);
0x5388 (6.2 to 6.3);
0x5C88
ULONG CcFastMdlReadNotPossible;
6.0 and higher  
0x370C (early 6.0);
0x380C (late 6.0);
0x478C (6.1);
0x538C (6.2 to 6.3);
0x5C8C
ULONG CcMapDataNoWait;
6.0 and higher  
0x3710 (early 6.0);
0x3810 (late 6.0);
0x4790 (6.1);
0x5390 (6.2 to 6.3);
0x5C90
ULONG CcMapDataWait;
6.0 and higher  
0x3714 (early 6.0);
0x3814 (late 6.0);
0x4794 (6.1);
0x5394 (6.2 to 6.3);
0x5C94
ULONG CcPinMappedDataCount;
6.0 and higher  
0x3718 (early 6.0);
0x3818 (late 6.0);
0x4798 (6.1);
0x5398 (6.2 to 6.3);
0x5C98
ULONG CcPinReadNoWait;
6.0 and higher  
0x371C (early 6.0);
0x381C (late 6.0);
0x479C (6.1);
0x539C (6.2 to 6.3);
0x5C9C
ULONG CcPinReadWait;
6.0 and higher  
0x3720 (early 6.0);
0x3820 (late 6.0);
0x47A0 (6.1);
0x53A0 (6.2 to 6.3);
0x5CA0
ULONG CcMdlReadNoWait;
6.0 and higher  
0x3724 (early 6.0);
0x3824 (late 6.0);
0x47A4 (6.1);
0x53A4 (6.2 to 6.3);
0x5CA4
ULONG CcMdlReadWait;
6.0 and higher  
0x3728 (early 6.0);
0x3828 (late 6.0);
0x47A8 (6.1);
0x53A8 (6.2 to 6.3);
0x5CA8
ULONG CcLazyWriteHotSpots;
6.0 and higher  
0x372C (early 6.0);
0x382C (late 6.0);
0x47AC (6.1);
0x53AC (6.2 to 6.3);
0x5CAC
ULONG CcLazyWriteIos;
6.0 and higher  
0x3730 (early 6.0);
0x3830 (late 6.0);
0x47B0 (6.1);
0x53B0 (6.2 to 6.3);
0x5CB0
ULONG CcLazyWritePages;
6.0 and higher  
0x3734 (early 6.0);
0x3834 (late 6.0);
0x47B4 (6.1);
0x53B4 (6.2 to 6.3);
0x5CB4
ULONG CcDataFlushes;
6.0 and higher  
0x3738 (early 6.0);
0x3838 (late 6.0);
0x47B8 (6.1);
0x53B8 (6.2 to 6.3);
0x5CB8
ULONG CcDataPages;
6.0 and higher  
0x373C (early 6.0);
0x383C (late 6.0);
0x47BC (6.1);
0x53BC (6.2 to 6.3);
0x5CBC
ULONG CcLostDelayedWrites;
6.0 and higher  
0x3740 (early 6.0);
0x3840 (late 6.0);
0x47C0 (6.1);
0x53C0 (6.2 to 6.3);
0x5CC0
ULONG CcFastReadResourceMiss;
6.0 and higher  
0x3744 (early 6.0);
0x3844 (late 6.0);
0x47C4 (6.1);
0x53C4 (6.2 to 6.3);
0x5CC4
ULONG CcCopyReadWaitMiss;
6.0 and higher  
0x3748 (early 6.0);
0x3848 (late 6.0);
0x47C8 (6.1);
0x53C8 (6.2 to 6.3);
0x5CC8
ULONG CcFastMdlReadResourceMiss;
6.0 and higher  
0x374C (early 6.0);
0x384C (late 6.0);
0x47CC (6.1);
0x53CC (6.2 to 6.3);
0x5CCC
ULONG CcMapDataNoWaitMiss;
6.0 and higher  
0x3750 (early 6.0);
0x3850 (late 6.0);
0x47D0 (6.1);
0x53D0 (6.2 to 6.3);
0x5CD0
ULONG CcMapDataWaitMiss;
6.0 and higher  
0x3754 (early 6.0);
0x3854 (late 6.0);
0x47D4 (6.1);
0x53D4 (6.2 to 6.3);
0x5CD4
ULONG CcPinReadNoWaitMiss;
6.0 and higher  
0x3758 (early 6.0);
0x3858 (late 6.0);
0x47D8 (6.1);
0x53D8 (6.2 to 6.3);
0x5CD8
ULONG CcPinReadWaitMiss;
6.0 and higher  
0x375C (early 6.0);
0x385C (late 6.0);
0x47DC (6.1);
0x53DC (6.2 to 6.3);
0x5CDC
ULONG CcMdlReadNoWaitMiss;
6.0 and higher  
0x3760 (early 6.0);
0x3860 (late 6.0);
0x47E0 (6.1);
0x53E0 (6.2 to 6.3);
0x5CE0
ULONG CcMdlReadWaitMiss;
6.0 and higher  
0x3764 (early 6.0);
0x3864 (late 6.0);
0x47E4 (6.1);
0x53E4 (6.2 to 6.3);
0x5CE4
ULONG CcReadAheadIos;
6.0 and higher  
0x3768 (early 6.0);
0x3868 (late 6.0);
0x47E8 (6.1);
0x53E8 (6.2 to 6.3);
0x5CE8
ULONG MmCacheTransitionCount;
6.0 and higher previously LONG volatile at 0x0D9C
0x376C (early 6.0);
0x386C (late 6.0);
0x47EC (6.1);
0x53EC (6.2 to 6.3);
0x5CEC
ULONG MmCacheReadCount;
6.0 and higher previously LONG volatile at 0x0DAC
0x3770 (early 6.0);
0x3870 (late 6.0);
0x47F0 (6.1);
0x53F0 (6.2 to 6.3);
0x5CF0
ULONG MmCacheIoCount;
6.0 and higher previously LONG volatile at 0x0DB0
0x3774 (early 6.0);
0x3874 (late 6.0);
0x47F4 (6.1);
0x53F4 (6.2 to 6.3);
0x5CF4
ULONG PrcbPad91 [3];
6.0 only  
ULONG PrcbPad91 [1];
6.1 only  
ULONG PrcbPad91 [3];
6.2 and higher  
0x47F8 (6.1)
ULONG64 RuntimeAccumulation;
6.1 only  

Windows Vista brought forward the PowerState to a cache boundary.

Offset Definition Applicable Versions Remarks
0x3780 (early 6.0);
0x3880 (late 6.0);
0x4800 (6.1);
0x5400 (6.2 to 6.3);
0x5D00
PROCESSOR_POWER_STATE PowerState;
6.0 and higher previously at 0x22D0
0x55C8 (6.2);
0x55E0 (6.3);
0x5ED0
PVOID ScbList [2];
6.2 and higher  
0x4900 (6.1);
0x55D8 (6.2);
0x55F0 (6.3);
0x5EE0
UCHAR PrcbPad92 [0x10];
6.1 only  
ULONG PrcbPad92 [0x16];
6.2 only  
ULONG PrcbPad92 [0x13];
6.3 only  
ULONG PrcbPad92 [7];
10.0 and higher  
0x2298 (5.2);
0x38B8 (early 6.0);
0x3998 (late 6.0);
0x4910 (6.1);
0x5630 (6.2);
0x563C (6.3);
0x5EFC
ULONG KeAlignmentFixupCount;
all  
0x229C (5.2)
ULONG KeDcacheFlushCount;
5.2 only  
0x22A0 (5.2)
ULONG KeExceptionDispatchCount;
5.2 only next at 0x337C
0x22A4 (5.2)
ULONG KeFirstLevelTbFills;
5.2 only  
0x22A8 (5.2)
ULONG KeFloatingEmulationCount;
5.2 only  
0x22AC (5.2)
ULONG KeIcacheFlushCount;
5.2 only  
0x22B0 (5.2)
ULONG KeSecondLevelTbFills;
5.2 only  
0x22B4 (5.2);
0x38BC (early 6.0);
0x399C (late 6.0)
UCHAR VendorString [0x0D];
5.2 to 6.0 next at 0x4BB8
0x22C1 (5.2);
0x38C9 (early 6.0);
0x39A9 (late 6.0)
UCHAR PrcbPad10 [2];
5.2 only  
UCHAR PrcbPad10 [3];
6.0 only  
0x22C4 (5.2);
0x38CC (early 6.0);
0x39AC (late 6.0)
ULONG FeatureBits;
5.2 to 6.0 next at 0x4BC8
0x22C8 (5.2);
0x38D0 (early 6.0);
0x39B0 (late 6.0)
LARGE_INTEGER UpdateSignature;
5.2 to 6.0 next at 0x4BD0
0x22D0 (5.2)
PROCESSOR_POWER_STATE PowerState;
5.2 only next at 0x3780
0x38D8 (early 6.0);
0x39B8 (late 6.0);
0x4918 (6.1);
0x5638 (6.2);
0x5640 (6.3);
0x5F00
KDPC DpcWatchdogDpc;
6.0 and higher  
0x3918 (early 6.0);
0x39F8 (late 6.0);
0x4958 (6.1);
0x5678 (6.2);
0x5680 (6.3);
0x5F40
KTIMER DpcWatchdogTimer;
6.0 and higher  
0x2440 (5.2);
0x3958 (early 6.0);
0x3A38 (late 6.0);
0x4998 (6.1);
0x56B8 (6.2);
0x56C0 (6.3);
0x5F80
CACHE_DESCRIPTOR Cache [5];
all  
0x247C (5.2);
0x3994 (early 6.0);
0x3A74 (late 6.0);
0x49D4 (6.1);
0x56F4 (6.2);
0x56FC (6.3);
0x5FBC
ULONG CacheCount;
all last member in 5.2

Appended For Windows Vista

Offset Definition Applicable Versions Remarks
0x3998 (early 6.0);
0x3A78 (late 6.0);
0x49D8 (6.1);
0x56F8 (6.2);
0x5700 (6.3);
0x5FC0
ULONG volatile CachedCommit;
6.0 and higher  
0x399C (early 6.0);
0x3A7C (late 6.0);
0x49DC (6.1);
0x56FC (6.2);
0x5704 (6.3);
0x5FC4
ULONG volatile CachedResidentAvailable;
6.0 and higher  
0x39A0 (early 6.0);
0x3A80 (late 6.0);
0x49E0 (6.1);
0x5700 (6.2);
0x5708 (6.3);
0x5FC8
PVOID HyperPte;
6.0 and higher  
0x39A8 (early 6.0);
0x3A88 (late 6.0);
0x49E8 (6.1);
0x5708 (6.2);
0x5710 (6.3);
0x5FD0
PVOID WheaInfo;
6.0 and higher  
0x39B0 (early 6.0);
0x3A90 (late 6.0);
0x49F0 (6.1);
0x5710 (6.2);
0x5718 (6.3);
0x5FD8
PVOID EtwSupport;
6.0 and higher  
0x39C0 (early 6.0);
0x3AA0 (late 6.0);
0x4A00 (6.1);
0x5720 (6.2 to 6.3);
0x5FE0
SLIST_HEADER InterruptObjectPool;
6.0 and higher  
0x39D0 (early 6.0);
0x3AB0 (late 6.0);
0x4A10 (6.1);
0x5730 (6.2 to 6.3);
0x5FF0
LARGE_INTEGER HypercallPagePhysical;
early 6.0 only  
SLIST_HEADER HypercallPageList;
late 6.0 and higher  
0x39D8 (early 6.0);
0x3AC0 (late 6.0);
0x4A20 (6.1);
0x5740 (6.2 to 6.3);
0x6000
PVOID HypercallPageVirtual;
6.0 to 6.3  
PVOID HypercallCachedPages;
10.0 and higher  
0x3AC8 (late 6.0);
0x4A28 (6.1);
0x5748 (6.2 to 6.3);
0x6008
PVOID VirtualApicAssist;
late 6.0 and higher  
0x3AD0 (late 6.0);
0x4A30 (6.1);
0x5750 (6.2 to 6.3);
0x6010
ULONGLONG *StatisticsPage;
late 6.0 and higher  
0x39E0 (early 6.0);
0x3AD8 (late 6.0);
0x4A38 (6.1)
PVOID RateControl;
6.0 to 6.1  
0x39E8 (early 6.0);
0x3AE0 (late 6.0);
0x4A40 (6.1)
ULONG64 CacheProcessorMask [5];
6.0 to 6.1 next as ULONG array at 0x5800
0x3A10 (early 6.0);
0x3B08 (late 6.0);
0x4A68 (6.1);
0x5758 (6.2 to 6.3);
0x6018
KAFFINITY PackageProcessorSet;
6.0 only  
KAFFINITY_EX PackageProcessorSet;
6.1 and higher  
0x5800 (6.2)
ULONG CacheProcessorMask [5];
6.2 only previously as ULONG64 array at 0x4A40;
next at 0x5828
0x5800 (6.3);
0x60C0
ULONG64 SharedReadyQueueMask;
6.3 and higher  
0x5808 (6.3);
0x60C8
KSHARED_READY_QUEUE *SharedReadyQueue;
6.3 and higher  
0x60D0
ULONG SharedQueueScanOwner;
10.0 and higher  
0x60D4
ULONG ScanSiblingIndex;
10.0 and higher previously at 0x5850
0x5810 (6.3);
0x60D8
ULONG64 CoreProcessorSet;
6.3 and higher previously at 0x5838
0x5828 (6.2);
0x5818 (6.3);
0x60E0
ULONG64 ScanSiblingMask;
6.2 and higher  
0x5820 (6.3);
0x60E8
ULONG64 LLCMask;
6.3 and higher  
0x5828 (6.3);
0x60F0
ULONG CacheProcessorMask [5];
6.3 and higher previously at 0x5800
0x5830 (6.2);
0x5850 (6.3)
ULONG ScanSiblingIndex;
6.2 to 6.3 next at 0x60D4
0x5854 (6.3)
ULONG SharedReadyQueueOffset;
6.3 only  
0x5834 (6.2)
ULONG LLCLevel;
6.2 only  
0x3A18 (early 6.0);
0x3B10 (late 6.0);
0x4A90 (6.1);
0x5838 (6.2)
ULONG64 CoreProcessorSet;
6.0 to 6.2 last member in 6.0;
next at 0x5810
0x4A98 (6.1)
PVOID PebsIndexAddress;
6.1 only  

Again, trouble is taken to pad to a cache boundary. Some of the padding was put to use in Windows 8.

Offset Definition Applicable Versions
0x4AA0 (6.1);
0x5840 (6.2);
0x5858 (6.3);
0x6118
ULONG64 PrcbPad93 [0x0C];
6.1 and higher
PROCESSOR_PROFILE_CONTROL_AREA *ProcessorProfileControlArea;
6.2 and higher
0x5848 (6.2);
0x5860 (6.3);
0x6120
PVOID ProfileEventIndexAddress;
6.2 and higher
0x5850 (6.2);
0x5858 (6.3);
0x6128
ULONG PrcbPad94 [6];
6.2 only
ULONG PrcbPad94 [3];
6.3 only
ULONG64 PrcbPad94 [0x0B];
10.0 and higher

Inserted For Windows 7

Windows 7 defines numerous performance counters for synchronisation.

Offset Definition Applicable Versions
0x4B00 (6.1)
ULONG SpinLockAcquireCount;
6.1 only
0x4B04 (6.1)
ULONG SpinLockContentionCount;
6.1 only
0x4B08 (6.1)
ULONG SpinLockSpinCount;
6.1 only
0x4B0C (6.1)
ULONG IpiSendRequestBroadcastCount;
6.1 only
0x4B10 (6.1)
ULONG IpiSendRequestRoutineCount;
6.1 only
0x4B14 (6.1)
ULONG IpiSendSoftwareInterruptCount;
6.1 only
0x4B18 (6.1)
ULONG ExInitializeResourceCount;
6.1 only
0x4B1C (6.1)
ULONG ExReInitializeResourceCount;
6.1 only
0x4B20 (6.1)
ULONG ExDeleteResourceCount;
6.1 only
0x4B24 (6.1)
ULONG ExecutiveResourceAcquiresCount;
6.1 only
0x4B28 (6.1)
ULONG ExecutiveResourceContentionsCount;
6.1 only
0x4B2C (6.1)
ULONG ExecutiveResourceReleaseExclusiveCount;
6.1 only
0x4B30 (6.1)
ULONG ExecutiveResourceReleaseSharedCount;
6.1 only
0x4B34 (6.1)
ULONG ExecutiveResourceConvertsCount;
6.1 only
0x4B38 (6.1)
ULONG ExAcqResExclusiveAttempts;
6.1 only
0x4B3C (6.1)
ULONG ExAcqResExclusiveAcquiresExclusive;
6.1 only
0x4B40 (6.1)
ULONG ExAcqResExclusiveAcquiresExclusiveRecursive;
6.1 only
0x4B44 (6.1)
ULONG ExAcqResExclusiveWaits;
6.1 only
0x4B48 (6.1)
ULONG ExAcqResExclusiveNotAcquires;
6.1 only
0x4B4C (6.1)
ULONG ExAcqResSharedAttempts;
6.1 only
0x4B50 (6.1)
ULONG ExAcqResSharedAcquiresExclusive;
6.1 only
0x4B54 (6.1)
ULONG ExAcqResSharedAcquiresShared;
6.1 only
0x4B58 (6.1)
ULONG ExAcqResSharedAcquiresSharedRecursive;
6.1 only
0x4B5C (6.1)
ULONG ExAcqResSharedWaits;
6.1 only
0x4B60 (6.1)
ULONG ExAcqResSharedNotAcquires;
6.1 only
0x4B64 (6.1)
ULONG ExAcqResSharedStarveExclusiveAttempts;
6.1 only
0x4B68 (6.1)
ULONG ExAcqResSharedStarveExclusiveAcquiresExclusive;
6.1 only
0x4B6C (6.1)
ULONG ExAcqResSharedStarveExclusiveAcquiresShared;
6.1 only
0x4B70 (6.1)
ULONG ExAcqResSharedStarveExclusiveAcquiresSharedRecursive;
6.1 only
0x4B74 (6.1)
ULONG ExAcqResSharedStarveExclusiveWaits;
6.1 only
0x4B78 (6.1)
ULONG ExAcqResSharedStarveExclusiveNotAcquires;
6.1 only
0x4B7C (6.1)
ULONG ExAcqResSharedWaitForExclusiveAttempts;
6.1 only
0x4B80 (6.1)
ULONG ExAcqResSharedWaitForExclusiveAcquiresExclusive;
6.1 only
0x4B84 (6.1)
ULONG ExAcqResSharedWaitForExclusiveAcquiresShared;
6.1 only
0x4B88 (6.1)
ULONG ExAcqResSharedWaitForExclusiveAcquiresSharedRecursive;
6.1 only
0x4B8C (6.1)
ULONG ExAcqResSharedWaitForExclusiveWaits;
6.1 only
0x4B90 (6.1)
ULONG ExAceResSharedWaitForExclusiveNotAcquires;
6.1 only
0x4B94 (6.1)
ULONG ExSetResOwnerPointerExclusive;
6.1 only
0x4B98 (6.1)
ULONG ExSetResOwnerPointerSharedNew;
6.1 only
0x4B9C (6.1)
ULONG ExSetResOwnerPointerSharedOld;
6.1 only
0x4BA0 (6.1)
ULONG ExTryToAcqExclusiveAttempts;
6.1 only
0x4BA4 (6.1)
ULONG ExTryToAcqExclusiveAcquires;
6.1 only
0x4BA8 (6.1)
ULONG ExBoostExclusiveOwner;
6.1 only
0x4BAC (6.1)
ULONG ExBoostSharedOwners;
6.1 only
0x4BB0 (6.1)
ULONG ExEtwSynchTrackingNotificationsCount;
6.1 only
0x4BB4 (6.1)
ULONG ExEtwSynchTrackingNotificationsAccountedCount;
6.1 only

Windows 8 tidies all the preceding counters into one SYNCH_COUNTERS structure.

Offset Definition Applicable Versions Remarks
0x5880 (6.2 to 6.3);
0x6180
SYNCH_COUNTERS SynchCounters;
6.2 and higher  
0x5938 (6.3);
0x6238
ULONG64 PteBitCache;
6.3 and higher  
0x5940 (6.3);
0x6240
ULONG PteBitOffset;
6.3 and higher  
0x5938 (6.2);
0x5948 (6.3);
0x6248
FILESYSTEM_DISK_COUNTERS FsCounters;
6.2 and higher  
0x4BB8 (6.1);
0x5948 (6.2);
0x5958 (6.3);
0x6258
UCHAR VendorString [0x0D];
6.1 and higher previously at 0x399C
0x4BC5 (6.1);
0x5955 (6.2);
0x5965 (6.3);
0x6265
UCHAR PrcbPad10 [3];
6.1 and higher  
0x4BC8 (6.1);
0x5958 (6.2);
0x5968 (6.3);
0x6268
ULONG FeatureBits;
6.1 to 6.2 previously at 0x39AC
ULONG64 FeatureBits;
6.3 and higher
0x5970 (6.3);
0x6270
ULONG PrcbPad11;
6.3 only  
ULONG PrcbPad110;
10.0 and higher  
0x4BD0 (6.1);
0x5960 (6.2);
0x5978 (6.3);
0x6278
LARGE_INTEGER UpdateSignature;
6.1 and higher previously at 0x39B0
0x4BD8 (6.1);
0x5968 (6.2);
0x5980 (6.3);
0x6280
CONTEXT *Context;
6.1 and higher  
0x4BE0 (6.1);
0x5970 (6.2);
0x5988 (6.3);
0x6288
ULONG ContextFlags;
6.1 only  
ULONG ContextFlagsInit;
6.2 and higher  
0x4BE8 (6.1);
0x5978 (6.2);
0x5990 (6.3);
0x6290
XSAVE_AREA *ExtendedState;
6.1 and higher  

Inserted for Windows 8 and 8.1

Offset Definition Applicable Versions
0x5998 (6.3);
0x6298
PVOID IsrStack;
6.3 and higher
0x5980 (6.2);
0x59A0 (6.3);
0x62A0
KENTROPY_TIMING_STATE EntropyTimingState;
6.2 and higher
0x5AF0 (6.3);
0x63F0
SINGLE_LIST_ENTRY AbSelfIoBoostsList;
6.3 and higher
0x5AF8 (6.3);
0x63F8
SINGLE_LIST_ENTRY AbPropagateBoostsList;
6.3 and higher
0x5B00 (6.3);
0x6400
KDPC AbDpc;
6.3 and higher

Inserted For Windows 10

Offset Definition Applicable Versions
0x6440
IOP_IRP_STACK_PROFILER IoIrpStackProfilerCurrent;
10.0 and higher
0x6494
IOP_IRP_STACK_PROFILER IoIrpStackProfilerPrevious;
10.0 and higher
0x6500
KSHARED_READY_QUEUE LocalSharedReadyQueue;
10.0 and higher
0x6760
KTIMER_EXPIRATION_TRACE TimerExpirationTrace;
10.0 and higher
0x6860
ULONG TimerExpirationTraceCount;
10.0 and higher
0x6868
PVOID ExSaPageArray;
10.0 and higher

Appended for Windows 7

The mailboxes for inter-processor communications were moved to the end of the KPRCB in Windows 7 so that the array can accommodate arbitrarily many processors but still be in the KPRCB. Both the pointer and the array are cache-aligned without formal padding.

Offset Definition Applicable Versions Remarks
0x4C00 (6.1);
0x5B00 (6.2);
0x5B40 (6.3);
0x6880
REQUEST_MAILBOX *Mailbox;
6.1 and higher  
0x4C80 (6.1);
0x5B40 (6.2);
0x5B80 (6.3);
0x68C0
REQUEST_MAILBOX RequestMailbox [ANYSIZE_ARRAY];
6.1 and higher previously at 0x2380;
last member in 6.1;
last member in 6.2;
last member in 6.3;
last member in 10.0