/** * SPB & FAR * System call dispatcher. * * A pointer to the trapframe created during exception entry (in * exception.S) is passed in. * * 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.) * * Upon syscall return the program counter stored in the trapframe * must be incremented by one instruction; otherwise the exception * return code will restart the "syscall" instruction and the system * call will repeat forever. * * If you run out of registers (which happens quickly with 64-bit * values) further arguments must be fetched from the user-level * stack, starting at sp+16 to skip over the slots for the * registerized values, with copyin(). */ void syscall(struct trapframe *tf) { int callno, err; int32_t retval; off_t pos = 0; off_t lsret; int whence; KASSERT(curthread != NULL); KASSERT(curthread->t_curspl == 0); KASSERT(curthread->t_iplhigh_count == 0); callno = tf->tf_v0; /* * Initialize retval to 0. Many of the system calls don't * really return a value, just 0 for success and -1 on * error. Since retval is the value returned on success, * initialize it to 0 by default; thus it's not necessary to * deal with it except for calls that return other values, * like write. */ retval = 0; 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); break; case SYS_open: err = sys_open((const char*)tf->tf_a0, tf->tf_a1, &retval); break; case SYS_read: err = sys_read((int)tf->tf_a0,(void*)tf->tf_a1,(size_t)tf->tf_a2,&retval); break; case SYS_write: err = sys_write((int)tf->tf_a0,(const void*)tf->tf_a1,(size_t)tf->tf_a2,&retval); break; case SYS_close: err = sys_close((int)tf->tf_a0, &retval); break; case SYS_lseek: pos |= (off_t)tf->tf_a2; pos <<= 32; //puts a2 and a3 into one var. pos |= (off_t)tf->tf_a3; err = copyin((const userptr_t)tf->tf_sp+16, &whence, sizeof(whence)); if (err) break; err = sys_lseek((int)tf->tf_a0, pos, (int)whence, &lsret); if(!err){ retval = lsret>>32; tf->tf_v1 = lsret; } break; case SYS_dup2: err = sys_dup2((int)tf->tf_a0 , (int)tf->tf_a1, &retval); break; case SYS_chdir: err = sys_chdir((const char*)tf->tf_a0); break; case SYS___getcwd: err = sys___getcwd((char*)tf->tf_a0, (size_t)tf->tf_a1, &retval); break; case SYS_fork: err = sys_fork(tf, &retval); break; case SYS_getpid: err = sys_getpid(&retval); break; case SYS__exit: err = sys__exit((int)tf->tf_a0, &retval); break; case SYS_waitpid: err = sys_waitpid((int) tf->tf_a0, (int*) tf->tf_a1, tf->tf_a2, &retval); break; case SYS_execv: err = sys_execv((const char*) tf->tf_a0, (char**) tf->tf_a1, &retval); break; default: kprintf("Unknown syscall %d\n", callno); err = ENOSYS; break; }
/* * System call dispatcher. * * A pointer to the trapframe created during exception entry (in * exception.S) is passed in. * * 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.) * * Upon syscall return the program counter stored in the trapframe * must be incremented by one instruction; otherwise the exception * return code will restart the "syscall" instruction and the system * call will repeat forever. * * If you run out of registers (which happens quickly with 64-bit * values) further arguments must be fetched from the user-level * stack, starting at sp+16 to skip over the slots for the * registerized values, with copyin(). */ void syscall(struct trapframe *tf) { int callno; int32_t retval; int err; KASSERT(curthread != NULL); KASSERT(curthread->t_curspl == 0); KASSERT(curthread->t_iplhigh_count == 0); callno = tf->tf_v0; /* * Initialize retval to 0. Many of the system calls don't * really return a value, just 0 for success and -1 on * error. Since retval is the value returned on success, * initialize it to 0 by default; thus it's not necessary to * deal with it except for calls that return other values, * like write. */ retval = 0; /* note the casts to userptr_t */ 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); break; /* process calls */ case SYS_fork: err = sys_fork(tf, &retval); break; case SYS_execv: err = sys_execv( (userptr_t)tf->tf_a0, (userptr_t)tf->tf_a1); break; case SYS__exit: sys__exit(tf->tf_a0); panic("Returning from exit\n"); case SYS_waitpid: err = sys_waitpid( tf->tf_a0, (userptr_t)tf->tf_a1, tf->tf_a2, &retval); break; case SYS_getpid: err = sys_getpid(&retval); break; /* file calls */ case SYS_open: err = sys_open( (userptr_t)tf->tf_a0, tf->tf_a1, tf->tf_a2, &retval); break; case SYS_dup2: err = sys_dup2( tf->tf_a0, tf->tf_a1, &retval); break; case SYS_close: err = sys_close(tf->tf_a0); break; case SYS_read: err = sys_read( tf->tf_a0, (userptr_t)tf->tf_a1, tf->tf_a2, &retval); break; case SYS_write: err = sys_write( tf->tf_a0, (userptr_t)tf->tf_a1, tf->tf_a2, &retval); break; case SYS_lseek: { /* * Because the position argument is 64 bits wide, * it goes in the a2/a3 registers and we have to * get "whence" from the stack. Furthermore, the * return value is 64 bits wide, so the extra * part of it goes in the v1 register. * * This is a trifle messy. */ uint64_t offset; int whence; off_t retval64; join32to64(tf->tf_a2, tf->tf_a3, &offset); err = copyin((userptr_t)tf->tf_sp + 16, &whence, sizeof(int)); if (err) { break; } err = sys_lseek(tf->tf_a0, offset, whence, &retval64); if (err) { break; } split64to32(retval64, &tf->tf_v0, &tf->tf_v1); retval = tf->tf_v0; } break; case SYS_chdir: err = sys_chdir((userptr_t)tf->tf_a0); break; case SYS___getcwd: err = sys___getcwd( (userptr_t)tf->tf_a0, tf->tf_a1, &retval); break; /* Even more system calls will go here */ default: kprintf("Unknown syscall %d\n", callno); err = ENOSYS; break; } 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 */ } /* * Now, advance the program counter, to avoid restarting * the syscall over and over again. */ tf->tf_epc += 4; /* Make sure the syscall code didn't forget to lower spl */ KASSERT(curthread->t_curspl == 0); /* ...or leak any spinlocks */ KASSERT(curthread->t_iplhigh_count == 0); }
void syscall(struct trapframe *tf) { int callno; int32_t retval; int err; KASSERT(curthread != NULL); KASSERT(curthread->t_curspl == 0); KASSERT(curthread->t_iplhigh_count == 0); callno = tf->tf_v0; /* * Initialize retval to 0. Many of the system calls don't * really return a value, just 0 for success and -1 on * error. Since retval is the value returned on success, * initialize it to 0 by default; thus it's not necessary to * deal with it except for calls that return other values, * like write. */ retval = 0; uint32_t v0, v1; off_t pos; int whence; //userptr_t *status; struct stat statbuf; 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 syscall ov*/ break; case SYS_open: err = sys_open((const_userptr_t)tf->tf_a0, tf->tf_a1, (mode_t)tf ->tf_a2, &retval); break; case SYS_close: err = sys_close((tf->tf_a0),&retval); break; case SYS_read: err = sys_read(tf->tf_a0, (userptr_t)tf->tf_a1, (size_t)tf -> tf_a2, &retval); //retval = (int32_t)bytes; break; case SYS_write: err = sys_write(tf->tf_a0, (userptr_t)tf->tf_a1, (size_t)tf -> tf_a2, &retval); //retval = (int32_t)bytes; break; case SYS_lseek: pos = tf->tf_a2; pos = pos << 32; pos += tf -> tf_a3; err = copyin((const_userptr_t)tf->tf_sp+16,&whence,sizeof(int)); if(err) { break; } err = sys_lseek(tf->tf_a0, pos, whence, &v0, &v1); if(err) { break; } retval = v0; tf->tf_v1 = v1; break; case SYS__exit: sys__exit(tf->tf_a0); // We are only here because of one of 2 reasons. We tried to kill the initial thread // while there was/were (an) immediate child(ren) of it running. // *NOTE* I'm actually NOT sure if that's a valid reason to be here // Second reason? Something went horribly, horribly wrong err = 0; break; case SYS_dup2: err = sys_dup2(tf->tf_a0,tf->tf_a1,&retval); break; case SYS_fstat: err = sys_fstat(tf->tf_a0, &statbuf); break; case SYS_fork: err = sys_fork(tf, &retval); break; case SYS_getpid: err = sys_getpid(&retval); break; case SYS_waitpid: err = sys_waitpid(tf->tf_a0, (int*)tf->tf_a1, (int)tf->tf_a2, &retval); break; case SYS___getcwd: err = sys___getcwd((char*)tf->tf_a0,(size_t)tf->tf_a1,&retval); break; case SYS_chdir: err = sys_chdir((char*)tf->tf_a0,&retval); break; case SYS_execv: err = sys_execv((const char*)tf->tf_a0, (char**)tf->tf_a1); break; case SYS_sbrk: err = sbrk((int)tf->tf_a0,&retval); break; default: kprintf("Unknown syscall %d\n", callno); err = ENOSYS; break; } 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 */ } /* * Now, advance the program counter, to avoid restarting * the syscall over and over again. */ tf->tf_epc += 4; /* Make sure the syscall code didn't forget to lower spl */ KASSERT(curthread->t_curspl == 0); /* ...or leak any spinlocks */ KASSERT(curthread->t_iplhigh_count == 0); }
/* * System call dispatcher. * * A pointer to the trapframe created during exception entry (in * exception.S) is passed in. * * 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.) * * Upon syscall return the program counter stored in the trapframe * must be incremented by one instruction; otherwise the exception * return code will restart the "syscall" instruction and the system * call will repeat forever. * * If you run out of registers (which happens quickly with 64-bit * values) further arguments must be fetched from the user-level * stack, starting at sp+16 to skip over the slots for the * registerized values, with copyin(). */ void syscall(struct trapframe *tf) { int callno; int32_t retval; int err = 0; KASSERT(curthread != NULL); KASSERT(curthread->t_curspl == 0); KASSERT(curthread->t_iplhigh_count == 0); callno = tf->tf_v0; /* * Initialize retval to 0. Many of the system calls don't * really return a value, just 0 for success and -1 on * error. Since retval is the value returned on success, * initialize it to 0 by default; thus it's not necessary to * deal with it except for calls that return other values, * like write. */ retval = 0; 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); break; /* Add stuff here */ case SYS_read: err = sys_read((int)tf->tf_a0, // filehandle (void*)tf->tf_a1, // buffer (size_t)tf->tf_a2, // size &retval); // return value break; case SYS_write: err = sys_write((int)tf->tf_a0, // filehandle (const void*)tf->tf_a1, // buffer (size_t)tf->tf_a2, // size &retval); // return value break; case SYS_open: err = sys_open((const char*)tf->tf_a0, // filename (int)tf->tf_a1, // flags &retval); // return value break; case SYS_close: err = sys_close((int)tf->tf_a0); // filehandle break; case SYS_dup2: err = sys_dup2((int)tf->tf_a0, // old_filehandle (int)tf->tf_a1, // new_filehandle &retval); // return value break; case SYS__exit: sys_exit((int)tf->tf_a0); // exitcode break; case SYS_getpid: retval = sys_getpid(); // exitcode break; case SYS_waitpid: err = sys_waitpid((pid_t)tf->tf_a0, (int*)tf->tf_a1, tf->tf_a2, &retval); break; case SYS_fork: err = sys_fork(tf, &retval); break; case SYS_execv: err = sys_execv((userptr_t)tf->tf_a0, (userptr_t)tf->tf_a1); break; case SYS_sbrk: err = sys_sbrk((intptr_t)tf->tf_a0, &retval); break; case SYS_lseek: { off_t offset = tf->tf_a2; offset = offset<<32; offset = offset|tf->tf_a3; int whence; int err_copyin = copyin((userptr_t)tf->tf_sp+16,&whence,sizeof(whence)); if (err_copyin) { break; } off_t retoffset; err = sys_lseek((int)tf->tf_a0, // filehandle offset, // desired offset whence, &retoffset); // return value if (!err) { retval = retoffset>>32; tf->tf_v1 = retoffset; } break; } break; case SYS___getcwd: err = sys___getcwd((char*)tf->tf_a0, // buffer (size_t)tf->tf_a1, // size &retval); // return value break; case SYS_chdir: err = sys_chdir((char*)tf->tf_a0); // path break; default: kprintf("Unknown syscall %d\n", callno); err = ENOSYS; break; }