LINUX系统调用

系统调用:用户无法读写内核空间地址

系统调用抽象了文件系统和磁盘等。
系统调用包装安全。
linux中,系统调用是访问内核的唯一手段,除了异常和陷入外,它是唯一合法入口。

系统调用的流程

  1. 保存进程寄存器状态,栈状态。
  2. 将系统调用号,参数保存到相应的寄存器。
  3. 切换到内核态,使用进程的内核栈。
  4. 执行系统调用在内核栈中。
  5. 恢复上下文,返回用户空间。

c库API,POSIX和系统调用

glibc(GNU C Library)是一种C语言库,是GNU计划中的一部分,用于提供与C语言编写的程序运行时环境所需的标准C库支持。它是Linux系统中的默认C库

posix包装了系统调用函数。
c库的API包装了POSIX中的函数。

系统调用号

当用户空间执行一个系统调用时,进程不会提及名称,而是使用系统调用号。

系统调用处理程序

应用程序通知内核执行系统调用是靠软中断实现的。
通过引发一个异常促使系统切换到内核态去执行异常处理程序,在x86系统上预定义的中断号是128,通过指令int $0x80触发该中断,导致系统切换到内核执行128号异常处理程序。

将系统调用号传给内核:放到eax寄存器

在x86上,通过eax寄存器传递给内核。在陷入内核之前,进程就需要将系统调用号放入eax寄存器。

将系统调用参数传给内核:将参数放到多个寄存器中

系统调用返回值也防盗防寄存器:eax寄存器

系统调用中的参数验证

内核必须保证:

  1. 参数指针只能是用户空间的。
  2. 参数指针是进程自己的空间的。
  3. 是可读或者可写的。
    可以通过capable()函数来检查调用者是否有权操作资源。

用户空间和内核空间数据的互相拷贝

copy_to_user(src,dst,len);返回没能拷贝完成的字节数,如果成功为0
copy_from_user(src,dst,len);
示例:将用户空间的内容拷贝到内核空间,然后再拷贝到目标用户空间的系统调用silly_copy

SYSCALL_DEFINE3(silly_copy,unsigned long*,src,unsigned long*,dst,unsigned long len)
{
	unsigned long buf;//内核的地址空间
	if (!copy_from_user(&buf,src,len))
		return -EFAULT;	//出错返回标准-EFAULT
	if (!copy_to_user(dst,&buf,len))
		return -EFAULT:
	return len;
}

如果内容在磁盘上没有载入内存,两个方法都会引起阻塞休眠,直到缺页处理程序将该页载入物理内存。

系统调用的上下文:进程上下文

内核在执行系统调用时候处于进程上下文,进程的上下文包括了进程的状态、寄存器值、内存映射,内核栈等信息,此时current指向进程。
会进行上下文切换,切换为内核栈。
内核在进程的内核栈中执行,在这个过程中,内核栈被用来保存与内核执行相关的局部变量、寄存器状态等信息。每个进程都有自己的内核栈,用于保存内核执行过程中的局部变量、寄存器状态等信息。

你可能感兴趣的:(Linux,linux,运维,服务器)