1 #include "types.h" 2 #include "param.h" 3 #include "mmu.h" 4 #include "proc.h" 5 #include "defs.h" 6 #include "x86.h" 7 #include "elf.h" 8 9 int 10 exec(char *path, char **argv) 11 { 12 char *s, *last; 13 int i, off; 14 uint sz = 0; 15 struct elfhdr elf; 16 struct inode *ip = 0; 17 struct proghdr ph; 18 pde_t *pgdir = 0, *oldpgdir; 19 20 if((ip = namei(path)) == 0) 21 return -1; 22 ilock(ip); 23 24 // Check ELF header 25 if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf)) 26 goto bad; 27 if(elf.magic != ELF_MAGIC) 28 goto bad; 29 30 if(!(pgdir = setupkvm())) 31 goto bad; 32 33 // Load program into memory. 34 for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ 35 if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph)) 36 goto bad; 37 if(ph.type != ELF_PROG_LOAD) 38 continue; 39 if(ph.memsz < ph.filesz) 40 goto bad; 41 if(!(sz = allocuvm(pgdir, sz, ph.va + ph.memsz))) 42 goto bad; 43 if(!loaduvm(pgdir, (char *)ph.va, ip, ph.offset, ph.filesz)) 44 goto bad; 45 } 46 iunlockput(ip); 47 48 // Allocate a one-page stack at the next page boundary 49 sz = PGROUNDUP(sz); 50 if(!(sz = allocuvm(pgdir, sz, sz + PGSIZE))) 51 goto bad; 52 53 // initialize stack content: 54 55 // "argumentN" -- nul-terminated string 56 // ... 57 // "argument0" 58 // 0 -- argv[argc] 59 // address of argumentN 60 // ... 61 // address of argument0 -- argv[0] 62 // address of address of argument0 -- argv argument to main() 63 // argc -- argc argument to main() 64 // ffffffff -- return PC for main() call 65 66 uint sp = sz; 67 68 // count arguments 69 int argc; 70 for(argc = 0; argv[argc]; argc++) 71 ; 72 if(argc >= MAXARG) 73 goto bad; 74 75 // push strings and remember where they are 76 uint strings[MAXARG]; 77 for(i = argc - 1; i >= 0; --i){ 78 sp -= strlen(argv[i]) + 1; 79 strings[i] = sp; 80 copyout(pgdir, sp, argv[i], strlen(argv[i]) + 1); 81 } 82 83 // push 0 for argv[argc] 84 sp -= 4; 85 int zero = 0; 86 copyout(pgdir, sp, &zero, 4); 87 88 // push argv[] elements 89 for(i = argc - 1; i >= 0; --i){ 90 sp -= 4; 91 copyout(pgdir, sp, &strings[i], 4); 92 } 93 94 // push argv 95 uint argvaddr = sp; 96 sp -= 4; 97 copyout(pgdir, sp, &argvaddr, 4); 98 99 // push argc 100 sp -= 4; 101 copyout(pgdir, sp, &argc, 4); 102 103 // push 0 in case main returns 104 sp -= 4; 105 uint ffffffff = 0xffffffff; 106 copyout(pgdir, sp, &ffffffff, 4); 107 108 // Save program name for debugging. 109 for(last=s=path; *s; s++) 110 if(*s == '/') 111 last = s+1; 112 safestrcpy(proc->name, last, sizeof(proc->name)); 113 114 // Commit to the user image. 115 oldpgdir = proc->pgdir; 116 proc->pgdir = pgdir; 117 proc->sz = sz; 118 proc->tf->eip = elf.entry; // main 119 proc->tf->esp = sp; 120 121 switchuvm(proc); 122 123 freevm(oldpgdir); 124 125 return 0; 126 127 bad: 128 cprintf("kernel: exec failed\n"); 129 if(pgdir) freevm(pgdir); 130 iunlockput(ip); 131 return -1; 132 } 133