/*1* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 20092* The President and Fellows of Harvard College.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12* 3. Neither the name of the University nor the names of its contributors13* may be used to endorse or promote products derived from this software14* without specific prior written permission.15*16* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829#include <types.h>30#include <kern/errno.h>31#include <kern/syscall.h>32#include <lib.h>33#include <mips/trapframe.h>34#include <copyinout.h>35#include <thread.h>36#include <current.h>37#include <syscall.h>3839#define MAKE_64BIT(x,y) (((int64_t)x) << 32 | y)40#define GET_LO(x) ((int32_t) x & 0x00000000FFFFFFFF)41#define GET_HI(x) ((int32_t) x & 0xFFFFFFFF00000000)4243/*44* System call dispatcher.45*46* A pointer to the trapframe created during exception entry (in47* exception.S) is passed in.48*49* The calling conventions for syscalls are as follows: Like ordinary50* function calls, the first 4 32-bit arguments are passed in the 451* argument registers a0-a3. 64-bit arguments are passed in *aligned*52* pairs of registers, that is, either a0/a1 or a2/a3. This means that53* if the first argument is 32-bit and the second is 64-bit, a1 is54* unused.55*56* This much is the same as the calling conventions for ordinary57* function calls. In addition, the system call number is passed in58* the v0 register.59*60* On successful return, the return value is passed back in the v061* register, or v0 and v1 if 64-bit. This is also like an ordinary62* function call, and additionally the a3 register is also set to 0 to63* indicate success.64*65* On an error return, the error code is passed back in the v066* register, and the a3 register is set to 1 to indicate failure.67* (Userlevel code takes care of storing the error code in errno and68* returning the value -1 from the actual userlevel syscall function.69* See src/user/lib/libc/arch/mips/syscalls-mips.S and related files.)70*71* Upon syscall return the program counter stored in the trapframe72* must be incremented by one instruction; otherwise the exception73* return code will restart the "syscall" instruction and the system74* call will repeat forever.75*76* If you run out of registers (which happens quickly with 64-bit77* values) further arguments must be fetched from the user-level78* stack, starting at sp+16 to skip over the slots for the79* registerized values, with copyin().80*/81void82syscall(struct trapframe *tf)83{84int callno;85int32_t retval;86int64_t retval64;87int err;88int nextra;89bool handle64;9091KASSERT(curthread != NULL);92KASSERT(curthread->t_curspl == 0);93KASSERT(curthread->t_iplhigh_count == 0);9495callno = tf->tf_v0;9697/*98* Initialize retval to 0. Many of the system calls don't99* really return a value, just 0 for success and -1 on100* error. Since retval is the value returned on success,101* initialize it to 0 by default; thus it's not necessary to102* deal with it except for calls that return other values,103* like write.104*/105106retval = 0;107handle64 = false;108109//award points for the process that just called the systemcall.110curthread->td_proc->p_nsyscalls++;111112switch (callno) {113case SYS_reboot:114err = sys_reboot(tf->tf_a0);115break;116117case SYS___time:118err = sys___time((userptr_t)tf->tf_a0,119(userptr_t)tf->tf_a1);120break;121122case SYS_open:123err = sys_open( (userptr_t) tf->tf_a0,124tf->tf_a1, &retval);125break;126127case SYS_close:128err = sys_close( tf->tf_a0 );129break;130131case SYS_write:132err = sys_write( tf->tf_a0,133(userptr_t) tf->tf_a1,134tf->tf_a2, &retval );135break;136137case SYS_read:138err = sys_read( tf->tf_a0,139(userptr_t) tf->tf_a1,140tf->tf_a2, &retval);141break;142143case SYS___getcwd:144err = sys___getcwd( (userptr_t)tf->tf_a0,145tf->tf_a1, &retval );146break;147148case SYS_lseek:149//get the value of whence from sp+16150err = copyin( (userptr_t)(tf->tf_sp + 16),151&nextra, sizeof( int ) );152if( err )153break;154155err = sys_lseek(156tf->tf_a0,157MAKE_64BIT( tf->tf_a2, tf->tf_a3 ),158nextra,159&retval64160);161162//if no errors occurred, we must handle163//a 64-bit return value.164handle64 = true;165break;166167case SYS_dup2:168err = sys_dup2( tf->tf_a0, tf->tf_a1, &retval );169break;170171case SYS_chdir:172err = sys_chdir( (userptr_t)tf->tf_a0 );173break;174175case SYS_getpid:176err = sys_getpid( &retval );177break;178case SYS__exit:179sys__exit( tf->tf_a0 );180err = 0;181break;182183case SYS_waitpid:184err = sys_waitpid( tf->tf_a0, (userptr_t)tf->tf_a1, tf->tf_a2, &retval );185break;186187case SYS_fork:188err = sys_fork( tf, &retval );189break;190191case SYS_execv:192err = sys_execv( (userptr_t) tf->tf_a0, (userptr_t) tf->tf_a1 );193break;194195case SYS_sbrk:196err = sys_sbrk( (intptr_t) tf->tf_a0, (void*)&retval );197break;198default:199kprintf("Unknown syscall %d\n", callno);200err = ENOSYS;201break;202}203204205if (err) {206/*207* Return the error code. This gets converted at208* userlevel to a return value of -1 and the error209* code in errno.210*/211tf->tf_v0 = err;212tf->tf_a3 = 1; /* signal an error */213}214else if( handle64 ) {215tf->tf_a3 = 0;216tf->tf_v0 = GET_HI( retval64 );217tf->tf_v1 = GET_LO( retval64 );218}219else {220/* Success. */221tf->tf_v0 = retval;222tf->tf_a3 = 0; /* signal no error */223}224225/*226* Now, advance the program counter, to avoid restarting227* the syscall over and over again.228*/229230tf->tf_epc += 4;231232/* Make sure the syscall code didn't forget to lower spl */233KASSERT(curthread->t_curspl == 0);234/* ...or leak any spinlocks */235KASSERT(curthread->t_iplhigh_count == 0);236}237238/*239* Enter user mode for a newly forked process.240*241* This function is provided as a reminder. You need to write242* both it and the code that calls it.243*244* Thus, you can trash it and do things another way if you prefer.245*/246void247enter_forked_process(struct trapframe *tf)248{249(void)tf;250}251252253