第15章 实现系统调用

在 1KOS中,我们使用中断向量0x80用于实现系统调用。0x80中断的ISR是trap gate而不是interrupt gate。我们需要在IDT表中的第0x80个中断向量中填入陷阱门(trap gate)描述符。而且设置描述符中DPL=0x3,这样用户态程序也能进行系统调用。在0x80的描述符中,代码段选择子是内核数据代码段,偏移地址是sys_call函数地址。sys_call的定义在interrupt.s中。

<

pre name=”code” class=”c”>

static void sys_call_install(void)
{
unsigned long long sys_call_entry = 0x0000ef0000000000ULL | ((unsigned long long)CODE_SEL << 16); //代表陷阱门,DPL=0x3
sys_call_entry |= ((unsigned long long )sys_call<<32) & 0xffff000000000000ULL;
sys_call_entry |= (unsigned long long )sys_call & 0xffff;
IDT[SYS_CALL_VECTOR] = sys_call_entry;
}

在idt_install()函数中调用sys_call_install()函数

void idt_install(void)
{
    unsigned int i = 0;
    //先填充IDT表
    
    for(i = 0; i < 256; i++)
    {
    isr_entry(i, (unsigned int )default_isr);
    }
    
    isr_entry(0, (unsigned int)divide_error);
    isr_entry(1, (unsigned int)debug_exception);
    isr_entry(2, (unsigned int)nmi);
    isr_entry(3, (unsigned int)breakpoint);
    isr_entry(4, (unsigned int)overflow);
    isr_entry(5, (unsigned int)bound);
    isr_entry(6, (unsigned int)invalid_opcode);
    isr_entry(7, (unsigned int)coprocessor_not_available);
    isr_entry(8, (unsigned int)double_fault);
    isr_entry(9, (unsigned int)coprocessor_segment_overrun);
    isr_entry(10, (unsigned int)invalid_tss);
    isr_entry(11, (unsigned int)segment_not_present);
    isr_entry(12, (unsigned int)stack_exception);
    isr_entry(13, (unsigned int)protection_exception);
    isr_entry(14, (unsigned int)page_fault);
    isr_entry(15, (unsigned int)intel_reserved);
    isr_entry(16, (unsigned int)coprecessor_error);

    isr_entry(0x20, (unsigned int)timer);

    //加载系统调用
    sys_call_install();

    ////载入idt_descr
    __asm__("lidt %0\n\t"::"m"(idt_descr));
}

sys_call函数的定义在interrupt.s中(参考了linux 0.11),如下所示

sys_call:
    cmpl   $NR_SYSTEM_CALLS-1,    %eax
    ja        bad_sys_call
    push    %ds
    push    %es
    push    %fs
    pushl   %esi
    pushl   %edi
    pushl   %edx
    pushl   %ecx
    pushl   %ebx
    movl    $DATA_SEL,    %edx    #设置ds,es使用内核数据段
    mov        %dx,    %ds
    mov        %dx,    %es
    mov        $USER_DATA_SEL,    %edx #设置fs使用用户数据段
    mov        %dx,    %fs     
    call    sys_call_table(,%eax,4)  #从系统调用函数表中调用指定的函数
    popl    %ebx
    popl    %ecx
    popl    %edx
    popl    %edi
    popl    %esi
    pop        %fs
    pop        %es
    pop        %ds
    iret

bad_sys_call:
    movl    $-1,    %eax
    iret

sys_call_table系统调用函数表的声明在syscall.h中,具体定义在syscall.c中。sys_call根据参数调用号(eax)的不同(参数放在eax、ebx、ecx、edx、edi、esi),执行不同的函数。

syscall.h的源代码如下所示(参考了linux 0.11)

#ifndef        _SYSCALL_H_
#define     _SYSCALL_H_

#include "kernel.h"
#include "task.h"
#include "mem.h"

#define     SYS_CALL_VECTOR    0x80

#define     __NR_create_task    0
#define     __NR_malloc        1
#define     __NR_free        2
#define     __NR_suspend_task   3
#define     __NR_resume_task    4
#define     __NR_sleep        5
#define     __NR_kprint        6
#define     __NR_delete_task    7
#define     __NR_clear_dead_task 8
#define     __NR_send_msg    9
#define     __NR_receive_msg    10

typedef int (*fn_ptr)();
extern    fn_ptr sys_call_table[NR_SYSTEM_CALLS];


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

#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;\
    return -1;\
}

#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;\
    return -1;\
}

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

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


#define     _syscall5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \
type  name(atype a,btype b,ctype c,dtype d,etype e)\
{\
    long __res;\
    __asm__ volatile("int $0x80"\
        :"=a"(__res)\
        :"0"(__NR_##name),"b"((long)(a)),"c"((long)(b)),"d"((long)(c)),"D"((long)(d)),"S"((long)(e)));\
    if(__res>=0)\
    return (type)__res;\
    return -1;\
}

//系统调用函数

int create_task(unsigned int task_function, unsigned int stack0_size, unsigned int stack3_size);
void *malloc(unsigned long size);
void *free(void *addr);
int suspend_task(int pid);
int resume_task(int pid);
int sleep(int ms);
int kprint(unsigned char attribute, char *string);
int delete_task(int pid);
int clear_dead_task(void);
int send_msg(int pid, struct msg *msg);
int receive_msg(struct msg *msg);


#endif

syscall.c的源代码如下所示(参考了linux 0.11)

#include "syscall.h"
#include "io.h"
#include "video.h"
#include "task.h"
#include "mem.h"

_syscall3(int,create_task,unsigned int,task_function,unsigned int, stack0_size, unsigned int ,stack3_size)

_syscall1(void*,malloc,unsigned long ,size)
_syscall1(void*,free,void *,addr)
_syscall1(int,suspend_task,int,pid)
_syscall1(int,resume_task,int,pid)
_syscall1(int,sleep,int,ms)
_syscall2(int,kprint,unsigned char,attribute,char *,string)
_syscall1(int,delete_task,int,pid)
_syscall0(int,clear_dead_task)
_syscall2(int,send_msg,int,pid,struct msg *,msg)
_syscall1(int,receive_msg,struct msg *,msg)


fn_ptr sys_call_table[]={
    sys_create_task,
    sys_malloc,
    sys_free,
    sys_suspend_task,
    sys_resume_task,
    sys_sleep,
    sys_kprint,
    sys_delete_task,
    sys_clear_dead_task,
    sys_send_msg,
    sys_receive_msg
    };

宏定义_syscall3(int,create_task,unsignedint,task_function,unsignedint, stack0_size, unsigned int ,stack3_size)生成的函数如下所示。 该函数把系统调用号0,参数task_function,参数stack0_size,参数stack3_size分别赋予不同的寄存器,然后触发0x80中断。0x80中断的中断处理函数sys_call先把各个参数压入栈中,然后根据”call sys_Call_table[0]”,也就是”call sys_create_task”,然后返回结果。

int create_task(unsigned int task_function,unsigned int stack0_size,unsigned int stack3_size)
{    
    long __res; 
    __asm__ volatile("int $0x80"
        :"=a"(__res) 
        :"0"(0),"b"((long)(task_function)),"c"((long)(stack0_size)),"d"((long)(stack3_size))
        ); 
    if(__res>=0) 
        return (int)__res; 
    return -1;
}

Leave a Reply

Your email address will not be published. Required fields are marked *