操作系统实验哈工大lab2——系统调用

前引

这个lab真的花了我很久的时间,将近做了5个晚上,可能我效率低吧,但是总算是做完了,我觉得这个实验还是比较有难度的,其实我是先做的内存管理那个实验,但是发现那个章节其中一个实验,是在前面的实验基础上进阶,所以又反过来做系统调用这个实验,还是一个一个按照顺序来吧。下面给出我的完整实验过程。

实验目的和内容

这个实验就是说用一个宏函数,将我们用户态的字符串,储存到内核空间,然后再用一个宏函数,把储存到内核空间的字符串取出来,实现两个系统调用函数。

提示

实验册给出了很多提示流程,这些流程建议反复看,有助于理解,而且要认真读,有些细节就决定了能否完成实验。

比如这里,这个实验的总体流程,

1.API函数的用处是什么:我们实验的困难点在于需要用用户态的函数(这个需要我们手搓 ),去取内核的数据,本身是行不通的。用户态是访问不了内核态的 ,所以需要我们用户态的函数,能实现中断,进入内核,用对应系统调用号调用相对应的内核函数(iam() )去执行(需要我们手搓),这个内核函数负责将储存在用户态的字符串,储存到内核态中去。

所以这个API函数就是我们用户态的函数,它就像用户态进入内核态的一个接口一样。

那么还有一个APi函数,需要进入内核,用系统调用号找到对应的内核函数(手搓whoami()),取出刚刚iam()储存到内核空间的字符串,然后返回给用户态,

在终端使用的效果类似这样

实验步骤

ok那么总结一下实验中哪些事情需要我们去做的

1.首先添加系统调用号

_syscall1(int,close,int,fd)这就是一个我们定义的宏函数,其中close对应的位置参数,就是我们手搓并且调用的内核函数,

这个宏函数的目的在于,我的理解很像一个中间件,使用了这个函数,close的内部就添加了int 0x80中断功能,并且宏函数还会提供内核函数的参数。下面是实验册解释

所以我们需要去内核中维护的系统调用表上加上两个编号,也就是iam和whoami的编号

在unitsd.h中加入对应的系统调用号,注意顺序

2.增加系统调用总数

文件名 system_call.s

路径 oslab/linux-0.11/kernel/system_call.s

把系统调用总数+2,(原本是72,改后应为74)

文件中这一行,改成这样,nr_system_calls = 74

3.函数调用表

文件名 sys.h

路径 include/linux/sys.h

注意顺序!!,之前调用号哪个在前,哪个在后,这里的顺序不能变!否则调用会乱(我就踩坑了,调用iam,结果跑出来whoami的打印信息)

4.修改Makefile

直接照抄

5.系统调用代码------iam() 和 whoami()

这里其实可以先写个壳子,里面具体的代码实现不用一次写出来,可以检查编译过没过,才能检查之前的编译问题有没有正确修改,这里我直接给出我的最终代码实现

oslab/linux-0.11/kernel 中创建 who.c 文件,这里提醒一下我的代码很乱(因为后面真的不想改了),但是是正确的,如果想要更为正确简洁的代码可以看一下这个博主的

love6:哈工大操作系统之基础(Lab2 添加系统调用实验全过程+跳坑解析)

arduino 复制代码
#include <string.h>  //memest
#include <errno.h>  
#include <asm/segment.h>  
#include <linux/kernel. h>   // printk,内核的打印函数
char name_buf[32]={0};  //内核全局变量缓冲区
int flag=0;  //标志
int sys_iam(const char * name)
{
	char temp;	
	int count=0;
	while((temp=get_fs_byte(name+count))!='\0'){
         //注意这里运算顺序,我们想要前面先运算,需要打括号
		if (count>=23){
			memset(name_buf,0,sizeof(name_buf));
			flag=1;
             //如果超越最大值了,后标志flag=1,后续whoami,读取后直接返回错误,不会返回上一个测试用例的储存值
			return -EINVAL;
		}
		name_buf[count++]=temp;
		flag=0;
               
	}
	name_buf[count]='\0';
	printk("%d neihe zifu has been uploaded",count);
	return count;
}
 int sys_whoami(char *buf , unsigned int size)
   {	
	if (flag==1){
		return -EINVAL;
	}
	int count=0;
	while (name_buf[count]!='\0'){
	if (count+1<=size){
		put_fs_byte(name_buf[count],buf+count);
		count++;
	} else {
		return -EINVAL;
                //不返回-1,是因为不能返回具体的错误信息,返回值<0代表调用失败
		}		
	}
	printk("neihe %d ge zi fu",count);
	put_fs_byte('\0',buf+count);
	return count;
}

6.内核函数编译

写完后就 cd ~/oslab/linux-0.11

然后 make clean && make all

这里一般会出现很多错误,需要自己完善内核函数的编译问题,多花点时间吧

最后如果没问题了会出现下面的结果

7.用户态函数

注意用户态函数,也就是main函数。需要先挂载

然后写函数

我们就在usr/root中创建

iam.c

arduino 复制代码
#define __LIBRARY__
#include <unistd.h>
#include <stdio.h>
_syscall1(int,iam,const char  *,name);


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

whoami.c

arduino 复制代码
#define __LIBRARY__
#include <unistd.h>
#include <stdio.h>

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

int main(int argc,char *argv[]){
	char buf[24]={0};
        //用户态缓冲区
	whoami(buf,24);
	printf("%s",buf);
	return 0;		
}

最后别忘了卸载 sudo umount hdc

8.测试一下

~/oslab 中 执行 ./run

启动boches

然后编译我们的用户态文件

gcc iam.c -o iam

gcc whoami.c -o whoami

./iam renhan 储存字符串

./whoami 读出字符串

9.测试一下打分文件

在上面我们只是初步用了自己的名字,试了一下程序,如果没问题后,要进一步的测试打分文件,在这个文件中会用多了案例,来看是否能完整实现实验要求

测试文件在home/teacher中

先挂载sudo ./mount-hdc

cp /home/teacher/testlab2.sh /home/teacher/testlab2.c hdc/usr/root/

执行上面的操作

然后文件就会出现在目录中

最后测试,进入boches

上面的是testlab2.c的执行结果,最高 50%

下面是testlab2.sh的执行结果,最高30%

只不过我的testlab2.sh,最后一个案例也失败了,不知道为什么改了很多次,如果需要完整正确的可以看看其他人的

关于挂载和卸载的原因(补充知识)

大概意思就是Ubuntu是我们的宿主机,然后在Ubuntu上启动boches模拟机,然后再启动linux0.11 ,

Image = Linux 0.11 内核本体,

root-0.11.img = Linux0.11 的虚拟硬盘,

Image是linux-0.11操作系统内核代码,需要在Ubuntu上面修改,然后root-0.11.img是硬盘(这里也像u盘),我们在Ubutnu上挂载(插上u盘),然后写我们的用户态测试代码,然后卸载(取出u盘),此时u盘

ai讲解:Ubuntu 是本次实验的宿主机系统,我们在 Ubuntu 中运行 Bochs x86 硬件模拟器,由 Bochs 加载运行 Linux 0.11。

  • Image:内核镜像文件,由内核源码编译得到,操作系统启动时将它载入内存,提供系统调用、中断、内存管理等内核能力;修改内核代码后要重新编译生成新Image才能生效。
  • root-0.11.img:虚拟硬盘镜像,内部存放 Linux 0.11 的文件系统。可以把它类比成 U 盘:在 Ubuntu 里挂载该镜像后,就能用 cp 命令把用户态可执行程序、测试脚本拷贝进去;操作结束必须卸载镜像,再启动 Bochs,防止宿主机、模拟器并发读写破坏磁盘数据。

后引

到这里就结束了,中途其实遇到了蛮多问题的(甚至想过不做了),但是如果肯花时间就能解决,最后实现的那一刻一切都是值得的,能给你增加不错的自信心。那么接下来的时间,我准备把进程与线程管理系统学一遍,把课后lab做一次。

相关推荐
IT_陈寒11 小时前
React useEffect依赖数组中埋的坑,这次终于让我逮到了
前端·人工智能·后端
TechEdu20260611 小时前
银河麒麟操作系统(KylinOS):架构、版本与应用概览
操作系统·计算机科学·kylinos
扎Zn了老Fe12 小时前
MyBatis-Plus必知必会:告别低效CRUD,高效开发持久层
后端·mybatis
用户4603812919412 小时前
终于知道AQS是啥东西了
后端
神奇小汤圆14 小时前
SpringBoot 相关的 Skills 全景指南
后端
神奇小汤圆14 小时前
高性能进程内队列 BufferQueue 1.0 版本发布
后端
爸爸61914 小时前
空数据状态与引导:多维度 UI 提示设计
后端
Reart15 小时前
Leetcode 674.最长连续递增序列 (719)
后端·算法
芒鸽15 小时前
HarmonyOS ArkUI Search 搜索框:联想词、历史记录与热门标签
后端