本文旨在分析FreeBSD系统调用的amd64平台相关部分的代码,系统调用作为系统内核与外界交互的接口,了解其原理对如何扩展以及如何使用有很大的帮助,不同于x86平台的系统调用路径,amd64的平台调用依赖于syscall指令,接下来我记录一下.
1. 系统调用硬件知识(MSR) MSR是(Model-Specific Register)的缩写,是x86_64平台上CPU实现的一类寄存器,提供了对硬件或者软件相关功能的一些控制.具体内容参考《x86_64体系探索及编程》一书的详细介绍.这里介绍几个重点
1.1 使用MSR 读取MSR指令的汇编指令分别是rdmsr和wrmsr指令.
1.2 EFER扩展功能寄存器的使用 因为读取这个寄存器的某些位表示CPU是否支持MSR的syscal指令,x64下long-mode模式也是通过这个寄存器来开启和激活的.
如上图所示,第0位SCE位是syscall Enable的缩写,此位置1表示syscall指令可用.LME置1表示long-mode模式开启。EFER寄存器的地址为0xC0000080H,这个地址是固定的.
1.3 支持syscall的MSR寄存器 这里主要说明一下LSTSTR寄存器是64位CPU的系统入口点.执行syscall指令时将会将这个寄存器的函数地址弹出到EIP中执行,参考这篇文章 。
1.4 系统调用辅助指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 static __inline uint64_t rdmsr (u_int msr) { uint32_t low, high; __asm __volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr)); return (low | ((uint64_t )high << 32 )); } static __inline void wrmsr (u_int msr, uint64_t newval) { uint32_t low, high; low = newval; high = newval >> 32 ; __asm __volatile("wrmsr" : : "a" (low), "d" (high), "c" (msr)); }
2. 系统调用配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 void amd64_conf_fast_syscall (void ) { uint64_t msr; msr = rdmsr (MSR_EFER) | EFER_SCE; wrmsr (MSR_EFER, msr); wrmsr (MSR_LSTAR, pti ? (u_int64_t )IDTVEC (fast_syscall_pti) : (u_int64_t )IDTVEC (fast_syscall)); wrmsr (MSR_CSTAR, (u_int64_t )IDTVEC (fast_syscall32)); msr = ((u_int64_t )GSEL (GCODE_SEL, SEL_KPL) << 32 ) | ((u_int64_t )GSEL (GUCODE32_SEL, SEL_UPL) << 48 ); wrmsr (MSR_STAR, msr); wrmsr (MSR_SF_MASK, PSL_NT | PSL_T | PSL_I | PSL_C | PSL_D | PSL_AC); }
3. 系统调用举例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #define RSYSCALL(name) ENTRY(__sys_##name); \ WEAK_REFERENCE(__sys_##name, name); \ WEAK_REFERENCE(__sys_##name, _##name); \ mov $SYS_##name,%eax; KERNCALL; \ jb HIDENAME(cerror); ret; \ END(__sys_##name) #define KERNCALL movq %rcx, %r10; syscall
syscall指令会触发CPU加载MSR_LSTAR寄存器中的处理函数,具体调用过程可以参考这篇文章 。
4. 系统调用处理函数 系统调用的处理函数是汇编实现,在(amd64/amd64/exception.S,line:526)中.这段汇编代码实际是一个黏合剂,最终是为了调用amd64_syscall函数,这是c语言实现的.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 SUPERALIGN_TEXT IDTVEC (fast_syscall_pti) swapgs lfence IDTVEC (fast_syscall) swapgs lfence fast_syscall_common: call amd64_syscall
本文没有对系统调用的细节进行说明,比如系统调用时的参数传递和检查,系统调用时的现场环境保存和恢复.这里是说明amd64位下的系统调用和x86的32位下的系统调用的方式不同以及具体调用的硬件支持的原理,让我们清晰的看到操作系统的实现总是分成机器无关的部分和机器相关的部分,系统调用也不例外.