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

swapgs

https://wiki.osdev.org/SWAPGS

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.

per-cpu variable

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**