操作系统实验3——系统调用

环境配置

​ 首先同样是配置环境

cd /home/shiyanlou/oslab
tar -zxvf hit-oslab-linux-20110823.tar.gz -C /home/shiyanlou

实验步骤

添加函数声明

cd ~/oslab/linux-0.11/include/linux
gedit sys.h

//添加内容:
extern int sys_whoami();
extern int sys_iam();

fn_ptr_sys_call_table[]={...sys_whoami,sys_iam}

首先找到sys.h,在其中加入函数声明和系统调用。添加后结果如下图:

在这里插入图片描述

图1

挂载虚拟机添加函数调用

​ 由于需要在unistd.h中新增系统调用号,而该文件不能在oslab中直接进行修改,因此首先运行sudo ./mount-hdc把虚拟机硬盘挂载在oslab/hdc目录下,然后在hdc/usr/include目录下修改unistd.h

cd ../../../
sudo ./mount-hdc
cd ./hdc/usr/include
gedit unistd.h
    
//添加内容:
//系统调用声明:
#define __NR_whoami 72
#define __NR_iam 73

​ 位置即结果如图2所示:

在这里插入图片描述

图2

​ 由于添加了两个系统调用,我们需要在system_call.s中修改系统总调用使数量+2。

cd ../../../
cd ./linux-0.11/kernel/
gedit system_call.s

//添加内容:
nr_system_calls = 74

​ 位置及结果如图3:

在这里插入图片描述

图3

创建操作系统文件

​ 通过前面的操作,我们已经可以从用户态的iam()来调用sys_iam()了,现在需要创建一个操作系统文件who.c,在其中我们可以实现内核函数sys_iam()

//此时已经在kernel目录下
gedit who.c
//who.c代码:
#include <string.h>
#include <errno.h>
#include <asm/segment.h>

char msg[24];

int sys_iam(const char * name)
{
    char tep[26];
    int i = 0;
    for(; i < 26; i++)
    {
        tep[i] = get_fs_byte(name+i);
        if(tep[i] == '\0')  break;
    }

    if (i > 23) return -(EINVAL);

    strcpy(msg, tep);
    return i;
}

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

sys_iamget_fs_byte()name指向的内存缓存区中获取数据,然后将这些数据按字节逐个存放在内核缓存区kernelname中。因为name中存放的名字是一段用户态内存缓存区,所以只能使用FS作为段寄存器,get_fs_byte()用来从用户态内存缓存区中取出一个字节。

编译操作系统

​ 在一切都准备好了之后,我们需要重新编译操作系统来产生系统镜像文件,并用新的镜像文件启动Bochs。为了让who.c文件可以和其它Linux代码编译链接到一起,我们需要修改Makefile文件。其中此处需要修改的是kernel/Makefile

//修改内容:
//第一处:
OBJS=...who.o

//第二处:
who.s who.o: who.c ../include/linux/kernel.h ../include/unistd.h
exit.s exit.o: exit.c ../include/errno.h ...

​ 修改位置如图4:

在这里插入图片描述

图4

​ 修改完后,退回linux-0.11目录下,运行make all指令编译内核,这样就能把who.c加入到内核中。此时用新生成的镜像文件启动Bochs引导出的操作系统就拥有了iamwhoami两个系统调用。

//此时位置为~/oslab/linux-0.11/kernel
cd ../
make all

测试文件编译

​ 在前面我们已经把虚拟机挂载在硬盘上了,为了测试新的操作系统,我们需要进入hdc/user/root目录中(虚拟机开机所在目录)创建iam.cwhoami.c

//进入目录cd ../cd ./hdc/usr/root
gedit iam.c//编写iam.c:#define __LIBRARY__ #include <unistd.h>_syscall1(int,iam,const char*,name);int main(int argc,char* argv[]){    iam(argv[1]);    return 0;}
gedit whoami.c//编写whoami.c:#define __LIBRARY__#include <unistd.h>#include <stdio.h>_syscall2(int, whoami, char*, name, unsigned int, size);int main(int argc, char ** argv){    char t[30];    whoami(t, 30);    printf("%s\n", t);    return 0;}

​ 此外,还可以把/home/teacher目录下的两个测试的脚本文件testlab2.ctestlab2.sh加入测试,需要将其移入目录里。

//此时位置是./hdc/usr/rootcp /home/teacher/testlab2.c ./cp /home/teacher/testlab2.sh ./

​ 此时设置文件已经全部处理好,可以运行虚拟机。

运行操作系统

​ 运行操作系统需要回到~/oslab目录下。

cd ../../.././run

​ 在Bochs虚拟机中对文件进行编译并运行:

//编译文件gcc -o iam iam.cgcc -o whoami whoami.cgcc -o testlab2 testlab2.c//进行系统调用./iam zhoujinchunwhoami

​ 系统调用运行结果如图5所示,成功输出我的名字:

在这里插入图片描述

图5

​ 此外,我们还可以运行脚本文件(实验给的评分用例,满分分别为50%和30%)来测试:

./testlab2./testlab2.sh

​ 运行结果如图6所示,可见最后iam.c满分,为50%,whoami.c满分,为30%。实验完成。
在这里插入图片描述

图6

问题回答

一. 从 Linux 0.11 现在的机制看,它的系统调用最多能传递几个参数?你能想出办法来扩大这个限制吗?

  1. Linux-0.11的系统调用通过寄存器ebxecxedx传递参数,最多能传递3个参数。

  2. 扩大传递参数的数量的方法:

    (1)增加传参所用的寄存器,但现实不太适用;

    (2)用这3个寄存器循环传值;

    (3)将寄存器拆分为高位和低位传递一直比较小的参数;

    (4)利用堆栈传递参数。

二. 用文字简要描述向 Linux 0.11 添加一个系统调用 foo()的步骤。

  1. include/unistd.h中定义宏__NR_foo,并添加函数声明和函数调用。
  2. kernel/system_call.s修改总调用数,使nr_system_calls数值加1。
  3. include/linux/sys.h中添加函数声明extern void sys_foo(),在系统调用入口表fn_ptr末端添加元素sys_foo
  4. 在内核文件中添加kernel/foo.c文件,实现sys_foo()函数。
  5. 修改kernel/Makefile,在OBJS中加入foo.o,并添加生成foo.sfoo.o的依赖规则。
  6. 退回linux-0.11目录下,运行make all指令编译内核,这样就能把foo.c加入到内核中。

课后习题二

一.针对2.2.1节中输出A、B、C的思考题,仿照图2.1画出进程创建关系,并给出输出相应字符的位置。

答:
在这里插入图片描述

二.针对实践项目2,画出一个完整的工作流程图,即第一步做了什么,产生了什么;第二步做了什么,产生了什么,如此等等。

答:(由于本作业的实验步骤部分的部分步骤是根据蓝桥云课实验楼的特殊环境添加的,单纯针对书上的实践项目2的步骤在流程图中仅写出了必需的步骤。)
在这里插入图片描述

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐