Instruction
LKGS
Loads GS from a selector but puts the descriptor's base in the IA32_KERNEL_GS_BASE MSR instead of the GS base; ring 0 of 64-bit mode only.
- Extensions
- Forms
- 2 (2 Legacy)
- Data
- Intel XED v2026.08.23
LKGS loads GS from a 16-bit selector in a register or memory word, as MOV to GS does, with one difference: the base address from the descriptor goes into the IA32_KERNEL_GS_BASE MSR (C0000102H), with bits 63:32 cleared, and the base that GS holds now stays as it was. A 64-bit kernel can thus give a user thread its GS selector while it keeps using its own GS base; the user’s base waits in the MSR until SWAPGS or, with FRED, the return with ERETU swaps it in. Why kernels need that is on LKGS’s extension page.
Checks
The descriptor checks are those of a data segment load. A null selector, 0 to 3, is accepted and clears the MSR. Otherwise a selector past its table’s limit, a system descriptor, code that may not be read, or an RPL above the descriptor’s DPL raise #GP with the selector as the error code, and a descriptor that is not present #NP. LKGS raises #UD at CPL above 0, outside 64-bit mode and where CPUID.(EAX=07H,ECX=1):EAX bit 18 is clear. No flag changes.
In Linux
Linux 7.3’s arch/x86/include/asm/gsseg.h loads a user’s GS selector
with LKGS wherever the processor has it, and otherwise with an assembly
routine that runs SWAPGS, a MOV to GS and SWAPGS again with interrupts
off, so that no interrupt finds the user’s base in place. Its exception
table entry for LKGS zeroes the register and runs LKGS again, so a
selector that faults ends up as the null selector. The kernel writes
the instruction as bytes (F2 0F 00 F7, lkgs %di) for older
assemblers; GNU as 2.44 and Clang 23 assemble the mnemonic, and neither
compiler has an intrinsic for it.
Not run here
The Zen 5 guest that ran the probe does not report LKGS in CPUID, so the probe left both forms unrun.
Forms
Operation
What the forms do, in pseudocode that our tests run against results recorded on real processors. How to read.
if CPL > 0:
fault(UD) # #UD, not #GP
s = src.read() # 16 bits
if s & ~3 == 0:
gs = s # null, as MOV GS loads one
kernel_gs_base = 0
else:
d = descriptor(s) # #GP(sel) past its table's limit
if not d >> 44 & 1:
fault(GP, s & ~3) # a system descriptor
if d >> 43 & 1 and not d >> 41 & 1:
fault(GP, s & ~3) # code that may not be read
if s & 3 > d >> 45 & 3:
fault(GP, s & ~3) # RPL above the DPL
if not d >> 47 & 1:
fault(NP, s & ~3)
gs = s # with the descriptor's attributes
b = d >> 16 & 0xFFFFFF | d >> 56 << 24
kernel_gs_base = b # 32 bits: bits 63:32 cleared
# unlike MOV GS, the GS base (gsbase) stays as it was: the new base
# waits in KERNEL_GS_BASE for SWAPGS or ERETUNot run on a processor: the Zen 5 guest that ran the probe does not report LKGS in CPUID.
Operands
| Operand | Kind | Action |
|---|---|---|
LKGS r/m16 64-bit mode only | ||
r/m16 | explicit | read |
IA32_KERNEL_GS_BASE | implicit | write |
Flags
None: XED records no flag that the forms test or change.
Attributes
What else XED records about the forms. How to read.
- All forms
- privileged: CPL 0 only; may abort a TSX transaction
CPUID and processors
Each form belongs to an XED ISA set. A form can be used when the processor reports every CPUID bit of one of its ISA set's alternatives.
| ISA set | CPUID | Processors |
|---|---|---|
LKGS | LKGS | Panther Lake, Nova Lake, Diamond Rapids, Zen 6 |
Sources
- Intel XED v2026.08.23 (commit
0bcb6237345c): forms, encodings, operands, flags, exception classes, attributes, ISA sets, CPUID bits and chip model. - The CPU data of x86-64.net: Zen 3 to Zen 6, from GCC’s
-marchfeature sets and AMD’s Processor Programming References, which the page of each processor cites. - Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 2 (325383-093, September 2026): Volume 2A, page 3-556 (LKGS)
- Flexible Return and Event Delivery (FRED) Specification (346446-009)
- Linux 7.3: arch/x86/entry/entry_32.S, entry_64.S and entry_64_fred.S, arch/x86/include/asm/gsseg.h, arch/x86/kernel/fred.c (SYSEXIT, LKGS and ERETS in the kernel's entry code)
The tables are derived from Intel XED, Copyright Intel Corporation, licensed under the Apache License 2.0; x86-64.net converted and reformatted them. The text is our own.