如何在OS161中添加开放系统调用的两个变体? [英] How to add the two variations of the open syscall in OS161?

查看:82
本文介绍了如何在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, $0, SYS_##sym  ; \
   .end sym         ; \
   .set reorder

SYSCALL(open, 45)


发出syscall时,将调用syscall调度程序. syscall调度程序采用指向trapframe的指针,该指针包括在发出syscall之前的寄存器值.寄存器之一包含系统调用号,调度程序将其分配给正确的系统调用功能.调度程序看起来像这样:


When a syscall is issued, a syscall dispatcher is called. The syscall dispatcher takes a pointer to a trapframe which includes the values of registers before the syscall is issued. One of the registers contains the syscall number, which the dispatcher uses to dispatch to the right syscall function. The dispatcher looks like this:

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

    ...

}

这是一条注释,描述了如何传递参数以及如何返回值:

Here is a comment that describes how arguments are passed and how to return values:

 * 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_reboottf->tf_a0调用,这是因为在发出系统调用之前,寄存器a0包含系统调用的第一个(也是唯一的)参数.

You can see that for example sys_reboot is called with tf->tf_a0, That's because before the syscall is issued, the register a0 contained the first (and only) parameter for the syscall.

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

I'm not gonna dive into details for simplicity and because it's probably irrelevant. For example, the process of issuing a syscall is a bit more complicated, but I've mentioned only the relevant stuff. Also not gonna talk about how to get arguments off the stack since I'll not need it here.

我应该实现sys_open syscall,但是我不确定如何知道open函数的哪个变体已被调用...

I'm supposed to implement the sys_open syscall, but I'm not sure how to know which variant of the open functions has been called...

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

All I have is the syscall number and the values of the registers, which includes the four arguments registers, the stack pointer and the other registers.

如何确定我是面对第一个变化(仅具有两个参数)还是面对第二个变化(具有3个参数),以便我能够表现得相对应?

How can I determine whether I'm facing the first variation (with only two parameters) or the second one (with 3 parameters) so that I can behave accordingly?

整个系统调用代码为 OS161的整个仓库位于此处.

The whole repo for OS161 is here.

在此处引导期间,异常处理程序代码已加载到内存中.

The exception handler code is loaded into memory during the boot here.

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

The code for the exception handler (the first code that runs when a syscall is issued) is here.

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

The exception handler is a function called mips_general_handler that just calls a function common_exception.

mips_general_handler common_exception common_exception将寄存器的所有值压入堆栈,还将指针压入压入值的开头(即已传递给被调用函数的指针),然后调用函数mips_trap此处找到

common_exception pushed all the values of the registers onto the stack, also pushes a pointer to the beginning of the pushed values (that's the pointer that's passed to the function being called) and calls the function mips_trap which can be found here.

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

The function misp_trap looks for the cause of the exception, and if it's a syscall, calls the function syscall which is given above.

推荐答案

首先,该OS161手册页错误错误地暗示了open()函数的两个版本. open()仅有一个版本-C不支持该手册页所暗示的函数重载. 对于POSIX open()的一个版本是

First, that OS161 man page is wrong in incorrectly implying that there are two versions of the open() function. There is only one version of open() - C does not support function overloading like that man page implies. Per POSIX the one version of open() is

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

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

请注意该手册页如何使您误以为有open()的两个版本.没有.在所谓的教学操作系统"中,这种草率的做法确实很糟糕.

Note how that man page confused you into thinking there are two versions of open(). There isn't. That kind of sloppiness is really bad in what's supposed to be a "teaching operating system".

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

The mode argument will be present if the oflag argument as the O_CREAT bit set:

O_CREAT

如果文件存在,则该标志无效,除非另有说明 O_EXCL.否则,如果未设置O_DIRECTORY,则文件应 创建为常规文件;文件的用户标识应设置为 流程的有效用户标识;文件的组ID 设置为文件父目录的组ID或 流程的有效组ID;和访问权限位 (请参见<sys/stat.h>)文件模式应设置为 oflag参数后面的参数作为类型mode_t 修改如下:对文件模式位执行按位与运算 以及进程文件模式的补码中的相应位 创建蒙版.因此,文件模式下的所有位其对应位 在文件模式下,创建掩码被清除.当其他位 如果设置了文件许可位,则效果未指定.这 oflag参数后面的参数不会影响文件是否 开放供阅读,写作或两者兼而有之.实施应 提供一种将文件的组ID初始化为文件组ID的方法 父目录.实现可以但不必提供 实现定义的方法,用于将文件的组ID初始化为 调用过程的有效组ID.

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指针参数应该包含oflag参数,而a3应该包含mode参数,如果oflag参数中的O_CREAT位设置了.如果用户进程调用代码未使用mode参数,但设置了O_CREAT位,

Assuming for OS161 the char *path argument is a 64-bit pointer and both int and mode_t are 32 bits, the a0 and a1 registers should contain the path pointer argument, a2 should contain the oflag argument, and a3 should contain the mode argument if the O_CREAT bit is set in the oflag argument. If the user-process calling code did not use the mode argument but did set the O_CREAT bit,

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

Note that the Linux open() syscall is implemented in exactly this way* - the mode argument is set by the calling process if it's relevant.

*-差不多了. Linux实际上将open()实现为openat( AT_FDCWD, ...).如果OS161提供openat(),则您可能还应该将open()实施为openat( AT_FDCWD, ...).

* - Almost. Linux actually implements open() as openat( AT_FDCWD, ...). If OS161 provides openat(), you should probably implement open() as openat( AT_FDCWD, ...) also.

这篇关于如何在OS161中添加开放系统调用的两个变体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆