lab2添加系统调用
前言
对于实验一,由于基本上按照实验册来就可以成功,故我就没有写博客。同时对于此博客更多的是纪念自己所学,如要实验参考:推荐博客:love6’s blog 首先先梳理一下系统调用:首先对于内存我们需要知道是分为用户态和内核态的,其中用户态不可直接访问内核态,而内核态是可以访问任何内存的,然后如何通过用户态来访问内核态呢,即利用API来访问,通过API来找到对应内核函数,然后来实现系统调用。 然后再讲一下本实验中具体系统调用过程:首先是通过API(应用程序接口)将系统调用号存入edx寄存器,然后调用int0x80号中断实现进入内核,内核中的中断处理程序通过系统调用号调用对应的内核函数,然后将其返回值存入edx寄存器中,然后返回到中断处理函数,中断处理程序返回到API中,然后API将edx返回给应用程序。
实验
首先是要复原原来的情况
#删除原来的文件
$ cd ~/oslab
$ sudo rm -rf .
首先我们先要知道我们要做的两个函数:
int iam(const char * name);
#完成的功能是将字符串参数 name 的内容拷贝到内核中保存下来
要求 name 的长度不能超过 23 个字符。返回值是拷贝的字符数。
如果 name 的字符个数超过了 23,则返回 “-1”,并置 errno 为 EINVAL。
int whoami(char* name, unsigned int size);
#它将内核中由 iam() 保存的名字拷贝到 name 指向的用户地址空间
中,同时确保不会对 name 越界访存(name 的大小由 size 说
明)。返回值是拷贝的字符数。如果 size 小于需要的空间,则返回“-1”,并置 errno 为 EINVAL。
这两个函数都是在kernal/who.c下创建。
对于实验步骤顺序而言我自己也是不太记得,就从我先想到开始吧,首先是先在linux-0.11下的include/unistd.h下修改必要信息,添加系统调用号,如下: 然后不要忘记在user下的unistd.h也添加系统调用号,关于如何进入则需要上个实验学的,采用sudo ./mount-hdc即可,当然再**./run之前需要采用sudo umount hdc**将挂载消除掉,然后就可以实现更改了
实现API
首先AP都是在linux-0.11下的lib路径下实现,我们需要实现iam函数API以及whoami函数API,其结果如下: 其中**LIBRARY**是为了标识 _syscall , _syscalln是代表n个参数,然后_syscall是一个宏,起到了对API的定义。
修改kernal/system_call.s
对于system_call.s 进行修改 系统调用的函数增加了,所以需要增加两个。
修改include/linux/sys.h
对于这里也要修改,添加函数引用 同时在sys_call_table中也要添加,且添加的顺序必须与其系统调用号一致。如图:
在内核中实现sys_iam()和sys_whoami()
其实现是在kernal/who.c中实现 代码如下:
#include<unistd.h>
#include<errno.h>
#include<asm/segment.h>
#include<string.h>
char msg[24];
int sys_whoami(char*name,unsigned int size){
int len=strlen(msg);
int i;
if(len>size){
errno=EINVAL;
return -EINVAL;
}
for(i=0;i<len;i++)put_fs_byte(msg[i],name+i);
return len;
}
int sys_iam(const char*name){
errno=0;
memset(msg,'\0',sizeof(msg));
int count=0;
char ch;
while((ch=get_fs_byte(name+count))!='\0'){
if(count>23){
errno=EINVAL;
return -EINVAL;
}
msg[count++]=ch;
}
if(count>23){
errno=EINVAL;
return -EINVAL;
}
return count;
}
其中要注意的是put_fs_byte() 函数和 get_fs_byte() 函数,其中put_fs_byte()函数原型为void put_fs_byte(char ch,const char*name) 是把字符ch拷贝到name对应的地址上去,其中get_fs_byte() 函数原型为 char get_fs_byte(const char * name) 返回 name地址上对应的字符,由于指针参数传递的为用户逻辑地址,如果内核态函数访问的话是不能访问到数据真正的地址的,get_fs_byte()函数和put_fs_byte()函数便是专门在用户态和内核态中进行数据访问设置的。
修改kernal/Makefile
makefile一共要修改两次,第一次为: 增加一个who.o即可 第二处为: 将其修改为: 然后就可以make all编译一遍就可以把who.c加入到内核中了,没有错误的话一般就代表成功了。
编写测试应用程序
由于我们进入的bochs模拟器中的路径为其root路径,所以为其方便性将其程序编写在root路径下,再此之前需要先sudo ./mount-hdc 挂载,然后就可以通过hdc进入bochs中的root中了,其函数如下: 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>
#include <string.h>
_syscall2(int,whoami,char*,pos,unsigned int,size);
int main(int argc,char* argv[])
{
char tempstr[24];
memset(tempstr,'\0',sizeof(tempstr));
whoami(tempstr,24);
printf("%s\n",tempstr);
return 0;
}
然后将其在bochs上利用gcc -o xxx xxx.c编译之后,就可以测试数据了 同时将testlab2.c 和testlab2.sh文件加入bochs模拟器中的usr/root中去便可以测试自己的分数了,可以自己到蓝桥实验楼那下载数据,只要自己创建一个Code文件夹,然后将所需文件加入那里,然后在下载文件那点击下载即可。编译完testlab2.c 文件后,测试: 其中testlab2代表测试的是内核函数,满分50%,testlab2.sh测试的是应用程序满分30%,有点遗憾自己并未得到满分,也确实不知道自己那里错了。但是为了接下来的实验,自己也就这样过了。
|