Linux系统调用实验
【实验目的】
理解系统调用的概念,熟悉系统调用的用法。
【实验设备】
装有Linux操作系统的PC机一台。
【实验要求】
编程创建系统调用mycall(),实现功能是显示字符串到屏幕上。
编译2.4.18内核,用新内核引导系统。
编程调用自己创建的系统调用。
【实验原理】
操作系统是用户与计算机之间的接口,用户通过操作系统的帮助,可以快速、有效和安全可靠地使用计算机系统中的各种资源来解决自己的问题。为了使用户方便的使用操作系统,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
生成 linux2.6.18。i686 文件夹.
1) 添加源代码
第一个任务是编写加到内核中的源程序,也就是将要加到一个内核文件中去的一个函数,该函数的名称应该是新的系统调用名称前面加上sys_标志。假设新加的系统调用为foo(),在linux2.6.18.i686/kernel/sys.c文件最后添加源代码,如下所示:
asmlinkage int sys_mycall(int x)
{
printk(“hello this is my new kernel\n”);
printk(“%d\n”,x);
}
2) 连接新的系统调用
添加新的系统调用之后,下一个任务是让LINUX内核的其余部分知道该程序的存在。为了从已有的内核程序中增加到新函数的链接,需要进行下面的操作。
进入目录linux2.6.18.i686/include/asm-i386/,打开文件unistd.h。这个文件包含了系统调用清单,用来给每个系统调用分配一个唯一的号码。系统调用号的定义格式如下:
#define __NR_name NNN
其中,name用系统调用名称代替,而NNN是该系统调用对应的号码。应该将新的系统调用名称加到清单的最后,并给它分配已经用到的系统调用号后面的一个号码。比如:
#define __NR_mycall 319
此处的系统调用号便是319。LINUX内核自身用到的系统调用号已经用到318 了。而如果读者还要自行增加系统调用,就必须从320开始。
更新NR_syscalls(NR_syscalls宏为系统调用个数的总数),这个宏大约在330行左右。
比如原先系统调用个数为318个,增加一个系统调用后
修改 #define NR_syscalls 318
为 #define NR_syscalls 319
另外一个需要进行的操作是进入目录linux2.6.18.i686/arch/i386/kernel/,打开文件syscall_table.S。该文件中有类似下面的清单:
ENTRY(sys_call_table)
.long sys_restart_syscall /* 0 – old “setup()” system call, used for restarting*/
.long sys_exit
.long sys_fork
那么就在该表的最后加上:
.long sys_mycall
3) 重新编译内核
为了使新的系统调用生效,需要重建LINUX的内核。必须以root身份登录。进入目录linux2.6.18.i686下,重建内核:
配置内核:
拷贝当前系统配置:
cp /boot/config-2.6.18-8.e15 .config
添加配置:
# make menuconfig
(make menuconfig 时遇到的问题:
scripts/kconfig/lxdialog/dialog.h:32:20: 错误:curses.h:没有此一档案或目录)
解决办法:
安装完ncurses-devel menuconfig就可以用了^^
安装命令:
rpm -ivh ncurses-devel-5.5-24.20060715.i386.rpm)
如果虚拟机硬盘用的是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 (安装内核文件)
装载内核
重新启动后选择Linux-2.6.18-prep启动,即可用新内核启动。(重启出现倒计时页面,把鼠标放在虚拟机区域单击,按上下键选择启动项)
4) 编写测试程序
编写测试程序如下所示:
编译运行结果如下:(注意必须在字符界面下运行,图形界面切换到字符界面按Ctl+Alt+Shift+F1,字符界面切换到图形界面按Alt+F7)
【实验作业】
1.创建一个自己的系统调用mycall(),实现功能:显示任意一串字符到屏幕上。
2.编程调用自己创建的系统调用。