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 18224f6598Srsc // Fetch the nth word-sized system call argument as a file descriptor 19224f6598Srsc // and return both the descriptor and the corresponding struct file. 20224f6598Srsc static int 21224f6598Srsc argfd(int argno, int *pfd, struct file **pf) 22224f6598Srsc { 23224f6598Srsc int fd; 24224f6598Srsc struct file *f; 25*9583b476Srsc struct proc *cp = curproc[cpu()]; 26224f6598Srsc 27224f6598Srsc if(argint(argno, &fd) < 0) 28224f6598Srsc return -1; 29*9583b476Srsc if(fd < 0 || fd >= NOFILE || (f=cp->ofile[fd]) == 0) 30224f6598Srsc return -1; 31224f6598Srsc if(pfd) 32224f6598Srsc *pfd = fd; 33224f6598Srsc if(pf) 34224f6598Srsc *pf = f; 35224f6598Srsc return 0; 36224f6598Srsc } 37224f6598Srsc 38224f6598Srsc // Allocate a file descriptor for the given file. 39224f6598Srsc // Takes over file reference from caller on success. 40224f6598Srsc static int 41224f6598Srsc fdalloc(struct file *f) 42224f6598Srsc { 43224f6598Srsc int fd; 44*9583b476Srsc struct proc *cp = curproc[cpu()]; 45*9583b476Srsc 46224f6598Srsc for(fd = 0; fd < NOFILE; fd++){ 47*9583b476Srsc if(cp->ofile[fd] == 0){ 48*9583b476Srsc cp->ofile[fd] = f; 49224f6598Srsc return fd; 50224f6598Srsc } 51224f6598Srsc } 52224f6598Srsc return -1; 53224f6598Srsc } 54224f6598Srsc 552685309fSrsc int 562685309fSrsc sys_pipe(void) 572685309fSrsc { 58224f6598Srsc int *fd; 59224f6598Srsc struct file *rf = 0, *wf = 0; 60224f6598Srsc int fd0, fd1; 61*9583b476Srsc struct proc *cp = curproc[cpu()]; 622685309fSrsc 63224f6598Srsc if(argptr(0, (void*)&fd, 2*sizeof fd[0]) < 0) 642685309fSrsc return -1; 65224f6598Srsc if(pipe_alloc(&rf, &wf) < 0) 66224f6598Srsc return -1; 67224f6598Srsc fd0 = -1; 68224f6598Srsc if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ 69224f6598Srsc if(fd0 >= 0) 70*9583b476Srsc cp->ofile[fd0] = 0; 71224f6598Srsc fileclose(rf); 72224f6598Srsc fileclose(wf); 73224f6598Srsc return -1; 74224f6598Srsc } 7570c3260dSrsc fd[0] = fd0; 7670c3260dSrsc fd[1] = fd1; 77224f6598Srsc return 0; 782685309fSrsc } 792685309fSrsc 802685309fSrsc int 812685309fSrsc sys_write(void) 822685309fSrsc { 83224f6598Srsc struct file *f; 84224f6598Srsc int n; 85224f6598Srsc char *cp; 862685309fSrsc 87224f6598Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0) 882685309fSrsc return -1; 89224f6598Srsc return filewrite(f, cp, n); 902685309fSrsc } 912685309fSrsc 922685309fSrsc int 932685309fSrsc sys_read(void) 942685309fSrsc { 95224f6598Srsc struct file *f; 96224f6598Srsc int n; 97224f6598Srsc char *cp; 982685309fSrsc 99224f6598Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0) 1002685309fSrsc return -1; 101224f6598Srsc return fileread(f, cp, n); 1022685309fSrsc } 1032685309fSrsc 1042685309fSrsc int 1052685309fSrsc sys_close(void) 1062685309fSrsc { 1072685309fSrsc int fd; 108224f6598Srsc struct file *f; 1092685309fSrsc 110224f6598Srsc if(argfd(0, &fd, &f) < 0) 1112685309fSrsc return -1; 112224f6598Srsc curproc[cpu()]->ofile[fd] = 0; 113224f6598Srsc fileclose(f); 1142685309fSrsc return 0; 1152685309fSrsc } 1162685309fSrsc 1172685309fSrsc int 1182685309fSrsc sys_open(void) 1192685309fSrsc { 1202685309fSrsc struct inode *ip, *dp; 121224f6598Srsc char *path; 122224f6598Srsc int omode; 123224f6598Srsc int fd; 124224f6598Srsc struct file *f; 1252685309fSrsc char *last; 1262685309fSrsc 127224f6598Srsc if(argstr(0, &path) < 0 || argint(1, &omode) < 0) 1282685309fSrsc return -1; 1292685309fSrsc 130224f6598Srsc if(omode & O_CREATE){ 131224f6598Srsc dp = namei(path, NAMEI_CREATE, 0, &last, &ip); 1322685309fSrsc if(dp){ 1332685309fSrsc ip = mknod1(dp, last, T_FILE, 0, 0); 1342685309fSrsc iput(dp); 1352685309fSrsc if(ip == 0) 1362685309fSrsc return -1; 1372685309fSrsc } else if(ip == 0){ 1382685309fSrsc return -1; 1392685309fSrsc } else if(ip->type == T_DIR){ 1402685309fSrsc iput(ip); 1412685309fSrsc return -1; 1422685309fSrsc } 1432685309fSrsc } else { 144224f6598Srsc ip = namei(path, NAMEI_LOOKUP, 0, 0, 0); 1452685309fSrsc if(ip == 0) 1462685309fSrsc return -1; 1472685309fSrsc } 148224f6598Srsc if(ip->type == T_DIR && ((omode & O_RDWR) || (omode & O_WRONLY))){ 1492685309fSrsc iput(ip); 1502685309fSrsc return -1; 1512685309fSrsc } 1522685309fSrsc 153224f6598Srsc if((f = filealloc()) == 0){ 1542685309fSrsc iput(ip); 1552685309fSrsc return -1; 1562685309fSrsc } 157224f6598Srsc if((fd = fdalloc(f)) < 0){ 1582685309fSrsc iput(ip); 159224f6598Srsc fileclose(f); 1602685309fSrsc return -1; 1612685309fSrsc } 1622685309fSrsc 1632685309fSrsc iunlock(ip); 164224f6598Srsc f->type = FD_FILE; 165224f6598Srsc if(omode & O_RDWR) { 166224f6598Srsc f->readable = 1; 167224f6598Srsc f->writable = 1; 168224f6598Srsc } else if(omode & O_WRONLY) { 169224f6598Srsc f->readable = 0; 170224f6598Srsc f->writable = 1; 1712685309fSrsc } else { 172224f6598Srsc f->readable = 1; 173224f6598Srsc f->writable = 0; 1742685309fSrsc } 175224f6598Srsc f->ip = ip; 176224f6598Srsc f->off = 0; 1772685309fSrsc 178224f6598Srsc return fd; 1792685309fSrsc } 1802685309fSrsc 1812685309fSrsc int 1822685309fSrsc sys_mknod(void) 1832685309fSrsc { 1842685309fSrsc struct inode *nip; 185224f6598Srsc char *path; 186224f6598Srsc int len; 187224f6598Srsc int type, major, minor; 1882685309fSrsc 189224f6598Srsc if((len=argstr(0, &path)) < 0 || argint(1, &type) < 0 || 190224f6598Srsc argint(2, &major) < 0 || argint(3, &minor) < 0) 1912685309fSrsc return -1; 1922685309fSrsc 193224f6598Srsc if(len >= DIRSIZ) 1942685309fSrsc return -1; 1952685309fSrsc 196224f6598Srsc if((nip = mknod(path, type, major, minor)) == 0) 1972685309fSrsc return -1; 1982685309fSrsc iput(nip); 199224f6598Srsc return 0; 2002685309fSrsc } 2012685309fSrsc 2022685309fSrsc int 2032685309fSrsc sys_mkdir(void) 2042685309fSrsc { 2052685309fSrsc struct inode *nip; 2062685309fSrsc struct inode *dp; 207224f6598Srsc char *path; 2082685309fSrsc struct dirent de; 2092685309fSrsc char *last; 2102685309fSrsc 211224f6598Srsc if(argstr(0, &path) < 0) 2122685309fSrsc return -1; 2132685309fSrsc 214224f6598Srsc dp = namei(path, NAMEI_CREATE, 0, &last, 0); 2152685309fSrsc if(dp == 0) 2162685309fSrsc return -1; 2172685309fSrsc 2182685309fSrsc nip = mknod1(dp, last, T_DIR, 0, 0); 2192685309fSrsc if(nip == 0){ 2202685309fSrsc iput(dp); 2212685309fSrsc return -1; 2222685309fSrsc } 2232685309fSrsc 22419297cafSrsc dp->nlink++; 2252685309fSrsc iupdate(dp); 2262685309fSrsc 2272685309fSrsc memset(de.name, '\0', DIRSIZ); 2282685309fSrsc de.name[0] = '.'; 2292685309fSrsc de.inum = nip->inum; 2302685309fSrsc writei(nip, (char*) &de, 0, sizeof(de)); 2312685309fSrsc 2322685309fSrsc de.inum = dp->inum; 2332685309fSrsc de.name[1] = '.'; 2342685309fSrsc writei(nip, (char*) &de, sizeof(de), sizeof(de)); 2352685309fSrsc 2362685309fSrsc iput(dp); 2372685309fSrsc iput(nip); 2382685309fSrsc 2392685309fSrsc return 0; 2402685309fSrsc } 2412685309fSrsc 2422685309fSrsc int 2432685309fSrsc sys_chdir(void) 2442685309fSrsc { 245*9583b476Srsc struct proc *cp = curproc[cpu()]; 2462685309fSrsc struct inode *ip; 247224f6598Srsc char *path; 2482685309fSrsc 249224f6598Srsc if(argstr(0, &path) < 0) 2502685309fSrsc return -1; 2512685309fSrsc 252224f6598Srsc if((ip = namei(path, NAMEI_LOOKUP, 0, 0, 0)) == 0) 2532685309fSrsc return -1; 2542685309fSrsc 255224f6598Srsc if(ip == p->cwd) { 2562685309fSrsc iput(ip); 2572685309fSrsc return 0; 2582685309fSrsc } 2592685309fSrsc 2602685309fSrsc if(ip->type != T_DIR) { 2612685309fSrsc iput(ip); 2622685309fSrsc return -1; 2632685309fSrsc } 2642685309fSrsc 265*9583b476Srsc idecref(cp->cwd); 266*9583b476Srsc cp->cwd = ip; 267*9583b476Srsc iunlock(cp->cwd); 2682685309fSrsc return 0; 2692685309fSrsc } 2702685309fSrsc 2712685309fSrsc int 2722685309fSrsc sys_unlink(void) 2732685309fSrsc { 274224f6598Srsc char *path; 2752685309fSrsc 276224f6598Srsc if(argstr(0, &path) < 0) 2772685309fSrsc return -1; 278224f6598Srsc return unlink(path); 2792685309fSrsc } 2802685309fSrsc 2812685309fSrsc int 2822685309fSrsc sys_fstat(void) 2832685309fSrsc { 284224f6598Srsc struct file *f; 285224f6598Srsc struct stat *st; 2862685309fSrsc 287224f6598Srsc if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof *st) < 0) 2882685309fSrsc return -1; 289224f6598Srsc return filestat(f, st); 2902685309fSrsc } 2912685309fSrsc 2922685309fSrsc int 2932685309fSrsc sys_dup(void) 2942685309fSrsc { 295224f6598Srsc struct file *f; 296224f6598Srsc int fd; 2972685309fSrsc 298224f6598Srsc if(argfd(0, 0, &f) < 0) 2992685309fSrsc return -1; 300224f6598Srsc if((fd=fdalloc(f)) < 0) 3012685309fSrsc return -1; 302224f6598Srsc fileincref(f); 303224f6598Srsc return fd; 3042685309fSrsc } 3052685309fSrsc 3062685309fSrsc int 3072685309fSrsc sys_link(void) 3082685309fSrsc { 309224f6598Srsc char *old, *new; 3102685309fSrsc 311224f6598Srsc if(argstr(0, &old) < 0 || argstr(1, &new) < 0) 3122685309fSrsc return -1; 313224f6598Srsc return link(old, new); 3142685309fSrsc } 3152685309fSrsc 3162685309fSrsc int 3172685309fSrsc sys_exec(void) 3182685309fSrsc { 3192685309fSrsc struct proc *cp = curproc[cpu()]; 320224f6598Srsc uint sz=0, ap, sp, p1, p2; 3212685309fSrsc int i, nargs, argbytes, len; 3222685309fSrsc struct inode *ip; 3232685309fSrsc struct elfhdr elf; 3242685309fSrsc struct proghdr ph; 3252685309fSrsc char *mem = 0; 3267366e042Srsc char *path, *s, *last; 327224f6598Srsc uint argv; 3282685309fSrsc 329224f6598Srsc if(argstr(0, &path) < 0 || argint(1, (int*)&argv) < 0) 3302685309fSrsc return -1; 331224f6598Srsc 332224f6598Srsc ip = namei(path, NAMEI_LOOKUP, 0, 0, 0); 3332685309fSrsc if(ip == 0) 3342685309fSrsc return -1; 3352685309fSrsc 3362685309fSrsc if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf)) 3372685309fSrsc goto bad; 3382685309fSrsc 3392685309fSrsc if(elf.magic != ELF_MAGIC) 3402685309fSrsc goto bad; 3412685309fSrsc 3422685309fSrsc sz = 0; 3432685309fSrsc for(i = 0; i < elf.phnum; i++){ 3442685309fSrsc if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph), 3452685309fSrsc sizeof(ph)) != sizeof(ph)) 3462685309fSrsc goto bad; 3472685309fSrsc if(ph.type != ELF_PROG_LOAD) 3482685309fSrsc continue; 3492685309fSrsc if(ph.memsz < ph.filesz) 3502685309fSrsc goto bad; 3512685309fSrsc sz += ph.memsz; 3522685309fSrsc } 3532685309fSrsc 3542685309fSrsc sz += 4096 - (sz % 4096); 3552685309fSrsc sz += 4096; 3562685309fSrsc 3572685309fSrsc mem = kalloc(sz); 3582685309fSrsc if(mem == 0) 3592685309fSrsc goto bad; 3602685309fSrsc memset(mem, 0, sz); 3612685309fSrsc 3622685309fSrsc nargs = 0; 3632685309fSrsc argbytes = 0; 3642685309fSrsc for(i = 0;; i++){ 365224f6598Srsc if(fetchint(cp, argv + 4*i, (int*)&ap) < 0) 3662685309fSrsc goto bad; 3672685309fSrsc if(ap == 0) 3682685309fSrsc break; 369224f6598Srsc len = fetchstr(cp, ap, &s); 3702685309fSrsc if(len < 0) 3712685309fSrsc goto bad; 3722685309fSrsc nargs++; 3732685309fSrsc argbytes += len + 1; 3742685309fSrsc } 3752685309fSrsc 3762685309fSrsc // argn\0 3772685309fSrsc // ... 3782685309fSrsc // arg0\0 3792685309fSrsc // 0 3802685309fSrsc // ptr to argn 3812685309fSrsc // ... 3822685309fSrsc // 12: ptr to arg0 3832685309fSrsc // 8: argv (points to ptr to arg0) 3842685309fSrsc // 4: argc 3852685309fSrsc // 0: fake return pc 3862685309fSrsc sp = sz - argbytes - (nargs+1)*4 - 4 - 4 - 4; 3872685309fSrsc *(uint*)(mem + sp) = 0xffffffff; 3882685309fSrsc *(uint*)(mem + sp + 4) = nargs; 3892685309fSrsc *(uint*)(mem + sp + 8) = (uint)(sp + 12); 3902685309fSrsc 3912685309fSrsc p1 = sp + 12; 3922685309fSrsc p2 = sp + 12 + (nargs + 1) * 4; 3932685309fSrsc for(i = 0; i < nargs; i++){ 394224f6598Srsc fetchint(cp, argv + 4*i, (int*)&ap); 395224f6598Srsc len = fetchstr(cp, ap, &s); 396224f6598Srsc memmove(mem + p2, s, len + 1); 3972685309fSrsc *(uint*)(mem + p1) = p2; 3982685309fSrsc p1 += 4; 3992685309fSrsc p2 += len + 1; 4002685309fSrsc } 4012685309fSrsc *(uint*)(mem + p1) = 0; 4022685309fSrsc 4037366e042Srsc // Save name for debugging. 4047366e042Srsc for(last=s=path; *s; s++) 4057366e042Srsc if(*s == '/') 4067366e042Srsc last = s+1; 4077366e042Srsc safestrcpy(cp->name, last, sizeof cp->name); 4087366e042Srsc 4092685309fSrsc // commit to the new image. 4102685309fSrsc kfree(cp->mem, cp->sz); 4112685309fSrsc cp->sz = sz; 4122685309fSrsc cp->mem = mem; 4132685309fSrsc mem = 0; 4142685309fSrsc 4152685309fSrsc for(i = 0; i < elf.phnum; i++){ 4162685309fSrsc if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph), 4172685309fSrsc sizeof(ph)) != sizeof(ph)) 4182685309fSrsc goto bad2; 4192685309fSrsc if(ph.type != ELF_PROG_LOAD) 4202685309fSrsc continue; 4212685309fSrsc if(ph.va + ph.memsz > sz) 4222685309fSrsc goto bad2; 4232685309fSrsc if(readi(ip, cp->mem + ph.va, ph.offset, ph.filesz) != ph.filesz) 4242685309fSrsc goto bad2; 4252685309fSrsc memset(cp->mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz); 4262685309fSrsc } 4272685309fSrsc 4282685309fSrsc iput(ip); 4292685309fSrsc 4302685309fSrsc cp->tf->eip = elf.entry; 4312685309fSrsc cp->tf->esp = sp; 4322685309fSrsc setupsegs(cp); 4332685309fSrsc 4342685309fSrsc return 0; 4352685309fSrsc 4362685309fSrsc bad: 4372685309fSrsc if(mem) 4382685309fSrsc kfree(mem, sz); 4392685309fSrsc iput(ip); 4402685309fSrsc return -1; 4412685309fSrsc 4422685309fSrsc bad2: 4432685309fSrsc iput(ip); 4442685309fSrsc proc_exit(); 4452685309fSrsc return 0; 4462685309fSrsc } 447