操作系统是用户与计算机之间的接口,用户通过操作系统的帮助,可以快速、有效和安全可靠地使用计算机系统中的各种资源来解决自己的问题。为了使用户方便的使用操作系统,OS向用户提供了“用户与操作系统的接口”。这种接口支持用户与操作系统之间进行交互,这些接口可以被分为命令和程序接口两种。前者直接提供给用户在键盘终端上使用;后者则是提供给用户(主要是程序员)编程时使用。而要学习系统调用,首先要从程序接口入手。
1、 程序接口
程序接口是操作系统专门为用户程序设置的,也是用户程序取得OS服务的唯一途径。程序接口通常由系统调用组成。在每个操作系统中,通常都有几十上百条系统调用,它们的作用各有不同,有的用于进程控制、有的用于存储管理、有的用于文件管理等等。在MS WINDOWS下面进行过WIN32编程的人员应该对windows提供的API函数有一定的印象,这些API函数就是windows操作系统提供给程序员的系统调用接口。而Linux作为一个操作系统,当然有它自己的系统调用。
2、 系统调用
通常,在OS的核心中都设置了一组用于实现各种系统功能的子程序,并将它们提供给程序员调用。程序员在需要OS提供某种服务的时候,便可以调用一条系统调用命令,去实现希望的功能,这就是系统调用。各个不同的操作系统有各自的系统调用,正如前文所讲的windows API,便是windows的系统调用,linux的系统调用与之不同的是linux由于内核代码完全公开,所以可以细致的分析出其系统调用的机制。
3、 系统调用和普通过程的区别
n 运行于不同的系统状态
如前所述,用户程序可以通过系统调用进入系统空间,而普通过程则只能在用户空间当中运行。
n 通过软中断切换
由于用户程序使用系统调用后要进入系统空间,所以需要调用一个软中断;而普通过程在被调用时没有这个过程。
4、 系统调用的类型
系统调用的作用与它所在的操作系统有密切关系,根据操作系统的性质不同,它们所提供的系统调用会有一定的差异,不过对于普通操作系统而言,应该具有下面几类系统调用。
⑴ 进程控制类型。
⑵ 文件操纵类型。
⑶ 进程通信类型。
⑷ 数据管理类型。
5、 系统调用的实现机制。
由于操作系统的不同,其系统调用的实现方式可能不同,然而实现机制应该是大致相同的,一般包含下面几个步骤:
n 设置系统调用号
在系统当中,往往设置多条系统调用命令,并赋予每条系统调用命令一个唯一的系统调用号。
n 处理系统调用
操作系统当中有个一张系统调用入口表。表中的每个表目都对应一条系统调用命令,它包含有该系统调用自带参数的数目、系统调用命令处理程序的入口地址等等。操作系统内核便是根据所输入的系统调用号在该表中查找到到相应的系统调用,进而转入它的入口地址去执行它。
6、 增加自己的系统调用
tar jxvf linux-2.6.18.i686.tar.bz2
cd linux-2.6.18.i686
1) 添加源代码
第一个任务是编写加到内核中的源程序,也就是将要加到一个内核文件中去的一个函数,该函数的名称应该是新的系统调用名称前面加上sys_标志。假设新加的系统调用为foo(),在linux-2.6.18.i686/kernel/sys.c文件中添加源代码,如下所示:
asmlinkage int sys_foo(int x) //foo修改为自己要加的
{
printk(“in kernel hello world! %d\n”,x);
}
2) 连接新的系统调用
添加新的系统调用之后,下一个任务是让LINUX内核的其余部分知道该程序的存在。为了从已有的内核程序中增加到新函数的链接,需要进行下面的操作。
进入目录linux-2.6.18.i686/include/asm-i386/,打开文件unistd.h。这个文件包含了系统调用清单,用来给每个系统调用分配一个唯一的号码。系统调用号的定义格式如下:
#define __NR_name NNN
其中,name用系统调用名称代替,而NNN是该系统调用对应的号码。应该将新的系统调用名称加到清单的最后,并给它分配已经用到的系统调用号后面的一个号码。比如:
#define __NR_foo 222
此处的系统调用号便是222。LINUX内核自身用到的系统调用号已经用到221了。而如果读者还要自行增加系统调用,就必须从223开始。
在ifdef __KERNEL__前加上 define __KERNEL__
另外一个需要进行的操作是进入目录linux-2.6.18.i686/arch/i386/kernel/,打开文件syscall_table.S。该文件中有类似下面的清单:
那么就在该表的最后加上:
.long sys_foo
3) 重新编译内核
为了使新的系统调用生效,需要重建LINUX的内核。必须以root身份登录。进入目录linux-2.6.18.i686/,重建内核:
配置内核:
拷贝当前系统配置:
cp /boot/config-2.6.*** .config
添加配置:
make menuconfig
如果虚拟机硬盘用的是SCSI的,则选上如下选项:
Device Drivers->
SCSI device support->
SCSI low-level drivers->
<M> BusLogic SCSI support
[*] Omit FlashPoint support
5. 编译
make (编译内核和模块)
6. make modules_install (安装模块)
7. make install (安装内核文件)
在此之前看boot/grub/grub.conf区别,重启选择启动内核。
8. 重新启动,选择“.....prep”内核来启动
4) 编写测试程序
参考mycall.c 来完成自己系统调用的测试。注意头文件的包含路径
运行的时候注意要切换到字符界面下
Shift+ctrl+alt+F1 : 切换到字符界面
Atl+F7 : 切换到图形界面
编译运行结果如下: