系统调用

一 工作原理
一般情况下,用户进程是不能访问内核的。它既不能访问内核所在的内存空间,也不能调用内核中的函数。系统调用是一个例外。其原理是进程先用适当的值填充寄
存器,然后调用一个特殊的指令,这个指令会让用户程序跳转到一个事先定义好的内核中的一个位置,内核根据应用程序所填充的固定值来找到相应的函数。

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);
}

编译之后,移至目标开发板运行。

posted on 2012-10-20 20:55  Daniel.G  阅读(390)  评论(0编辑  收藏  举报