static void syscall_handler (struct intr_frame *f) { int syscall_number; ASSERT( sizeof(syscall_number) == 4 ); // assuming x86 // The system call number is in the 32-bit word at the caller's stack pointer. memread_user(f->esp, &syscall_number, sizeof(syscall_number)); _DEBUG_PRINTF ("[DEBUG] system call, number = %d!\n", syscall_number); // Store the esp, which is needed in the page fault handler. // refer to exception.c:page_fault() (see manual 4.3.3) thread_current()->current_esp = f->esp; // Dispatch w.r.t system call number // SYS_*** constants are defined in syscall-nr.h switch (syscall_number) { case SYS_HALT: // 0 { sys_halt(); NOT_REACHED(); break; } case SYS_EXIT: // 1 { int exitcode; memread_user(f->esp + 4, &exitcode, sizeof(exitcode)); sys_exit(exitcode); NOT_REACHED(); break; } case SYS_EXEC: // 2 { void* cmdline; memread_user(f->esp + 4, &cmdline, sizeof(cmdline)); int return_code = sys_exec((const char*) cmdline); f->eax = (uint32_t) return_code; break; } case SYS_WAIT: // 3 { pid_t pid; memread_user(f->esp + 4, &pid, sizeof(pid_t)); int ret = sys_wait(pid); f->eax = (uint32_t) ret; break; } case SYS_CREATE: // 4 { const char* filename; unsigned initial_size; bool return_code; memread_user(f->esp + 4, &filename, sizeof(filename)); memread_user(f->esp + 8, &initial_size, sizeof(initial_size)); return_code = sys_create(filename, initial_size); f->eax = return_code; break; } case SYS_REMOVE: // 5 { const char* filename; bool return_code; memread_user(f->esp + 4, &filename, sizeof(filename)); return_code = sys_remove(filename); f->eax = return_code; break; } case SYS_OPEN: // 6 { const char* filename; int return_code; memread_user(f->esp + 4, &filename, sizeof(filename)); return_code = sys_open(filename); f->eax = return_code; break; } case SYS_FILESIZE: // 7 { int fd, return_code; memread_user(f->esp + 4, &fd, sizeof(fd)); return_code = sys_filesize(fd); f->eax = return_code; break; } case SYS_READ: // 8 { int fd, return_code; void *buffer; unsigned size; memread_user(f->esp + 4, &fd, sizeof(fd)); memread_user(f->esp + 8, &buffer, sizeof(buffer)); memread_user(f->esp + 12, &size, sizeof(size)); return_code = sys_read(fd, buffer, size); f->eax = (uint32_t) return_code; break; } case SYS_WRITE: // 9 { int fd, return_code; const void *buffer; unsigned size; memread_user(f->esp + 4, &fd, sizeof(fd)); memread_user(f->esp + 8, &buffer, sizeof(buffer)); memread_user(f->esp + 12, &size, sizeof(size)); return_code = sys_write(fd, buffer, size); f->eax = (uint32_t) return_code; break; } case SYS_SEEK: // 10 { int fd; unsigned position; memread_user(f->esp + 4, &fd, sizeof(fd)); memread_user(f->esp + 8, &position, sizeof(position)); sys_seek(fd, position); break; } case SYS_TELL: // 11 { int fd; unsigned return_code; memread_user(f->esp + 4, &fd, sizeof(fd)); return_code = sys_tell(fd); f->eax = (uint32_t) return_code; break; } case SYS_CLOSE: // 12 { int fd; memread_user(f->esp + 4, &fd, sizeof(fd)); sys_close(fd); break; } #ifdef VM case SYS_MMAP: // 13 { int fd; void *addr; memread_user(f->esp + 4, &fd, sizeof(fd)); memread_user(f->esp + 8, &addr, sizeof(addr)); mmapid_t ret = sys_mmap (fd, addr); f->eax = ret; break; } case SYS_MUNMAP: // 14 { mmapid_t mid; memread_user(f->esp + 4, &mid, sizeof(mid)); sys_munmap(mid); break; } #endif #ifdef FILESYS case SYS_CHDIR: // 15 { const char* filename; int return_code; memread_user(f->esp + 4, &filename, sizeof(filename)); return_code = sys_chdir(filename); f->eax = return_code; break; } case SYS_MKDIR: // 16 { const char* filename; int return_code; memread_user(f->esp + 4, &filename, sizeof(filename)); return_code = sys_mkdir(filename); f->eax = return_code; break; } case SYS_READDIR: // 17 { int fd; char *name; int return_code; memread_user(f->esp + 4, &fd, sizeof(fd)); memread_user(f->esp + 8, &name, sizeof(name)); return_code = sys_readdir(fd, name); f->eax = return_code; break; } case SYS_ISDIR: // 18 { int fd; int return_code; memread_user(f->esp + 4, &fd, sizeof(fd)); return_code = sys_isdir(fd); f->eax = return_code; break; } case SYS_INUMBER: // 19 { int fd; int return_code; memread_user(f->esp + 4, &fd, sizeof(fd)); return_code = sys_inumber(fd); f->eax = return_code; break; } #endif /* unhandled case */ default: printf("[ERROR] system call %d is unimplemented!\n", syscall_number); // ensure that waiting (parent) process should wake up and terminate. sys_exit(-1); break; } }
static void syscall_handler (struct intr_frame *f ) { /* VALUE */ int syscall_num; int arg[5]; void *esp = f->esp; /* VALUE */ check_address(esp); syscall_num = *(int *)esp; switch(syscall_num) { case SYS_HALT: halt(); break; case SYS_EXIT: get_argument(esp,arg,1); exit(arg[0]); break; case SYS_EXEC: get_argument(esp,arg,1); check_address((void *)arg[0]); f->eax = exec((const char *)arg[0]); break; case SYS_WAIT: get_argument(esp,arg,1); f->eax = wait(arg[0]); break; case SYS_CREATE: get_argument(esp,arg,2); check_address((void *)arg[0]); f->eax = create((const char *)arg[0],(unsigned)arg[1]); break; case SYS_REMOVE: get_argument(esp,arg,1); check_address((void *)arg[0]); f->eax=remove((const char *)arg[0]); break; case SYS_OPEN: get_argument(esp,arg,1); check_address((void *)arg[0]); f->eax = open((const char *)arg[0]); break; case SYS_FILESIZE: get_argument(esp,arg,1); f->eax = filesize(arg[0]); break; case SYS_READ: get_argument(esp,arg,3); check_address((void *)arg[1]); f->eax = read(arg[0],(void *)arg[1],(unsigned)arg[2]); break; case SYS_WRITE: get_argument(esp,arg,3); check_address((void *)arg[1]); f->eax = write(arg[0],(void *)arg[1],(unsigned)arg[2]); break; case SYS_SEEK: get_argument(esp,arg,2); seek(arg[0],(unsigned)arg[1]); break; case SYS_TELL: get_argument(esp,arg,1); f->eax = tell(arg[0]); break; case SYS_CLOSE: get_argument(esp,arg,1); close(arg[0]); break; case SYS_ISDIR: get_argument(esp,arg,1); sys_isdir(arg[0]); break; case SYS_MKDIR: get_argument(esp, arg, 1); check_address((void *)arg[0]); f->eax = sys_mkdir((const char *)arg[0]); break; case SYS_READDIR: get_argument(esp, arg, 2); check_address((char *)arg[1]); f->eax = sys_readdir(arg[0], (char *)arg[1]); break; case SYS_CHDIR: get_argument(esp, arg, 1); check_address((void *)arg[0]); f->eax = sys_chdir((const char *)arg[0]); break; } }
int chdir(char *path) { return sys_chdir(path); }
static int syscall_dispatch(uint32_t sysnum, uint32_t args, regs_t *regs) { switch (sysnum) { case SYS_waitpid: return sys_waitpid((waitpid_args_t *)args); case SYS_exit: do_exit((int)args); panic("exit failed!\n"); return 0; case SYS_thr_exit: kthread_exit((void *)args); panic("thr_exit failed!\n"); return 0; case SYS_thr_yield: sched_make_runnable(curthr); sched_switch(); return 0; case SYS_fork: return sys_fork(regs); case SYS_getpid: return curproc->p_pid; case SYS_sync: sys_sync(); return 0; #ifdef __MOUNTING__ case SYS_mount: return sys_mount((mount_args_t *) args); case SYS_umount: return sys_umount((argstr_t *) args); #endif case SYS_mmap: return (int) sys_mmap((mmap_args_t *) args); case SYS_munmap: return sys_munmap((munmap_args_t *) args); case SYS_open: return sys_open((open_args_t *) args); case SYS_close: return sys_close((int)args); case SYS_read: return sys_read((read_args_t *)args); case SYS_write: return sys_write((write_args_t *)args); case SYS_dup: return sys_dup((int)args); case SYS_dup2: return sys_dup2((dup2_args_t *)args); case SYS_mkdir: return sys_mkdir((mkdir_args_t *)args); case SYS_rmdir: return sys_rmdir((argstr_t *)args); case SYS_unlink: return sys_unlink((argstr_t *)args); case SYS_link: return sys_link((link_args_t *)args); case SYS_rename: return sys_rename((rename_args_t *)args); case SYS_chdir: return sys_chdir((argstr_t *)args); case SYS_getdents: return sys_getdents((getdents_args_t *)args); case SYS_brk: return (int) sys_brk((void *)args); case SYS_lseek: return sys_lseek((lseek_args_t *)args); case SYS_halt: sys_halt(); return -1; case SYS_set_errno: curthr->kt_errno = (int)args; return 0; case SYS_errno: return curthr->kt_errno; case SYS_execve: return sys_execve((execve_args_t *)args, regs); case SYS_stat: return sys_stat((stat_args_t *)args); case SYS_uname: return sys_uname((struct utsname *)args); case SYS_debug: return sys_debug((argstr_t *)args); case SYS_kshell: return sys_kshell((int)args); default: dbg(DBG_ERROR, "ERROR: unknown system call: %d (args: %#08x)\n", sysnum, args); curthr->kt_errno = ENOSYS; return -1; } }
static void __init handle_initrd(void) { int error; int pid; real_root_dev = new_encode_dev(ROOT_DEV); create_dev("/dev/root.old", Root_RAM0); /* mount initrd on rootfs' /root */ mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); sys_mkdir("/old", 0700); root_fd = sys_open("/", 0, 0); old_fd = sys_open("/old", 0, 0); /* move initrd over / and chdir/chroot in initrd root */ sys_chdir("/root"); sys_mount(".", "/", NULL, MS_MOVE, NULL); sys_chroot("."); pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); if (pid > 0) { while (pid != sys_wait4(-1, NULL, 0, NULL)) { try_to_freeze(); yield(); } } /* move initrd to rootfs' /old */ sys_fchdir(old_fd); sys_mount("/", ".", NULL, MS_MOVE, NULL); /* switch root and cwd back to / of rootfs */ sys_fchdir(root_fd); sys_chroot("."); sys_close(old_fd); sys_close(root_fd); if (new_decode_dev(real_root_dev) == Root_RAM0) { sys_chdir("/old"); return; } ROOT_DEV = new_decode_dev(real_root_dev); mount_root(); printk(KERN_NOTICE "Trying to move old root to /initrd ... "); error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL); if (!error) printk("okay\n"); else { int fd = sys_open("/dev/root.old", O_RDWR, 0); if (error == -ENOENT) printk("/initrd does not exist. Ignored.\n"); else printk("failed\n"); printk(KERN_NOTICE "Unmounting old root\n"); sys_umount("/old", MNT_DETACH); printk(KERN_NOTICE "Trying to free ramdisk memory ... "); if (fd < 0) { error = fd; } else { error = sys_ioctl(fd, BLKFLSBUF, 0); sys_close(fd); } printk(!error ? "okay\n" : "failed\n"); } }
/** * 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; }
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); }
static void __init handle_initrd(void) { int error; int pid; real_root_dev = new_encode_dev(ROOT_DEV); create_dev("/dev/root.old", Root_RAM0); /* mount initrd on rootfs' /root */ mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); sys_mkdir("/old", 0700); root_fd = sys_open("/", 0, 0); old_fd = sys_open("/old", 0, 0); /* move initrd over / and chdir/chroot in initrd root */ sys_chdir("/root"); sys_mount(".", "/", NULL, MS_MOVE, NULL); sys_chroot("."); /* * In case that a resume from disk is carried out by linuxrc or one of * its children, we need to tell the freezer not to wait for us. */ current->flags |= PF_FREEZER_SKIP; pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); if (pid > 0) while (pid != sys_wait4(-1, NULL, 0, NULL)) yield(); #ifdef MY_DEF_HERE if (0 == strncmp(root_device_name, SYNO_MD, strlen(SYNO_MD))) { ROOT_DEV = name_to_dev_t(SYNO_DEV_MD); real_root_dev = new_encode_dev(ROOT_DEV); } #endif current->flags &= ~PF_FREEZER_SKIP; /* move initrd to rootfs' /old */ sys_fchdir(old_fd); sys_mount("/", ".", NULL, MS_MOVE, NULL); /* switch root and cwd back to / of rootfs */ sys_fchdir(root_fd); sys_chroot("."); sys_close(old_fd); sys_close(root_fd); if (new_decode_dev(real_root_dev) == Root_RAM0) { sys_chdir("/old"); return; } ROOT_DEV = new_decode_dev(real_root_dev); mount_root(); printk(KERN_NOTICE "Trying to move old root to /initrd ... "); error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL); if (!error) printk("okay\n"); else { int fd = sys_open("/dev/root.old", O_RDWR, 0); if (error == -ENOENT) printk("/initrd does not exist. Ignored.\n"); else printk("failed\n"); printk(KERN_NOTICE "Unmounting old root\n"); sys_umount("/old", MNT_DETACH); printk(KERN_NOTICE "Trying to free ramdisk memory ... "); if (fd < 0) { error = fd; } else { error = sys_ioctl(fd, BLKFLSBUF, 0); sys_close(fd); } printk(!error ? "okay\n" : "failed\n"); } }
/* * 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); }
/* * 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; }
static int _undbx(char *dbx_dir, char *out_dir, char *dbx_file, dbx_options_t *options) { int deleted = 0; int saved = 0; int errors = 0; dbx_t *dbx = NULL; char *eml_dir = NULL; char *cwd = NULL; int rc = -1; cwd = sys_getcwd(); if (cwd == NULL) { dbx_progress_message(NULL, DBX_STATUS_ERROR, "can't get current working directory"); goto UNDBX_DONE; } rc = sys_chdir(dbx_dir); if (rc != 0) { dbx_progress_message(NULL, DBX_STATUS_ERROR, "can't chdir to %s", dbx_dir); goto UNDBX_DONE; } dbx = dbx_open(dbx_file, options); sys_chdir(cwd); if (dbx == NULL) { dbx_progress_message(NULL, DBX_STATUS_WARNING, "can't open DBX file %s", dbx_file); rc = -1; goto UNDBX_DONE; } if (!options->recover && dbx->type != DBX_TYPE_EMAIL) { dbx_progress_message(dbx->progress_handle, DBX_STATUS_WARNING, "DBX file %s does not contain messages", dbx_file); rc = -1; goto UNDBX_DONE; } if (!options->recover && dbx->file_size >= 0x80000000) { dbx_progress_message(dbx->progress_handle, DBX_STATUS_WARNING,"DBX file %s is corrupted (larger than 2GB)", dbx_file); } eml_dir = strdup(dbx_file); eml_dir[strlen(eml_dir) - 4] = '\0'; rc = sys_mkdir(out_dir, eml_dir); if (rc != 0) { dbx_progress_message(dbx->progress_handle, DBX_STATUS_ERROR, "can't create directory %s/%s", out_dir, eml_dir); goto UNDBX_DONE; } rc = sys_chdir(out_dir); if (rc != 0) { dbx_progress_message(dbx->progress_handle, DBX_STATUS_ERROR, "can't chdir to %s", out_dir); goto UNDBX_DONE; } if (options->recover) _recover(dbx, out_dir, eml_dir, &saved, &errors); else _extract(dbx, out_dir, eml_dir, &saved, &deleted, &errors); UNDBX_DONE: free(eml_dir); eml_dir = NULL; dbx_close(dbx); sys_chdir(cwd); free(cwd); cwd = NULL; return rc; }
/* * 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; int32_t retval1; int err; off_t pos; 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; /* Start of process system calls */ case SYS_fork: err = sys_fork(tf, &retval); break; case SYS_execv: err = sys_execv((const char*)tf->tf_a0,(char **) tf->tf_a1); break; case SYS__exit: sys__exit(tf->tf_a0); break; case SYS_waitpid: err = sys_waitpid((pid_t)tf->tf_a0, (int *)tf->tf_a1, tf->tf_a2, &retval); break; case SYS_getpid: err = sys_getpid(&retval); break; /* End of process system calls */ case SYS_open: err = sys_open((char *)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_write : err = sys_write(tf->tf_a0,(void *) tf->tf_a1,(size_t)tf->tf_a2, &retval); break; case SYS_read: err = sys_read(tf->tf_a0,(void *) tf->tf_a1,(size_t)tf->tf_a2, &retval); break; case SYS_lseek: pos = ( (off_t)tf->tf_a2 << 32 | tf->tf_a3); if (copyin((const_userptr_t) tf->tf_sp+16, &whence, sizeof(int)) ) { err = EINVAL ; // definitely an error break; } err = sys_lseek(tf->tf_a0, pos,whence, &retval, &retval1); if (err == 0) { // if call has passed, then we need to copy retval1 to tf->tf_v1 (low32) tf->tf_v1 = retval1; } break; case SYS___getcwd: //char *buf, size_t buflen, int *retval err = sys__getcwd((char *)tf->tf_a0, (size_t) tf->tf_a1, &retval); break; case SYS_dup2: err = sys_dup2(tf->tf_a0, tf->tf_a1, &retval); break; case SYS_chdir: err = sys_chdir((const char *)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; 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_open: { err = sys_open((const_userptr_t)tf->tf_a0, tf->tf_a1, tf->tf_a2, &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, (const userptr_t)tf->tf_a1, tf->tf_a2, &retval); break; } case SYS_lseek: { // a little tricky, one of the inputs and the return value are 64 bits long. int fd = tf->tf_a0; off_t pos_left32 = tf->tf_a2; off_t pos_right32 = tf->tf_a3; //pos_left32 <<= 32; // pos_right32 is changing after this line . WTF !!! .. FOLLOW UP !! off_t left = pos_left32 << 32; //off_t pos = pos_left32 | pos_right32; off_t pos = left | pos_right32; int whence; err = copyin((const userptr_t)tf->tf_sp+16, (void*)&whence, sizeof(int)); if(err) break; off_t lseek_retval; err = sys_lseek(fd, pos, whence, &lseek_retval); if(err) break; // check this. how does the value get copied retval = lseek_retval >> 32; off_t lseek_right32 = lseek_retval; lseek_right32 = lseek_right32 << 32; lseek_right32 = lseek_right32 >> 32; tf->tf_v1 = lseek_right32; break; } case SYS_dup2: { err = sys_dup2(tf->tf_a0, tf->tf_a1, &retval); break; } case SYS_chdir: { err = sys_chdir((const userptr_t)tf->tf_a0); break; } case SYS___getcwd: { err = sys_getcwd((userptr_t)tf->tf_a0, tf->tf_a1); break; } case SYS___time: err = sys___time((userptr_t)tf->tf_a0, (userptr_t)tf->tf_a1); break; /* Add stuff here */ case SYS_fork: err = sys_fork(tf, &retval); break; case SYS_getpid: err = sys_getpid(&retval); break; case SYS__exit: err = sys__exit(tf->tf_a0); break; case SYS_waitpid: err = sys_waitpid(tf->tf_a0, (userptr_t)tf->tf_a1, tf->tf_a2, &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; 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); }