17373530徐永鑫 L28 2019-10-26 01:16:49 系统调用
594 0

“操作系统与Linux内核导读(北京航空航天大学)”实验报告

系统调用

实验报告

实验目的

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

实验内容和结果

此次实验的基本内容是:在 Linux 0.11 上添加两个系统调用,并编写两个简单的应用程序测试它们。

(1)iam()
第一个系统调用是 iam(),其原型为:

int iam(const char * name);
copy

完成的功能是将字符串参数 name 的内容拷贝到内核中保存下来。要求 name 的长度不能超过 23 个字符。返回值是拷贝的字符数。如果 name 的字符个数超过了 23,则返回 “-1”,并置 errno 为 EINVAL。
在 kernal/who.c 中实现此系统调用。

(2)whoami()
第二个系统调用是 whoami(),其原型为:

int whoami(char* name, unsigned int size);
copy

它将内核中由 iam() 保存的名字拷贝到 name 指向的用户地址空间中,同时确保不会对 name 越界访存(name 的大小由 size 说明)。返回值是拷贝的字符数。如果 size 小于需要的空间,则返回“-1”,并置 errno 为 EINVAL。
也是在 kernal/who.c 中实现。

(3)测试程序
运行添加过新系统调用的 Linux 0.11,在其环境下编写两个测试程序 iam.c 和 whoami.c。最终的运行结果是:

$ ./iam lizhijun
$ ./whoami
lizhijun 
copy

首先将环境复原 图片描述

然后将iam和whoami添加到系统调用函数里

在/include/unistd.h加上iam和whoami的系统调用号,并将kernel/system_call.s里的nr_system_calls改为74 图片描述 图片描述 图片描述

再在include/linux/sys.h里是sys_call_table[]末尾添加iam和whoami的函数名,并添加它们的声明 图片描述 图片描述

接下来是实现iam和whoami这两个函数

在kernel文件夹里创建who.c文件,实现whoami()和iam()函数 图片描述

who.c具体代码如下

#include <errno.h>                   
#include <asm/segment.h>

char buf[24];

int sys_iam(const char *name)
{
    int count;
    int i;
    char temp[24];

    for (count = 0; count < 24; count++)
    {
        temp[count] = get_fs_byte(name + count);
        if (temp[count] == '\0')
            break;
    }
    if (count == 24)
        return -EINVAL;
    for (i = 0; i <= count; i++)
        buf[i] = temp[i];
    return count;
}

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

}
copy

然后修改kernel/Makefile文件,添加who.o的声明和生成who.s和who.o依赖,再make all编译内核 图片描述 图片描述 图片描述

然后在挂载的镜像中修改/include/unistd.h,并添加上iam.c和whoami.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;
}
copy

测试文件whoami.c的具体代码如下

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

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

int main()
{
    char arr[24];
    whoami(arr, 24);
    printf("%s", arr);

    return 0;
}
copy

卸掉挂载镜像,再./run,在Bochs运行内核,编译之后,运行测试结果如下 图片描述

最后将testlab2.c和testlab2.sh都复制到挂载的镜像下面,再卸载镜像,再次在Bochs运行内核 图片描述

编译之后,运行结果如下 图片描述

从 Linux 0.11 现在的机制看,它的系统调用最多能传递几个参数?你能想出办法来扩大这个限制吗?
Linux-0.11的系统调用通过寄存器ebx、ecx、edx传递参数,最多能传递3个参数。
可以通过利用堆栈传递参数来增加传递参数的个数。

用文字简要描述向 Linux 0.11 添加一个系统调用 foo() 的步骤。
先在/include/unistd.h中定义__NR_foo,然后将/kernel/system_call.s里的nr_system_calls增加1,之后在include/linux/sys.h里是sys_call_table[]末尾添加foo的函数名,并添加它的声明,然后添加/kernel/foo.c文件,实现foo()函数,最后修改/kernel/Makefile文件,添加foo.o的声明和生成foo.s和foo.o依赖。

总结

本次实验学习了系统调用相关知识,尝试实现了系统调用函数,对数据是怎样在用户态和核心态之间传输有了更深的理解。

最新评论
暂无评论~