哈工大操作系统实验2:添加系统调用iam()、whoami()

哈工大操作系统实验2:添加系统调用iam()、whoami()

需要添加到内核中的文件:

lib/whoami.clib/iam.ckernel/who.c

需要修改的内核文件:

include/unistd.hinclude/linux/sys.hkernel/system_call.slib/Makefilekernel/Makefile

为测试而添加的用户程序:

iam.cwhoami.c


  1. include/linux/sys.h中的_sys_call_table表内添加两个新的系统调用函数,以及两个extern...;如下所示:

    请添加图片描述

  2. 表项中有了两个新增的函数sys_iamsys_whoami,我们倒着推一下,是谁会调用这两个函数呢?答案是kernel/system_call.s,修改该汇编代码;如下所示:

    请添加图片描述

  3. 修改include/unistd.h,在其中添加两个系统调用号,正是有了系统调用号,才可以决定int 0x80的具体走向。

    请添加图片描述

  4. 系统调用通过内嵌汇编方式调用int 0x80中断,进入了上述的system_call.s再进一步找到_sys_call_table,根据系统调用号在表中找到真正的内核代码(或者内核函数)地址,也即sys_iam()sys_whoami().

    ①话说回来,用户级程序通过系统调用引发int 0x80中断,进入系统内核;所以现在我们添加这些可以被用户程序直接调用的接口,也即whoami()iam(),这里我是模仿lib/write.c

    ②添加文件lib/whoami.clib/iam.c

    whoami.c文件内容如下:

    #define __LIBRARY__
    #include <unistd.h>
    
    _syscall2(int, whoami, char *, name, unsigned int, size)
    /*
     * 该宏展开就是函数int whoami(char* name, unsigned int size)
     * 头文件<unistd.h>中定义了该宏的展开形式和规则,其通过内嵌汇编的方式调用中断
     */    
    

    iam.c文件内容如下:

    #define __LIBRARY__
    #include <unistd.h>
    
    _syscall1(int, iam, const char *, name)
    /*
     * 该宏展开就是函数int iam(const char* name)
     */
    
  5. 有了上述的准备,用户程序可以调用系统接口(第4步),展开成内嵌汇编进入系统内核;然后根据系统调用号(第3步)的分流引导,从kernel/system_call.s跳转到include/linux/sys.h中的_sys_call_table表,执行 真正的系统内核函数sys_iamsys_whoami,因此接下来是对这两个系统内核函数的具体实现

    添加实现文件kernel/who.c其文件内容如下:

    /*
     * 函数sys_iam()和sys_whoami()的实现
     */
    
    #include <unistd.h>			
    #include <asm/segment.h>	/*get_fs_byte() put_fs_byte()函数调用的头文件*/
    #include <errno.h>			/*错误代码 EINVAL等要用到*/
    #include <string.h>			/*C语言字符串处理头文件*/
    
    /*实现方式1:(自己写的)*/
    char kernelchars[23];
    int sys_iam(char *name)
    {
    	char temp[30];
    	int counter = 0;
    
    	for (; counter < 30; counter++)
    	{                                                
            temp[counter] = get_fs_byte(&name[counter]); 
            if (temp[counter] == '\0')   break;
    	}
    
    	if (counter >= 23)
    	{
    		errno = EINVAL;
    		return -1;
    	}
    	strcpy(kernelchars, temp); 
    	return counter + 1;        
    }
    
    /*
     * 功能:将内核中由iam()保存的字符串读取出来,保存到name指向的用户空间(该用户空间应预留'\0'的位置),同时确保不会对name访问越界
     * 返回值:复制的字符数,包含'\0'
     * 若size小于需要的空间,则返回-1,并设置errno=EINVAL
     */
    int sys_whoami(char *name, unsigned int size)
    {
    	unsigned int counter = 0;
    	char temp[24];
    	int j = 0;	
    	temp[counter] = kernelchars[counter];
    	while (temp[counter] != '\0')
    	{
            counter++;
            temp[counter] = kernelchars[counter];
        }
        if (size < counter + 1){
        	errno = EINVAL;
    		return -1;
        }
    	
    	for(; j < counter; j++){
    		put_fs_byte(temp[j], &name[j]);
    	}
    
        return counter + 1;
    }
    
    /***********************************************************************/
    /*实现方式2:(调试的时候参考网上小伙伴的)*/
    /*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;
    }*/
    
    
  6. 内核代码的修改基本完成了,接下来是为编译做准备的修改Makefile

    ①因为在lib中添加了新的文件(第4步),所以应该修改一下lib/Makefile,这里也是模仿的write.c的依赖写法,具体如下所示:

    请添加图片描述

    ②因为新添加了kernel/who.c文件,所以kernel/Makefile也需要修改,具体如下:

    请添加图片描述
    请添加图片描述

  7. 在宿主机重新编译Linux内核0.11

  8. 在宿主机器上挂载hdc—修改hdc/usr/include/unistd.h(其实就是添加上两个系统调用号,如下所示)–卸载hdc

    请添加图片描述

  9. 编写用户级别的测试程序

    第一种:单个文件同时调用测试之前添加的系统调用

    #include <errno.h>
    #define __LIBRARY__
    #include <unistd.h>
    #include <stdio.h>
    
    _syscall1(int,iam,const char*,name);
    _syscall2(int,whoami,char*,name,unsigned int ,size);
    
    int main(int argc, char** argv)
    {
    	char s[30];
    	iam(argv[1]);
    	whoami(s,30);
    	printf("%s\n",s);
    	return 0;
    }
    

    第二种:分开测试,写一个测试iam()iam.c和一个测试whoami()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;
    }
    
    /********************************************************/
    
    /*whoami.c如下:*/
    #define __LIBRARY__
    #include <stdio.h>
    #include <unistd.h>
    _syscall2(int, whoami, char*, name, unsigned int, size);
    
    int main(int argc, char* argv[]){
    	char name[13];             
    	whoami(name,sizeof(name));
    	printf("%s\n", name);
    
    	return 0;
    }
    
  10. 在Bochs中模拟器中运行Linux 0.11,先编译然后测试

    ① 单个测试文件

    请添加图片描述

    ②两个测试文件时

    请添加图片描述

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咖啡与乌龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值