概述
1、系统调用 在用户空间进程和硬件 设备之间增加了一具中间层。其作用如下:
(1)为用户空间提供了一种硬件 的抽象接口。
(2)保证了系统的稳定 和安全
(3)每个进程 运行在虚拟系统中,而在用户空间和系统的其余部分提供这样一层公共接口。
2、系统调用是用户空间访问内核的唯一手段,不能直接调用内核函数
3、一般情况下用户程序通过在用户空间实现的应用编程接口(API)而不是直接通过系统调用 来编程 。最流行的应用编程接口基于POSIX标准 。
4、访问系统调用通常通过C库中定义的函数调用 来进行。系统调用 在出现错误 时,C库会所错误 码写入errno全局变量,可通过perror()库函数将该 变量翻译成用户可理解的错误字符串。
5、系统调用 在内核中的实现举例:
//get_pid:取得进程PID
//DEFINE0后面的0表示调用时参数为0
SYSCALL_DEFINE0(getpid){
return task_tgid_vnr(current);//返回current->tgid
}
SYSCALL_DEFINE是一个宏,展开如下:
asmlinkage long sys_getpid(void)
asmlinkage是一个编译指令,通知编译器仅从栈中提取该函数的参数。所有系统调用 都需要这个限定词
此外,注意:get_pid在内核定义为sys_getpid(),这是LINUX系统调用在内核定义时应遵守的命名规则。
6、每个系统调用 被 赋予一个系统调用号,关联唯一的系统调用。
7、sys_ni_syscall()为LINUX定义的一个未实现的系统调用,即无效系统调用 ,只返回-ENOSYS
8、内核在sys_call_table中记录了系统调用表所有已经注册过的系统调用的列表,在x86-64中,定义于arch/i386/kernel/syscall_64.c,为每个有效的系统调用指定了唯一的系统调用号。
9、内核空间的系统调用函数定义在受保护的地址空间中。调用内核的唯一方式是通知内核,靠软中断袜,在X86系统上预定义的软中断号128,通过int $0x80触发该中断 ,该指令会触发一个异常,并导致系统切换到内核态,执行128号异常处理程序(程序名字为system_call()),最近,X86处理器增加了一条sysenter指令,比软中断更快更专业。
10、系统调用的相关参数
(1)通过eax寄存器将系统调用号传递给内核。在陷入内核之前,用户空间将相应系统调用对应的号放入eax中。
(2)system_call函数要检查系统调用号的有效性,不然就是一个无效系统调用。通过传入的系统调用号与NR_syscalls比较来检查有效性。大于或等于 NR_syscalls,该函数返回 -ENOSYS,表示调用失败,否则可继续执行对应的系统调用:
call *sys_call_table(,%rax,8)
sys_call_table在64位系统下,以64位(8字节)存放,32位4字节,上例中,最后一个参数为8,表示为64位系统。
(3)通过其它寄存器传递参数。在x86-32系统上,ebx、ecx、edx 、esi、edi按顺序 存放前5个参数,**如果需要6个或更多,则使用一个单独的寄存器存放放指向所有这些参数在用户空间中的地址指针。
注意:系统调用号相关错误,返回-ENOSYS
11 、系统调用实现
(1)实现新的系统调用 首先决定其用途,其次考虑接口设计,为将来多做考虑。然后,注意只是提供机制,不能提供策略,最后当写一个系统调用时,时刻注意可移植性和健壮性。
(2)系统调用实现时,必须验证传入参数的合法性,更重要是要验证用户提供的参数指针的有效性:
A.指针指向的内存区域属于用户空间
B.指针指向的内存区域在进程的地址空间
C.如果读,该内存应被标记为可读,如果写,该内存应标记 可写如果可执行,应标记为可执行。
(3)用户空间的数据是不能直接使用,需要在内核空间和用户空间进行来回COPY
A.向用户空间写:
copy_to_user()
B.从用户空间读
copy_from_user()
C.最后一个参数是需要COPY的数据长度(字节数)
D.发生错误返回 -EFAULT
12、系统允许检查针对 特定资源的特殊权限,调用者可使用capable()函数来检查是否有权对指定资源进行操作,返回非0表示有权,返回0表示无权。
具体返回值看
linux/capability.h
最后
以上就是英俊水壶为你收集整理的linux内核杂记(13)-系统调用(1)的全部内容,希望文章能够帮你解决linux内核杂记(13)-系统调用(1)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复