哈工大操作系统实验课——系统调用(lab3)

I 实验题目

在linux-0.11上添加两个系统调用并测试
(1)iam()
原型为int iam(const char *name)
将字符串参数name的内容拷贝到内核下保存下来,如果name长度小于等于23,返回拷贝的字符数。如果name的字符个数超过了23,返回-1,置errno为EINVAL。
(2)whoami()
原型为int whoami(char *name, unsigned int size);
iam()保存的名字拷贝到name所指的地址空间。确保不对name越界访问。返回值是拷贝的字符数,如果size小于需要的空间,则返回“-1”,置errno为EINVAL。

II 操作步骤

1.include/unistd.h中添加系统调用号

//include/unistd.h
#define __NR_whoami 72
#define __NR_iam 73

2.kernel/system_call.s修改系统总调用数为74

//kernel/system_call.s
nr_system_calls = 74

3.include/linux/sys.h添加调用

//include/linux/sys.h
extern int sys_whoami();
extern int sys_iam();

fn_ptr_sys_call_table[]={...sys_whoami,sys_iam}

4.编写kernel/who.c

//kernel/who.c
#include <linux/kernel.h>
#include <asm/segment.h>
#include <unistd.h>
#include <errno.h>
int wholen = 0;
char whobuf[30];
int sys_iam(const char* name){
    int len;    //计算输入字符串长度
    for(len=0; len<24; len++){
        char tmp = get_fs_byte(name+len);    
        if(tmp == 0)
            break;
    }
    //如果字符串长度大于23,直接返回-1,并设置errno
    if(len == 24){    
        /*
        设置errno这一步卡了我好久。
        一开始我是直接赋值给errno,例如:errno = EINVAL; return -1。结果一直过不了。
        后面看到别人是直接返回-EINVAL,改了之后就可以了。
        */
        return -EINVAL;
    }
    //拷贝到内核准备好的缓冲区
    for(wholen = 0; wholen<=len; wholen++){
        whobuf[wholen] = get_fs_byte(name+wholen);
    }

    return wholen;

}

int sys_whoami(char* name, unsigned int size){
    //判断是否有足够的空间存储
    if(size < wholen){
        return -EINVAL;
    }
    //拷贝
    int i;    
    for(i=0; i<=wholen; i++){
        put_fs_byte(whobuf[i], name+i);    
    }

    return wholen;
}

5.修改kernel/Makefile

//kernel/Makefile
OBJS=...who.o

#Dependencies:
who.s who.o:who.c ../include/linux/kernel.h ../include/unistd.h

6.编写iam.c与whoami.c

#define __LIBRARY__        
#include "unistd.h" 
_syscall1(int, iam, const char*, name); 
int main(int argc, char** argv){
    int wlen = 0;
    if(argc < 1){
        printf("not enougth argument\n");
        return -2;
    }
    wlen = iam(argv[1]);
    return wlen;
}
#define __LIBRARY__        
#include "unistd.h" 
_syscall2(int, whoami,char*,name,unsigned int,size);    

int main(int argc, char** argv){
    char buf[30];
    int rlen;
    rlen = whoami(buf, 30);
    printf("%s\n", buf);
    return rlen;
}

7.命令

~/oslab/linu-0.11

make all

../run

III 测试

1.挂载虚拟硬盘

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

2.在其中添加iam.c whoam.c以及教师文件夹里的testlab2.c testlab2.sh

3.替换部分库文件

sudo cp ~/oslab/linux-0.11/include/linux/sys.h ~/oslab/hdc/usr/include/linux/sys.h
sudo cp ~/oslab/linux-0.11/include/unistd.h ~/oslab/hdc/usr/include/unistd.h

4.卸载hdc

cd ~/oslab
sudo umount hdc

5.编译与运行

cd linux-0.11
make
../run

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

./iam "lg's student"
./whoami
./testlab2

在这里插入图片描述
在这里插入图片描述

IV 实验报告

  1. 从 Linux 0.11 现在的机制看,它的系统调用最多能传递几个参数?你能想出办法来扩大这个限制吗?
    Linux-0.11的系统调用通过寄存器ebx、ecx、edx传递参数,最多能传递3个参数。
    结构体,堆栈,寄存器拆分为高低位,寄存器循环传值
  2. 用文字简要描述向 Linux 0.11 添加一个系统调用 foo() 的步骤。
    (1)include/unistd.h中添加系统调用号
    (2)在kernel/system_call.s修改总调用数
    (3)include/linux/sys.h添加调用
    (4)在内核文件中实现foo.c
    (5)修改kernel/Makefile

V 总结

图片源于https://www.cnblogs.com/tradoff/p/5734582.html
图片源于https://www.cnblogs.com/tradoff/p/5734582.html
iam()的系统调用流程如上图所示,关键的步骤在于根据include/unistd.h中添加的系统调用号解析系统调用,根据函数调用表在include/linux/sys.h中找到函数入口地址,在kernel中找到函数并实现。
关于中断的陷入,有以下描述:将 system_call 函数地址写到 0x80 对应的中断描述符中,也就是在中断 0x80 发生后,自动调用函数 system_call。

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值