MOOC哈工大操作系统实验2:添加系统调用

首先进入实验楼后,解压目标文件,做一下初始化的工作。

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

1. 在linux-0.11/include/linux/sys.h中添加函数声明extern int sys_iam()和extern int sys_whoami(); 然后在中断向量表fn_ptr sys_call_table[]的最后面填上系统调用sys_iam()和sys_whoami()。

cd ./linux-0.11/include/linux
vim sys.h

打开sys.h后,可以看到如下图的代码,其中红色圈起来的是我们要添加的内容:
在这里插入图片描述
即先添加函数声明:
extern int sys_iam();
extern int sys_whoami();
再在中断向量表最后面添加:sys_iam, sys_whoami

2.在linux-0.11/kernel/system_call.s中修改系统调用的个数nr_system_calls,使其增加2。

cd ../../kernel
vim system_call.s

如图所示,将nr_system_calls由72改成74.
在这里插入图片描述
**3.新增系统调用号,在虚拟机中修改unistd.h。先通过运行sudo ./mount-hdc 把虚拟机硬盘挂载在oslab/hdc目录下,然后在hdc/usr/include目录下修改unistd.h。
增加#define __NR_iam 72 和 #define __NR_whoami 73

首先运行mount-hdc来把虚拟机硬盘挂载在oslab/hdc目录下,然后切换目录打开unistd.h

cd ../../
sudo ./mount-hdc
cd ./hdc/usr/include
vim unistd.h

如图添加#define __NR_iam 72 和 #define __NR_whoami 73
在这里插入图片描述
4.新增who.c文件,实现系统调用的函数
切换目录到linux-0.01/kernel ,在这里创建一个who.c文件。

cd ../../../linux-0.11/kernel
vim

在这里首先要说明题目中的要求文件中iam()函数 “ 如果 name 的字符个数超过了 23,则返回 “-1”,并置 errno 为 EINVAL。”
这里我觉得可能是写错了?我在代码中返回-1后是通不过最后的测试的,只有返回EINVAL才可以通过测试。也就是说,EINVAL是错误代码的一个取值,题目实际上应该是让我们返回这个值EINVAL;同时<errno.h>头文件会自动帮我们把变量errno置为对应的错误码EINVAL,所以我们就不用再写errno = EINVAL 了。在代码中<errno.h>头文件定义了错误代码,关于错误代码error如果不清楚可以参考https://blog.csdn.net/m0_37221216/article/details/101212781

还有一个点需要注意,如果把用户态的数据传入核心态,如这道题中我要把用户态地址name处的字符串传入核心态,name是一个指针,那么是不能直接用 * name代表name指向的字符串的,因为指针传递的是应用程序所在地址空间的逻辑地址,在内核中如果直接访问这个地址,访问到的是内核空间中的数据,不会是用户空间的。所以这里需要通过get_fs_byte()和put_fs_byte()函数来实现用户态与核心态数据的交换。其中get_fs_byte()函数的参数是用户空间的逻辑地址,返回值是该地址处的一个字符的内容;其中put_fs_byte()函数的功能是向用户空间中地址处写一个字节的内容,有两个参数,第一个参数是要写入的数据,第二个参数是用户空间中的逻辑地址。

who.c文件的代码如下:
其中

#include <string.h>  //提供复制字符串的函数strcpy
#include <errno.h> //定义了错误代码
#include <asm/segment.h> //提供get_fs_byte等函数

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;
}

5.修改linux-0.01/kernel目录下的Makefile文件,在OBJS中加入who.o,并添加生成who.s、who.o的依赖规则。

vim Makefile

要添加的内容如图所示:即添加who.c 和 who.s who.o: who.c …/include/linux/kernel.h …/include/unistd.h
在这里插入图片描述
在这里插入图片描述
修改完后,退回linux-0.11目录下,运行make all指令编译内核,who.c会被加入到内核。

cd ../
make all

6.新增iam.c 跟whoami.c文件以测试是否添加系统调用成功
注意这两个文件是要在linux 0.11版本上编译的,所以我们应当先通过运行mount-hdc文件来把虚拟机的硬盘挂载在oslab/hdc 目录下,然后进入hdc/user/root目录中(这个目录就是虚拟机一开机的所在的目录)再创建iam.c和whoami.c。

cd ../
sudo ./mount-hdc
cd ./hdc/usr/root

内核源代码的unistd.h文件中定义了宏函数_syscalln(),其中n代表携带的参数个数,该宏函数展开时会通过int0x80进入内核并找到对应编号的系统调用。若我们要在用户程序中直接执行对应的系统调用,那么该系统调用宏的形式如下(具体参考linux-0.11内核完全注释的5.5章节或课程实验提示):

#define LIBRARY
#include <unistd.h>
_syscalln( …)

因此在iam.c和whoami.c文件代码中需要包含这三行代码,然后我们就可以在main函数中直接使用系统调用了。
main函数的两个参数是argc和argv[],其中argc的值是在命令行运行程序时给的参数的个数;argv是一个指针数组,argv[1]是在命令行执行程序时传递给它的第一个参数的地址, argv[2] 是在命令行执行程序时传递给它的第二个参数的地址…因此在iam.c文件中的main里直接使用系统调用函数iam,参数即为argv[1]。

iam.c的代码如下:

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

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

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;
}

7.运行和测试:
首先把/home/teacher 目录下的两个测试文件testlab2.c和testlab2.sh移动到虚拟机的硬盘中的开机目录里

cd ~/oslab
sudo ./mount-hdc
cd ./hdc/usr/root
cp /home/teacher/testlab2.c ./
cp /home/teacher/testlab2.sh ./

然后切换到oslab目录,运行虚拟机

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

在弹出的bochs虚拟机窗口中的命令行中,编译几个C语言文件

gcc -o iam iam.c
gcc -o whoami whoami.c
gcc -o testlab2 testlab2.c

编译好了以后,就可以最后的运行测试了:在虚拟机中通过iam将你的名字从用户态传入内核。然后通过whoami将传入内核的名字打印出来

./iam zhaotianhao
whoami

结果如下:
在这里插入图片描述
然后我们还可以运行两个测试文件testlab2.c和testlab2.sh

./testlab2
./testlab2.sh

结果如下:第一个满分50%,第二个满分为30%
在这里插入图片描述
在这里插入图片描述

  • 12
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值