exec.c (2447B)
1 #include "types.h" 2 #include "param.h" 3 #include "memlayout.h" 4 #include "mmu.h" 5 #include "proc.h" 6 #include "defs.h" 7 #include "x86.h" 8 #include "elf.h" 9 10 int 11 exec(char *path, char **argv) 12 { 13 char *s, *last; 14 int i, off; 15 uintp argc, sz, sp, ustack[3+MAXARG+1]; 16 struct elfhdr elf; 17 struct inode *ip; 18 struct proghdr ph; 19 pde_t *pgdir, *oldpgdir; 20 21 if((ip = namei(path)) == 0) 22 return -1; 23 ilock(ip); 24 pgdir = 0; 25 26 // Check ELF header 27 if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf)) 28 goto bad; 29 if(elf.magic != ELF_MAGIC) 30 goto bad; 31 32 if((pgdir = setupkvm()) == 0) 33 goto bad; 34 35 // Load program into memory. 36 sz = 0; 37 for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ 38 if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph)) 39 goto bad; 40 if(ph.type != ELF_PROG_LOAD) 41 continue; 42 if(ph.memsz < ph.filesz) 43 goto bad; 44 if((sz = allocuvm(pgdir, sz, ph.vaddr + ph.memsz)) == 0) 45 goto bad; 46 if(loaduvm(pgdir, (char*)ph.vaddr, ip, ph.off, ph.filesz) < 0) 47 goto bad; 48 } 49 iunlockput(ip); 50 ip = 0; 51 52 // Allocate two pages at the next page boundary. 53 // Make the first inaccessible. Use the second as the user stack. 54 sz = PGROUNDUP(sz); 55 if((sz = allocuvm(pgdir, sz, sz + 2*PGSIZE)) == 0) 56 goto bad; 57 clearpteu(pgdir, (char*)(sz - 2*PGSIZE)); 58 sp = sz; 59 60 // Push argument strings, prepare rest of stack in ustack. 61 for(argc = 0; argv[argc]; argc++) { 62 if(argc >= MAXARG) 63 goto bad; 64 sp = (sp - (strlen(argv[argc]) + 1)) & ~(sizeof(uintp)-1); 65 if(copyout(pgdir, sp, argv[argc], strlen(argv[argc]) + 1) < 0) 66 goto bad; 67 ustack[3+argc] = sp; 68 } 69 ustack[3+argc] = 0; 70 71 ustack[0] = 0xffffffff; // fake return PC 72 ustack[1] = argc; 73 ustack[2] = sp - (argc+1)*sizeof(uintp); // argv pointer 74 75 #if X64 76 proc->tf->rdi = argc; 77 proc->tf->rsi = sp - (argc+1)*sizeof(uintp); 78 #endif 79 80 sp -= (3+argc+1) * sizeof(uintp); 81 if(copyout(pgdir, sp, ustack, (3+argc+1)*sizeof(uintp)) < 0) 82 goto bad; 83 84 // Save program name for debugging. 85 for(last=s=path; *s; s++) 86 if(*s == '/') 87 last = s+1; 88 safestrcpy(proc->name, last, sizeof(proc->name)); 89 90 // Commit to the user image. 91 oldpgdir = proc->pgdir; 92 proc->pgdir = pgdir; 93 proc->sz = sz; 94 proc->tf->eip = elf.entry; // main 95 proc->tf->esp = sp; 96 switchuvm(proc); 97 freevm(oldpgdir); 98 return 0; 99 100 bad: 101 if(pgdir) 102 freevm(pgdir); 103 if(ip) 104 iunlockput(ip); 105 return -1; 106 }