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; 25224f6598Srsc 26224f6598Srsc if(argint(argno, &fd) < 0) 27224f6598Srsc return -1; 289583b476Srsc if(fd < 0 || fd >= NOFILE || (f=cp->ofile[fd]) == 0) 29224f6598Srsc return -1; 30224f6598Srsc if(pfd) 31224f6598Srsc *pfd = fd; 32224f6598Srsc if(pf) 33224f6598Srsc *pf = f; 34224f6598Srsc return 0; 35224f6598Srsc } 36224f6598Srsc 37224f6598Srsc // Allocate a file descriptor for the given file. 38224f6598Srsc // Takes over file reference from caller on success. 39224f6598Srsc static int 40224f6598Srsc fdalloc(struct file *f) 41224f6598Srsc { 42224f6598Srsc int fd; 439583b476Srsc 44224f6598Srsc for(fd = 0; fd < NOFILE; fd++){ 459583b476Srsc if(cp->ofile[fd] == 0){ 469583b476Srsc cp->ofile[fd] = f; 47224f6598Srsc return fd; 48224f6598Srsc } 49224f6598Srsc } 50224f6598Srsc return -1; 51224f6598Srsc } 52224f6598Srsc 532685309fSrsc int 542685309fSrsc sys_pipe(void) 552685309fSrsc { 56224f6598Srsc int *fd; 57dca5b5caSrsc struct file *rf, *wf; 58224f6598Srsc int fd0, fd1; 592685309fSrsc 60224f6598Srsc if(argptr(0, (void*)&fd, 2*sizeof fd[0]) < 0) 612685309fSrsc return -1; 62224f6598Srsc if(pipe_alloc(&rf, &wf) < 0) 63224f6598Srsc return -1; 64224f6598Srsc fd0 = -1; 65224f6598Srsc if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ 66224f6598Srsc if(fd0 >= 0) 679583b476Srsc cp->ofile[fd0] = 0; 68224f6598Srsc fileclose(rf); 69224f6598Srsc fileclose(wf); 70224f6598Srsc return -1; 71224f6598Srsc } 7270c3260dSrsc fd[0] = fd0; 7370c3260dSrsc fd[1] = fd1; 74224f6598Srsc return 0; 752685309fSrsc } 762685309fSrsc 772685309fSrsc int 782685309fSrsc sys_write(void) 792685309fSrsc { 80224f6598Srsc struct file *f; 81224f6598Srsc int n; 82224f6598Srsc char *cp; 832685309fSrsc 84224f6598Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0) 852685309fSrsc return -1; 86224f6598Srsc return filewrite(f, cp, n); 872685309fSrsc } 882685309fSrsc 892685309fSrsc int 902685309fSrsc sys_read(void) 912685309fSrsc { 92224f6598Srsc struct file *f; 93224f6598Srsc int n; 94224f6598Srsc char *cp; 952685309fSrsc 96224f6598Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0) 972685309fSrsc return -1; 98224f6598Srsc return fileread(f, cp, n); 992685309fSrsc } 1002685309fSrsc 1012685309fSrsc int 1022685309fSrsc sys_close(void) 1032685309fSrsc { 1042685309fSrsc int fd; 105224f6598Srsc struct file *f; 1062685309fSrsc 107224f6598Srsc if(argfd(0, &fd, &f) < 0) 1082685309fSrsc return -1; 109b6095304Srsc cp->ofile[fd] = 0; 110224f6598Srsc fileclose(f); 1112685309fSrsc return 0; 1122685309fSrsc } 1132685309fSrsc 1142685309fSrsc int 1152685309fSrsc sys_open(void) 1162685309fSrsc { 1172685309fSrsc struct inode *ip, *dp; 118*e2a620daSrsc char *path, *name; 119*e2a620daSrsc int namelen; 120224f6598Srsc int omode; 121*e2a620daSrsc int fd, dev; 122*e2a620daSrsc uint inum; 123224f6598Srsc struct file *f; 1242685309fSrsc 125224f6598Srsc if(argstr(0, &path) < 0 || argint(1, &omode) < 0) 1262685309fSrsc return -1; 1272685309fSrsc 128*e2a620daSrsc switch(omode & O_CREATE){ 129*e2a620daSrsc default: 130*e2a620daSrsc case 0: // regular open 131*e2a620daSrsc if((ip = namei(path)) == 0) 132*e2a620daSrsc return -1; 133*e2a620daSrsc break; 134*e2a620daSrsc 135*e2a620daSrsc case O_CREATE: 136*e2a620daSrsc if((dp = nameiparent(path, &name, &namelen)) == 0) 137*e2a620daSrsc return -1; 138*e2a620daSrsc if(dirlookup(dp, name, namelen, 0, &inum) >= 0){ 139*e2a620daSrsc dev = dp->dev; 1402685309fSrsc iput(dp); 141*e2a620daSrsc ip = iget(dev, inum); 1422685309fSrsc }else{ 143*e2a620daSrsc if((ip = dircreat(dp, name, namelen, T_FILE, 0, 0)) == 0){ 144*e2a620daSrsc iput(dp); 1452685309fSrsc return -1; 1462685309fSrsc } 147*e2a620daSrsc iput(dp); 148*e2a620daSrsc } 149*e2a620daSrsc break; 150*e2a620daSrsc } 151*e2a620daSrsc 152*e2a620daSrsc if(ip->type == T_DIR && (omode & (O_RDWR|O_WRONLY|O_CREATE))){ 1532685309fSrsc iput(ip); 1542685309fSrsc return -1; 1552685309fSrsc } 1562685309fSrsc 157224f6598Srsc if((f = filealloc()) == 0){ 1582685309fSrsc iput(ip); 1592685309fSrsc return -1; 1602685309fSrsc } 161224f6598Srsc if((fd = fdalloc(f)) < 0){ 1622685309fSrsc iput(ip); 163224f6598Srsc fileclose(f); 1642685309fSrsc return -1; 1652685309fSrsc } 1662685309fSrsc 1672685309fSrsc iunlock(ip); 168224f6598Srsc f->type = FD_FILE; 169224f6598Srsc if(omode & O_RDWR) { 170224f6598Srsc f->readable = 1; 171224f6598Srsc f->writable = 1; 172224f6598Srsc } else if(omode & O_WRONLY) { 173224f6598Srsc f->readable = 0; 174224f6598Srsc f->writable = 1; 1752685309fSrsc } else { 176224f6598Srsc f->readable = 1; 177224f6598Srsc f->writable = 0; 1782685309fSrsc } 179224f6598Srsc f->ip = ip; 180224f6598Srsc f->off = 0; 1812685309fSrsc 182224f6598Srsc return fd; 1832685309fSrsc } 1842685309fSrsc 1852685309fSrsc int 1862685309fSrsc sys_mknod(void) 1872685309fSrsc { 1882685309fSrsc struct inode *nip; 189224f6598Srsc char *path; 190224f6598Srsc int len; 191224f6598Srsc int type, major, minor; 1922685309fSrsc 193224f6598Srsc if((len=argstr(0, &path)) < 0 || argint(1, &type) < 0 || 194224f6598Srsc argint(2, &major) < 0 || argint(3, &minor) < 0) 1952685309fSrsc return -1; 1962685309fSrsc 197224f6598Srsc if(len >= DIRSIZ) 1982685309fSrsc return -1; 1992685309fSrsc 200224f6598Srsc if((nip = mknod(path, type, major, minor)) == 0) 2012685309fSrsc return -1; 2022685309fSrsc iput(nip); 203224f6598Srsc return 0; 2042685309fSrsc } 2052685309fSrsc 2062685309fSrsc int 2072685309fSrsc sys_mkdir(void) 2082685309fSrsc { 2092685309fSrsc struct inode *nip; 2102685309fSrsc struct inode *dp; 211*e2a620daSrsc char *name, *path; 2122685309fSrsc struct dirent de; 213*e2a620daSrsc int namelen; 2142685309fSrsc 215224f6598Srsc if(argstr(0, &path) < 0) 2162685309fSrsc return -1; 2172685309fSrsc 218*e2a620daSrsc dp = nameiparent(path, &name, &namelen); 2192685309fSrsc if(dp == 0) 2202685309fSrsc return -1; 221*e2a620daSrsc if(dirlookup(dp, name, namelen, 0, 0) >= 0){ 222*e2a620daSrsc iput(dp); 223*e2a620daSrsc return -1; 224*e2a620daSrsc } 2252685309fSrsc 226*e2a620daSrsc nip = dircreat(dp, name, namelen, T_DIR, 0, 0); 2272685309fSrsc if(nip == 0){ 2282685309fSrsc iput(dp); 2292685309fSrsc return -1; 2302685309fSrsc } 2312685309fSrsc 23219297cafSrsc dp->nlink++; 2332685309fSrsc iupdate(dp); 2342685309fSrsc 2352685309fSrsc memset(de.name, '\0', DIRSIZ); 2362685309fSrsc de.name[0] = '.'; 2372685309fSrsc de.inum = nip->inum; 2382685309fSrsc writei(nip, (char*) &de, 0, sizeof(de)); 2392685309fSrsc 2402685309fSrsc de.inum = dp->inum; 2412685309fSrsc de.name[1] = '.'; 2422685309fSrsc writei(nip, (char*) &de, sizeof(de), sizeof(de)); 2432685309fSrsc 2442685309fSrsc iput(dp); 2452685309fSrsc iput(nip); 2462685309fSrsc 2472685309fSrsc return 0; 2482685309fSrsc } 2492685309fSrsc 2502685309fSrsc int 2512685309fSrsc sys_chdir(void) 2522685309fSrsc { 2532685309fSrsc struct inode *ip; 254224f6598Srsc char *path; 2552685309fSrsc 256224f6598Srsc if(argstr(0, &path) < 0) 2572685309fSrsc return -1; 2582685309fSrsc 259*e2a620daSrsc if((ip = namei(path)) == 0) 2602685309fSrsc return -1; 2612685309fSrsc 2622685309fSrsc if(ip->type != T_DIR) { 2632685309fSrsc iput(ip); 2642685309fSrsc return -1; 2652685309fSrsc } 2662685309fSrsc 267*e2a620daSrsc iunlock(ip); 2689583b476Srsc idecref(cp->cwd); 2699583b476Srsc cp->cwd = ip; 2702685309fSrsc return 0; 2712685309fSrsc } 2722685309fSrsc 2732685309fSrsc int 2742685309fSrsc sys_unlink(void) 2752685309fSrsc { 276224f6598Srsc char *path; 2772685309fSrsc 278224f6598Srsc if(argstr(0, &path) < 0) 2792685309fSrsc return -1; 280224f6598Srsc return unlink(path); 2812685309fSrsc } 2822685309fSrsc 2832685309fSrsc int 2842685309fSrsc sys_fstat(void) 2852685309fSrsc { 286224f6598Srsc struct file *f; 287224f6598Srsc struct stat *st; 2882685309fSrsc 289224f6598Srsc if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof *st) < 0) 2902685309fSrsc return -1; 291224f6598Srsc return filestat(f, st); 2922685309fSrsc } 2932685309fSrsc 2942685309fSrsc int 2952685309fSrsc sys_dup(void) 2962685309fSrsc { 297224f6598Srsc struct file *f; 298224f6598Srsc int fd; 2992685309fSrsc 300224f6598Srsc if(argfd(0, 0, &f) < 0) 3012685309fSrsc return -1; 302224f6598Srsc if((fd=fdalloc(f)) < 0) 3032685309fSrsc return -1; 304224f6598Srsc fileincref(f); 305224f6598Srsc return fd; 3062685309fSrsc } 3072685309fSrsc 3082685309fSrsc int 3092685309fSrsc sys_link(void) 3102685309fSrsc { 311224f6598Srsc char *old, *new; 3122685309fSrsc 313224f6598Srsc if(argstr(0, &old) < 0 || argstr(1, &new) < 0) 3142685309fSrsc return -1; 315224f6598Srsc return link(old, new); 3162685309fSrsc } 3172685309fSrsc 3182685309fSrsc int 3192685309fSrsc sys_exec(void) 3202685309fSrsc { 321224f6598Srsc uint sz=0, ap, sp, p1, p2; 3222685309fSrsc int i, nargs, argbytes, len; 3232685309fSrsc struct inode *ip; 3242685309fSrsc struct elfhdr elf; 3252685309fSrsc struct proghdr ph; 3262685309fSrsc char *mem = 0; 3277366e042Srsc char *path, *s, *last; 328224f6598Srsc uint argv; 3292685309fSrsc 330224f6598Srsc if(argstr(0, &path) < 0 || argint(1, (int*)&argv) < 0) 3312685309fSrsc return -1; 332224f6598Srsc 333*e2a620daSrsc if((ip = namei(path)) == 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