Geoff Chappell - Software Analyst
The name KPRCB stands for (Kernel) Processor Control Block. The kernel keeps one for each logical processor as the last member of the processor’s KPCR. The KPRCB (formally _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.
The KPRCB is highly specific to the processor architecture. Indeed, public symbol files confirm that Microsoft differentiates the x86 and x64 implementations not by conditional compilation but by defining them in separate headers: i386_x.h and amd64_x.h. This is a good measure of their dissimilarity. Presenting them as one, especially since each is large and has a complex history, is infeasible. This website’s attempt at documentation follows what’s known of Microsoft’s source code and presents the x86 KPRCB and x64 KPRCB separately.
That said, do not neglect the correspondences between them, at least for a second reading. The x64 KPRCB developed from roughly a decade of the x86, such that some of the new structure’s older elements may be better understood with reference to their origins in the old. The likelihood for many such cases is that my coverage for the x64 KPRCB attends only to the differences, taking as granted that you have read the corresponding material about the x86 KPRCB.
Of course, most of the kernel’s work is far enough away from the processor architecture that the differences in the KPRCB for different processor architectures get hidden to some extent. Where they can’t have members in common, it should not surprise if the differences are abstracted behind an interface.
A simple example is of finding the address of the KPRCB for the processor that currently executes your code. The means of finding it differs between the architectures, but Microsoft defines processor-specific implementations of an inlined routine named KeGetCurrentPrcb. You call this rather than code for the differences. Or, rather, Microsoft’s programmers do. Only very rarely has Microsoft made it available to others even as an obscure definition buried deep in the headers. In the early days of Windows, Microsoft defined this routine in NTDDK.H but only for the supported non-Intel processors, never for the x86. Programmers knew of it for the x86, though, because it was not only inlined throughout the x86 kernel but was instantiated and therefore had its name and address in symbol files. This stopped for Windows XP but plainly the routine continued to exist. In recent times, formal definition again became available outside Microsoft in the NTOSP.H that was published, possibly by oversight, in the Windows Driver Kit (WDK) for Windows 10 in its original and Version 1511 editions only.
Some of this abstraction into inline routines is disclosed in public symbols. In practice, the inline routines that get their names and types into public symbols are only those that are called from inline routines. For what it’s worth, the public symbol files for the kernel from the original Windows 10 have names and types for the following inline routines that access the KPRCB on the x86 and x64:
KPRCB *KeGetCurrentPrcb (VOID); VOID KiIpiStallOnPacketTargetsPrcb (ULONG, KPRCB *); VOID ExFreeToPPLookasideList (PP_NPAGED_LOOKASIDE_NUMBER, PVOID, KPRCB *);
For the x86 only, there is also a routine for getting the KPRCB for a given processor number:
KPRCB *KiGetPrcb (ULONG);
Of course, the likely code for this on the x86 has equivalent code inlined throughout the x64 kernel. It just doesn’t show in the public symbols. Revelations go only so far.