您的位置:首页 > 运维架构 > Linux

内核驱动开发第五天linux系统调用

2015-03-10 20:37 169 查看
1.系统调用
一般情况下,用户进程是不能访问内核的。它既不能访问内核中的数据,也不能调用内核中的函数。但系统调用是一个例外。还有一个是中断
Linux内核中设置了一组用于实现各

种系统功能的子程序,称为系统调

用。用户可以通过系统调用命令在自

己的应用程序中调用它们。

2.区别
系统调用和普通的函数调用非常相

似,区别仅仅在于,系统调用由操作

系统内核实现,运行于内核态;而普

通的函数调用由函数库或用户自己提

供,运行于用户态。

3.库函数
Linux系统还提供了一些C语言函数

库,这些库对系统调用进行了一些包

装和扩展,这些库函数与系统调用的

关系非常紧密

4.系统调用数
在2.6.29 版内核中,共有系统调用332个,可

在arch/arm/include/asm/unistd.h中找到它

们。

5.使用系统调用
#include<time.h>

main()

{

time_t the_time;

the_time=time((time_t *)0); /*调用time系统调用*/

printf("The time is %ld\n",the_time);

}

/* 从格林尼治时间1970年1月1日0:00开始到现在的秒数。 */

6.工作原理
一般情况下,用户进程是不能访问内核的。它既不能访

问内核所在的内存空间,也不能调用内核中的函数。系

统调用是一个例外。

其原理是进程先用适当的值填充寄

存器,然后调用一个特殊的指令,这个指令会让用户程

序跳转到一个事先定义好的内核中的一个位置,内核根据应用程序所填充的固定值来找到相应的函数执行。
1.适当的值
在文件include/asm/unistd.h中为每一个系统调用规定了唯一的编号,这个号码称为系统调用号
  #define__NR_restart_syscall  (__NR_SYSCALL_BASE+0)
2.特殊的指令

v 在Intel CPU中,这个指令由中断0x80实现。

v 在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_dup3)

CALL(sys_pipe2)

/* 360 */
CALL(sys_inotify_init1)

具体流程

1.

#define __syscall(name) "swi\t" __NR_##name "\n\t“

int open( const char * pathname, int flags)

{
。。。。。。

__syscall(open);

。。。。。。

}

转化为

int open( const char * pathname, int flags)
{

。。。。。。

swi\t __NR_open

。。。。。。

}

2.
/* arch/arm/kernel/entry-common.S */

ENTRY(vector_swi)

......

..
....

....
..

......

adr tbl, sys_call_table

......

..
....

....
..

......

ldrcc pc, [tbl, scno, lsl #2]

......

......

......

@ load syscall table pointer

@ call sys_* routine

......

ENTRY(sys_call_table)

#include "calls.S"

3.

/* 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_dup3)

CALL(sys_pipe2)

/* 360 */
CALL(sys_inotify_init1)

/*************************************************

**************************************************/

通过反汇编c库来查看具体的系统调用过程

arm-linux-objdump -D -S libc.so.6 >log

通过分析反汇编的文件来查看具体的系统调用

/*************************************************

**************************************************/

7.实现系统调用

向内核中添加新的系统调用,需要执行 3

个步骤:

1. 添加新的内核函数

2. 更新头文件 unistd.h

3. 针对这个新函数更新系统调用表

calls.S

实现系统调用

1. 在kernel/sys.c中添加函数:

asmlinkage int sysMul(int a, int b)

{

int c;

c = a*b;

return c;

}
/*asmlinkage 使用锥栈进行参数传递*/
2. 在arch/arm/include/asm/unistd.h中添

加如下代码:

#define __NR_sysMul 361

3.在arch/arm/kernel/calls.S中添加代

码,指向新实现的系统调用函数:

CALL(sysMul)

8.调用方式
#include <stdio.h>

#include <linux/unistd.h>

main()

{

int result;

result =

syscall(361,1, 2);//调用系统调用

printf("result = ", result);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: