微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM Linux系统调用的原理

ARM Linux系统调用的原理

时间:11-09 来源:互联网 点击:

ted.*/

591 if ((no & 0xffff) <= 0x7ff)

592 return -ENOSYS;

593 break;

594}

595 #ifdef CONFIG_DEBUG_USER

596/*

597* experience shows that these seem to indicate that

598* something catastrophic has happened

599*/

600if (user_debug & UDBG_SYSCALL) {

601 printk("[%d] %s: arm syscall%d\n",

602task_pid_nr(current),current->comm, no);

603 dump_instr("", regs);

604 if (user_mode(regs)) {

605 __show_regs(regs);

606 c_backtrace(regs->ARM_fp, processor_mode(regs));

607 }

608}

609 #endif

610info.si_signo = SIGILL;

611info.si_errno = 0;

612info.si_code = ILL_ILLTRP;

613info.si_addr = (void __user*)instruction_pointer(regs) -

614 (thumb_mode(regs) ? 2 : 4);

615

616arm_notify_die("Oops - bad syscall(2)", regs, &info, no,0);

617return 0;

618 }

这个函数处理所有的辨别不出来的系统调用。系统调用号正确也好不正确也好,最终都是通过ret_fast_syscall例程来返回,因为我们看到,在进入系统调用处理函数之前,先加载了符号ret_fast_syscall进lr寄存器。ret_fast_syscall定义如下:

arch/arm/kernel/entry-common.S

ret_fast_syscall:

UNWIND(.fnstart )

UNWIND(.cantunwind )

disable_irq @ disable interrupts

ldr r1, [tsk, #TI_FLAGS]

tst r1, #_TIF_WORK_MASK

bne fast_work_pending

/*perform architecture specific actions before user return */

arch_ret_to_userr1, lr

restore_user_regsfast = 1, offset = S_OFF

UNWIND(.fnend )

fast_work_pending:

str r0, [sp, #S_R0+S_OFF]! @ returned r0

work_pending:

tst r1, #_TIF_NEED_RESCHED

bne work_resched

tst r1, #_TIF_SIGPENDING_TIF_NOTIFY_RESUME

beq no_work_pending

mov r0, sp @regs

mov r2, why @syscall

bl do_notify_resume

b ret_slow_syscall @ Check work again

work_resched:

bl schedule

/*

* "slow" syscall return path. "why" tells us if this was a realsyscall.

*/

ENTRY(ret_to_user)

ret_slow_syscall:

disable_irq @ disable interrupts

ldr r1, [tsk, #TI_FLAGS]

tst r1, #_TIF_WORK_MASK

bne work_pending

no_work_pending:

/*perform architecture specific actions before user return */

arch_ret_to_userr1, lr

restore_user_regsfast = 0, offset = 0

ENDPROC(ret_to_user)

对于我们的平台来说,上面的arch_ret_to_user为空。restore_user_regs宏用于恢复现场并返回,restore_user_regs宏定义如下:

arch/arm/kernel/entry-header.S

.macro restore_user_regs, fast = 0, offset = 0

ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr

ldr lr, [sp, #\offset + S_PC]! @ get pc

msr spsr_cxsf, r1 @save in spsr_svc

#if defined(CONFIG_CPU_32v6K)

clrex @ clear the exclusive monitor

#elif defined (CONFIG_CPU_V6)

strex r1, r2, [sp] @clear the exclusive monitor

#endif

.if \fast

ldmdb sp, {r1 - lr}^ @get calling r1 - lr

.else

ldmdb sp, {r0 - lr}^ @get calling r0 - lr

.endif

mov r0, r0 @ARMv5T and earlier require a nop

@after ldm {}^

add sp, sp, #S_FRAME_SIZE - S_PC

movs pc, lr @return & move spsr_svc into cpsr

.endm

添加新的系统调用

第一、打开arch/arm/kernel/calls.S,在最后添加系统调用的函数原型的指针,例如:

CALL(sys_set_senda)

补充说明一点关于NR_syscalls的东西,这个常量表示系统调用的总的个数,在较新版本的内核中,文件arch/arm/kernel/entry-common.S中可以找到:

.equ NR_syscalls,0

#define CALL(x).equ NR_syscalls,NR_syscalls+1

#include"calls.S"

#undef CALL

#define CALL(x).long x

相当的巧妙,不是吗?在系统调用表中每添加一个系统调用,NR_syscalls就自动增加一。在这个地方先求出NR_syscalls,然后重新定义CALL(x)宏,这样也可以不影响文件后面系统调用表的建立。

第二、打开include/asm-arm/unistd.h,添加系统调用号的宏,感觉这步可以省略,因为这个地方定义的系统调用号主要是个C库,比如uClibc、Glibc用的。例如:

#define__NR_plan_set_senda(__NR_SYSCALL_BASE+365)

为了向后兼容,系统调用只能增加而不能减少,这里的编号添加时,也必须按顺序来。否则会导致核心运行错误。

第三,实例化该系统调用,即编写新添加系统调用的实现例如:

SYSCALL_DEFINE1(set_senda, int,iset)

{

if(iset)

UART_PUT_CR(&at91_port[2],AT91C_US_SEN

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top