How to add the two variations of the open syscall in OS161?

℡╲_俬逩灬. 提交于 2021-01-28 07:52:23

问题


From the man pages of 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);

How the standard c library function open is defined:

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

The declaration:

/*
 * 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)

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

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.


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.

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?


Some useful information:

The whole code for syscall is here.

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.

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

mips_general_handler is here.

common_exception is here.

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.

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.


回答1:


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

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".

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

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.

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,

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.

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



来源:https://stackoverflow.com/questions/63721977/how-to-add-the-two-variations-of-the-open-syscall-in-os161

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!