当前位置: 首页 > news >正文

余姚建设网站公司wordpress主题赚钱

余姚建设网站公司,wordpress主题赚钱,广州注册公司流程及费用,如何搭建游戏平台ARM Linux系统调用的原理ARM Linux系统调用的原理操作系统为在用户态运行的进程与硬件设备进行交互提供了一组接口。在应用程序和硬件之间设置一个额外层具有很多优点。首先#xff0c;这使得编程更加容易#xff0c;把用户从学习硬件设备的低级编程特性中解放出来。其次这使得编程更加容易把用户从学习硬件设备的低级编程特性中解放出来。其次这极大地提高了系统的安全性因为内核在试图满足某个请求之前在接口级就可以检查这种请求的正确性。最后更重要的是这些接口使得程序具有可移植性因为只要内核所提供的一组接口相同那么在任一内核之上就可以正确地编译和执行程序。Unix系统通过向内核发出系统调用(system call)实现了用户态进程和硬件设备之间的大部分接口。系统调用是操作系统提供的服务用户程序通过各种系统调用来引用内核提供的各种服务系统调用的执行让用户程序陷入内核该陷入动作由swi软中断完成。应用编程接口(API)与系统调用的不同在于前者只是一个函数定义说明了如何获得一个给定的服务而后者是通过软件中断向内核发出的一个明确的请求。POSIX标准针对API而不针对系统调用。Unix系统给程序员提供了很多API库函数。libc的标准c库所定义的一些API引用了封装例程(wrapper routine)(其唯一目的就是发布系统调用)。通常情况下每个系统调用对应一个封装例程而封装例程定义了应用程序使用的API。反之则不然一个API没必要对应一个特定的系统调用。从编程者的观点看API和系统调用之间的差别是没有关系的唯一相关的事情就是函数名、参数类型及返回代码的含义。然而从内核设计者的观点看这种差别确实有关系因为系统调用属于内核而用户态的库函数不属于内核。大部分封装例程返回一个整数其值的含义依赖于相应的系统调用。返回-1通常表示内核不能满足进程的请求。系统调用处理程序的失败可能是由无效参数引起的也可能是因为缺乏可用资源或硬件出了问题等等。在libc库中定义的errno变量包含特定的出错码,每个出错码定义为一个常量宏。当用户态的进程调用一个系统调用时CPU切换到内核态并开始执行一个内核函数。因为内核实现了很多不同的系统调用因此进程必须传递一个名为系统调用号(system call number)的参数来识别所需的系统调用。所有的系统调用核都返回一个整数值。这些返回值与封装例程返回值的约定是不同的。在内中整数或0表示系统调用成功结束而负数表示一个出错条件。在后一种情况下这个值就是存放在errno变量中必须返回给应用程序的负出错码。ARM Linux系统利用SWI指令来从用户空间进入内核空间还是先让我们了解下这个SWI指令吧。SWI指令用于产生软件中断从而实现从用户模式到管理模式的变换CPSR保存到管理模式的SPSR执行转移到SWI向量。在其他模式下也可使用SWI指令处理器同样地切换到管理模式。指令格式如下SWI{cond} immed_24其中immed_2424位立即数值为从0——16777215之间的整数。使用SWI指令时通常使用以下两种方法进行参数传递SWI异常处理程序可以提供相关的服务这两种方法均是用户软件协定。1)、指令中24位的立即数指定了用户请求的服务类型参数通过通用寄存器传递。SWI异常处理程序要通过读取引起软件中断的SWI指令以取得24为立即数。如MOV R0,#34SWI 122)、指令中的24位立即数被忽略用户请求的服务类型由寄存器R0的值决定参数通过其他的通用寄存器传递。如MOV R0, #12MOV R1, #34SWI 0在SWI异常处理程序中取出SWI立即数的步骤为首先确定引起软件中断的SWI指令是ARM指令还是Thumb指令这可通过对SPSR访问得到然后取得该SWI指令的地址这可通过访问LR寄存器得到接着读出指令分解出立即数(低24位)。由用户空间进入系统调用通常情况下我们写的用户空间应用程序都是通过封装的C lib来调用系统调用的。以0.9.30版uClibc中的open为例来追踪一下这个封装的函数是如何一步一步的调用系统调用的。在include/fcntl.h中有定义#define open open64open实际上只是open64的一个别名而已。在libc/sysdeps/linux/common/open64.c中可以看到extern __typeof(open64) __libc_open64;extern __typeof(open) __libc_open;可见open64也只不过是__libc_open64的别名而__libc_open64函数在同一个文件中定义libc_hidden_proto(__libc_open64)int __libc_open64 (const char *file, int oflag, ...){mode_t mode 0;if (oflag O_CREAT){va_list arg;va_start (arg, oflag);mode va_arg (arg, mode_t);va_end (arg);}return __libc_open(file, oflag | O_LARGEFILE, mode);}libc_hidden_def(__libc_open64)最终__libc_open64又调用了__libc_open函数这个函数在文件libc/sysdeps/linux/common/open.c中定义libc_hidden_proto(__libc_open)int __libc_open(const char *file, int oflag, ...){mode_t mode 0;if (oflag O_CREAT) {va_list arg;va_start (arg, oflag);mode va_arg (arg, mode_t);va_end (arg);}return __syscall_open(file, oflag, mode);}libc_hidden_def(__libc_open)这个函数也是仅仅根据打开标志oflag的值来判断是否有第三个参数若由则获得其值。之后便用获得的参数来调用__syscall_open(file, oflag, mode)。__syscall_open在同一个文件中定义static __inline__ _syscall3(int, __syscall_open, const char *, file,int, flags, __kernel_mode_t, mode)在文件libc/sysdeps/linux/arm/bits/syscalls.h文件中可以看到#undef _syscall3#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \type name(type1 arg1,type2 arg2,type3 arg3) \{ \return (type) (INLINE_SYSCALL(name, 3, arg1, arg2, arg3)); \}这个宏实际上完成定义一个函数的工作宏的第一个参数是函数的返回值类型第二个参数是函数名之后的参数就如同它们的参数名所表明的那样分别是函数的参数类型及参数名。__syscall_open实际上为int __syscall_open (const char * file,int flags, __kernel_mode_t mode){return (int) (INLINE_SYSCALL(__syscall_open, 3, file, flags, mode));}INLINE_SYSCALL为同一个文件中定义的宏#undef INLINE_SYSCALL#define INLINE_SYSCALL(name, nr, args...)\({ unsigned int _inline_sys_result INTERNAL_SYSCALL (name, , nr, args);\if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_inline_sys_result, ), 0))\{\__set_errno (INTERNAL_SYSCALL_ERRNO (_inline_sys_result, ));\_inline_sys_result (unsigned int) -1;\}\(int) _inline_sys_result; })INLINE_SYSCALL宏中最值得注意的是INTERNAL_SYSCALL其定义如下#undef INTERNAL_SYSCALL#if !defined(__thumb__)#if defined(__ARM_EABI__)#define INTERNAL_SYSCALL(name, err, nr, args...)\({unsigned int __sys_result;\{\register int _a1 __asm__ (r0), _nr __asm__ (r7);\LOAD_ARGS_##nr (args)\_nr SYS_ify(name);\__asm__ __volatile__ (swi0x0 syscall #name\: r (_a1)\: r (_nr) ASM_ARGS_##nr\: memory);\__sys_result _a1;\}\(int) __sys_result; })#else /* defined(__ARM_EABI__) */#define INTERNAL_SYSCALL(name, err, nr, args...)\({ unsigned int __sys_result;\{\register int _a1 __asm__ (a1);\LOAD_ARGS_##nr (args)\__asm__ __volatile__ (swi%1 syscall #name\: r (_a1)\: i (SYS_ify(name)) ASM_ARGS_##nr\: memory);\__sys_result _a1;\}\(int) __sys_result; })#endif这里也将同文件中的LOAD_ARGS宏的定义贴出来#define LOAD_ARGS_0()#define ASM_ARGS_0#define LOAD_ARGS_1(a1)\_a1 (int) (a1);\LOAD_ARGS_0 ()#define ASM_ARGS_1ASM_ARGS_0, r (_a1)#define LOAD_ARGS_2(a1, a2)\register int _a2 __asm__ (a2) (int) (a2);\LOAD_ARGS_1 (a1)#define ASM_ARGS_2ASM_ARGS_1, r (_a2)#define LOAD_ARGS_3(a1, a2, a3)\register int _a3 __asm__ (a3) (int) (a3);\LOAD_ARGS_2 (a1, a2)这几个宏用来在寄存器中加载相应的参数参数传递的方式和普通的C函数也没有什么太大的区别同样都是将参数列表中的参数依次放入寄存器r0、r1、r2、r3…中。上面的SYS_ify(name)宏是用来获得系统调用号的。#define SYS_ify(syscall_name)(__NR_##syscall_name)也就是__NR___syscall_open在libc/sysdeps/linux/common/open.c中可以看到这个宏的定义#define __NR___syscall_open __NR_open__NR_open在内核代码的头文件中有定义。在这里我们忽略定义__thumb__的情况而假设我们编译出来的库函数使用的都是ARM指令集。在上面的代码中我们看到根据是否定义宏__ARM_EABI__INTERNAL_SYSCALL会被展开为两种不同的版本。关于这一点与应用二进制接口ABI有关不同的ABI则会有不同的传递系统调用号的方法。对于比较新的EABI则在r7寄存器保存系统调用号通过swi0x0来陷入内核。否则通过swi指令的24位立即数参数来传递系统调用号。后面还会有内核中关于这个问题的更详细的说明。同时这两种调用方式的系统调用号也是存在这区别的在内核的文件arch/arm/inclue/asm/unistd.h中可以看到#define __NR_OABI_SYSCALL_BASE0x900000#if defined(__thumb__) || defined(__ARM_EABI__)#define __NR_SYSCALL_BASE0#else#define __NR_SYSCALL_BASE__NR_OABI_SYSCALL_BASE#endif/** This file contains the system call numbers.*/#define __NR_restart_syscall(__NR_SYSCALL_BASE0)#define __NR_exit(__NR_SYSCALL_BASE1)#define __NR_fork(__NR_SYSCALL_BASE2)#define __NR_read(__NR_SYSCALL_BASE3)#define __NR_write(__NR_SYSCALL_BASE4)#define __NR_open(__NR_SYSCALL_BASE5)……接下来来看操作系统对系统调用的处理。我们回到ARM Linux的异常向量表因为当执行swi时会从异常向量表中取例程的地址从而跳转到相应的处理程序中。在文件arch/arm/kernel/entry-armv.S中我们看到SWI异常向量W(ldr)pc, .LCvswi stubs_offset而.LCvswi在同一个文件中定义为.LCvswi:.wordvector_swi也就是最终会执行例程vector_swi来完成对系统调用的处理接下来我们来看下在arch/arm/kernel/entry-common.S中定义的vector_swi例程(删去一些和我们的示例平台无关的代码).align5ENTRY(vector_swi)subsp, sp, #S_FRAME_SIZEstmiasp, {r0 - r12} Calling r0 - r12ARM(addr8, sp, #S_PC)ARM(stmdbr8, {sp, lr}^) 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.*/ldrr10, [lr, #-4] get SWI instruction#ifdef CONFIG_CPU_ENDIAN_BE8//rev指令的功能是反转字中的字节序revr10, r10 little endian instruction#endif#elif defined(CONFIG_AEABI)…#else/* Legacy ABI only. */ldrscno, [lr, #-4] get SWI instruction#endif#ifdef CONFIG_ALIGNMENT_TRAPldrip, __cr_alignmentldrip, [ip]mcrp15, 0, ip, c1, c0 update control register#endifenable_irq// tsk是寄存器r9的别名在arch/arm/kernel/entry-header.S中定义// tsk.reqr9 current thread_info//获得线程对象的基地址。get_thread_info tsk// tbl是r8寄存器的别名在arch/arm/kernel/entry-header.S中定义// tbl.reqr8 syscall table pointer//用来存放系统调用表的指针系统调用表在后面调用adrtbl, sys_call_table load syscall table pointerldrip, [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.*/bicsr10, r10, #0xff000000eornescno, r10, #__NR_OABI_SYSCALL_BASEldrnetbl, sys_oabi_call_table#elif !defined(CONFIG_AEABI)// scno是寄存器r7的别名bicscno, scno, #0xff000000 mask off SWI op-codeeorscno, scno, #__NR_SYSCALL_BASE check OS number#endifstmdbsp!, {r4, r5} push fifth and sixth argststip, #_TIF_SYSCALL_TRACE are we tracing syscalls?bne__sys_tracecmpscno, #NR_syscalls check upper syscall limitadrlr, BSYM(ret_fast_syscall) return addressldrccpc, [tbl, scno, lsl #2] call sys_* routineaddr1, sp, #S_OFF// why也是r8寄存器的别名2:movwhy, #0 no longer a real syscallcmpscno, #(__ARM_NR_BASE - __NR_SYSCALL_BASE)eorr0, scno, #__NR_SYSCALL_BASE put OS number backbcsarm_syscallbsys_ni_syscall not private funcENDPROC(vector_swi)上面的zero_fp是一个宏在arch/arm/kernel/entry-header.S中定义.macrozero_fp#ifdef CONFIG_FRAME_POINTERmovfp, #0#endif.endm而fp位寄存器r11。像每一个异常处理程序一样要做的第一件事当然就是保护现场了。紧接着是获得系统调用的系统调用号。然后以系统调用号作为索引来查找系统调用表如果系统调用号正常的话就会调用相应的处理例程来处理就是上面的那个ldrccpc, [tbl, scno, lsl #2]语句然后通过例程ret_fast_syscall来返回。在这个地方我们接着来讨论ABI的问题。现在我们首先来看两个宏一个是CONFIG_OABI_COMPAT意思是说与old ABI兼容另一个是CONFIG_AEABI意思是说指定现在的方式为EABI。这两个宏可以同时配置也可以都不配也可以配置任何一种。我们来看一下内核是怎么处理这一问题的。我们知道sys_call_table在内核中是个跳转表这个表中存储的是一系列的函数指针这些指针就是系统调用函数的指针如(sys_open)。内核是根据一个系统调用号(对于EABI来说为系统调用表的索引)找到实际该调用内核哪个函数然后通过运行该函数完成系统调用的。首先对于old ABI内核给出的处理是为它建立一个单独的system call table,叫sys_oabi_call_table。这样兼容方式下就会有两个system call table,以old ABI方式的系统调用会执行old_syscall_table表中的系统调用函数EABI方式的系统调用会用sys_call_table中的函数指针。配置无外乎以下4中第一、两个宏都配置行为就是上面说的那样。第二、只配置CONFIG_OABI_COMPAT那么以old ABI方式调用的会用sys_oabi_call_table以EABI方式调用的用sys_call_table和1实质上是相同的。只是情况1更加明确。第三、只配置CONFIG_AEABI系统中不存在sys_oabi_call_table对old ABI方式调用不兼容。只能 以EABI方式调用用sys_call_table。第四、两个都没有配置系统默认会只允许old ABI方式但是不存在old_syscall_table最终会通过sys_call_table完成函数调用系统会根据ABI的不同而将相应的系统调用表的基地址加载进tbl寄存器也就是r8寄存器。接下来来看系统调用表如前面所说的那样有两个同样都在文件arch/arm/kernel/entry-armv.S中#define ABI(native, compat) native#ifdef CONFIG_AEABI#define OBSOLETE(syscall) sys_ni_syscall#else#define OBSOLETE(syscall) syscall#endif.typesys_call_table, #objectENTRY(sys_call_table)#include calls.S#undef ABI#undef OBSOLETE另外一个为#define ABI(native, compat) compat#define OBSOLETE(syscall) syscall.typesys_oabi_call_table, #objectENTRY(sys_oabi_call_table)#include calls.S#undef ABI#undef OBSOLETE这样看来貌似两个系统调用表是完全一样的。这里预处理指令include的独特用法也挺有意思系统调用表的内容就是整个arch/arm/kernel/calls.S文件的内容(由于太长这里就不全部列出了)/* 0 */CALL(sys_restart_syscall)CALL(sys_exit)CALL(sys_fork_wrapper)CALL(sys_read)CALL(sys_write)/* 5 */CALL(sys_open)CALL(sys_close)……上面的CALL()是个宏它同样在文件arch/arm/kernel/entry-armv.S中定义#define CALL(x) .equ NR_syscalls,NR_syscalls1#include calls.S#undef CALL#define CALL(x) .long x在定义宏CALL()的地方我们看到calls.S已经被包含了一次只不过在这里不是为了建立系统调用表而仅仅是为了获得系统的系统调用的数量并保存在宏NR_syscalls中。在SWI向量中我们也看到是使用了这个宏的。最后再罗嗦一点如果用sys_open来搜的话是搜不到系统调用open的定义的系统调用函数都是用宏来定义的比如对于open有这样的定义---------------------------------------------------------------------fs/open.c1066 SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)1067 {1068long ret;10691070if (force_o_largefile())1071flags | O_LARGEFILE;10721073ret do_sys_open(AT_FDCWD, filename, flags, mode);1074/* avoid REGPARM breakage on x86: */1075asmlinkage_protect(3, ret, filename, flags, mode);1076return ret;1077 }---------------------------------------------------------------------继续回到vector_swi如果系统调用号不正确则会调用arm_syscall函数来进行处理这个函数定义如下---------------------------------------------------------------------arch/arm/kernel/traps.c465 #define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE)466 asmlinkage int arm_syscall(int no, struct pt_regs *regs)467 {468struct thread_info *thread current_thread_info();469siginfo_t info;470471if ((no 16) ! (__ARM_NR_BASE 16))472return bad_syscall(no, regs);473474switch (no 0xffff) {475case 0: /* branch through 0 */476info.si_signo SIGSEGV;477info.si_errno 0;478info.si_code SEGV_MAPERR;479info.si_addr NULL;480481arm_notify_die(branch through zero, regs, info, 0, 0);482return 0;483484case NR(breakpoint): /* SWI BREAK_POINT */485regs-ARM_pc - thumb_mode(regs) ? 2 : 4;486ptrace_break(current, regs);487return regs-ARM_r0;488489/*490* Flush a region from virtual address r0 to virtual address r1491 * _exclusive_.There is no alignment requirement on either address;492* user space does not need to know the hardware cache layout.493*494* r2 contains flags.It should ALWAYS be passed as ZERO until it495* is defined to be something else.For now we ignore it, but may496* the fires of hell burn in your belly if you break this rule. ;)497*498* (at a later date, we may want to allow this call to not flush499* various aspects of the cache.Passing will guarantee that500* everything necessary gets flushed to maintain consistency in501* the specified region).502*/503case NR(cacheflush):504do_cache_op(regs-ARM_r0, regs-ARM_r1, regs-ARM_r2);505return 0;506507case NR(usr26):508if (!(elf_hwcap HWCAP_26BIT))509break;510regs-ARM_cpsr ~MODE32_BIT;511return regs-ARM_r0;512513case NR(usr32):514if (!(elf_hwcap HWCAP_26BIT))515break;516regs-ARM_cpsr | MODE32_BIT;517return regs-ARM_r0;518519case NR(set_tls):520thread-tp_value regs-ARM_r0;521 #if defined(CONFIG_HAS_TLS_REG)522asm (mcr p15, 0, %0, c13, c0, 3 : : r (regs-ARM_r0) );523 #elif !defined(CONFIG_TLS_REG_EMUL)524/*525* User space must never try to access this directly.526* Expect your app to break eventually if you do so.527* The user helper at 0xffff0fe0 must be used instead.528* (see entry-armv.S for details)529*/530*((unsigned int *)0xffff0ff0) regs-ARM_r0;531 #endif532return 0;533534 #ifdef CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG535/*536* Atomically store r1 in *r2 if *r2 is equal to r0 for user space.537* Return zero in r0 if *MEM was changed or non-zero if no exchange538* happened.Also set the user C flag accordingly.539* If access permissions have to be fixed up then non-zero is540* returned and the operation has to be re-attempted.541*542* *NOTE*: This is a ghost syscall private to the kernel.Only the543* __kuser_cmpxchg code in entry-armv.S should be aware of its544* existence.Dont ever use this from user code.545*/546case NR(cmpxchg):547for (;;) {548extern void do_DataAbort(unsigned long addr, unsigned int fsr,549struct pt_regs *regs);550unsigned long val;551unsigned long addr regs-ARM_r2;552struct mm_struct *mm current-mm;553pgd_t *pgd; pmd_t *pmd; pte_t *pte;554spinlock_t *ptl;555556regs-ARM_cpsr ~PSR_C_BIT;557down_read(mm-mmap_sem);558pgd pgd_offset(mm, addr);559if (!pgd_present(*pgd))560goto bad_access;561pmd pmd_offset(pgd, addr);562if (!pmd_present(*pmd))563goto bad_access;564pte pte_offset_map_lock(mm, pmd, addr, ptl);565if (!pte_present(*pte) || !pte_dirty(*pte)) {566pte_unmap_unlock(pte, ptl);567goto bad_access;568}569val *(unsigned long *)addr;570val - regs-ARM_r0;571if (val 0) {572*(unsigned long *)addr regs-ARM_r1;573regs-ARM_cpsr | PSR_C_BIT;574}575pte_unmap_unlock(pte, ptl);576up_read(mm-mmap_sem);577return val;578579bad_access:580up_read(mm-mmap_sem);581/* simulate a write access fault */582do_DataAbort(addr, 15 (1 11), regs);583}584 #endif585586default:587/* Calls 9f00xx..9f07ff are defined to return -ENOSYS588if not implemented, rather than raising SIGILL.This589way the calling program can gracefully determine whether590afeature is supported.*/591if ((no 0xffff) 0x7ff)592return -ENOSYS;593break;594}595 #ifdef CONFIG_DEBUG_USER596/*597* experience shows that these seem to indicate that598* something catastrophic has happened599*/600if (user_debug UDBG_SYSCALL) {601printk([%d] %s: arm syscall %d\n,602task_pid_nr(current), current-comm, no);603dump_instr(, regs);604if (user_mode(regs)) {605__show_regs(regs);606c_backtrace(regs-ARM_fp, processor_mode(regs));607}608}609 #endif610info.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);615616arm_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.Sret_fast_syscall:UNWIND(.fnstart)UNWIND(.cantunwind)disable_irq disable interruptsldrr1, [tsk, #TI_FLAGS]tstr1, #_TIF_WORK_MASKbnefast_work_pending/* perform architecture specific actions before user return */arch_ret_to_user r1, lrrestore_user_regs fast 1, offset S_OFFUNWIND(.fnend)fast_work_pending:strr0, [sp, #S_R0S_OFF]! returned r0work_pending:tstr1, #_TIF_NEED_RESCHEDbnework_reschedtstr1, #_TIF_SIGPENDING|_TIF_NOTIFY_RESUMEbeqno_work_pendingmovr0, sp regsmovr2, why syscallbldo_notify_resumebret_slow_syscall Check work againwork_resched:blschedule/** slow syscall return path.why tells us if this was a real syscall.*/ENTRY(ret_to_user)ret_slow_syscall:disable_irq disable interruptsldrr1, [tsk, #TI_FLAGS]tstr1, #_TIF_WORK_MASKbnework_pendingno_work_pending:/* perform architecture specific actions before user return */arch_ret_to_user r1, lrrestore_user_regs fast 0, offset 0ENDPROC(ret_to_user)---------------------------------------------------------------------对于我们的平台来说上面的arch_ret_to_user为空。restore_user_regs宏用于恢复现场并返回restore_user_regs宏定义如下---------------------------------------------------------------------arch/arm/kernel/entry-header.S.macrorestore_user_regs, fast 0, offset 0ldrr1, [sp, #\offset S_PSR] get calling cpsrldrlr, [sp, #\offset S_PC]! get pcmsrspsr_cxsf, r1 save in spsr_svc#if defined(CONFIG_CPU_32v6K)clrex clear the exclusive monitor#elif defined (CONFIG_CPU_V6)strexr1, r2, [sp] clear the exclusive monitor#endif.if\fastldmdbsp, {r1 - lr}^ get calling r1 - lr.elseldmdbsp, {r0 - lr}^ get calling r0 - lr.endifmovr0, r0 ARMv5T and earlier require a nop after ldm {}^addsp, sp, #S_FRAME_SIZE - S_PCmovspc, 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_syscalls1#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_BASE365)为了向后兼容系统调用只能增加而不能减少这里的编号添加时也必须按顺序来。否则会导致核心运行错误。第三实例化该系统调用即编写新添加系统调用的实现例如SYSCALL_DEFINE1(set_senda, intiset){if(iset)UART_PUT_CR(at91_port[2],AT91C_US_SENDA);elseUART_PUT_CR(at91_port[2],AT91C_US_RSTSTA);return 0;}第四、打开include/linux/syscalls.h添加函数声明asmlinkage long sys_set_senda(int iset);第五、在应用程序中调用该系统调用可以参考uClibc的实现。第六、结束。参考文档
http://www.pierceye.com/news/329772/

相关文章:

  • 网站网页设计案例wordprees可以做棋类网站吗
  • 天河区门户网站官网小学生一分钟新闻播报
  • 漯河网站建设lhwzzz网络服务器机柜
  • 有口碑的武进网站建设国内做房车游网站
  • 山东省城乡住房和城乡建设厅网站济南网站建设wuliankj
  • 网站首页跳出弹窗wordpress远程后台设置
  • 免费信息网站建设平台影响网站排名的因素 权重
  • 做房产网站接不到电话湖北网站建设平台
  • 厦门国外网站建设公司排名上海自贸区注册公司优惠政策
  • 网站建设的公司实习做什么成都住建局官网住建智慧建管
  • 建一个免费看电影的网站犯法不国家企业信用信息没有网站怎么做
  • 长春网站vantage wordpress
  • 帝国cms如何做网站地图自己做的网站还要买域名么
  • 网站建设与维护税率网络营销案例及视频
  • 网站建设 繁体精品课网站制作
  • 常州 招网站开发seo的名词解释
  • 二级域名网站seo竞价网站建设
  • 麻栗坡网站建设正规网站建设
  • 邯郸网站建设哪家好重庆app开发
  • 自学网站开发多久大型网站建站
  • 网站设计定制多少钱新增备案网站负责人
  • 匿名聊天网站开发网站关键字挖掘
  • 外国域名注册很多网站做网站的人找不到了
  • 好的学习网站打广告免费浏览器网站
  • 美团先做网站还是app学生网站建设的总结与评价
  • 网站建设代理网站wordpress微博
  • dw建设网站视频宁波seo优化项目
  • 网站里添加百度地图浙江网站建设公司
  • php网站开发最新需求排名优化百度
  • 网站制作的电话智慧校园信息门户网站建设