哈工大操作系统课程实验三

先上运行结果:
在这里插入图片描述
可以看到,是成功实现所需功能的了

一、实验目的

建立对系统调用接口的深入认识;
掌握系统调用的基本过程;
能完成系统调用的全面控制;
为后续实验做准备。

二、实验步骤

1.修改unistd.h
图片描述
其中新增代码为

#define __NR_iam 72
#define __NR_whoami 73

2.修改include/linux/sys.h
进入/home/shiyanlou/oslab/linux-0.11/中修改,有两个点需要修改:
1)仿照前面各个系统调用的写法,添加如下代码

extern int sys_iam();
extern int sys_whoami();

2)在sys_call_table中新加两个系统调用:

sys_iam,sys_whoami()

3.修改kernel/system_call.s
把nr_system_call的值从72改成74,因为我们加了两个系统调用

4.修改Makefile
Makefile 在代码树中有很多,分别负责不同模块的编译工作。我们要修改的是 kernel/Makefile。需要修改两处。

(1)第一处
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
添加了 who.o。

(2)第二处
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.编写3个.c文件
1)who.c

#define __LIBRARY__
#include<unistd.h>
#include <errno.h>
#include<asm/segment.h>
#include<linux/kernel.h>
char tmp[64] = {0};
int sys_iam(char * name){
	int k = 0;
	while(get_fs_byte(name+k)!='\0')
		k++;
	if (k>23){
		return -EINVAL;
	}
	else{
		int i = 0;
	while((tmp[i]=get_fs_byte(name+i))!='\0')
			i++;
		return k;	
	}
}

int sys_whoami(char * name, unsigned int size){
	int i = 0;
	while(tmp[i]!='\0'){
		i++;
	}
	if (size<i){
		return -EINVAL;
	}
	i = 0;
	while(tmp[i]!='\0'){
		put_fs_byte(tmp[i],name+i);
		i++;
	}
	return i;
}

然后是两个测试程序
2)iam.c

#define __LIBRARY__
#include <unistd.h>
_syscall1(int,iam,char*,name)

int main(int argc,char * argv[])
{
	iam(argv[1]);
	return 0;
}

3)whoami.c

#define __LIBRARY__
#include <unistd.h>
#include<stdio.h>

_syscall2(int,whoami,char*,name,unsigned int,size)

char arr[24];

int main()
{
	whoami(arr,24);
	printf("%s",arr);
	return 0;
}

三、注意事项

1)进入/home/shiyanlou/oslab/linux-0.11目录中才能执行make all指令
2)/home/shiyanlou/oslab/linux-0.11/include/asm/segment.h中的put_fs_XXXget_fs_XXX是用户空间和内核空间之间沟通的桥梁,以后还会用到
3)我在who.c里用string.h中的strlen函数时会在运行iam可执行文件时出现段错误,不清楚原因
4)sys_XXX(type arg1,...)是内核态,而其参数arg1是用户态的地址数据,要在内核态中获得参数中的地址数据,就需要通过get_fs_byte(arg1)函数获取,此时.c文件需要包含头文件asm/segment.h

四、实验结果

1.运行testlab2.c,得分为50%
图片描述

2.运行testlab2.sh,得分30%
图片描述

五、两个问答题

1.从 Linux 0.11 现在的机制看,它的系统调用最多能传递几个参数?你能想出办法来扩大这个限制吗?
查看linux-0.11/include/unistd.h,可看到最多只能传递3个参数;
扩大限制的方法:
i)定义一个结构体,这个结构体里面可以有很多参数,然后把结构体的入口地址当作参数进行传递
ii)用ebx,edx,ecx循环传值
iii)再加几个寄存器,比如edi,esi,ebp等

2.用文字简要描述向 Linux 0.11 添加一个系统调用 foo() 的步骤.
主要分成三个部分
1)修改Linux内核文件
2)在kernel文件夹下实现系统调用,并执行make all指令把新的系统调用加入到内核中
3)挂载Linux,并修改/usr/include/unistd.h

下面是详细的步骤

1)修改Linux内核文件

a.修改linux-0.11/include/unistd.h,增加如下代码:

#define __NR_foo 72

b.修改linux-0.11/include/linux/sys.h

添加代码:

extern int sys_foo();

并在sys_call_table表中新增一个系统调用sys_foo
c.修改linux-0.11/kernel/system_call.s中的nr_system_calls,使其增加1

d.修改linux-0.11/kernel/Makefile,在OBJS中添加foo.o,并添加生成foo.s和foo.o的依赖规则

2)在kernel文件夹下通过foo.c实现sys_foo()

3)在Ubuntu中挂载Linux系统,进入/usr/include/unistd.h中添加__NR_foo的宏定义

六、补充

1.我们通过open()来分析一下,用户和内核是怎么传数据的:
1)系统调用是用eax,ebx,ecx,edx来传递参数的
2)open所传递的文件名指针是由ebx传递。也就是说,进入内核后,我们通过ebx取出文件名字符串。但是,openebx指向的数据在用户空间,而当前要执行的是内核空间的代码,如何把用户空间中的ebx中的数据传到内核空间中?
3)然后接着看open的处理,获取用户地址空间(用户数据段)中的数据靠的是fs段寄存器,然后就通过sys_call_table表,跳转去执行sys_open()
4)在sys_open()中,将参数依次传递给了open_namei(),dir_namei(),get_dir(),最后,我们在get_dir()中可看到以下代码:

static struct m_inode * get_dir(const char * pathname)
{
    ……
    if ((c=get_fs_byte(pathname))=='/') {
        ……
    }
    ……
}

get_dir再往后,就没有函数了,所以一定是在这里完成了用户空间和内核空间的数据传送,这个传送,用的就是get_fs_byte,这个方法能够获取用户空间中一个字节的数据
5)所以,用户空间往内核空间传数据,用的是get_fs_byte;顺带一提,内核往用户空间传数据,用的是put_fs_byte()

七、参考博客

1.https://www.cnblogs.com/XiangfeiAi/p/4745548.html
2.https://blog.csdn.net/ccshijtgc/article/details/60327339
3.https://blog.csdn.net/wangyi_lin/article/details/6921110

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值