HitOSlab-实验2-系统调用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


1. 前言!!!

来缕一缕系统调用的一个过程
1.当系统调用函数被调用时,如wtite(int,char*,int),会被unistd.h所定义的宏展开

		#define syscall3(type,  name,  atype,a,  btype,b,  ctype,c)
			type name(atype a, btype b, ctype c){
				long __res;
				__asm__ ("int 0x80"
				: "=a"(__res)) : ""(__NR_##name),"b"((long)(a)),"c"((long)(b)), 
				"d"((long)(c));
				if(__res >= 0) return (type)__res
				errno = -__res; return -1;
			}
这里可以看到系统调用通过int 0x80 中断来进入内核
操作系统提供的中断(0x80)入口 (80号中断描述符的特权级为3),使得用户态程序可以进入到内核态
1.如上,系统调用号放在%ax寄存器,触发 int 0x80 中断
2. 处理 int 0x80中断 ,在系统初始化时int 0x80中断的权限级(DPL)被设置为3,所以可以访问内核空间
3.  调用中断处理函数,通过系统调用号去 查询系统调用函数表,然后去调用真正的系统函数 ,将函数结果保存在%ax寄存器内 返回用户

来看一下int 0x80号中断所执行的中断处理函数,它在system_call.s 中

system_call:
        cmpl $nr_system_calls-1,%eax
        ja bad_sys_call
        push %ds
        push %es
        push %fs
        pushl %edx
        pushl %ecx              # push %ebx,%ecx,%edx as parameters
        pushl %ebx              # to the system call
        movl $0x10,%edx         # set up ds,es to kernel space
        mov %dx,%ds
        mov %dx,%es
        movl $0x17,%edx         # fs points to local data space
        mov %dx,%fs
        call sys_call_table(,%eax,4)
        pushl %eax
        movl current,%eax
        cmpl $0,state(%eax)             # state
        jne reschedule
        cmpl $0,counter(%eax)           # counter

#push %ebx,%ecx,%edx as parameters系统调用参数通过 这三个寄存器传递
call sys_call_table(,%eax,4) 这一句就是根据eax寄存器存放的系统调用号,去执行所对应的系统调用函数。

这张系统调用表sys_call_table 存放在linux-0.11/include/linux/sys.h中
在这里插入图片描述
然后将会去调用我们所实现的系统调用函数了。
提示:以下是本篇文章正文内容,下面案例可供参考

一、添加的系统调用

1. 编写提供给上层用户接口的测试函数

/* iam.c iam函数 */
#define __LIBRARY__
#include <unistd.h>
_syscall1(int, iam, const char*, name);

int main(int argc, char *argv[])
{
    /*调用系统调用iam()*/
    iam(argv[1]);
    return 0;
}
/* whoami.c whoami函数*/
#define __LIBRARY__
#include <unistd.h>
#include <stdio.h>

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

int main(int argc, char *argv[])
{
    char username[64] = {0};
    /*调用系统调用whoami()*/
    whoami(username, 24);
    printf("%s\n", username);
    return 0;
}

_syscall2(int, whoami,char *,name,unsigned int,size); 是一个宏在unistd.h中定义

#define _syscall2(type,name,atype,a,btype,b) \
type name(atype a,btype b) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
        : "=a" (__res) \
        : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b))); \
if (__res >= 0) \
        return (type) __res; \
errno = -__res; \
return -1; \
}

2.添加系统调用号

在unistd.h文件中 添加

#define __NR_whoami     72
#define __NR_iam        73

在sys.h文件中的系统调用表添加函数入口地址
在这里插入图片描述
在system_call.s 中要加上系统调用的总数量
在这里插入图片描述

3.实现系统调用函数

创建一个who.c放在linux-0.11/kernel/下 在里面实现俩个系统函数

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

char m_name[24];

//将参数name的内容拷贝到m_name中
// 返回值: 拷贝的字符数,若字符数大小超过23,返回-1,同时设置errno为EINVAL
int sys_iam(const char* name){ 
	
	int i;
	char temp[30];
	
	for(i=0; i<30; i++){
		temp[i] = get_fs_byte(name+i);
		if(temp[i] == '\0') break;
	}
	
	i = 0;
	while(i<30 && temp[i] != '\0') i++;
	int len = i;

	
	if(len > 23){
		errno = EINVAL;
		return -1;
	}
	
	strcpy(m_name,temp);
	return i;

}


//将m_name 拷贝到name指向的用户空间中,size指定name的大小,防止越界
//成功返回拷贝字节数,失败返回-1,并设置errno为EINVAL
int sys_whoami(char* name,unsigned int size){
	int len = 0;

//	for(;m_name[len]!='\0';len++);
	while(m_name[len] != '\0')
		len++;

	if(len > size){
		errno = EINVAL;
		return -1;
	}
	int  i = 0;
	for(i=0;i<size;i++){
		put_fs_byte(m_name[i],name+i);
		if(m_name[i] == '\0') 
			break;
	}
	return i;
}

4.重新编译

修改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

可以重新编译了,make all 一下

5.测试

将编写的接口测试函数挂载到linux-0.11中
在oslab/,输入命令sudo ./mount-hdc挂载。把测试文件拷贝进linux-011中,因为要在那里测试系统调用。在linxu-0.11中编译执行
在这里插入图片描述
执行testlab2.sh
在这里插入图片描述
执行testlab.c
在这里插入图片描述

6.实验报告

问题:从Linux 0.11现在的机制看,它的系统调用最多能传递几个参数?你能想出办法来扩大这个限制吗? 用文字简要描述向Linux 0.11添加一个系统调用foo()的步骤。

在linux 0.11 下 的系统调用最多可以传递3个参数,通过bx,cx,dx通用寄存器传递。
如何扩大:
1.将寄存器拆分,分为高位和低位
2.将参数通过结构体指针打包,通过传递指针来实现参数扩大

总结

暂时先这样,不太会写文章,再补充

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值