Kernel散记——系统调用
这里是指arm linux架构(Android4.4)
1,referen
http://blog.csdn.net/myarrow/article/details/7036266
1.1,这是讲得比较全面。读完之后,你大致可以讲得清系统调用的过程
“系统调用就是用户民通过swi指令陷入内核,cpu由user模式进入svc模式的过程,调用的过程大致是先备份当前任务的上下文(相应的堆栈信息),然后通过swi指令的参数,来找到对应的系统调用表,执行完系统调用,把返回值写在指定的寄存器,恢复原来的现场,完成系统调用”
1.2,同时还讲了系统调用和普通API的区别(主要是有没有陷入内核态)
http://blog.csdn.net/myarrow/article/details/7036215
这里主要列出了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()的.
整个流程是这样的,通了流程,有需要有精力就可以深入细节啦。