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

ARM Linux系统调用的原理

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

swi 0x0来陷入内核。否则,通过swi指令的24位立即数参数来传递系统调用号。后面还会有内核中关于这个问题的更详细的说明。

同时这两种调用方式的系统调用号也是存在这区别的,在内核的文件arch/arm/inclue/asm/unistd.h中可以看到:

#define __NR_OABI_SYSCALL_BASE 0x900

#if defined(__thumb__) defined(__ARM_EABI__)

#define __NR_SYSCALL_BASE 0

#else

#define __NR_SYSCALL_BASE __NR_OABI_SYSCALL_BASE

#endif

/*

* This file contains the system call numbers.

*/

#define __NR_restart_syscall (__NR_SYSCALL_BASE+ 0)

#define __NR_exit (__NR_SYSCALL_BASE+ 1)

#define __NR_fork (__NR_SYSCALL_BASE+ 2)

#define __NR_read (__NR_SYSCALL_BASE+ 3)

#define __NR_write (__NR_SYSCALL_BASE+ 4)

#define __NR_open (__NR_SYSCALL_BASE+ 5)

……

接下来来看操作系统对系统调用的处理。我们回到ARMLinux的异常向量表,因为当执行swi时,会从异常向量表中取例程的地址从而跳转到相应的处理程序中。在文件arch/arm/kernel/entry-armv.S中我们看到SWI异常向量:

W(ldr) pc,.LCvswi + stubs_offset

而.LCvswi在同一个文件中定义为:

.LCvswi:

.word vector_swi

也就是最终会执行例程vector_swi来完成对系统调用的处理,接下来我们来看下在arch/arm/kernel/entry-common.S中定义的vector_swi例程(删去一些和我们的示例平台无关的代码):

.align 5

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

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 needto look at the swi

* value to determine if it is an EABI or anold ABI call.

*/

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

#ifdef CONFIG_CPU_ENDIAN_BE8

//rev指令的功能是反转字中的字节序

rev r10, r10 @little endian instruction

#endif

#elif defined(CONFIG_AEABI)

#else

/*Legacy ABI only. */

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

#endif

#ifdef CONFIG_ALIGNMENT_TRAP

ldr ip, __cr_alignment

ldr ip, [ip]

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

#endif

enable_irq

// tsk 是寄存器r9的别名,在arch/arm/kernel/entry-header.S中定义:// tsk .req r9 @current thread_info

// 获得线程对象的基地址。

get_thread_infotsk

// tbl是r8寄存器的别名,在arch/arm/kernel/entry-header.S中定义:

// tbl .req r8 @syscall table pointer,

// 用来存放系统调用表的指针,系统调用表在后面调用

adr tbl, sys_call_table @ load syscall table pointer

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

#if defined(CONFIG_OABI_COMPAT)

/*

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

*

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

* get the old ABI syscall table address.

*/

bics r10, r10, #0xff

eorne scno, r10, #__NR_OABI_SYSCALL_BASE

ldrne tbl, =sys_oabi_call_table

#elif !defined(CONFIG_AEABI)

// scno是寄存器r7的别名

bic scno, scno, #0xff @ mask off SWI op-code

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, BSYM(ret_fast_syscall) @ return address

ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine

add r1, sp, #S_OFF

// why也是r8寄存器的别名

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

ENDPROC(vector_swi)

上面的zero_fp是一个宏,在arch/arm/kernel/entry-header.S中定义:

.macro zero_fp

#ifdef CONFIG_FRAME_POINTER

mov fp, #0

#endif

.endm

而fp位寄存器r11。

像每一个异常处

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

网站地图

Top