如何在 OS161 中添加 open 系统调用的两个变体?
How to add the two variations of the open syscall in OS161?
来自 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, [=12=], 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);
...
}
这是一条描述如何传递参数以及如何 return 值的注释:
* 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_handler
是 here.
common_exception
是 here.
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()
有两个版本。没有。那种草率在本该是“教学操作系统”的地方真的很糟糕。
如果 oflag
参数设置为 O_CREAT
位,则 mode
参数将出现:
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 位指针,并且 int
和 mode_t
都是 32 位,那么 a0
和 a1
寄存器应该包含 path
指针参数,a2
应该包含 oflag
参数,如果 O_CREAT
位,a3
应该包含 mode
参数在 oflag
参数中设置。如果 user-process 调用代码没有使用 mode
参数但确实设置了 O_CREAT
位,
请注意 the Linux open()
syscall 正是以这种方式实现的* - mode
参数由调用进程设置(如果相关)。
* - 差不多。 Linux 实际上将 open()
实现为 openat( AT_FDCWD, ...)
。如果 OS161 提供 openat()
,您可能也应该将 open()
实现为 openat( AT_FDCWD, ...)
。
来自 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, [=12=], 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);
...
}
这是一条描述如何传递参数以及如何 return 值的注释:
* 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_handler
是 here.
common_exception
是 here.
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()
有两个版本。没有。那种草率在本该是“教学操作系统”的地方真的很糟糕。
如果 oflag
参数设置为 O_CREAT
位,则 mode
参数将出现:
O_CREAT
If the file exists, this flag has no effect except as noted under
O_EXCL
below. Otherwise, ifO_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 typemode_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 位指针,并且 int
和 mode_t
都是 32 位,那么 a0
和 a1
寄存器应该包含 path
指针参数,a2
应该包含 oflag
参数,如果 O_CREAT
位,a3
应该包含 mode
参数在 oflag
参数中设置。如果 user-process 调用代码没有使用 mode
参数但确实设置了 O_CREAT
位,
请注意 the Linux open()
syscall 正是以这种方式实现的* - mode
参数由调用进程设置(如果相关)。
* - 差不多。 Linux 实际上将 open()
实现为 openat( AT_FDCWD, ...)
。如果 OS161 提供 openat()
,您可能也应该将 open()
实现为 openat( AT_FDCWD, ...)
。