1首先来讲讲应用程序如何实现系统调用(用户态->内核态)?
我们以应用程序的write()函数为例:
1)首先用户态的write()函数会进入glibc库,里面会将write()转换为swi(Software Interrupt)指令,从而产生软件中断,swi指令如下所示:
代码语言:javascript复制swi #val //val: bit[23:0]立即数,该val用来判断用户函数需要调用哪个内核函数
2)然后CPU会跳到异常向量入口vector_swi处,根据swi指令后面的val值,在某个数组表里找到对应的sys_write()函数
代码如下所示(位于archarmkernelentry-common.S):
代码语言:javascript复制ENTRY(vector_swi)
/*保护用户态的现场*/
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0 - r12
add r8, sp, #S_PC
stmdb r8, {sp, lr}^ @ 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
... ...
ldr scno, [lr, #-4] @ get SWI instruction //获取SWI值
A710( and ip, scno, #0x0f000000 @ check for SWI)
A710( teq ip, #0x0f000000) //校验SWI的bit[27:24]是否为0xf
A710( bne .Larm710bug)
... ...
enable_irq //调用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 //只保留SWI的bit[23:0],也就是val值
eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
//对于2440而讲,__NR_SYSCALL_BASE基地址等于0x900000,也就是说val值为0x900000时,异或后,scno则等于0,表示数组表的基地址(第一个函数位置)
... ...
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine //pc=(tbl scno)<<2,实现调用sys_write()
//tbl:数组表基地址, scno:要调用的sys_write()的索引值 lsl #2:左移2位,一个函数指针占据4个字节
从上面代码可以看出,2440的val基值为0x900000,也就是说要调用数组表的第一个函数时,则使用:
代码语言:javascript复制swi #0x900000
2 接下来,我们便来自制一个系统调用
1)在内核中,仿照一个sys_hello函数,然后放入数组表,供swi调用 2)写应用程序,直接通过swi指令,来调用sys_hello函数
3 仿照sys_hello()
3.1先来查找数组表,以sys_write为例,搜索找到位于arch/arm/kernel/calls.S,如下图所示:
其中CALL定义如下所示:
代码语言:javascript复制.equ NR_syscalls,0 //将NR_syscalls=0
#define CALL(x) .equ NR_syscalls,NR_syscalls 1 //将CALL(x) 定义为:NR_syscalls=NR_syscalls 1 ,也就是每有一个CALL(),则该CALL值则 1
#include "calls.S" //将calls.S的内容包进来,CALL(x)上面已经有了定义,就会将calls.S里面的所有CALL(sys_xx)排列起来
#undef CALL //撤销CALL定义
#define CALL(x) .long x //然后再将排列起来的sys_xx以long(4字节)对齐,一个函数指针占据4字节
3.2 所以我们在call.S文件的CALL()列表的最后添加一段, 如下图所示, sys_hello()的val值为352:
3.3 fsread_write.c文件里写一个sys_hello()函数
代码语言:javascript复制asmlinkage void sys_hello(const char __user * buf, size_t count) //打印count长数据
{
char ker_buf[100];
if(buf)
{ copy_from_user(ker_buf, buf, (count<100)? count : 100);
ker_buf[99]='