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

标签 c operating-system kernel mips system-calls

摘自OS161的手册页:

概要

#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)

当发出系统调用时,系统调用调度程序将被调用。系统调用调度程序采用指向陷阱帧的指针,其中包含发出系统调用之前的寄存器值。其中一个寄存器包含系统调用号,调度程序使用该号来调度到正确的系统调用函数。调度程序如下所示:

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 .

OS161 的整个存储库是 here .

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

异常处理程序的代码(发出系统调用时运行的第一个代码)是 here .

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

mips_general_handlerhere .

common_exceptionhere .

common_exception 将寄存器的所有值推送到堆栈上,还将指针推送到推送值的开头(即传递给正在调用的函数的指针)并调用函数 mips_trap,可以找到here .

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

最佳答案

首先,OS161 手册页错误错误地暗示 open() 有两个版本。功能。 open() 只有一个版本- C 不支持函数重载,如手册页所暗示的那样。 Per POSIX open() 的一个版本是

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

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

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

mode如果 oflag 则将出现参数参数为 O_CREAT位设置:

O_CREAT

If the file exists, this flag has no effect except as noted under O_EXCL below. Otherwise, if O_DIRECTORY is not set the file shall be created as a regular file; the user ID of the file shall be set to the effective user ID of the process; the group ID of the file shall be set to the group ID of the file's parent directory or to the effective group ID of the process; and the access permission bits (see <sys/stat.h>) of the file mode shall be set to the value of the argument following the oflag argument taken as type mode_t modified as follows: a bitwise AND is performed on the file-mode bits and the corresponding bits in the complement of the process' file mode creation mask. Thus, all bits in the file mode whose corresponding bit in the file mode creation mask is set are cleared. When bits other than the file permission bits are set, the effect is unspecified. The argument following the oflag argument does not affect whether the file is open for reading, writing, or for both. Implementations shall provide a way to initialize the file's group ID to the group ID of the parent directory. Implementations may, but need not, provide an implementation-defined way to initialize the file's group ID to the effective group ID of the calling process.

假设 OS161 为 char *path参数是一个 64 位指针,并且 intmode_t是 32 位,a0a1寄存器应包含 path指针参数,a2应包含 oflag参数,和a3应包含 mode参数如果 O_CREAT位设置在 oflag争论。如果用户进程调用代码没有使用mode参数但确实设置了 O_CREAT一点,

请注意the Linux open() syscall正是以这种方式实现* - mode参数由调用进程设置(如果相关)。

* - 几乎。 Linux实际上实现了open()openat( AT_FDCWD, ...) 。如果OS161提供openat() ,您可能应该实现 open()openat( AT_FDCWD, ...)还有。

关于c - 如何在 OS161 中添加 open 系统调用的两个变体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63721977/

相关文章:

linux - 系统调用号与系统调用处理程序指针冲突

c - 如何将键盘输入输入内核?

linux - 通过 sk_buff 将以太网数据包重定向到本地主机

c++ - c语言中**ptr是什么意思

c - fputs 与 fprintf 和 double

c++ - 使用 pThreads 在线程之间共享 3D 数组

自定义内核 : Implement filesystem

c - 为什么 gcc 不将逗号视为序列点?

operating-system - 使用 Minix 2 或 3 学习操作系统开发?

python - 如何在 Windows 上使用 Python 读取系统信息?