1 作用
用户–>系统调用–>硬件。
作用:
1)为用户空间提供了一种硬件的抽象接口
2)保证安全性,内核可以根据权限、用户类型等对需要的访问进行裁决
2 源码分析
以arm
平台代码为例。
发生系统调用时,会通过swi指令,陷入到内核态。swi指令格式
SWI{cond} immed_24
然后进入异常向量vector_swi,在arch/arm/kernel/entry-common.S中
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
#if defined(CONFIG_OABI_COMPAT)
ldr r10, [lr, #-4] @ get SWI instruction //获取swi指令码
A710( and ip, r10, #0x0f000000 @ check for SWI ) //检测是否是正确的swi指令,在s3c2440手册中有描述格式
A710( teq ip, #0x0f000000 )
A710( bne .Larm710bug )
...
enable_irq
get_thread_info tsk
adr tbl, sys_call_table @ load syscall table pointer //tbl数组基地址
ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing
...
bic scno, scno, #0xff000000 @ mask off SWI op-code //清除高8位
eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
...
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine //将对应调用号的函数地址赋给pc
在/arch/arm/include/asm中
#define __NR_OABI_SYSCALL_BASE 0x900000
#if defined(__thumb__) || defined(__ARM_EABI__)
#define __NR_SYSCALL_BASE 0
#else
#define __NR_SYSCALL_BASE __NR_OABI_SYSCALL_BASE
#endif
__NR_SYSCALL_BASE为0x900000
2 增加系统调用
在arch/arm/kernel/calls.S中,在最后添加
...
CALL(sys_rt_tgsigqueueinfo)
CALL(sys_perf_event_open)
CALL(sys_hello) //增加的
在arch/arm/include/asm/unistd.h中增加
#define __NR_hello (__NR_SYSCALL_BASE+365)
在fs/read_write.c中增加
asmlinkage void sys_hello(const char __user * buf, int count)
{
char ker_buf[100];
if (buf)
{
copy_from_user(ker_buf, buf, (count < 100) ? count : 100);
ker_buf[99] = '\0';
printk("sys_hello: %s\n", ker_buf);
}
}
include/linux/syscalls.h文件里添加声明
asmlinkage void sys_hello(const char __user * buf, int count);
测试程序
#include <errno.h>
#include <unistd.h>
//#include <sysdep.h>
//#if defined(__thumb__) || defined(__ARM_EABI__)
//#define __NR_SYSCALL_BASE 0
//#else
#define __NR_SYSCALL_BASE 0x900000
//#endif
void hello(char *buf, int count)
{
/* swi */
asm ("mov r0, %0\n" /* save the argment in r0 */
"mov r1, %1\n" /* save the argment in r0 */
"swi %2\n" /* do the system call */
:
: "r"(buf), "r"(count), "i" (__NR_SYSCALL_BASE + 365)
: "r0", "r1");
}
int main(int argc, char **argv)
{
printf("in app, call hello\n");
hello("www.100ask.net", 15);
return 0;
}
编译
arm-linux-gcc -static syscall.c -o syscall
在开发板运行,能看到输出信息。