码迷,mamicode.com
首页 > 其他好文 > 详细

Kernel散记——系统调用

时间:2015-06-16 19:14:19      阅读:141      评论:0      收藏:0      [点我收藏+]

标签:

 Kernel散记——系统调用
这里是指arm linux架构(Android4.4)

1,referen
1.1,这是讲得比较全面。读完之后,你大致可以讲得清系统调用的过程
“系统调用就是用户民通过swi指令陷入内核,cpu由user模式进入svc模式的过程,调用的过程大致是先备份当前任务的上下文(相应的堆栈信息),然后通过swi指令的参数,来找到对应的系统调用表,执行完系统调用,把返回值写在指定的寄存器,恢复原来的现场,完成系统调用”
1.2,同时还讲了系统调用和普通API的区别(主要是有没有陷入内核态)

这里主要列出了Linux系统调用的列表,供参考

2,我的理解。以clone()为例
2.1 API有的不需要系统调用,比如Math.h里面。有的需要,比如接下来讲的pthread.h
2.2 在用户空间。创建一个线程,有如下API调用:
     #include <pthread.h>
     pthread_create(&tid, &attr, thr_fn, NULL);
=>$android_root/bionic/libc/include/pthrea.h
     int pthread_create(pthread_t *thread, pthread_attr_t const * attr,                                                                                             
                   void *(*start_routine)(void *), void * arg);
=>$adnroid_root/bionic/libc/bionic/pthread_create.cpp
     int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr,                                                                                          
                   void* (*start_routine)(void*), void* arg) {
     ...
     int tid = __pthread_clone(start_routine, child_stack, flags, arg);//最终调用到这里
     }
=>bionic/libc/arch-arm/bionic/Clone.S
这里是通过汇编来实现的。
     // int  __pthread_clone(void* (*fn)(void*), void* child_stack, int flags, void* arg);
     ENTRY(__pthread_clone)
    # Push ‘fn‘ and ‘arg‘ onto ‘child_stack‘.
    stmdb   r1!, {r0, r3}

    # The sys_clone system call only takes two arguments: ‘flags‘ and ‘child_stack‘.
    # ‘child_stack‘ is already in r1, but we need to move ‘flags‘ into position.
    mov     r0, r2

    # System call.
    mov     ip, r7
    ldr     r7, =__NR_clone //系统调用号定义在unistd.h #define __NR_clone (__NR_SYSCALL_BASE+120),即120号写入R7
    swi     #0  //通过swi软中断指令陷入内核
     ...
END(__pthread_clone)


2.3 在Kernel空间
首先处理SWI指令
$kernel_root/arch/arm/kernel/entry-common.S
/*=============================================================================
* SWI handler
*-----------------------------------------------------------------------------
*/

    .align  5
ENTRY(vector_swi)
    sub sp, sp, #S_FRAME_SIZE
    stmia   sp, {r0 - r12}          @ Calling r0 - r12 
ARM(   add r8, sp, #S_PC       )
ARM(   stmdb   r8, {sp, lr}^       )   @ Calling sp, lr
THUMB( mov r8, sp          )   
THUMB( store_user_sp_lr r8, r10, S_SP  )   @ calling sp, lr
    mrs r8, spsr            @ called from non-FIQ mode, so ok. 
    str lr, [sp, #S_PC]         @ Save calling PC
    str r8, [sp, #S_PSR]        @ Save CPSR
    str r0, [sp, #S_OLD_R0]     @ Save OLD_R0
    zero_fp
...
      addne   scno, r7, #__NR_SYSCALL_BASE    @ put OS number in //从R7把系统调用号读出来
...
    adr tbl, sys_call_table     @ load syscall table pointer //再根据系统调用号,查询sys_call_table这个表,找到相应的系统调用
ENTRY(sys_call_table)
#include "calls.S"
sys_call_table即calls.S
=>calls.S
...
/* 120 */   CALL(sys_clone)//120号对应的就是sys_clone
... 
=>entry-common.S
 ldrcc   pc, [tbl, scno, lsl #2]     @ call sys_* routine//这里执行系统调用。

那么在哪实现sys_clone的呢?不同的系统的调用,在不同的目录里,比较open就是在fs/下面,clone就就在kernel下面。使用宏SYSCALL_DEFINE来配合使用。
=>kernel/fork.c
#ifdef __ARCH_WANT_SYS_CLONE  
#ifdef CONFIG_CLONE_BACKWARDS
SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
         int __user *, parent_tidptr,
         int, tls_val,
         int __user *, child_tidptr)
#elif defined(CONFIG_CLONE_BACKWARDS2)
SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags,
         int __user *, parent_tidptr,
         int __user *, child_tidptr,
         int, tls_val)
#elif defined(CONFIG_CLONE_BACKWARDS3)
SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp,
        int, stack_size,
        int __user *, parent_tidptr,
        int __user *, child_tidptr,
        int, tls_val)
#else
SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
         int __user *, parent_tidptr,
         int __user *, child_tidptr,
         int, tls_val)
#endif
{
    return do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr);                                                                                        
}
#endif
=>
最终是调用forkc.c/do_fork()的.
整个流程是这样的,通了流程,有需要有精力就可以深入细节啦。

Kernel散记——系统调用

标签:

原文地址:http://blog.csdn.net/koffuxu/article/details/46521393

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!