1.定义
一般情况下,用户进程是不能访问内核的。它既不能访问内核中的数据,也不能调用内核中的函数。但系统调用是一个例外。Linux内核中设置了一组用于实现各种系统功能的函数,称为系统调用。用户可以通过系统调用命令在自己的应用程序中调用它们。
2.和函数调用的区别系统调用和普通的函数调用非常相似,区别仅仅在于,系统调用由操作系统内核实现,运行于内核态;而普通的函数调用由函数库或用户自己提供,运行于用户态。
3.库函数
Linux系统还提供了一些C语言函数库,这些库函数对系统调用进行了一些包装和扩展。
4.系统调用数
在2.6.36/2.6.38 版内核中,共有系统调用369个,可在arch/arm/include/asm/unistd.h中找到它们。
5.工作原理概述void main()
{
creat(“testfile”,0666)<0)
}
应用程序首先用适当的值填充寄存器,然后调用一个特殊的指令跳转到内核某一固定的位置,内核根据应用程序所填充的固定值来找到相应的函数执行。
(1) 适当的值
在文件include/asm/unistd.h中为每个系统调用规定了唯一的编号,这个号称为系统调用号
#define __NR_restart_syscall(__NR_SYSCALL_BASE+ 0)
#define __NR_exit (__NR_SYSCALL_BASE+ 1)
#define __NR_fork (__NR_SYSCALL_BASE+ 2)
#define __NR_read (__NR_SYSCALL_BASE+ 3)
(2) 特殊的指令
在Intel CPU中,这个指令由中断0x80实现。
在ARM中,这个指令是SWI(已经重命名为SVC指令)。
(3) 固定的位置
在ARM体系中,应用程序跳转到的固定内核位置是ENTRY(vector_swi) <entry-common.S>。
(4) 相应的函数
内核根据应用程序传递来的系统调用号,从系统调用表sys_call_table找到相应的内核函数。
CALL(sys_restart_syscall)
CALL(sys_exit)
CALL(sys_fork_wrapper)
6.实现系统调用向内核中添加新的系统调用,需要执行 3个步骤:
(1) 添加新的内核函数
(2) 更新头文件 unistd.h
(3) 针对这个新函数更新系统调用表calls.S
7.系统调用举例
(1) 在kernel/sys.c中添加函数:
asmlinkage int sys_add(int a, int b)
{
return a+b;
}
/* asmlinkage:使用栈传递参数 */
(2) 在arch/arm/include/asm/unistd.h中添
加如下代码:
#define __NR_add (__NR_SYSCALL_BASE+370)
(3) 在arch/arm/kernel/calls.S中添加代码,指向新实现的系统调用函数:
CALL(sys_add)
(4)使用系统调用
#include<stdio.h>
#include<linux/unistd.h>
int main()
{
int result;
result=syscall(370,3,4);
printf("result=%d\n",result);
return 0;
}