amd64中系统调用指令
syscall and sysret
使用syscall指令需要在IA32_EFER这个MSR寄存器开启SCE
进入长模式前 使用:
mov ecx, 0xC0000080 ; Read from the EFER MSR.
rdmsr
or eax, 0x00000101 ; Set the LME bit.
wrmsr
IA32_EFER寄存器如下图

syscall
syscall只能实现ring3 到 ring0的调用
使用前需要在MSR寄存器写入段寄存器值和入口地址

在64bit模式中 LSTAR寄存器指定了SYSCALL的入口地址
STAR寄存器的48-63位存放ring0的CS 和 SS(忽略)
SFMASK寄存器指定了SYSCALL SYSRET如何处理rflags
sysret
sysret只能实现ring0 到 ring3的调用
主要工作为
- 把RIP值设定成RCX
- 切换CS, 根据下面约定(64 bit)

3. rflags处理,RFLAGS由r11寄存器的值恢复
RFLAGS ← (R11 & 3C7FD7H) | 2;
(* Clear RF, VM, reserved bits; set bit 1 *)
swappgs
KernelGSBase 是一个MSR寄存器 等于是装一个GS寄存器值的变量
swappgs将KernelGSBase与当前GS段寄存器的base做交换
当用户态使用syscall进入内核,但syscall并不会自动处理内核栈,此时的rsp仍然是用户态的rsp, 系统调用不会使用用户态的栈, 可以把内核的一段临时空间放在KernelGSBase中,使用swappgs切换内核临时空间,在sysret前再次调用swappgs重新切换用户态的状态.
这里指的内核栈属于per CPU的内核临时空间

例如可以把用户态的rsp保存在临时空间,切换内核栈rsp,然后把用户态的rsp push到内核栈。
获取per CPU临时空间的指令 假设swappgs已经调用且KernelGSBase设置了正确的地址
