系统调用是操作系统提供给用户(应用程序)的一组接口,每个系统调用都有一个对应的系统调用函数来完成相应的工作。用户通过这个接口向操作系统申请服务,如访问硬件,管理进程等等。但是因为用户程序运行在用户空间,而系统调用运行在内核空间,因此用户程序不能直接调用系统调用函数,我们经常看到的比如fork、open、write 等等函数实际上并不是真正的系统调用函数,他们都只是c库,在这些函数里将执行一个软中断 swi 指令,产生一个软中断,使CPU 陷入内核态,接着在内核中进行一系列的判断,判断出是哪个系统调用,再转到真正的系统调用函数,完成相应的功能。下面举一个简单的例子说明从用户态调用一个“系统调用”,到内核处理的整个执行流程。
用户态程序如下:
void pk()
{
__asm__(
”ldr r7 =365 \n”
”swi \n”
:
:
:
);
}
int main()
{
pk();
retrun 0;
}
上面的代码中,我自己实现了一个新的系统调用,具体怎么做,后面再具体描述。pk()事实上就可以类比于平时我们在用户程序里调用的 open() 等函数,这个函数只做了一件简单的事:将系统调用号传给 r7 ,,然后产生一软中断。接着CPU陷入内核
内核态:
CPU相应这个软中断以后,PC指针会到相应的中断向量表中取指,中断向量表在内核代码中:arch/arm/kernel/entry-armv.S 中定义
.LCvswi:.wordvector_swi
.globl__stubs_end__stubs_end:
.equstubs_offset, __vectors_start + 0x200 – __stubs_start
.globl__vectors_start__vectors_start:ARM(swiSYS_ERROR0)THUMB(svc#0 )THUMB(nop )W(b)vector_und + stubs_offsetW(ldr)pc, .LCvswi + stubs_offset #响应中断后pc指向这里W(b)vector_pabt + stubs_offsetW(b)vector_dabt + stubs_offsetW(b)vector_addrexcptn + stubs_offsetW(b)vector_irq + stubs_offsetW(b)vector_fiq + stubs_offset
.globl__vectors_end__vectors_end:
当pc取到如上的指令后,会跳到 vector_swi 这个标号,这个标号在arch/arm/kernel/entry-commen.S 中定义。
.align5ENTRY(vector_swi)subsp, sp, #S_FRAME_SIZEstmiasp, {r0 – r12} @ Calling r0 – r12ARM(addr8, sp, #S_PC )ARM(stmdbr8, {sp, lr}^ )@ Calling sp, lrTHUMB(movr8, sp )THUMB(store_user_sp_lr r8, r10, S_SP)@ calling sp, lrmrsr8, spsr @ called from non-FIQ mode, so ok.strlr, [sp, #S_PC] @ Save calling PCstrr8, [sp, #S_PSR] @ Save CPSRstrr0, [sp, #S_OLD_R0] @ Save OLD_R0zero_fp
/* * Get the system call number. #取出系统调用号 */
#if defined(CONFIG_OABI_COMPAT)
/* * If we have CONFIG_OABI_COMPAT then we need to look at the swi * value to determine if it is an EABI or an old ABI call. */#ifdef CONFIG_ARM_THUMBtstr8, #PSR_T_BITmovner10, #0 @ no thumb OABI emulationldreqr10, [lr, #-4] @ get SWI instruction#elseldrr10, [lr, #-4] @ get SWI instruction A710(andip, r10, #0x0f000000 @ check for SWI ) A710(teqip, #0x0f000000 ) A710(bne.Larm710bug )#endif#ifdef CONFIG_CPU_ENDIAN_BE8revr10, r10 @ little endian instruction#endif
#elif defined(CONFIG_AEABI)
/* * Pure EABI user space always put syscall number into scno (r7). */ A710(ldrip, [lr, #-4] @ get SWI instruction) A710(andip, ip, #0x0f000000 @ check for SWI ) A710(teqip, #0x0f000000 ) A710(bne.Larm710bug )
#elif defined(CONFIG_ARM_THUMB)
/* Legacy ABI only, possibly thumb mode. */tstr8, #PSR_T_BIT @ this is SPSR from save_user_regsaddnescno, r7, #__NR_SYSCALL_BASE@ put OS number inldreqscno, [lr, #-4]
#else
/* Legacy ABI only. */ldrscno, [lr, #-4] @ get SWI instruction A710(andip, scno, #0x0f000000 @ check for SWI ) A710(teqip, #0x0f000000 ) A710(bne.Larm710bug )
#endif
你并不一定会从此拥有更美好的人生,