Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 系统调用如何从用户空间到内核空间再回到用户空间?_Linux_Linux Kernel_Linux Device Driver_Embedded Linux - Fatal编程技术网

Linux 系统调用如何从用户空间到内核空间再回到用户空间?

Linux 系统调用如何从用户空间到内核空间再回到用户空间?,linux,linux-kernel,linux-device-driver,embedded-linux,Linux,Linux Kernel,Linux Device Driver,Embedded Linux,我研究了一些文章,在这些文章中,我得到了如下信息:像open()这样的系统调用调用glibc中的包装函数,然后引发了一个陷阱,它将上下文从用户空间切换到内核空间,然后使用cpu寄存器调用内核空间中的系统调用参数/参数 但是我想我还是缺少了系统调用的一步一步的过程或详细的顺序。如果人们能够提供将ARM arch作为参考的步骤,那就太好了。提前感谢。软件中断异常用于在ARM情况下调用系统调用。它将执行其地址存储在物理地址0x08的函数 Syscall包装器库函数连接到特定于体系结构的Syscall实

我研究了一些文章,在这些文章中,我得到了如下信息:像open()这样的系统调用调用glibc中的包装函数,然后引发了一个陷阱,它将上下文从用户空间切换到内核空间,然后使用cpu寄存器调用内核空间中的系统调用参数/参数


但是我想我还是缺少了系统调用的一步一步的过程或详细的顺序。如果人们能够提供将ARM arch作为参考的步骤,那就太好了。提前感谢。

软件中断异常用于在ARM情况下调用系统调用。它将执行其地址存储在物理地址
0x08
的函数

Syscall包装器库函数连接到特定于体系结构的Syscall实现(检查
sysdeps/unix
libc源代码目录)。 在本例中,将执行来自
sysdeps/unix/sysv/linux/arm/syscall.S
文件的syscall。在此函数中,它将系统调用号存储在
R7
R0-R6
用于向系统调用发送参数

示例程序集代码:

     mov  r7, #SYSCALL NO
     mov  r0, #ARG1
     mov  r1, #ARG2
     swi 0x0
生成软件异常时,将调用
vector\u swi()
。此函数从R7获取系统调用号, 从
sys\u call\u表
中查找并执行注册的函数地址

有关实现详细信息,请检查以下内核文件:

  • include/linux/syscalls.h
  • 拱/臂/包括/asm/unistd.h
  • arch/arm/kernel/calls.S
  • arch/arm/kernel/entry\u common.S
  • arch/arm/kernel/sys\u arm.c

  • 软件中断异常用于在ARM情况下调用系统调用。它将执行其地址存储在物理地址
    0x08
    的函数

    Syscall包装器库函数连接到特定于体系结构的Syscall实现(检查
    sysdeps/unix
    libc源代码目录)。 在本例中,将执行来自
    sysdeps/unix/sysv/linux/arm/syscall.S
    文件的syscall。在此函数中,它将系统调用号存储在
    R7
    R0-R6
    用于向系统调用发送参数

    示例程序集代码:

         mov  r7, #SYSCALL NO
         mov  r0, #ARG1
         mov  r1, #ARG2
         swi 0x0
    
    生成软件异常时,将调用
    vector\u swi()
    。此函数从R7获取系统调用号, 从
    sys\u call\u表
    中查找并执行注册的函数地址

    有关实现详细信息,请检查以下内核文件:

  • include/linux/syscalls.h
  • 拱/臂/包括/asm/unistd.h
  • arch/arm/kernel/calls.S
  • arch/arm/kernel/entry\u common.S
  • arch/arm/kernel/sys\u arm.c

  • 系统调用的处理分为两部分

  • 从系统调用的开始到生成 处理器异常,以进入previllege模式。 对于ARM,该模式应为SVC(监控)模式。 本部分涉及使用正确的系统调用号填充通用寄存器,并在系统调用中传递参数, 以及将处理器的状态触发为特权模式
  • 第二部分(与第一部分相比要复杂一些)涉及在特权模式下处理系统调用,并从特权模式返回
  • 2a。在ARM的异常表中,异常向量(本例中为SVC)将控件定向到异常的公共处理程序。 以下是SVC的异常向量:

    [文件:arch\arm\kernel\entry armv.S]

    W(ldr)  pc, __vectors_start + 0x1000
    
    vector_\name:
        .if \correction
        sub lr, lr, #\correction
        .endif
    
    stmia   sp, {r0, lr}        @ save r0, lr
    mrs lr, spsr
    str lr, [sp, #8]        @ save spsr
    
    mrs lr, spsr 
    ...
    and lr, lr, #0x0f
    ...
     ARM(   ldr lr, [pc, lr, lsl #2]    )
    movs    pc, lr          @ branch to handler in SVC mode
    ...
    .word   vector_swi
    
    以下是异常的公共处理程序条目:

    [文件:arch\arm\kernel\entry armv.S]

    W(ldr)  pc, __vectors_start + 0x1000
    
    vector_\name:
        .if \correction
        sub lr, lr, #\correction
        .endif
    
    stmia   sp, {r0, lr}        @ save r0, lr
    mrs lr, spsr
    str lr, [sp, #8]        @ save spsr
    
    mrs lr, spsr 
    ...
    and lr, lr, #0x0f
    ...
     ARM(   ldr lr, [pc, lr, lsl #2]    )
    movs    pc, lr          @ branch to handler in SVC mode
    ...
    .word   vector_swi
    
    2b。在完成此公共处理程序时,r0、lr和spsr分别保存在堆栈上的[SP]、[SP+4]和[SP+8]地址处

    [文件:arch\arm\kernel\entry armv.S]

    W(ldr)  pc, __vectors_start + 0x1000
    
    vector_\name:
        .if \correction
        sub lr, lr, #\correction
        .endif
    
    stmia   sp, {r0, lr}        @ save r0, lr
    mrs lr, spsr
    str lr, [sp, #8]        @ save spsr
    
    mrs lr, spsr 
    ...
    and lr, lr, #0x0f
    ...
     ARM(   ldr lr, [pc, lr, lsl #2]    )
    movs    pc, lr          @ branch to handler in SVC mode
    ...
    .word   vector_swi
    
    2c。然后,公共处理程序将控制器转移/分支到SVC特定处理程序:

    [文件:arch\arm\kernel\entry armv.S]

    W(ldr)  pc, __vectors_start + 0x1000
    
    vector_\name:
        .if \correction
        sub lr, lr, #\correction
        .endif
    
    stmia   sp, {r0, lr}        @ save r0, lr
    mrs lr, spsr
    str lr, [sp, #8]        @ save spsr
    
    mrs lr, spsr 
    ...
    and lr, lr, #0x0f
    ...
     ARM(   ldr lr, [pc, lr, lsl #2]    )
    movs    pc, lr          @ branch to handler in SVC mode
    ...
    .word   vector_swi
    
    在公共处理程序的末尾,控制器被传输到SVC处理程序vector_swi

    2d。现在让我们看看如何在SVC处理程序中处理syscall。 按以下顺序在新帧上推进SP后,调用者的上下文保存为:

    [文件:arch\arm\kernel\entry common.S]

    ENTRY(vector_swi)
    ...
    
    elif defined(CONFIG_AEABI)
    
        /*
         * Pure EABI user space always put syscall number into scno (r7).
         */
    #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
        ...
    
    adr tbl, sys_call_table     @ load syscall table pointer
    
    ENTRY(sys_call_table)
    #include "calls.S"
    #undef ABI
    ...
    
    adr lr, BSYM(ret_fast_syscall)  @ return address
        ldrcc   pc, [tbl, scno, lsl #2]     @ call sys_* routine
        ...
    
    ret_fast_syscall:
    ...
    restore_user_regs fast = 1, offset = S_OFF
    ...
    
    (r0-r12,sp,lr)_usr_模式,lr_exp(在这种情况下exp=svc)

    通过存储r0-r12、sp、lr、pc的该上下文值,该上下文将用于从SVC模式返回用户模式

    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
    
    2e。系统调用号是根据过程调用标准获取的,通常存储在scno(r7寄存器)中

    [文件:arch\arm\kernel\entry common.S]

    ENTRY(vector_swi)
    ...
    
    elif defined(CONFIG_AEABI)
    
        /*
         * Pure EABI user space always put syscall number into scno (r7).
         */
    #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
        ...
    
    adr tbl, sys_call_table     @ load syscall table pointer
    
    ENTRY(sys_call_table)
    #include "calls.S"
    #undef ABI
    ...
    
    adr lr, BSYM(ret_fast_syscall)  @ return address
        ldrcc   pc, [tbl, scno, lsl #2]     @ call sys_* routine
        ...
    
    ret_fast_syscall:
    ...
    restore_user_regs fast = 1, offset = S_OFF
    ...
    
    2f。然后,sys_call_表的地址存储在tbl寄存器(r8)中

    [文件:arch\arm\kernel\entry common.S]

    ENTRY(vector_swi)
    ...
    
    elif defined(CONFIG_AEABI)
    
        /*
         * Pure EABI user space always put syscall number into scno (r7).
         */
    #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
        ...
    
    adr tbl, sys_call_table     @ load syscall table pointer
    
    ENTRY(sys_call_table)
    #include "calls.S"
    #undef ABI
    ...
    
    adr lr, BSYM(ret_fast_syscall)  @ return address
        ldrcc   pc, [tbl, scno, lsl #2]     @ call sys_* routine
        ...
    
    ret_fast_syscall:
    ...
    restore_user_regs fast = 1, offset = S_OFF
    ...
    
    sys_call_表包含根据其编号的syscall列表。 文件call.S包含该列表

    [文件:arch\arm\kernel\entry common.S]

    ENTRY(vector_swi)
    ...
    
    elif defined(CONFIG_AEABI)
    
        /*
         * Pure EABI user space always put syscall number into scno (r7).
         */
    #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
        ...
    
    adr tbl, sys_call_table     @ load syscall table pointer
    
    ENTRY(sys_call_table)
    #include "calls.S"
    #undef ABI
    ...
    
    adr lr, BSYM(ret_fast_syscall)  @ return address
        ldrcc   pc, [tbl, scno, lsl #2]     @ call sys_* routine
        ...
    
    ret_fast_syscall:
    ...
    restore_user_regs fast = 1, offset = S_OFF
    ...
    
    2g。然后,通过使用syscall no的偏移量分支到sys_call_表,将涉及正确的syscall处理程序。 reurn地址设置在标签“ret\u fast\u syscall”处

    [文件:arch\arm\kernel\entry common.S]

    ENTRY(vector_swi)
    ...
    
    elif defined(CONFIG_AEABI)
    
        /*
         * Pure EABI user space always put syscall number into scno (r7).
         */
    #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
        ...
    
    adr tbl, sys_call_table     @ load syscall table pointer
    
    ENTRY(sys_call_table)
    #include "calls.S"
    #undef ABI
    ...
    
    adr lr, BSYM(ret_fast_syscall)  @ return address
        ldrcc   pc, [tbl, scno, lsl #2]     @ call sys_* routine
        ...
    
    ret_fast_syscall:
    ...
    restore_user_regs fast = 1, offset = S_OFF
    ...
    
    2h。然后,以这样的方式恢复用户模式寄存器,即从步骤2d中存储的值存储(r0-r12、sp、lr、pc)_usr_模式。 这在宏“restore\u user\u regs”中完成

    [文件:arch\arm\kernel\entry common.S]

    ENTRY(vector_swi)
    ...
    
    elif defined(CONFIG_AEABI)
    
        /*
         * Pure EABI user space always put syscall number into scno (r7).
         */
    #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
        ...
    
    adr tbl, sys_call_table     @ load syscall table pointer
    
    ENTRY(sys_call_table)
    #include "calls.S"
    #undef ABI
    ...
    
    adr lr, BSYM(ret_fast_syscall)  @ return address
        ldrcc   pc, [tbl, scno, lsl #2]     @ call sys_* routine
        ...
    
    ret_fast_syscall:
    ...
    restore_user_regs fast = 1, offset = S_OFF
    ...
    
    [文件:arch\arm\kernel\entry header.S]

    macro   restore_user_regs, fast = 0, offset = 0
        mov r2, sp
        ...
    
        .if \fast
        ldmdb   sp, {r1 - r12}          @ get calling r1 - r12
        .else
        ldmdb   sp, {r0 - r12}          @ get calling r0 - r12
        .endif
        add sp, sp, #S_FRAME_SIZE - S_SP
        movs    pc, lr              @ return & move spsr_svc into cpsr
        .endm
    

    系统调用的处理分为两部分

  • 从系统调用的开始到生成 处理器异常,以进入previllege模式。 对于ARM,该模式应为SVC(监控)模式。 本部分涉及使用正确的系统调用号填充通用寄存器,并在系统调用中传递参数, 以及将处理器的状态触发为特权模式
  • 第二部分(与第一部分相比要复杂一些)涉及在特权模式下处理系统调用,并从特权模式返回
  • 2a