12685309fSrsc #include "types.h" 22685309fSrsc #include "stat.h" 32685309fSrsc #include "param.h" 42685309fSrsc #include "mmu.h" 52685309fSrsc #include "proc.h" 62685309fSrsc #include "defs.h" 72685309fSrsc #include "x86.h" 82685309fSrsc #include "traps.h" 92685309fSrsc #include "syscall.h" 102685309fSrsc #include "spinlock.h" 112685309fSrsc #include "buf.h" 122685309fSrsc #include "fs.h" 132685309fSrsc #include "fsvar.h" 142685309fSrsc #include "elf.h" 159936bffaSrsc #include "file.h" 162685309fSrsc #include "fcntl.h" 172685309fSrsc 18*224f6598Srsc // Fetch the nth word-sized system call argument as a file descriptor 19*224f6598Srsc // and return both the descriptor and the corresponding struct file. 20*224f6598Srsc static int 21*224f6598Srsc argfd(int argno, int *pfd, struct file **pf) 22*224f6598Srsc { 23*224f6598Srsc int fd; 24*224f6598Srsc struct file *f; 25*224f6598Srsc struct proc *p = curproc[cpu()]; 26*224f6598Srsc 27*224f6598Srsc if(argint(argno, &fd) < 0) 28*224f6598Srsc return -1; 29*224f6598Srsc if(fd < 0 || fd >= NOFILE || (f=p->ofile[fd]) == 0) 30*224f6598Srsc return -1; 31*224f6598Srsc if(pfd) 32*224f6598Srsc *pfd = fd; 33*224f6598Srsc if(pf) 34*224f6598Srsc *pf = f; 35*224f6598Srsc return 0; 36*224f6598Srsc } 37*224f6598Srsc 38*224f6598Srsc // Allocate a file descriptor for the given file. 39*224f6598Srsc // Takes over file reference from caller on success. 40*224f6598Srsc static int 41*224f6598Srsc fdalloc(struct file *f) 42*224f6598Srsc { 43*224f6598Srsc int fd; 44*224f6598Srsc struct proc *p = curproc[cpu()]; 45*224f6598Srsc for(fd = 0; fd < NOFILE; fd++){ 46*224f6598Srsc if(p->ofile[fd] == 0){ 47*224f6598Srsc p->ofile[fd] = f; 48*224f6598Srsc return fd; 49*224f6598Srsc } 50*224f6598Srsc } 51*224f6598Srsc return -1; 52*224f6598Srsc } 53*224f6598Srsc 542685309fSrsc int 552685309fSrsc sys_pipe(void) 562685309fSrsc { 57*224f6598Srsc int *fd; 58*224f6598Srsc struct file *rf = 0, *wf = 0; 59*224f6598Srsc int fd0, fd1; 602685309fSrsc struct proc *p = curproc[cpu()]; 612685309fSrsc 62*224f6598Srsc if(argptr(0, (void*)&fd, 2*sizeof fd[0]) < 0) 632685309fSrsc return -1; 64*224f6598Srsc if(pipe_alloc(&rf, &wf) < 0) 65*224f6598Srsc return -1; 66*224f6598Srsc fd0 = -1; 67*224f6598Srsc if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ 68*224f6598Srsc if(fd0 >= 0) 69*224f6598Srsc p->ofile[fd0] = 0; 70*224f6598Srsc fileclose(rf); 71*224f6598Srsc fileclose(wf); 72*224f6598Srsc return -1; 73*224f6598Srsc } 74*224f6598Srsc return 0; 752685309fSrsc } 762685309fSrsc 772685309fSrsc int 782685309fSrsc sys_write(void) 792685309fSrsc { 80*224f6598Srsc struct file *f; 81*224f6598Srsc int n; 82*224f6598Srsc char *cp; 832685309fSrsc 84*224f6598Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0) 852685309fSrsc return -1; 86*224f6598Srsc return filewrite(f, cp, n); 872685309fSrsc } 882685309fSrsc 892685309fSrsc int 902685309fSrsc sys_read(void) 912685309fSrsc { 92*224f6598Srsc struct file *f; 93*224f6598Srsc int n; 94*224f6598Srsc char *cp; 952685309fSrsc 96*224f6598Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0) 972685309fSrsc return -1; 98*224f6598Srsc return fileread(f, cp, n); 992685309fSrsc } 1002685309fSrsc 1012685309fSrsc int 1022685309fSrsc sys_close(void) 1032685309fSrsc { 1042685309fSrsc int fd; 105*224f6598Srsc struct file *f; 1062685309fSrsc 107*224f6598Srsc if(argfd(0, &fd, &f) < 0) 1082685309fSrsc return -1; 109*224f6598Srsc curproc[cpu()]->ofile[fd] = 0; 110*224f6598Srsc fileclose(f); 1112685309fSrsc return 0; 1122685309fSrsc } 1132685309fSrsc 1142685309fSrsc int 1152685309fSrsc sys_open(void) 1162685309fSrsc { 1172685309fSrsc struct inode *ip, *dp; 118*224f6598Srsc char *path; 119*224f6598Srsc int omode; 120*224f6598Srsc int fd; 121*224f6598Srsc struct file *f; 1222685309fSrsc char *last; 1232685309fSrsc 124*224f6598Srsc if(argstr(0, &path) < 0 || argint(1, &omode) < 0) 1252685309fSrsc return -1; 1262685309fSrsc 127*224f6598Srsc if(omode & O_CREATE){ 128*224f6598Srsc dp = namei(path, NAMEI_CREATE, 0, &last, &ip); 1292685309fSrsc if(dp){ 1302685309fSrsc ip = mknod1(dp, last, T_FILE, 0, 0); 1312685309fSrsc iput(dp); 1322685309fSrsc if(ip == 0) 1332685309fSrsc return -1; 1342685309fSrsc } else if(ip == 0){ 1352685309fSrsc return -1; 1362685309fSrsc } else if(ip->type == T_DIR){ 1372685309fSrsc iput(ip); 1382685309fSrsc return -1; 1392685309fSrsc } 1402685309fSrsc } else { 141*224f6598Srsc ip = namei(path, NAMEI_LOOKUP, 0, 0, 0); 1422685309fSrsc if(ip == 0) 1432685309fSrsc return -1; 1442685309fSrsc } 145*224f6598Srsc if(ip->type == T_DIR && ((omode & O_RDWR) || (omode & O_WRONLY))){ 1462685309fSrsc iput(ip); 1472685309fSrsc return -1; 1482685309fSrsc } 1492685309fSrsc 150*224f6598Srsc if((f = filealloc()) == 0){ 1512685309fSrsc iput(ip); 1522685309fSrsc return -1; 1532685309fSrsc } 154*224f6598Srsc if((fd = fdalloc(f)) < 0){ 1552685309fSrsc iput(ip); 156*224f6598Srsc fileclose(f); 1572685309fSrsc return -1; 1582685309fSrsc } 1592685309fSrsc 1602685309fSrsc iunlock(ip); 161*224f6598Srsc f->type = FD_FILE; 162*224f6598Srsc if(omode & O_RDWR) { 163*224f6598Srsc f->readable = 1; 164*224f6598Srsc f->writable = 1; 165*224f6598Srsc } else if(omode & O_WRONLY) { 166*224f6598Srsc f->readable = 0; 167*224f6598Srsc f->writable = 1; 1682685309fSrsc } else { 169*224f6598Srsc f->readable = 1; 170*224f6598Srsc f->writable = 0; 1712685309fSrsc } 172*224f6598Srsc f->ip = ip; 173*224f6598Srsc f->off = 0; 1742685309fSrsc 175*224f6598Srsc return fd; 1762685309fSrsc } 1772685309fSrsc 1782685309fSrsc int 1792685309fSrsc sys_mknod(void) 1802685309fSrsc { 1812685309fSrsc struct inode *nip; 182*224f6598Srsc char *path; 183*224f6598Srsc int len; 184*224f6598Srsc int type, major, minor; 1852685309fSrsc 186*224f6598Srsc if((len=argstr(0, &path)) < 0 || argint(1, &type) < 0 || 187*224f6598Srsc argint(2, &major) < 0 || argint(3, &minor) < 0) 1882685309fSrsc return -1; 1892685309fSrsc 190*224f6598Srsc if(len >= DIRSIZ) 1912685309fSrsc return -1; 1922685309fSrsc 193*224f6598Srsc if((nip = mknod(path, type, major, minor)) == 0) 1942685309fSrsc return -1; 1952685309fSrsc iput(nip); 196*224f6598Srsc return 0; 1972685309fSrsc } 1982685309fSrsc 1992685309fSrsc int 2002685309fSrsc sys_mkdir(void) 2012685309fSrsc { 2022685309fSrsc struct inode *nip; 2032685309fSrsc struct inode *dp; 204*224f6598Srsc char *path; 2052685309fSrsc struct dirent de; 2062685309fSrsc char *last; 2072685309fSrsc 208*224f6598Srsc if(argstr(0, &path) < 0) 2092685309fSrsc return -1; 2102685309fSrsc 211*224f6598Srsc dp = namei(path, NAMEI_CREATE, 0, &last, 0); 2122685309fSrsc if(dp == 0) 2132685309fSrsc return -1; 2142685309fSrsc 2152685309fSrsc nip = mknod1(dp, last, T_DIR, 0, 0); 2162685309fSrsc if(nip == 0){ 2172685309fSrsc iput(dp); 2182685309fSrsc return -1; 2192685309fSrsc } 2202685309fSrsc 2212685309fSrsc dp->nlink += 1; 2222685309fSrsc iupdate(dp); 2232685309fSrsc 2242685309fSrsc memset(de.name, '\0', DIRSIZ); 2252685309fSrsc de.name[0] = '.'; 2262685309fSrsc de.inum = nip->inum; 2272685309fSrsc writei(nip, (char*) &de, 0, sizeof(de)); 2282685309fSrsc 2292685309fSrsc de.inum = dp->inum; 2302685309fSrsc de.name[1] = '.'; 2312685309fSrsc writei(nip, (char*) &de, sizeof(de), sizeof(de)); 2322685309fSrsc 2332685309fSrsc iput(dp); 2342685309fSrsc iput(nip); 2352685309fSrsc 2362685309fSrsc return 0; 2372685309fSrsc } 2382685309fSrsc 2392685309fSrsc int 2402685309fSrsc sys_chdir(void) 2412685309fSrsc { 242*224f6598Srsc struct proc *p = curproc[cpu()]; 2432685309fSrsc struct inode *ip; 244*224f6598Srsc char *path; 2452685309fSrsc 246*224f6598Srsc if(argstr(0, &path) < 0) 2472685309fSrsc return -1; 2482685309fSrsc 249*224f6598Srsc if((ip = namei(path, NAMEI_LOOKUP, 0, 0, 0)) == 0) 2502685309fSrsc return -1; 2512685309fSrsc 252*224f6598Srsc if(ip == p->cwd) { 2532685309fSrsc iput(ip); 2542685309fSrsc return 0; 2552685309fSrsc } 2562685309fSrsc 2572685309fSrsc if(ip->type != T_DIR) { 2582685309fSrsc iput(ip); 2592685309fSrsc return -1; 2602685309fSrsc } 2612685309fSrsc 262*224f6598Srsc idecref(p->cwd); 263*224f6598Srsc p->cwd = ip; 264*224f6598Srsc iunlock(p->cwd); 2652685309fSrsc return 0; 2662685309fSrsc } 2672685309fSrsc 2682685309fSrsc int 2692685309fSrsc sys_unlink(void) 2702685309fSrsc { 271*224f6598Srsc char *path; 2722685309fSrsc 273*224f6598Srsc if(argstr(0, &path) < 0) 2742685309fSrsc return -1; 275*224f6598Srsc return unlink(path); 2762685309fSrsc } 2772685309fSrsc 2782685309fSrsc int 2792685309fSrsc sys_fstat(void) 2802685309fSrsc { 281*224f6598Srsc struct file *f; 282*224f6598Srsc struct stat *st; 2832685309fSrsc 284*224f6598Srsc if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof *st) < 0) 2852685309fSrsc return -1; 286*224f6598Srsc return filestat(f, st); 2872685309fSrsc } 2882685309fSrsc 2892685309fSrsc int 2902685309fSrsc sys_dup(void) 2912685309fSrsc { 292*224f6598Srsc struct file *f; 293*224f6598Srsc int fd; 2942685309fSrsc 295*224f6598Srsc if(argfd(0, 0, &f) < 0) 2962685309fSrsc return -1; 297*224f6598Srsc if((fd=fdalloc(f)) < 0) 2982685309fSrsc return -1; 299*224f6598Srsc fileincref(f); 300*224f6598Srsc return fd; 3012685309fSrsc } 3022685309fSrsc 3032685309fSrsc int 3042685309fSrsc sys_link(void) 3052685309fSrsc { 306*224f6598Srsc char *old, *new; 3072685309fSrsc 308*224f6598Srsc if(argstr(0, &old) < 0 || argstr(1, &new) < 0) 3092685309fSrsc return -1; 310*224f6598Srsc return link(old, new); 3112685309fSrsc } 3122685309fSrsc 3132685309fSrsc int 3142685309fSrsc sys_exec(void) 3152685309fSrsc { 3162685309fSrsc struct proc *cp = curproc[cpu()]; 317*224f6598Srsc uint sz=0, ap, sp, p1, p2; 3182685309fSrsc int i, nargs, argbytes, len; 3192685309fSrsc struct inode *ip; 3202685309fSrsc struct elfhdr elf; 3212685309fSrsc struct proghdr ph; 3222685309fSrsc char *mem = 0; 323*224f6598Srsc char *path, *s; 324*224f6598Srsc uint argv; 3252685309fSrsc 326*224f6598Srsc if(argstr(0, &path) < 0 || argint(1, (int*)&argv) < 0) 3272685309fSrsc return -1; 328*224f6598Srsc 329*224f6598Srsc ip = namei(path, NAMEI_LOOKUP, 0, 0, 0); 3302685309fSrsc if(ip == 0) 3312685309fSrsc return -1; 3322685309fSrsc 3332685309fSrsc if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf)) 3342685309fSrsc goto bad; 3352685309fSrsc 3362685309fSrsc if(elf.magic != ELF_MAGIC) 3372685309fSrsc goto bad; 3382685309fSrsc 3392685309fSrsc sz = 0; 3402685309fSrsc for(i = 0; i < elf.phnum; i++){ 3412685309fSrsc if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph), 3422685309fSrsc sizeof(ph)) != sizeof(ph)) 3432685309fSrsc goto bad; 3442685309fSrsc if(ph.type != ELF_PROG_LOAD) 3452685309fSrsc continue; 3462685309fSrsc if(ph.memsz < ph.filesz) 3472685309fSrsc goto bad; 3482685309fSrsc sz += ph.memsz; 3492685309fSrsc } 3502685309fSrsc 3512685309fSrsc sz += 4096 - (sz % 4096); 3522685309fSrsc sz += 4096; 3532685309fSrsc 3542685309fSrsc mem = kalloc(sz); 3552685309fSrsc if(mem == 0) 3562685309fSrsc goto bad; 3572685309fSrsc memset(mem, 0, sz); 3582685309fSrsc 3592685309fSrsc nargs = 0; 3602685309fSrsc argbytes = 0; 3612685309fSrsc for(i = 0;; i++){ 362*224f6598Srsc if(fetchint(cp, argv + 4*i, (int*)&ap) < 0) 3632685309fSrsc goto bad; 3642685309fSrsc if(ap == 0) 3652685309fSrsc break; 366*224f6598Srsc len = fetchstr(cp, ap, &s); 3672685309fSrsc if(len < 0) 3682685309fSrsc goto bad; 3692685309fSrsc nargs++; 3702685309fSrsc argbytes += len + 1; 3712685309fSrsc } 3722685309fSrsc 3732685309fSrsc // argn\0 3742685309fSrsc // ... 3752685309fSrsc // arg0\0 3762685309fSrsc // 0 3772685309fSrsc // ptr to argn 3782685309fSrsc // ... 3792685309fSrsc // 12: ptr to arg0 3802685309fSrsc // 8: argv (points to ptr to arg0) 3812685309fSrsc // 4: argc 3822685309fSrsc // 0: fake return pc 3832685309fSrsc sp = sz - argbytes - (nargs+1)*4 - 4 - 4 - 4; 3842685309fSrsc *(uint*)(mem + sp) = 0xffffffff; 3852685309fSrsc *(uint*)(mem + sp + 4) = nargs; 3862685309fSrsc *(uint*)(mem + sp + 8) = (uint)(sp + 12); 3872685309fSrsc 3882685309fSrsc p1 = sp + 12; 3892685309fSrsc p2 = sp + 12 + (nargs + 1) * 4; 3902685309fSrsc for(i = 0; i < nargs; i++){ 391*224f6598Srsc fetchint(cp, argv + 4*i, (int*)&ap); 392*224f6598Srsc len = fetchstr(cp, ap, &s); 393*224f6598Srsc memmove(mem + p2, s, len + 1); 3942685309fSrsc *(uint*)(mem + p1) = p2; 3952685309fSrsc p1 += 4; 3962685309fSrsc p2 += len + 1; 3972685309fSrsc } 3982685309fSrsc *(uint*)(mem + p1) = 0; 3992685309fSrsc 4002685309fSrsc // commit to the new image. 4012685309fSrsc kfree(cp->mem, cp->sz); 4022685309fSrsc cp->sz = sz; 4032685309fSrsc cp->mem = mem; 4042685309fSrsc mem = 0; 4052685309fSrsc 4062685309fSrsc for(i = 0; i < elf.phnum; i++){ 4072685309fSrsc if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph), 4082685309fSrsc sizeof(ph)) != sizeof(ph)) 4092685309fSrsc goto bad2; 4102685309fSrsc if(ph.type != ELF_PROG_LOAD) 4112685309fSrsc continue; 4122685309fSrsc if(ph.va + ph.memsz > sz) 4132685309fSrsc goto bad2; 4142685309fSrsc if(readi(ip, cp->mem + ph.va, ph.offset, ph.filesz) != ph.filesz) 4152685309fSrsc goto bad2; 4162685309fSrsc memset(cp->mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz); 4172685309fSrsc } 4182685309fSrsc 4192685309fSrsc iput(ip); 4202685309fSrsc 4212685309fSrsc cp->tf->eip = elf.entry; 4222685309fSrsc cp->tf->esp = sp; 4232685309fSrsc setupsegs(cp); 4242685309fSrsc 4252685309fSrsc return 0; 4262685309fSrsc 4272685309fSrsc bad: 4282685309fSrsc if(mem) 4292685309fSrsc kfree(mem, sz); 4302685309fSrsc iput(ip); 4312685309fSrsc return -1; 4322685309fSrsc 4332685309fSrsc bad2: 4342685309fSrsc iput(ip); 4352685309fSrsc proc_exit(); 4362685309fSrsc return 0; 4372685309fSrsc } 438