In x86-64 mode, only the FS and GS registers participate in a limited form of segmentation;
only their base addresses are used to calculate effective addresses.
Due in part to the requirement for per-CPU data, as well as the design of AMD's SYSCALL/SYSRET instructions in long mode, the GS register often holds a base address to a structure containing per-CPU data.
x86-64 用于支持 per-CPU data
The typical use of SWAPGS is to keep the 'user' GS (which likely has a base address of 0) in the GSBase MSR, and the address of the kernel's per-CPU structure in KernelGSBase.
用户态的时候设置为 GSBase MSR 一般值为 0,进入内核态设置为 KernelGSBase 的值,指向 per-CPU structure
b *interrupt_entry+11
1: x/5i $pc
0xffffffff81c00920 <interrupt_entry>: clac
0xffffffff81c00923 <interrupt_entry+3>: cld
**0xffffffff81c00924 <interrupt_entry+4>: test BYTE PTR [rsp+0x18],0x3 // test cs, 0x3**
0xffffffff81c00929 <interrupt_entry+9>: je 0xffffffff81c0096c <interrupt_entry+76>
**=> 0xffffffff81c0092b <interrupt_entry+11>: swapgs**
0xffffffff81c0092e <interrupt_entry+14>: nop DWORD PTR [rax]
0xffffffff81c00931 <interrupt_entry+17>: push rdi
0xffffffff81c00932 <interrupt_entry+18>: xchg ax,ax
0xffffffff81c00934 <interrupt_entry+20>: mov rdi,cr3
**(gdb) i reg gs_base**
gs_base 0x0 0
(gdb) ni
1: x/5i $pc
=> 0xffffffff81c0092e <interrupt_entry+14>: nop DWORD PTR [rax]
0xffffffff81c00931 <interrupt_entry+17>: push rdi
0xffffffff81c00932 <interrupt_entry+18>: xchg ax,ax
0xffffffff81c00934 <interrupt_entry+20>: mov rdi,cr3
0xffffffff81c00937 <interrupt_entry+23>: bts rdi,0x3f
**(gdb) i reg gs_base**
gs_base 0xffff88807da00000
https://www.kernel.org/doc/Documentation/x86/entry_64.txt
Dealing with the swapgs instruction is especially tricky.
Swapgs toggles whether gs is the kernel gs or the user gs.
The swapgs instruction is rather fragile: it must nest perfectly and only in single depth, it should only be used if entering from user mode to kernel mode and then when returning to user-space, and precisely so. If we mess that up even slightly, we crash.
DECLARE_PER_CPU(struct task_struct *, current_task);
(gdb)
Breakpoint 1, 0xffffffff81071e0e in get_current () at ./arch/x86/include/asm/current.h:15
15 return this_cpu_read_stable(current_task);
1: x/5i $pc
**=> 0xffffffff81071e0e <check_kill_permission+78>: mov rbx,QWORD PTR gs:0x15d00**
#define this_cpu_read_stable(var) percpu_stable_op("mov", var)
asm(op "q "__percpu_arg(P1)",%0"
#define __percpu_arg(x) __percpu_prefix "%" #x
#define __percpu_prefix "%%"__stringify(__percpu_seg)":"
#define __percpu_seg **gs**