如何在 OS161 中添加 open 系统调用的两个变体?

2024-04-10

从手册页OS161:

Synopsis

#include <unistd.h>
#include <fcntl.h>

int
open(const char *filename, int flags);
int
open(const char *filename, int flags, mode_t mode);

标准c库函数是如何实现的open被定义为:

int open(const char *filename, int flags, ...);

声明:

/*
 * Definition for each syscall.
 * All we do is load the syscall number into v0, the register the
 * kernel expects to find it in, and jump to the shared syscall code.
 * (Note that the addiu instruction is in the jump's delay slot.)
 */

#define SYS_open         45

#define SYSCALL(sym, num) \
   .set noreorder       ; \
   .globl sym           ; \
   .type sym,@function      ; \
   .ent sym         ; \
sym:                ; \
   j __syscall                  ; \
   addiu v0, $0, SYS_##sym  ; \
   .end sym         ; \
   .set reorder

SYSCALL(open, 45)

当发出系统调用时,系统调用调度程序被调用。系统调用调度程序接受一个指向trapframe其中包括发出系统调用之前寄存器的值。其中一个寄存器包含系统调用号,调度程序使用该号来调度到正确的系统调用函数。调度程序看起来像这样:

void
syscall(struct trapframe *tf)
{
    int callno;

    ...

    callno = tf->tf_v0;

    ...

    switch (callno) {
        case SYS_reboot:
        err = sys_reboot(tf->tf_a0);
        break;

        case SYS___time:
        err = sys___time((userptr_t)tf->tf_a0,
                 (userptr_t)tf->tf_a1);

    ...

}

以下注释描述了如何传递参数以及如何返回值:

 * The calling conventions for syscalls are as follows: Like ordinary
 * function calls, the first 4 32-bit arguments are passed in the 4
 * argument registers a0-a3. 64-bit arguments are passed in *aligned*
 * pairs of registers, that is, either a0/a1 or a2/a3. This means that
 * if the first argument is 32-bit and the second is 64-bit, a1 is
 * unused.
 *
 * This much is the same as the calling conventions for ordinary
 * function calls. In addition, the system call number is passed in
 * the v0 register.
 *
 * On successful return, the return value is passed back in the v0
 * register, or v0 and v1 if 64-bit. This is also like an ordinary
 * function call, and additionally the a3 register is also set to 0 to
 * indicate success.
 *
 * On an error return, the error code is passed back in the v0
 * register, and the a3 register is set to 1 to indicate failure.
 * (Userlevel code takes care of storing the error code in errno and
 * returning the value -1 from the actual userlevel syscall function.
 * See src/user/lib/libc/arch/mips/syscalls-mips.S and related files.)

例如你可以看到sys_reboot被称为tf->tf_a0,那是因为在发出系统调用之前,寄存器a0包含系统调用的第一个(也是唯一的)参数。

为了简单起见,我不会深入讨论细节,因为它可能无关紧要。例如,发出系统调用的过程有点复杂,但我只提到了相关的内容。也不会谈论如何从堆栈中获取参数,因为我在这里不需要它。


我应该实施sys_open系统调用,但我不确定如何知道哪个变体open函数被称为...

我所拥有的只是系统调用号和寄存器的值,其中包括四个参数寄存器、堆栈指针和其他寄存器。

如何确定我面临的是第一个变体(仅具有两个参数)还是第二个变体(具有 3 个参数),以便我可以采取相应的行为?


一些有用的信息:

系统调用的完整代码是here https://github.com/ops-class/os161/blob/master/kern/arch/mips/syscall/syscall.c#L79.

OS161 的整个存储库是here https://github.com/ops-class/os161.

异常处理程序代码在引导期间加载到内存中。

异常处理程序的代码(发出系统调用时运行的第一个代码)是here https://github.com/ops-class/os161/blob/master/kern/arch/sys161/main/start.S#L131.

异常处理程序是一个名为mips_general_handler只是调用一个函数common_exception.

mips_general_handler is here https://github.com/ops-class/os161/blob/master/kern/arch/mips/locore/exception-mips1.S#L86.

common_exception is here https://github.com/ops-class/os161/blob/master/kern/arch/mips/locore/exception-mips1.S#L106.

common_exception将寄存器的所有值推入堆栈,还将指针推入推入值的开头(即传递给正在调用的函数的指针)并调用该函数mips_trap可以找到here https://github.com/ops-class/os161/blob/master/kern/arch/mips/locore/trap.c#L126.

功能misp_trap查找异常的原因,如果是系统调用,则调用该函数syscall这是上面给出的。


首先,OS161 手册页是wrong错误地暗示有两个版本open()功能。只有一个版本open()- C 不支持函数重载,如手册页所暗示的那样。根据 POSIX https://pubs.opengroup.org/onlinepubs/9699919799/functions/openat.html的一个版本open() is

SYNOPSIS
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *path, int oflag, ...);

请注意该手册页如何让您误以为有两个版本open()。没有。对于所谓的“教学操作系统”来说,这种草率确实很糟糕。

The mode如果oflag论证为O_CREAT位设置:

O_CREAT

如果文件存在,则此标志无效,除非如下所述O_EXCL以下。否则,如果O_DIRECTORY未设置文件应 创建为常规文件;文件的用户 ID 应设置为 进程的有效用户ID;文件的组 ID 应 设置为文件父目录的组 ID 或 进程的有效组ID;和访问权限位 (看<sys/stat.h>)的文件模式应设置为值 oflag 参数后面的参数被视为类型mode_t修改如下:对文件模式位执行按位 AND 以及进程文件模式补码中的相应位 创作面具。因此,文件模式中的所有位的对应位 在文件模式中创建掩码设置被清除。当位其他 如果设置了文件权限位,则效果未指定。这 oflag 参数后面的参数不会影响文件是否 可供阅读、写作或两者皆可。实施应 提供一种将文件的组 ID 初始化为文件的组 ID 的方法 父目录。实现可以但不需要提供 将文件的组 ID 初始化为实现定义的方法 调用进程的有效组ID。

假设对于 OS161char *path参数是一个 64 位指针并且两者int and mode_t是 32 位,a0 and a1寄存器应包含path指针参数,a2应包含oflag论证,以及a3应包含mode论证如果O_CREAT位被设置在oflag争论。如果用户进程调用代码没有使用mode论点但确实设置了O_CREAT bit,

注意Linuxopen() syscall https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-5.html正是以这种方式实现的* -mode参数由调用进程设置(如果相关)。

* - 几乎。 Linux实际上实现了open() as openat( AT_FDCWD, ...)。如果OS161提供openat(),你可能应该实施open() as openat( AT_FDCWD, ...) also.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 OS161 中添加 open 系统调用的两个变体? 的相关文章

随机推荐