系统调用笔记

哈工大操作系统实验2系统调用-LMLPHP
用户态只能通过系统调用去访问内核,即只能通过中断处理访问, INT 0X80
哈工大操作系统实验2系统调用-LMLPHP
就是我们的C语言程序,调用一个在unistd.h定义的宏,_syscall*()*代表的是参数的个数,这个宏的意义差不多等于创建一个函数。这个函数只有一个代码就是int 0x80。

系统调用read,宏展开后(就是创建了一个read函数)
哈工大操作系统实验2系统调用-LMLPHP
int 0x80是由main.c中sched_init()创建的。其实就是初始化好了IDT表
哈工大操作系统实验2系统调用-LMLPHP
INT 0X80会根据进入内核,调用system_call. system_call 就会去根据__NR_##name去查表执行相应的处理函数
哈工大操作系统实验2系统调用-LMLPHP

实验记录

实验要求我们添加两个系统调用,iam()和whoami()
运行结果

$ ./iam lizhijun
$ ./whoami
lizhijun

1

首先是编写最外层的用户程序iam.c和whoami.c
注意 _syscall 要写在 #define __ LIBRARY __ #include<unistd.h>下面

iam.c

哈工大操作系统实验2系统调用-LMLPHP

whoami.c

哈工大操作系统实验2系统调用-LMLPHP

2

有了用户程序,我们就要编写系统调用sys_iam和sys_whoami
在linux-0.11/kernel下添加who.c

#define __LIBRARY__
#include <unistd.h>
#include <errno.h>
#include <asm/segment.h>


char temp[64]={0};


int sys_iam(const char* name)
{
   int i=0;
   while(get_fs_byte(name+i)!='\0') //从用户态获取一个字符并返回这个字符
        i++;
   if(i>23){
        return -EINVAL;
   }
   printk("%d\n",i);
   i=0;
   while((temp[i]=get_fs_byte(name+i))!='\0'){
i++;
    }
    return i;
}


int sys_whoami(char* name,unsigned int size)
{
    int i=0;
    while (temp[i]!='\0')
i++;
    if (size<i)
    return -1;
    i=0;
    while(temp[i]!='\0'){
put_fs_byte(temp[i],(name+i));//把内核态的一个字符存到用户态程序中,也就是name->temp
i++;
    }
    return i;
}

3 修改相关的头文件

linux-0.11/include/linux/sys.h

这个头文件修改的意义是把 iam与whoami两个函数加到全局变量,和中断函数表中就可以了,中断被调用的时候,先查找中断向量表,
找到相应的函数名,调用其函数。
哈工大操作系统实验2系统调用-LMLPHP

linux-0.11/kernel/system_call.s

这里要修个nr_system_calls 本来是72 也就是有72个系统调用函数,我们加了两个所以改成74
哈工大操作系统实验2系统调用-LMLPHP

hdc/usr/include/unistd.h

unistd.h 不能直接在oslab直接直接修改,而需要在虚拟机中修改,在oslab中有一个mount-hdc脚本
运行sudo ./mount-hdc 可以把虚拟机硬盘挂载在oslab/hdc 目录下。
在hdc/usr/include 目录下修改unistd.h
哈工大操作系统实验2系统调用-LMLPHP

4 就是修改linux-0.11/kernel下的MakeFile

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
另一处:
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
Makefile修改后,和往常一样“make all”就能自动把who.c加入到内核中了。如果编译时提示who.c有错误,就说明修改生效了。所以,有意或无意地制造一两个错误也不完全是坏事,至少能证明Makefile是对的。

5 编译运行

编译必须在虚拟机下编译,因为你修改的unistd.h只在虚拟机生效

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

哈工大操作系统实验2系统调用-LMLPHP

总结

添加一个系统调用主要是

1.编写用户程序,这个用户程序需要包含_syscall* 宏(创建一个函数),然后调用这个函数
2.编写系统调用函数放到linux-0.11/kernel
3.各种相关头文件的修改
linux-0.11/include/linux/sys.h添加extern int sys_xxx和添加syscall_table[]
linux-0.11/kernel/system_call.s 修改nr_system_calls(syscall_table中的系统调用函数个数)
hdc/usr/include/unistd.h 其实也就是编译的库文件 添加__ NR_xx 系统调用号
linux-0.11/kernel下的MakeFile修改OBJS和Dependencies

参考博客

实验指导书

实验环境:实验楼

10-03 22:11