Control Registers are used to change the set behavior of a CPU.There are currently 5 different Control Registers for x86 processors, and 2 additional control registers for x64 processors.
Each Control Register is called CR with a number, the numbers range from CR0 to CR4, with EFER and CR8 on x64. Most of the Control Registers are controlled by bit flags, which is then used to change the behavior of the CPU.
CR0: This register is usually 32-bits, however, this 64-bits when running in Long Mode on a x64 processor. Let’s investigate the different bit flags which can be set.
PG – is used to enable paging, and to incorporates the use of the CR3 register, the CR3 register is used for paging, and to convert linear addresses to physical addresses by using the page directories and page tables. The upper 20 bits of this register form the PDBR (Page Directory Base Register) which stores the physical address of the first page directory entry (PDE). The Page Directory is the highest structure in the paging process.
CD – disables caching.
NW – disables write back caching.
AM – enables alignment checking, this also sets the AC flag in the EFLAGS register. The CPU Ring level must be level 3. Any unaligned instructions will result in a exception on a x64 system. The AC flag never seems to be able to displayed in WinDbg.
WP – decides if the CPU is able to write to read-only pages.
NE – Enables floating point x87 error detection. x87 is like an extension of x86.
ET – Not used anymore.
TS – Enables the saving of x87 task context switches, when using x87 instructions.
EM – If set, the CPU doesn’t use a x87 FPU, otherwise it will use a x87 FPU.
MP – Controls WAIT and FWAIT instructions, when the TS flag is set.
PE – If set, the CPU is running in Protected Mode, else Real Mode is enabled.
CR2: Contains the address which the program attempted to access, when a page fault has happened, which is called the Page Fault Linear Address (PFLA).
CR3: See PG bit in CR0 register.
CR4: This register is used in Protected Mode, and mainly used with paging settings.
SMAP/SMEP – If these two bits are set, enables Supervisor Mode Access Protection and/or Supervisor Mode Execution Protection, any access of data or execution in a higher ring will result in a fault. More Information – Ring (computer security)
OSXSAVE – Enables XSAVE (Save Processor Extended States) and Processor Extended States, a incorrect processor extended state can result in a Stop 0x131; More Information – KeSaveExtendedProcessorState and CPU Modes. Check Volume 3, Chapter 13 of the Intel Developer Manual
PCIDE – Enables Process Context Identifiers, these are used to cache linear address in the TLB, and then preserve this data. Originally, using a MOV CR3 would result in the cache being cleared, and resulting a much slower search through page tables. See Volume 3, Chapter 4.10.1 of the Intel Developer’s Manual.
SMXE – Safer Mode Extensions Table, Volume 1, Chapter 5.21, I’m not completely sure about these yet.
VMXE – Enables Virtual Machine Extensions, used for running more privileged instructions in virtual machines, since originally virtual machines ran at Ring 3 and had limited access to hardware and I/O ports. More Information – Intel’s CPU Extensions and x86 Virtualization
OSXMMEXCPT – Enables unmasked SSE Exceptions – More Information – x87 and SSE Floating Point Assists
OSFXSR –Provides operating system support for FXSAVE and FXRSTOR instructions, and enables SSE (Streaming SIMD Extensions), and better FPU saving and restoration.
PCE – Enables RDPMC (Read Performance Monitoring Counters) at any privilege level, otherwise RDPMC can only be used at Ring Level 0. More Information – RDPMC
PGE – Enables address translations, regarding PDEs and PTEs to be shared between different address spaces.
MCE – Enables Machine Check Exceptions
PAE – Physical Address Extension, changing 32-bit virtual memory addresses into 36-bit virtual memory addresses, enabling more RAM to be mapped on a x86 system, beyond the 4GB limit. However, this isn’t recommended due to driver compatibility problems and instability.
PSE – Enables Page Size Extension, allows for pages to be larger than 4KiB, and therefore reduces the number of pages stored in the TLB.
DE – Enables Debugging Extensions, and to allow Debugging Registers to set breakpoints on I/O address spaces.
TSD – This flag enables the RDTSC instruction to be only executed from Ring 0, the RDTSC instruction is used to read from a 64-bit TSC (Time Stamp Counter) register, to gain CPU timing information. If not set, then the RDTSC instruction can be used on all privilege levels.
PVI – Enables support of the VIF flag in Protected Mode. Good article here.
VME – Enables the support of the VIF flag in virtual-8086 mode. This special mode is used to enable real-mode programs to run on protected mode.
There are currently 6 different debug registers, which are used for debugging hardware. These debug registers can either be 32-bit or 64-bit, depending upon the type of processor and what mode the processor is running in. These debug registers are used with the MOV instruction, and can only be used at Ring 0. Any other privilege levels will result in a General Protection fault.
DR0 to DR3 contains the linear address of four different breakpoints for debugging hardware, a breakpoint is simply running the code until a certain point, where you suspect there may be a bug. This method greatly improves debugging programs. Hardware breakpoints can be set programmatically as seen demonstrated in this article.
The other debug registers DR6 and DR7 are used to set different flags for the hardware breakpoints, and execute the debug exception handler. DR6 is called the Debug Status Register and is used to determine which exceptions have occurred, and return this information to the exception handler, which will then execute some code detailing the events of the problem to the developer. The DR7 register is called the Debug Control register, and is used to set bit flags for the DR0 to DR3 registers, the first two flags are used to set a breakpoint for a local task or a global task. On Windows, you can only set breakpoints for local tasks, and therefore after a task swtich, the breakpoint is cleared.
Each breakpoint has a two bit entry, which defines where the breakpoint will happen and how large of a memory area the breakpoint will watch.
- 00b = Code Execution
- 01b = Data Writes
- 10b = Reserved and unsupported by hardware
- 11b Data Reads or Writes
- 00b = 1 Byte
- 01b = 2 Bytes
- 10b = 8 Bytes
- 11b = 4 Bytes
There were 4 different test registers available to use, the Test Registers are TR4, TR5, TR6 and TR7. Please note these registers are no longer supported by modern processors, as a result this section is for interest and historical academic purposes. These registers are largely undocumented too, and can only be used with the MOV instruction at Ring 0, like before accessing at other rings results in a General Protection Fault, and will generate a Invalid Opcode fault on modern processors. These registers have been partially replaced with MSRs.
The EFLAGs register is the updated version of the 16-bit FLAGS register, the EFLAGS register is 32-bits, and is used to show the current state of the CPU. The EFLAGs register can affect the operation of certain Assembly instructions. I’ll provide a debugging example of this with WinDbg. These bit flags are either true or false, or 1 and 0.
CF (Carry Flag) – Used for carrying binary data from previous arithmetic operations which were too large for the width of the ALU.
PF (Parity Flag) – Used to show wherever the binary representation of the last operation was even or odd. The flag is set to 1 if even, and 0 if odd. It’s usually used for JMP instructions and arithmetic and logical operations.
AF (Adjust Flag) – Indicates when a Carry has been used on the four most significant bits of a operation.
ZF (Zero Flag) – Used primarily for conditional branch instructions, typically instructions are executed in a sequence of how they appear in the program, however, branch instructions can be introduced into the code, to tell the program to execute instructions from a different sequence of code. You may notice these in WinDbg.
IF (Interrupt Enable Flag) – Indicates wherever the CPU will be able to handle and respond to hardware interrupts on the INTR pin. This is a very useful flag for debugging Stop 0x101. CLI and STI instructions are used to clear or set this flag.
DF (Direction Flag) – Used primarily for moving strings between two different memory locations, for example with the MOVS instruction. It can apply to any instruction which uses the REP (Repeat prefix) too.
OF (Overflow Flag) – This flag is used to show that a arithmetic operation result didn’t fit the width of the ALU, leading to a arithmetic overflow. I would be careful not to think that this flag can be used to indicate stack overflows. Good reading of this topic here.
IOPL (I/O Privilege Level) – This flag is used to indicate which Ring Level I/O operations can occur at. It tends to be set to Ring 0, to stop Ring 3 programs from accessing I/O ports.
NT (Nested Task Flag) – Used in Protected Mode, and shows that one task has called another task through the CALL instruction, rather than using the JMP instruction.
RF (Resume Flag) – Used by debug registers DR6 and DR7, to turn off certain breakpoint exceptions.
VM (Virtual 8086 Mode Flag) – Used for visualization purposes.
AC (Alignment Check Flag) – No longer used. Used for checking unaligned memory access. Additional reading here.
VIF (Virtual Interrupt Flag) – Excludes certain tasks from processing hardware interrupts.
VIP (Virtual Interrupt Pending Flag) – Used to signal if another virtual interrupt is pending, while a current virtual interrupt is being processed.
ID (CPUID Instruction Flag) – Enables the execution of CPUID instructions, these instructions can be used to determine processor features and architecture.
I’ve got a debugging example on TSF here – My results of BSOD 11-30-13