linux arm 系统,Linux ARM系统调用实现

本文详细介绍了Linux在ARM平台上的系统调用实现方式,主要通过SWI异常中断来实现。首先,讲解了SWI指令及其在系统调用中的作用,然后展示了SWI异常中断处理程序的两级结构。接着,分析了Linux系统调用注册函数`trap_init`,以及SWI异常处理函数`vector_swi`如何获取和处理系统调用号。最后,概述了系统调用结束后如何返回到用户空间的过程。
摘要由CSDN通过智能技术生成

Linux ARM系统调用实现

一.Arm SWI 异常中断

本部分参考《ARM体系结构与编程》杜春雷

ARM版本的Linux的系统调用的实现是通过发一个SWI异常中断的方式实现的,通过SWI异常可以实现用户空间陷入到内核的操作。通常SWI异常中断处理程序可以分为两级:第一级SWI异常中断处理程序为汇编语言,用于确定SWI中的24位立即数;第二级SWI异常中断处理程序实现SWI的各个功能。

1.1 SWI指令

在SWI指令中包含有24位的立即数,通过该立即数可以使用户跳转到不同的执行分支上。在进入SWI异常时,LR寄存器保存的是SWI指令的下一条,所以,SWI指令应该是:

LDR  R0,[LR, # -4]

取SWI指令的24位立即数

BIC R0,R0,#0XFF00 0000

在linux系统调用时,采用该两行代码取得系统调用号。

1.2实现代码

AREA TopLevelSWI, CODE, READONLY

EXPORT SWI_Handler

SWI_Handler

STMFD sp!, [r0-r12, lr]

LDR r0, [lr, # -4]

BIC r0, r0, #0xff00 0000

BLC C_SWI_Handler  //使用R0寄存器中的值,调用相应的SWI异常中断的第二级处理程序。

LDMFD sp!, [r0-r12, pc]^

END

/

Void C_SWI_Handler(unsigned number)

{

Switch(number)

Case 0://执行分支0;

Break;

Case 1://执行分支1;

Break;

Default:

break

}

二.Linux系统调用的实现

Linux系统调用是应用程序的API函数调用内核提供的系统调用实现对linux内核或者硬件的访问,在ARM平台上是通过产生SWI异常来实现的。

2.1SWI异常执行函数的注册

void __init trap_init(void)

{

unsigned long vectors = CONFIG_VECTORS_BASE;

memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);

}

该函数在start_kernel()中执行,即初始化的时候执行。

.LCvswi:

.word      vector_swi/* SYS_CALL*/

.globl      __stubs_end

__stubs_end:

.equ stubs_offset, __vectors_start + 0x200 - __stubs_start

.globl      __vectors_start

__vectors_start:

swi  SYS_ERROR0

b     vector_und + stubs_offset

ldrpc, .LCvswi + stubs_offset //此处即为定义的SWI函数,指向vector_swi

b     vector_pabt + stubs_offset

b     vector_dabt + stubs_offset

b     vector_addrexcptn + stubs_offset

b     vector_irq + stubs_offset

b     vector_fiq + stubs_offset

.globl      __vectors_end

__vectors_end:

.data

.globl      cr_alignment

.globl      cr_no_alignment

cr_alignment:

.space     4

cr_no_alignment:

.space     4

2.2 linux SWI函数vector_swi

.align       5

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

//保存寄存器值到栈中

/*

* 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_THUMB

tst    r8, #PSR_T_BIT

movne     r10, #0                         @ no thumb OABI emulation

ldreq       r10, [lr, #-4]                 @ get SWI instruction,取swi指令中的立即数,即系统调用号

#else

ldr   r10, [lr, #-4]                 @ get SWI instruction // here get syscall num swi

A710(  and  ip, r10, #0x0f000000            @ check for SWI          )

A710(  teq   ip, #0x0f000000                                        )

A710(  bne  .Larm710bug                                     )

#endif

#elif defined(CONFIG_AEABI)

/*

* Pure EABI user space always put syscall number into scno (r7).

*/

A710(  ldr   ip, [lr, #-4]                    @ get SWI instruction   )

A710(  and  ip, ip, #0x0f000000              @ check for SWI          )

A710(  teq   ip, #0x0f000000                                        )

A710(  bne  .Larm710bug                                     )

#elif defined(CONFIG_ARM_THUMB)

/* Legacy ABI only, possibly thumb mode. */

tst    r8, #PSR_T_BIT                  @ this is SPSR from save_user_regs

addne      scno, r7, #__NR_SYSCALL_BASE      @ put OS number in  /*__NR_SYSCALL_BASE*/

ldreq  scno, [lr, #-4]// scno是寄存器r7的别名

#else

/* Legacy ABI only. */

ldr   scno, [lr, #-4]               @ get SWI instruction

A710(  and  ip, scno, #0x0f000000          @ check for SWI          )

A710(  teq   ip, #0x0f000000                                        )

A710(  bne  .Larm710bug                                     )

#endif

#ifdef CONFIG_ALIGNMENT_TRAP

ldr   ip, __cr_alignment

ldr   ip, [ip]

mcr p15, 0, ip, c1, c0           @ update control register

#endif

enable_irq

get_thread_info tsk

adr   tbl, sys_call_table          @ load syscall table pointer/* important here load sys_call_table, details see line268,line269,and see call.s*///系统调用函数的基指针

ldr   ip, [tsk, #TI_FLAGS]           @ check for syscall tracing

#if defined(CONFIG_OABI_COMPAT)

/*

* If the swi argument is zero, this is an EABI call and we do nothing.

*

* If this is an old ABI call, get the syscall number into scno and

* get the old ABI syscall table address.

*/

bics r10, r10, #0xff000000                        // here get syscall num swi

eorne      scno, r10, #__NR_OABI_SYSCALL_BASE

ldrne       tbl, =sys_oabi_call_table

#elif !defined(CONFIG_AEABI)

bic   scno, scno, #0xff000000             @ mask off SWI op-code   //here get syscall num swi

eor   scno, scno, #__NR_SYSCALL_BASE  @ check OS number

#endif

stmdb     sp!, {r4, r5}                 @ push fifth and sixth args

tst    ip, #_TIF_SYSCALL_TRACE             @ are we tracing syscalls?

bne  __sys_trace

cmp scno, #NR_syscalls              @ check upper syscall limit

adr   lr, ret_fast_syscall         @ return address系统调用结束后的返回函数,恢复寄存器

ldrcc       pc, [tbl, scno, lsl #2]            @ call sys_* routine  /* execut the call function,将调用号逻辑左移2位*/系统调用的执行函数

add  r1, sp, #S_OFF

2:     mov why, #0                        @ no longer a real syscall

cmp scno, #(__ARM_NR_BASE - __NR_SYSCALL_BASE)

eor   r0, scno, #__NR_SYSCALL_BASE      @ put OS number back

bcs  arm_syscall    //系统调用号不正确

b     sys_ni_syscall               @ not private func

2.3 linux系统调用的返回函数

ret_fast_syscall:

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_user r1, lr

@ fast_restore_user_regs

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

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

msr  spsr_cxsf, r1                @ save in spsr_svc

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

mov r0, r0

add  sp, sp, #S_FRAME_SIZE - S_PC

movs      pc, lr                            @ return & move spsr_svc into cpsr

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值