系统调用(syscall”)是用户级程序要求操作系统为它做某些事情的途径。
所有的系统调用都需要asmlinkage限定词。asmlinkage限定词用于通知编译器进从栈中提取该函数的参数。
在Linux中,每个系统调用被赋予一个系统调用号,这样,通过这个独一无二的号就可以关联系统调用,而不是系统调用的名称。系统调用号相当关键,一旦分配就不能再有任何变更,否则编译好的应用程序就会崩溃。
Linux有一个“未实现”系统调用sys_ni_syscall(),它除了返回-ENOSYS外不做任何其他工作,这个错误号就是专门针对无效的系统调用而设的。如果一个系统调用被删除或是不可用,这个函数就负责“填补空位”。
内核记录了系统调用表中的所有已注册过的系统调用的列表,存储在sys_call_table中。
powerpc 32位的系统调用处理程序是DoSyscall,定义在在arch/powerpc/kernel/head_32.S
/* System call */
. = 0xc00
SystemCall:
EXCEPTION_PROLOG
EXC_XFER_EE_LITE(0xc00, DoSyscall)
EXCEPTION_PROLOG 是一个宏,负责从用户空间到内核空间的切换,这需要保存用户进程的寄存器状态。使用此例程的地址和函数 DoSyscall
的地址来调用 EXC_XFER_EE_LITE。最后,某些状态将会被保存,DoSyscall 将会被调用。DoSyscall函数最终使用系统调用号将系统调用表的地址和索引加载到它。DoSyscall 找到正确的系统调用地址后,它将控制权转交给那个系统调用。
powerpc 64位的系统调用处理程序是system_call_common定义在在arch/powerpc/kernel/head_64.S
#define _NR_mycall 356
修改__NR_syscalls的值,-表示原来的值,+表示重新定义的值。
-#define __NR_syscalls 356
+#define __NR_syscalls 357
在kernel/sys.c定义系统调用。
SYSCALL_DEFINE1(mycall, unsigned int, len)
{
...
}
宏SYSCALL_DEFINEn,其中n是从1到6,代表传递给系统调用的参数个数,第一个参数是系统调用的名称,后面的参数是按照系统调用参数的顺
序排列的每个参数的类型和名称。
在相应的systbl.h文件把系统调用号添加到系统调用表中。具体操作如下:
SYSCALL(get_cpu_clock)
系统调用创建容易且使用方便。
Linux系统调用的高性能显而易见。
问题是:
你需要一个系统调用号。系统调用被加入文档内核后就被固化了,为了避免应用程序的崩溃,它不允许做改动。
需要将系统调用分别注册到每个需要支持的体系结构中去。
在脚本中不容易调用系统调用,也不能从文件系统直接访问系统调用。
如果仅仅进行简单的信息交换,系统调用就大材小用了。
替代方法:
创建一个设备节点,通过read()和write()访问它。用ioctl进行特别的设置操作和获取特别信息。
一些接口如信号量,可以用文件描述符表示以进行操作。
所有的系统调用都需要asmlinkage限定词。asmlinkage限定词用于通知编译器进从栈中提取该函数的参数。
在Linux中,每个系统调用被赋予一个系统调用号,这样,通过这个独一无二的号就可以关联系统调用,而不是系统调用的名称。系统调用号相当关键,一旦分配就不能再有任何变更,否则编译好的应用程序就会崩溃。
Linux有一个“未实现”系统调用sys_ni_syscall(),它除了返回-ENOSYS外不做任何其他工作,这个错误号就是专门针对无效的系统调用而设的。如果一个系统调用被删除或是不可用,这个函数就负责“填补空位”。
内核记录了系统调用表中的所有已注册过的系统调用的列表,存储在sys_call_table中。
powerpc 32位的系统调用处理程序是DoSyscall,定义在在arch/powerpc/kernel/head_32.S
/* System call */
. = 0xc00
SystemCall:
EXCEPTION_PROLOG
EXC_XFER_EE_LITE(0xc00, DoSyscall)
EXCEPTION_PROLOG 是一个宏,负责从用户空间到内核空间的切换,这需要保存用户进程的寄存器状态。使用此例程的地址和函数 DoSyscall
的地址来调用 EXC_XFER_EE_LITE。最后,某些状态将会被保存,DoSyscall 将会被调用。DoSyscall函数最终使用系统调用号将系统调用表的地址和索引加载到它。DoSyscall 找到正确的系统调用地址后,它将控制权转交给那个系统调用。
powerpc 64位的系统调用处理程序是system_call_common定义在在arch/powerpc/kernel/head_64.S
如何新增一个系统调用?
以Powerpc平台为例:
首先在相应的unistd.h文件里定义好系统调用号,该系统调用号是未被使用的。#define _NR_mycall 356
修改__NR_syscalls的值,-表示原来的值,+表示重新定义的值。
-#define __NR_syscalls 356
+#define __NR_syscalls 357
在kernel/sys.c定义系统调用。
SYSCALL_DEFINE1(mycall, unsigned int, len)
{
...
}
宏SYSCALL_DEFINEn,其中n是从1到6,代表传递给系统调用的参数个数,第一个参数是系统调用的名称,后面的参数是按照系统调用参数的顺
序排列的每个参数的类型和名称。
在相应的systbl.h文件把系统调用号添加到系统调用表中。具体操作如下:
SYSCALL(get_cpu_clock)
系统调用的优缺点
系统调用创建容易且使用方便。
Linux系统调用的高性能显而易见。
问题是:
你需要一个系统调用号。系统调用被加入文档内核后就被固化了,为了避免应用程序的崩溃,它不允许做改动。
需要将系统调用分别注册到每个需要支持的体系结构中去。
在脚本中不容易调用系统调用,也不能从文件系统直接访问系统调用。
如果仅仅进行简单的信息交换,系统调用就大材小用了。
替代方法:
创建一个设备节点,通过read()和write()访问它。用ioctl进行特别的设置操作和获取特别信息。
一些接口如信号量,可以用文件描述符表示以进行操作。
把增加的信息作为一个文件放在sysfs的合适位置。
参考文档:
《Linux内核设计与实现》
理解Linux的系统调用 http://os.51cto.com/art/200512/13510.htm