Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass struct to xv6 system call

I'm aware that we are not able to pass parameters to xv6 system call directly and we are forced to use it's built in methods.

But all examples and questions in this site is about how to send integer to system call. Which it's answer is using argint() method.

But my question is, is there anyway to pass "struct" to a xv6 system call? Are there any bulit-in methods for this purpose too?

If there is, could you please say a simple example?

like image 703
Ramtin Mousavi Avatar asked Dec 18 '22 19:12

Ramtin Mousavi


2 Answers

Passing a struct through system call is possible.

While one can't pass a struct itself as a system call parameter, passing a pointer to it is possible and will allow using it as both an input or output parameter.

Allowing to use as argument the data itself and not a pointer to it will damage the requirement of the system calls mechanism- as passing data must be implemented in a generic way to allow all data types to (as well as future structs) be used.

Let's have a look on an existing implementation of the system call fstat.

int fstat(int fd, struct stat *st);

fstat requires a file descriptor number as an input and outputs a matching stats information using struct stat.

struct stat {
  short type;  // Type of file
  int dev;     // File system's disk device
  uint ino;    // Inode number
  short nlink; // Number of links to file
  uint size;   // Size of file in bytes
};

Although fstat uses a struct pointer as an output parameter, using it as an input will be similar.

The function sys_fstat in kernel code starts the implementation of fstat system call (XV6's convention is to handle parameter fetching from user space by sys_* functions).

int sys_fstat(void)
{
  struct file *f;
  struct stat *st;

  if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)
    return -1;
  return filestat(f, st);
}

This function first gets a corresponding struct file to the file descriptor number received by the first fstat function argument (using argfd). Then, fetches the struct stat pointer received by the second fstat function argument using argptr and saves the given pointer in a local (function scope) pointer variable.

At this point, all arguments were fetched and can be used by the kernel implementation.

Note: Although the struct stat pointer is a user-space pointer (located on the lower half of the virtual space), it is safe for the kernel to use it here because when the kernel is serving a process' system call, it uses the process' own paging table.

like image 189
Omer Efrat Avatar answered Jan 05 '23 15:01

Omer Efrat


Although the above answer is correct but i prefered to write my own solutions to make it more usable for other viwers.

i used argptr to pass a pointer-to-struct to my system call.

in sysproc.c:

int sys_counts (void){

    struct countTable *ct;
    argptr (0 , (void*)&ct ,sizeof(*ct));
    return counts(ct);
    }

in proc.c:

int counts (struct countTable *ct){


    for (int i=0 ; i<22 ; i++){
    (ct->system_calls)[i] = count_calls[i] ;
    } 


    return 22;
    }

and finally in my user-space-program:

int main (){

    struct countTable *ct = malloc (sizeof (struct countTable));

    // call system call
    counts(ct);


    exit();
    }
like image 42
Ramtin Mousavi Avatar answered Jan 05 '23 16:01

Ramtin Mousavi