栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux0.11操作系统(哈工大李治军老师)实验楼实验3-系统调用

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux0.11操作系统(哈工大李治军老师)实验楼实验3-系统调用

这次内容是在Linux0.11上添加两个系统调用,并编写两个简单的应用程序测试它们
  1. iam
    第一个系统调用是 iam(),其原型为:
int iam(const char * name);

完成的功能是将字符串参数 name 的内容拷贝到内核中保存下来。要求 name 的长度不能超过 23 个字符。返回值是拷贝的字符数。如果 name 的字符个数超过了 23,则返回 “-1”,并置 errno 为 EINVAL。

在 kernal/who.c 中实现此系统调用。

  1. whoami
    第二个系统调用是 whoami(),其原型为:
int whoami(char* name, unsigned int size);

它将内核中由 iam() 保存的名字拷贝到 name 指向的用户地址空间中,同时确保不会对 name 越界访存(name 的大小由 size 说明)。返回值是拷贝的字符数。如果 size 小于需要的空间,则返回“-1”,并置 errno 为 EINVAL。

也是在 kernal/who.c 中实现。

  1. 测试程序
    运行添加过新系统调用的 Linux 0.11,在其环境下编写两个测试程序 iam.c 和 whoami.c。

调用系统调用,是调用系统库中为该系统调用编写的一个接口函数,叫 API(Application Programming Interface)。API 并不能完成系统调用的真正功能,它要做的是去调用真正的系统调用,过程是:

把系统调用的编号存入 EAX;
把函数参数存入其它通用寄存器;
触发 0x80 号中断(int 0x80)。

查看一下/lib/close.c,研究一下close() 的API:

#define __LIBRARY__
#include 

_syscall1(int, close, int, fd)

其中_syscall1是一个宏定义,在include/unistd.h中定义

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

这里将__NR_close的调用号存入eax中,fd存入ebx中,然后执行 int $0x80中断调用。

int 0x80触发以后,就是内核的中断处理了。
调用IDT(中断描述表)中0x80对应位置的system_call。

__NR_close在include/unistd.h中定义:

#define __NR_close    6

_NR##name用于确定调用sys_call_table表中的哪一个中断处理函数,sys_call_table表定义在include/linux/sys.h

extern int sys_setup();
extern int sys_exit();
extern int sys_fork();
extern int sys_read();
extern int sys_write();
extern int sys_open();
extern int sys_close();
extern int sys_waitpid();

fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid....}

而使用int 0x80来调用系统调用,实在操作系统初始化时,在

sched_init();

中完成了对系统调用的初始化。

sched_init()
{
	set_system_gate(0x80,&system_call);
}

#define set_system_gate(n,addr) 
	_set_gate(&idt[n],15,3,addr)
	
#define _set_gate(gate_addr,type,dpl,addr) 
__asm__ ("movw %%dx,%%axnt" 
	"movw %0,%%dxnt" 
	"movl %%eax,%1nt" 
	"movl %%edx,%2" 
	: 
	: "i" ((short) (0x8000+(dpl<<13)+(type<<8))), 
	"o" (*((char *) (gate_addr))), 
	"o" (*(4+(char *) (gate_addr))), 
	"d" ((char *) (addr)),"a" (0x00080000))


movw %%dx,%%ax 将ax置为0008:addr
movw %0,%%dx 将dx置为0x8000+(dpl<<13)+(type<<8),
分别赋给idt中0x80偏移的低4字节,高4字节。
所以当执行int 0x80中断时,就调用system_call

在本实验中,我们在/oslab/linux-0.11/include/unistd.h 中添加两个调用号

#define __NR_whoami     72
#define __NR_iam        73

并且将kernel/system_call.s中

nr_system_calls = 72 
改为
nr_system_calls = 74

在include/linux/sys.h中添加系统调用名,并且更新系统调用表

extern int sys_whoami();
extern int sys_iam();

fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid....sys_whoami, sys_iam}

接下来为新添加的系统调用编写实现代码
在linux-0.11/kernel目录下,创建who.c

#include 
#include 
#include 

char _myname[24];

int sys_iam(const char *name)
{
    char str[25];
    int i = 0;

    do
    {
        // get char from user input
        str[i] = get_fs_byte(name + i);
    } while (i <= 25 && str[i++] != '');

    if (i > 24)
    {
        errno = EINVAL;
        i = -1;
    }
    else
    {
        // copy from user mode to kernel mode
        strcpy(_myname, str);
    }

    return i;
}

int sys_whoami(char *name, unsigned int size)
{
    int length = strlen(_myname);
    printk("%sn", _myname);

    if (size < length)
    {
        errno = EINVAL;
        length = -1;
    }
    else
    {
        int i = 0;
        for (i = 0; i < length; i++)
        {
            // copy from kernel mode to user mode
            put_fs_byte(_myname[i], name + i);
        }
    }
    return length;
}

之后修改kernel/Makefile文件,用以链接kernel/who.c与其它代码

vim +27  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 who.o


### 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

再完成系统的编译,为linux-0.11编写测试程序iam.c, whoami.c

#define __LIBRARY__
#include  
#include 
#include  
#include 
_syscall1(int, iam, const char*, name);
   
int main(int argc, char *argv[])
{
    
    iam(argv[1]);
    return 0;
}

#define __LIBRARY__
#include  
#include 
#include  
#include 
#include 
   
_syscall2(int, whoami,char *,name,unsigned int,size);
   
int main(int argc, char *argv[])
{
    char username[64] = {0};
    
    whoami(username, 24);
    printf("%sn", username);
    return 0;
}



#define __LIBRARY__


#include "unistd.h"


_syscall1(int, iam, const char*, name);


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

把编写好的测试程序通过挂载到虚拟机操作系统

~/oslab$ sudo ./mount-hdc 
~/oslab$ cp iam.c whoami.c hdc/usr/root

执行脚本./run 进入虚拟机操作系统修改虚拟机系统调用号跟第一步是一样的

#define __NR_whoami	   	72
#define __NR_iam	   	73   

在虚拟机 gcc 编译执行测试程序


到这里就算是完成了该实验

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/881591.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号