Table of contents

Int movs

Macro Operation x86 Opcode Notes

macro_252D NOT [mem+8] F7 /2 Bitwise complement

macro_2535 NEG [mem+8] F7 /3 Two's complement negate

macro_2509 MOV [mem+8], reg 89 Register to memory

macro_251C MOV [mem+8], imm C7 /0 Immediate to memory

macro_2512 CMOVcc synthesis or SETcc 0F 40-4F or 0F 90-9F Conditional with register

macro_2524 Conditional with imm Synthetic No direct x86 equivalent

macro_12A5 MOV [mem+8], 1 (?) C7 /0 or test/bit op Unclear, needs more context

FP Transcendental Operation Analysis (msrom-612, 0x1FFE-0x21E1)

Overview

This code block implements a floating-point transcendental function (likely FPATAN or similar) using polynomial approximation. The code demonstrates critical patterns for transferring data between TMP registers (computational domain) and ST registers (architectural FP stack).

Cross-Domain Transfer UOPs

UOP.020(source_constant, value_register, U2_flags)

UOP.220(constant, ST_register, U2_flags)

UOP.7EE(operand1, operand2, operation_code, U2_flags)

UFPOP_7X8(operand1, operand2, U2_flags)

UOP.262(operand1, operand2)

FP Field Extract UOPs

UOP.029(ST_register, ST_register)

UOP.060(FP_value, CONST_0)

UOP.061(FP_value, CONST_0)

UOP.063(FP_value, CONST_0)

UOP.064(FP_value, CONST_0)

FP Computation UOPs

UOP.0A1(CONST_0, FP_value)

UOP.223(operand1, operand2)

UOP.227(CONST_0, operand)

UOP.228(operand1, operand2)

UOP.267(operand1, operand2)

Integer Operations on FP Exponents

UOP.124(operand1, operand2)

U2 Flag Bit Analysis

Based on observed patterns in code:

Execution Flow Pattern

Special Cases Handled

Key Insight

The U2.80 bit is the "architectural visibility" flag. Operations without this bit execute in a shadow computational domain where:

Only operations with U2.80 (or composite flags like U2.C9 containing it) can:

SYSENTER/SYSEXIT

The Pentium Pro SYSENTER/SYSEXIT Bug: A Microcode Analysis

The Pentium Pro implemented SYSENTER and SYSEXIT instructions that Intel quietly left undocumented at launch. When Linux 2.6 later enabled these instructions based on the documented Pentium II behavior, Pentium Pro systems crashed. The reason has now been confirmed through direct analysis of the processor's microcode.

SYSENTER works. SYSEXIT does not.

SYSENTER on the Pentium Pro behaves correctly and is functionally equivalent to the Pentium II version. It reads the kernel entry point and stack from the SYSENTER MSRs, switches to ring 0, and clears the interrupt flag before transferring control. A kernel using SYSENTER for the call half and IRET for the return would have worked fine on Pentium Pro all along, as was suspected by Linux developers at the time.

SYSEXIT, however, is a completely different implementation from what Intel later documented for the Pentium II.

A different calling convention

The most fundamental problem is that SYSEXIT on the Pentium Pro reads its inputs from different registers than the Pentium II. The documented Pentium II SYSEXIT takes the return address from EDX and the user stack pointer from ECX, and derives the user-mode code and stack segment selectors automatically from the SYSENTER_CS MSR (adding fixed offsets to produce the ring-3 CS and SS). This is the design that operating systems implemented against.

The Pentium Pro SYSEXIT works differently. It still takes the stack pointer from ECX, but it reads the new instruction pointer from ESI. More critically, it reads the user-mode code segment selector directly from the DI register and the stack segment selector from BX, rather than computing them from the MSR. This was apparently intended to give the operating system explicit control over the user-mode segment descriptors, enabling non-flat memory models. In practice it was fatal.

The null selector crash

In normal kernel code, DI and BX frequently contain zero or arbitrary values left over from system call argument handling. When DI is zero, SYSEXIT loads the null descriptor into CS. The null descriptor (GDT entry 0) is architecturally reserved and must never be loaded into a code segment register. The Pentium Pro microcode checks that the SYSENTER_CS MSR is nonzero, but performs no validity check on the value in DI.

The result: SYSEXIT completes without error, CPL is set to 3, and the CPU begins executing in user mode with a null CS. The very first instruction fetch causes a General Protection Fault. The fault handler tries to report the error and return via IRET, but the error frame on the stack contains the null CS selector that caused the fault in the first place. IRET restores that null CS, causing an immediate second General Protection Fault. Two consecutive General Protection Faults produce a Double Fault, which is what Linux users observed.

This is also the exact behavior described by Intel's own erratum for the Pentium Pro: "SYSENTER/SYSEXIT instructions can implicitly load null segment selector to SS and CS registers." Intel published the erratum, apparently without fully acknowledging that SYSEXIT was the culprit and that DI was the vector.

EFLAGS are not restored

The Pentium II SYSEXIT clears most processor flags before returning to user mode, including the interrupt flag. The Pentium Pro SYSEXIT clears nothing. A kernel that disabled interrupts during syscall handling would return to user mode with interrupts still disabled, causing the system to gradually freeze as no timer or device interrupts could be serviced.

The STI timing problem

The Linux kernel, like many operating systems, uses a STI instruction immediately before SYSEXIT to re-enable interrupts before returning to user mode. The x86 architecture guarantees that an interrupt enabled by STI will not be taken until after the following instruction completes. On Pentium II, SYSEXIT honors this guarantee cleanly because the microcode contains an explicit pipeline checkpoint partway through the instruction, after all segment registers and the privilege level have been committed to a consistent state. If an interrupt arrives, it is held until that safe point.

The Pentium Pro SYSEXIT contains no such checkpoint. An interrupt that arrives during the execution of SYSEXIT may find the processor in a partially-updated state: the privilege level may already be set to ring 3 while the stack still points to a kernel address, or the code segment may be committed while the stack segment is not. Interrupt delivery in this half-updated state produces a stack fault or a protection fault, both of which escalate to a Double Fault.

Why Intel did not fix it

The Pentium Pro was already in production when this problem was identified. The fix Intel implemented for the Pentium II was architectural: rather than reading CS and SS from general-purpose registers, SYSEXIT computes them automatically from the SYSENTER_CS MSR, eliminating the possibility of a null selector being specified and removing the dependence on register state that kernel code cannot reliably control. This change made the instruction safe to document and use.

Intel's decision not to fix later Pentium Pro steppings was likely a cost/timeline judgment. No software used SYSEXIT at the time, so there was no pressure to patch a product that was already shipping. The workaround — not documenting the instruction — was cheap. The consequence surfaced years later when Linux began exploiting the Pentium II behavior and discovered the hard way that Pentium Pros behaved differently.

The correct CPUID check

Intel's documented check for SYSEXIT support — "family 6, model less than 3, stepping less than 3" — excludes only the earliest Pentium Pro models. Later Pentium Pros with model 1, stepping 9 pass the check and are incorrectly identified as supporting the Pentium II SYSEXIT behavior. The corrected check, using a combined model-stepping value, excludes all Pentium Pro processors. The discrepancy between these two checks is what made the Linux 2.6 crashes dependent on the specific CPU stepping and caused confusion about which processors were actually affected.


The author is not affiliated with, endorsed by, or sponsored by Intel Corporation or its affiliates. All trademarks, including but not limited to Intel, Pentium, and any other registered or unregistered marks mentioned herein, are the property of their respective owners. Their use in this context is solely for descriptive and informational purposes and constitutes nominative fair use under applicable trademark laws.
  • index page
  • uop description
  • ADC
  • ADD
  • AND
  • BSF
  • BSR
  • BSWAP
  • BTEST
  • DIV
  • FANDNOT
  • FCALCTW
  • FCMOV
  • FCOM
  • FMERGE
  • FMOV
  • FPEXTRACT
  • FPORDATATYPE
  • FPSIGNEXT
  • FREADROM
  • FXORS
  • IDIV
  • IMUL
  • INTEXTRACT
  • LEA
  • LOAD
  • MOVE
  • MOVEFROMCREG
  • MOVETOCREG
  • MUL
  • OR
  • PORTIN
  • PORTOUT
  • RCL
  • RCR
  • RDSEGFLD
  • ROL
  • ROR
  • SAL
  • SAR
  • SBC
  • SHL
  • SHR
  • SIGEVENT
  • STA
  • STRD
  • SUB
  • SUBR
  • TRANSPORTUIP
  • UOP
  • U_JCC
  • U_JMP
  • U_JMP_INDIR
  • WRSEGFLD
  • WUCONCAT
  • WUEXTRBK
  • WUINSERT
  • WUMERGE
  • XOR