一 工作原理
一般情况下,用户进程是不能访问内核的。它既不能访问内核所在的内存空间,也不能调用内核中的函数。系统调用是一个例外。其原理是进程先用适当的值填充寄
存器,然后调用一个特殊的指令,这个指令会让用户程序跳转到一个事先定义好的内核中的一个位置,内核根据应用程序所填充的固定值来找到相应的函数。
1 适当的值
在文件(arch/arm/)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)
#define __NR_write (__NR_SYSCALL_BASE+ 4)
#define __NR_open (__NR_SYSCALL_BASE+ 5)
#define __NR_close (__NR_SYSCALL_BASE+ 6)
2 特殊的指令
* 在Intel CPU中,这个指令由中断0x80实现。
* 在ARM中,这个指令是SWI(已经重命名为SVC指令)。
3 固定的位置
在ARM体系中,应用程序跳转到的固定内核位置是ENTRY(vector_swi) <entry-common.S>
4 相应的函数
内核根据应用程序传递来的系统调用号,从系统调用表sys_call_table找到相应的内核函数。(arch/arm/)kernel/calls.S
/* 0 */ CALL(sys_restart_syscall)
CALL(sys_exit)
CALL(sys_fork_wrapper)
CALL(sys_read)
CALL(sys_write)
/* 5 */ CALL(sys_open)
CALL(sys_close)
二 实现系统调用
向内核中添加新的系统调用,需执行以下3个步骤:
1 添加新的内核函数 <kernel/sys.c>
2 更新头文件unistd.h <(arch/arm/)include/asm/unistd.h>
3 针对这个新函数更新系统调用表call.S <(arch/arm/)kernel/calls.S>
example:
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+365)
3.在arch/arm/kernel/calls.S中添加代
码,指向新实现的系统调用函数:
CALL(sys_add)
/*****************重新编译内核 移植到目标开发板**********************/
三 使用系统调用:
#include<stdio.h>
#include<linux/unistd.h>
int main(void)
{
int result;
result = syscall(365, 1, 2);
printf("result =", result);
}
编译之后,移至目标开发板运行。