Blog
Blog copied to clipboard
Chapter 5 System Calls
系统调用为用户态程序提供了与内核交换的接口。
一般的,用户程序通常与API打交道而非系统调用,如下图所示。
POSIX
is composed of a series of standards from the IEEE that aim to provide a portable operating system standard roughly based on Unix.
可以将POSIX
理解为规范系统调用和用户态API的标准。
系统调用
SYSCALL_DEFINE0(getpid)
{
return task_tgid_vnr(current); // returns current->tgid
}
SYSCALL_DEFINE0
是个宏,后面的0表示没有参数。
系统调用号
每个系统调用都有一个系统调用号。sys_call_table
存放了内核已经注册的系统调用。x86架构通过int $0x80
发起中断进程内核态,并执行系统调用处理函数,eax
寄存器存放了系统调用号。 On x86-32, the registers ebx, ecx, edx, esi, and edi contain, in order, the first five arguments.
参数检查
系统调用必须检查所有参数以确保他们是有效且合法的。其中一项比较重要的检查是检查用户传递的指针。
- 指针指向进程地址空间中的一个内存区域。进程不能欺骗内核读取其他人的数据
- 如果读取,则内存标记为可读。如果是写,内存被标记为可写。如果执行,则内存被标记为可执行。该进程必须不能绕过内存访问限制
对写入用户态,使用copy_to_usr()
;对于从用户态读取,使用copy_from_user
。这两个函数都有可能阻塞,例如用户内存被交换到磁盘,进程需要睡眠直到page fault将磁盘页面放回内存中。capable()
函数进行权限检查,例如capable(CAP_SYS_NICE)
检查是否有权限修改nice值。
系统调用上下文
系统调用上下文属于进程上下文。因为其他进程可能调用相同的系统调用系统保证系统调用是可重入的。
用户态直接访问系统调用
例如使用open
,如下
#define __NR_open 5
_syscall3(long, open, const char *, filename, int, flags, int, mode)
第一个参数是返回类型,第二个是系统调用名字,后面的想系统调用参数。 不过一般不推荐这么做。