Magenta源代码笔记(5) —— 系统调用

来源:互联网 发布:大话数据结构 java版 编辑:程序博客网 时间:2024/06/08 16:24

系统调用从用户态发起后切换到内核态执行,以下将从这两个方面分析Magenta系统调用的流程。

Magenta系统调用的大致流程如下:

1、用户态调用系统调用函数(mx开头)

2、设置调用编号以及参数

3、调用svc指令进入内核态运行

4、根据调用编号调用内核中相应的处理程序

5、处理返回结果并返回

首先分析一下用户侧的代码

用户侧有关系统调用的代码位于system/ulib/magenta目录中

system/ulib/magenta/syscalls_arm32.S

// Copyright 2016 The Fuchsia Authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file./* define and implement the magenta syscall wrappers for 32bit arm */.text#define MAGENTA_SYSCALL_MAGIC 0xf0f0// EABI unwind directives cause an implicit reference to this symbol,// though it's never actually used for anything.  Define it locally// just to resolve that reference.__aeabi_unwind_cpp_pr0 = 0xdeadbeef.cfi_sections .debug_frame.macro push_regs reglist:vararg    push {\reglist}    .save {\reglist}    push_regs_cfi \reglist.endm.macro push_regs_cfi reg, reglist:vararg    .cfi_adjust_cfa_offset 4    .cfi_rel_offset \reg, 0    .ifnb \reglist    push_regs_cfi \reglist    .endif.endm.macro pop_regs reglist:vararg    pop {\reglist}    pop_regs_cfi \reglist.endm.macro pop_regs_cfi reg, reglist:vararg    .cfi_adjust_cfa_offset -4    .cfi_same_value \reg    .ifnb \reglist    pop_regs_cfi \reglist    .endif.endm.macro syscall nargs, name, n.globl \name.type \name,STT_FUNC\name:    .fnstart    .cfi_startproc    .cfi_same_value r4    .cfi_same_value r5    .cfi_same_value r6    .cfi_same_value r7.if \nargs < 5    movw   r12, #\n    movt   r12, #MAGENTA_SYSCALL_MAGIC    svc    #0xff00ff    mov    r12, #0    bx     lr.endif.if \nargs == 5    push_regs r4, r5    ldr    r4, [sp, #8]    movw   r12, #\n    movt   r12, #MAGENTA_SYSCALL_MAGIC    svc    #0xff00ff    mov    r12, #0    pop_regs r4, r5    bx     lr.endif.if \nargs == 6    push_regs r4, r5    ldrd   r4, r5, [sp, #8]    movw   r12, #\n    movt   r12, #MAGENTA_SYSCALL_MAGIC    svc    #0xff00ff    mov    r12, #0    pop_regs r4, r5    bx     lr.endif.if \nargs == 7    push_regs r4, r5, r6, r7    ldrd   r4, r5, [sp, #16]    ldr    r6, [sp, #24]    movw   r12, #\n    movt   r12, #MAGENTA_SYSCALL_MAGIC    svc    #0xff00ff    mov    r12, #0    pop_regs r4, r5, r6, r7    bx     lr.endif.if \nargs == 8    push_regs r4, r5, r6, r7    ldrd   r4, r5, [sp, #16]    ldrd   r6, r7, [sp, #24]    movw   r12, #\n    movt   r12, #MAGENTA_SYSCALL_MAGIC    svc    #0xff00ff    mov    r12, #0    pop_regs r4, r5, r6, r7    bx     lr.endif    .cfi_endproc    .fnend.size \name, . - \name.endm#if LIBDDK#define MAGENTA_SYSCALL_DEF(a...)#define MAGENTA_DDKCALL_DEF(nargs64, nargs32, n, ret, name, args...) syscall nargs32, mx_##name, n#else#define MAGENTA_DDKCALL_DEF(a...)#define MAGENTA_SYSCALL_DEF(nargs64, nargs32, n, ret, name, args...) syscall nargs32, mx_##name, n#endif#include <magenta/syscalls.inc>

首先需要介绍一个比较重要的宏

#define MAGENTA_SYSCALL_DEF(nargs64, nargs32, n, ret, name, args...) syscall nargs32, mx_##name, n
这是这个宏在用户侧的实现。

汇编代码中最后包含的文件便是使用这个宏定义的系统调用,如

MAGENTA_SYSCALL_DEF(3, 3, 80, mx_handle_t, process_create, USER_PTR(const char) name, uint32_t name_len, uint32_t flags)
带入上述汇编文件中

调用了汇编中的宏syscall

其作用即是保存调用的参数至各寄存器之后调用svc指令进入用户态

需要注意的是r12寄存器,它的高16位是magic number用于内核态的验证,低16位即是系统调用的编号

返回后按普通函数返回


内核侧系统调用分析

内核侧系统调用的代码位于目录kernel/lib/syscalls中

kernel/lib/syscalls/syscalls.cpp

extern "C" void arm_syscall_handler(struct arm_fault_frame* frame) {    uint64_t ret = 0;    uint32_t syscall_num = frame->r[12];    /* check for magic value to differentiate our syscalls */    if (unlikely((syscall_num & 0xf0f00000) != 0xf0f00000)) {        TRACEF("syscall does not have magenta magic, 0x%x @ PC 0x%x\n", syscall_num, frame->pc);        ret = ERR_BAD_SYSCALL;        goto out;    }    syscall_num &= 0x000fffff;    /* re-enable interrupts to maintain kernel preemptiveness */    arch_enable_ints();    LTRACEF_LEVEL(2, "arm syscall: num 0x%x, pc 0x%x\n", syscall_num, frame->pc);    /* build a function pointer to call the routine.     * the args are jammed into the function independent of if the function     * uses them or not, which is safe for simple arg passing.     */    syscall_func sfunc;    switch (syscall_num) {#define MAGENTA_SYSCALL_DEF(nargs64, nargs32, n, ret, name, args...)                               \    case n:                                                                                        \        sfunc = reinterpret_cast<syscall_func>(sys_##name);                                        \        break;#include <magenta/syscalls.inc>        default:            sfunc = reinterpret_cast<syscall_func>(sys_invalid_syscall);    }    /* call the routine */    ret = sfunc(frame->r[0], frame->r[1], frame->r[2], frame->r[3], frame->r[4],                         frame->r[5], frame->r[6], frame->r[7]);    LTRACEF_LEVEL(2, "ret 0x%llx\n", ret);out:    /* check to see if there are any pending signals */    thread_process_pending_signals();    /* unpack the 64bit return back into r0 and r1 */    frame->r[0] = ret & 0xffffffff;    frame->r[1] = static_cast<uint32_t>((ret >> 32) & 0xffffffff);}
arm_syscall_handler函数为arm的svc的处理程序,在用户侧的汇编代码中调用svc后会跳转到这个函数

这个函数主要完成了以下几个工作:

1、计算magic number并验证

2、计算系统调用编号

3、开中断

4、根据系统调用编号调用sys_开头的函数

5、处理返回值

其中关于系统调用编号的判断和系统调用名称的获取,采用了同名的宏MAGENTA_SYSCALL_DEF,同样引入了magenta/syscalls.inc文件。

0 0
原创粉丝点击