1. asst2.c -> main() -> read(fd, &buf[i], MAX_BUF - i)
read() function only has prototype in unistd.h
ssize_t read(int filehandle, void *buf, size_t size);
but has no defination, call read() function will call the magic assembly code
2. the magic assembly code
the magic assembly code will create a trapframe structure (defined in trapframe.h) as following:
- store the 1st argument(filehandle) of read() in trapframe.tf_a0
- store the 2nd argument(*buf) of read() in trapframe.tf_a1
- store the 3rd argument(size) of read() in trapframe.tf_a2
- store SYS_read in trapframe.tf_v0 to indicate the type of this system call is read (SYS_read is a constant which is defined in syscall.h)
- store EX_SYS in trapframe.tf_cause to indicate this is a system call (this is not important to know for this assignment)
- ...
and then use this trapframe as an argument to invoke mips_trap() function
3. trap.c -> mips_trap(struct trapframe *tf)
in this function, it pass the argument tf and invoke syscall(tf)
of course, it does something else, but these are not important to know for this assignment.
4. syscall.c -> syscall(struct trapframe *tf)
- retreive trapframe.tf_v0 to a local varible callno:
callno = tf->tf_v0;
- using a switch-case statement to determine which system call is
switch (callno) {
case SYS_read:
Call our function, for example, sys_read() in file.c
break;
remember we already have filehandle, *buf and size in trapframe, we can easily retreive these information
int filehandle = tf->tf_a0
void * buf = (void*)tf->tf_a1
size_t size = (size_t)tf->tf_a2
- therefore, we can call sys_read() like this
err = sys_read(filehandle, buf, size, &retval);
the reason we need to use &retval is because we need two return value, I will explain later
5. file.c -> sys_read()
in this file, we write our sys_read() function, the return value is worth to be noticed.
the return of read() function
Based on OS/161 Reference Manual - Read, read function should return like this:
- when success
- The count of bytes read is returned.
- when failed
- returns -1
- sets errno to a suitable error code for the error condition encountered
the return of sys_read() function
- when success
- return 0
- set retval the bytes that read is returned.
- when failed
- returns the error code defined in errno.h
the reason why the return value of sys_read() will lead to the return value of read() is following. This is not important to know for this assignment.
6. syscall.c -> syscall()
this code save err and retval to some particular trapframe, when those function returns, the magic assembly code will use the trapframe to generate the return value for read().
if (err) {
/*
* Return the error code. This gets converted at
* userlevel to a return value of -1 and the error
* code in errno.
*/
tf->tf_v0 = err;
tf->tf_a3 = 1; /* signal an error */
}
else {
/* Success. */
tf->tf_v0 = retval;
tf->tf_a3 = 0; /* signal no error */
}