来自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)当发出syscall时,调用syscall调度程序。syscall dispatcher接受一个指向trapframe的指针,该指针包括发出syscall之前寄存器的值。其中一个寄存器包含syscall编号,dispatcher使用它向右syscall函数分派。调度员看起来如下:
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调用的,这是因为在颁发syscall之前,寄存器a0包含了syscall的第一个(也是唯一的)参数。
我不会为了简单而钻研细节,因为这可能是无关紧要的。例如,发布syscall的过程有点复杂,但我只提到了相关内容。另外,我也不会讨论如何从堆栈中获取参数,因为我这里不需要它。
我应该实现sys_open系统调用,但我不确定如何知道open函数的哪个变体被调用了.
我只有syscall数字和寄存器的值,其中包括四个参数寄存器、堆栈指针和其他寄存器。
如何确定我面对的是第一个变化(只有两个参数)还是第二个变化(有3个参数),这样我就可以相应地进行操作了?
一些有用的信息:
syscall的全部代码是这里。
OS161的整个回购程序是这里。
异常处理程序代码在这里引导期间加载到内存中。
异常处理程序(在发出syscall时运行的第一段代码)的代码是这里。
异常处理程序是一个名为mips_general_handler的函数,它只调用一个函数common_exception。
mips_general_handler是这里。
common_exception是这里。
common_exception将寄存器的所有值推到堆栈上,还将指向推送值开头的指针(即传递给被调用函数的指针)推送到堆栈中,并调用可以找到这里的函数mips_trap。
函数misp_trap查找异常的原因,如果是syscall,则调用上面给出的函数syscall。
发布于 2020-09-03 11:16:26
首先,OS161手册页是错误的,这意味着open()函数有两个版本。只有一个版本的open() -C不像手册页所暗示的那样支持函数重载。POSIX open()的一个版本是
SYNOPSIS
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int oflag, ...);请注意,该手册页如何使您感到困惑,以为有两个版本的open()。没有,这种粗野在所谓的“教学操作系统”中是很糟糕的。
如果将mode参数设置为oflag位,则将出现O_CREAT参数:
O_CREAT如果文件存在,则此标志除如下面O_EXCL下面所述外没有任何效果。否则,如果未设置O_DIRECTORY,则应将文件创建为常规文件;文件的用户ID应设置为进程的有效用户ID;文件的组ID应设置为文件父目录的组ID或进程的有效组ID;并将访问权限位(请参见文件模式的<sys/stat.h>**) )设置为作为类型**mode_t采取的mode_t参数后面的参数的值,修改如下:按位对文件模式位和相应位执行,以补充进程的文件模式创建掩码。因此,设置了文件模式创建掩码中相应位的文件模式中的所有位被清除。当设置文件权限位以外的位时,将不指定效果。O频参数后面的参数不影响文件是为读、写打开的,还是为两者打开的。实现应该提供一种将文件的组ID初始化为父目录的组ID的方法。实现可能(但不需要)提供一种实现定义的方法,将文件的组ID初始化为调用进程的有效组ID。
假设OS161的char *path参数是64位指针,int和mode_t都是32位,a0和a1寄存器应该包含path指针参数,a2应该包含oflag参数,如果O_CREAT位设置在oflag参数中,a3应该包含mode参数。如果用户进程调用代码没有使用mode参数,而是设置了O_CREAT位,
请注意,赛瑟尔正是以这种方式实现的*-- mode参数是由调用过程设置的(如果相关的话)。
*-几乎。Linux实际上将open()实现为openat( AT_FDCWD, ...)。如果OS161提供了openat(),那么您可能也应该将open()实现为openat( AT_FDCWD, ...)。
https://stackoverflow.com/questions/63721977
复制相似问题