系统调用接口
前言
实验参考蓝桥云操作系统原理与实践_Linux - 蓝桥云课 (lanqiao.cn)
https://www.lanqiao.cn/courses/115?spm=a2c6h.12873639.article-detail.7.7d6e4563wUBwKz
CSDN博主
https://blog.csdn.net/leoabcd12/article/details/119986747
其中代码插入使用的是PPT 和word编辑器
http://word.wd1x.com/
有任何错误请多多指正,祝好!!
一、 实验目的
- 建立对系统调用接口的深入认识;
- 掌握系统调用的基本过程;
- 能完成系统调用的全面控制;
- 为后续实验做准备。
二、 实验内容
此次实验的基本内容是:在 Linux 0.11 上添加两个系统调用,并编写两个简单的应用程序测试它们。
(1)iam()
第一个系统调用是 iam(),其原型为:
int iam(const char * name);
完成的功能是将字符串参数 name 的内容拷贝到内核中保存下来。要求 name 的长度不能超过 23 个字符。返回值是拷贝的字符数。如果 name 的字符个数超过了 23,则返回 “-1”,并置 errno 为 EINVAL。
在 kernal/who.c 中实现此系统调用。
(2)whoami()
第二个系统调用是 whoami(),其原型为:
int whoami(char* name, unsigned int size);
它将内核中由 iam() 保存的名字拷贝到 name 指向的用户地址空间中,同时确保不会对 name 越界访存(name 的大小由 size 说明)。返回值是拷贝的字符数。如果 size 小于需要的空间,则返回“-1”,并置 errno 为 EINVAL。
也是在 kernal/who.c 中实现。
(3)测试程序
运行添加过新系统调用的 Linux 0.11,在其环境下编写两个测试程序 iam.c 和 whoami.c。最终的运行结果是:
$ ./iam lizhijun
$ ./whoami
lizhijun
三、 实验步骤
- 实验前准备
首先通过如下的代码,将oslab文件夹里面的hit-oslab-linux-20110823.tar.gz完成linux环境的搭建
# 进入到 oslab 所在的文件夹
$ cd /home/shiyanlou/oslab/
# 解压,并指定解压到 /home/shiyanlou/
# 这样的话,在 /home/shiyanlou/oslab/ 中就能找到解压后的所有文件
$ tar -zxvf hit-oslab-linux-20110823.tar.gz \
-C /home/shiyanlou/
# 查看是否解压成功
$ ls -al
除了压缩包 hit-oslab-linux-20110823.tar.gz 之外,其他的就是压缩包中的内容
其次,请将 Linux 0.11 的源代码恢复到原始状态。首先输入以下代码将Linux恢复到原始状态
# 删除原来的文件
$ cd ~/oslab
$ sudo rm -rf ./*
# 重新拷贝
$ cp -r /home/teacher/oslab/* ./
2. 添加iam和whoami系统调用编号的宏定义(_NR_xxxxxx),文件:include/unistd.h。
点击桌面的【home】【oslab】【Linux 0.11】【include】【unistd.h】,右键打开,在
【#define __NR_setregid 71 】后面加入如下两行代码(如图1所示)
#define __NR_whoami 72
#define __NR_iam 73
(图1)
3. 修改系统调用总数, 文件:kernel/system_call.s
点击【shiyanlou】【oslab】【linux-0.11】【kernel】,打开system_call.s文件
将nr_system_calls = 72改为nr_system_calls = 74 如图2所示
(图2)
4. 为新增的系统调用添加系统调用名并维护系统调用表,文件:include/linux/sys.h
【shiyanlou】【oslab】【linux-0.11】【include】,打开sys.h文件,
在extern int sys_setregid(); 后面添加如下的两行代码并将sys_setreuid,改为sys_setregid ,sys_whoami,sys_iam,如图3所示
extern int sys_whoamio;
extern int sys_iam();
(图3)
5. 为新增的系统调用编写代码实现,在linux-0.11/kernel目录下,创建一个文件 who.c。
在kernel目录下,右键新建文件文件,文件名为【who.c】,在打开的文件里面输入以下的代码,完成who.c文件的创建,如图4所示。
(图4)
#include <asm/segment.h>
#include <errno.h>
#include <string.h>
char _myname[24];
int sys_iam(const char *name)
{
char str[25];
int i = 0;
do
{
// get char from user input
str[i] = get_fs_byte(name + i);
} while (i <= 25 && str[i++] != '\0');
if (i > 24)
{
errno = EINVAL;
i = -1;
}
else
{
// copy from user mode to kernel mode
strcpy(_myname, str);
}
return i;
}
int sys_whoami(char *name, unsigned int size)
{
int length = strlen(_myname);
printk("%s\n", _myname);
if (size < length)
{
errno = EINVAL;
length = -1;
}
else
{
int i = 0;
for (i = 0; i < length; i++)
{
// copy from kernel mode to user mode
put_fs_byte(_myname[i], name + i);
}
}
return length;
}
- 修改 Makefile
要想让我们添加的 【kernel】【who.c】 可以和其它 Linux 代码编译链接到一起,必须要修Makefile 文件。Makefile 在代码树中有很多,分别负责不同模块的编译工作。这里要修改的是【kernel】【Makefile】。此处需要修改两处。首先将
OBJS = sched.o system_call.o traps.o asm.o fork.o \
panic.o printk.o vsprintf.o sys.o exit.o \
signal.o mktime.o
修改为
OBJS = sched.o system_call.o traps.o asm.o fork.o \
panic.o printk.o vsprintf.o sys.o exit.o \
signal.o mktime.o who.o
(如图6所示)
再者将
### Dependencies:
exit.s exit.o: exit.c ../include/errno.h ../include/signal.h \
../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \
../include/asm/segment.h
修改为
### Dependencies:
who.s who.o: who.c ../include/linux/kernel.h ../include/unistd.h
exit.s exit.o: exit.c ../include/errno.h ../include/signal.h \
../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \
../include/asm/segment.h
(图5修改前)
(图6第一处修改)
(图7第二处修改)
添加了who.s who.o: who.c …/include/linux/kernel.h …/include/unistd.h。
7. 编写测试程序
到此为止,内核中需要修改的部分已经完成,接下来需要编写测试程序来验证新增的系统调用是否已经被编译到linux-0.11内核可供调用。首先在oslab目录下编写iam.c,whoami.c。
Iam.c和whoami.c的代码下面所示。
Iam.c
/* iam.c */
#define __LIBRARY__
#include <unistd.h>
#include <errno.h>
#include <asm/segment.h>
#include <linux/kernel.h>
_syscall1(int, iam, const char*, name);
int main(int argc, char *argv[])
{
/*调用系统调用iam()*/
iam(argv[1]);
return 0;
}
whoami.c
/* whoami.c */
#define __LIBRARY__
#include <unistd.h>
#include <errno.h>
#include <asm/segment.h>
#include <linux/kernel.h>
#include <stdio.h>
_syscall2(int, whoami,char *,name,unsigned int,size);
int main(int argc, char *argv[])
{
char username[64] = {0};
/*调用系统调用whoami()*/
whoami(username, 24);
printf("%s\n", username);
return 0;
}
以上两个文件需要放到启动后的linux-0.11操作系统上运行,验证新增的系统调用是否有效,那如何才能将这两个文件从宿主机转到稍后虚拟机中启动的linux-0.11操作系统上呢?这里我们采用挂载方式实现宿主机与虚拟机操作系统的文件共享,在 oslab 目录下执行以下命令挂载hdc目录到虚拟机操作系统上。
sudo ./mount-hdc
(如图8所示)
(图8)
再通过以下命令将上述两个文件拷贝到虚拟机linux-0.11操作系统/usr/root/目录下,命令在oslab/目录下执行:
cp iam.c whoami.c hdc/usr/root
如果目标目录下存在对应的两个文件则可启动虚拟机进行测试了。如图9所示
(图9)
8. 编译
在【oslab】目录下输入./run,在调试的页面中输入以下代码.如图10所示。
[/usr/root]# gcc -o iam iam.c
[/usr/root]# gcc -o whoami whoami.c
(图10)
9. 运行测试
在下面的窗口输入两行代码,点击回车进行运行。如图11所示。
[/usr/root]# ./iam wcf
[/usr/root]# ./whoami
(图11)
10.命令执行后,很可能会报以下错误:
(图12)
这代表虚拟机操作系统中/usr/include/unistd.h文件中没有新增的系统调用调用号为新增系统调用设置调用号。【oslab】【hdc】【usr】【include】【unistd.h】打开unistd.h加入下面两行代码。
#define __NR_whoami 72
#define __NR_iam 73
再次执行:实验成功!
四、 实验总结
在本次实验中也遇到了不少的问题,其中不少部分是在CSDN和老师的指导下完成的,其中主要涉及到最困难的部分是后期编译和调试的时候,失败了好几次,后来通过查阅资料和各种辅助也也顺利完成了实验。