Chinaunix首页 | 论坛 | 博客
  • 博客访问: 592258
  • 博文数量: 92
  • 博客积分: 5026
  • 博客等级: 大校
  • 技术积分: 1321
  • 用 户 组: 普通用户
  • 注册时间: 2008-02-28 11:04
文章分类

全部博文(92)

文章存档

2011年(9)

2010年(17)

2009年(12)

2008年(54)

我的朋友

分类:

2011-04-16 13:57:19

注:本文涉及的硬件平台默认为x86

为什么需要系统调用:

系统调用是用户态访问进入到内核态从而可以访问内核资源的一个桥梁。比如说在用户态可以调用getpid()这个系统调用来获取当前进程号,当前进程号是存在内核的task_struct结构体中的,只有内核态才能访问到。如果用户态试图访问内核地址空间将会产生一个段错误。

 

Android的系统调用:

首先内核需要实现好相应的系统调用号的处理函数。

linux-syscall.h定义系统调用号

#define __NR_getpid                       (__NR_SYSCALL_BASE + 20)

syscalls.txt生命要生成代码的系统调用汇编文件

# each non comment line has the following format:

# return_type    func_name[:syscall_name[:call_id]]([parameter_list])  (#syscall_number|stub)

pid_t       getpid ()    20

通过gensyscalls.py产生汇编文件getpid.S,内容如下:

/* autogenerated by gensyscalls.py */

#include

 

    .text

    .type getpid, @function

    .globl getpid

    .align 4

 

getpid:

    movl    $__NR_getpid, %eax        //将系统调用好保存到eax寄存器

    int     $0x80                     //编程异常。陷入到内核态

    cmpl    $-129, %eax

    jb      1f

    negl    %eax

    pushl   %eax

    call    __set_errno

    addl    $4, %esp

    orl     $-1, %eax

1:

    ret

 

Linux内核处理流程:

在用户态执行了int $0x80之后,cpu产生了一个编程异常。Cpu的控制单元做了一系列的硬件处理之后,比如保存eflagscseipssesp寄存器,并载入新的值切换到内核态。然后cpu跳转到0x80相应的中断处理函数处执行。(硬件处理流程具体见深入理解linux内核的中断和异常的硬件处理)

 

内核的中断处理函数是:system_call

ENTRY(system_call)

        RING0_INT_FRAME                 # can't unwind into user space anyway

        pushl %eax                      # save orig_eax

        CFI_ADJUST_CFA_OFFSET 4

        SAVE_ALL                     #保存大多数寄存器的内容

        GET_THREAD_INFO(%ebp)

                                        # system call tracing in operation / emulation

        testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)

        jnz syscall_trace_entry

        cmpl $(nr_syscalls), %eax

        jae syscall_badsys

syscall_call:

        call *sys_call_table(,%eax,4)         #调用相应系统调用号的处理函数

        movl %eax,PT_EAX(%esp)          # store the return value

syscall_exit:                              #退出系统调用

        LOCKDEP_SYS_EXIT

        DISABLE_INTERRUPTS(CLBR_ANY)    # make sure we don't miss an interrupt

                                        # setting need_resched or sigpending

                                        # between sampling and the iret

        TRACE_IRQS_OFF

        movl TI_flags(%ebp), %ecx

        testl $_TIF_ALLWORK_MASK, %ecx  # current->work

        jne syscall_exit_work

restore_all:

        TRACE_IRQS_IRET

restore_all_notrace:

        movl PT_EFLAGS(%esp), %eax      # mix EFLAGS, SS and CS

        # Warning: PT_OLDSS(%esp) contains the wrong/random values if we

        # are returning to the kernel.

        # See comments in process.c:copy_thread() for details.

        movb PT_OLDSS(%esp), %ah

        movb PT_CS(%esp), %al

        andl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax

        cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax

        CFI_REMEMBER_STATE

        je ldt_ss                       # returning to user-space with LDT SS

restore_nocheck:

        RESTORE_REGS 4                  # skip orig_eax/error_code

        CFI_ADJUST_CFA_OFFSET -4

irq_return:

        INTERRUPT_RETURN

 

阅读(6708) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~