xref: /xv6-public/exec.c (revision 6670d3b5)
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   uint 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   begin_op();
22 
23   cprintf("exec %s\n", path);
24   if((ip = namei(path)) == 0){
25     end_op();
26     return -1;
27   }
28   ilock(ip);
29   pgdir = 0;
30 
31   // Check ELF header
32   if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf))
33     goto bad;
34   if(elf.magic != ELF_MAGIC)
35     goto bad;
36 
37   if((pgdir = setupkvm()) == 0)
38     goto bad;
39 
40   // Load program into memory.
41   sz = 0;
42   for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
43     if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph))
44       goto bad;
45     if(ph.type != ELF_PROG_LOAD)
46       continue;
47     if(ph.memsz < ph.filesz)
48       goto bad;
49     if(ph.vaddr + ph.memsz < ph.vaddr)
50       goto bad;
51     if((sz = allocuvm(pgdir, sz, ph.vaddr + ph.memsz)) == 0)
52       goto bad;
53     if(ph.vaddr % PGSIZE != 0)
54       goto bad;
55     if(loaduvm(pgdir, (char*)ph.vaddr, ip, ph.off, ph.filesz) < 0)
56       goto bad;
57   }
58   iunlockput(ip);
59   end_op();
60   ip = 0;
61 
62   // Allocate two pages at the next page boundary.
63   // Make the first inaccessible.  Use the second as the user stack.
64   sz = PGROUNDUP(sz);
65   if((sz = allocuvm(pgdir, sz, sz + 2*PGSIZE)) == 0)
66     goto bad;
67   clearpteu(pgdir, (char*)(sz - 2*PGSIZE));
68   sp = sz;
69 
70   // Push argument strings, prepare rest of stack in ustack.
71   for(argc = 0; argv[argc]; argc++) {
72     if(argc >= MAXARG)
73       goto bad;
74     sp = (sp - (strlen(argv[argc]) + 1)) & ~3;
75     if(copyout(pgdir, sp, argv[argc], strlen(argv[argc]) + 1) < 0)
76       goto bad;
77     ustack[3+argc] = sp;
78   }
79   ustack[3+argc] = 0;
80 
81   ustack[0] = 0xffffffff;  // fake return PC
82   ustack[1] = argc;
83   ustack[2] = sp - (argc+1)*4;  // argv pointer
84 
85   sp -= (3+argc+1) * 4;
86   if(copyout(pgdir, sp, ustack, (3+argc+1)*4) < 0)
87     goto bad;
88 
89   // Save program name for debugging.
90   for(last=s=path; *s; s++)
91     if(*s == '/')
92       last = s+1;
93   safestrcpy(proc->name, last, sizeof(proc->name));
94 
95   // Commit to the user image.
96   oldpgdir = proc->pgdir;
97   proc->pgdir = pgdir;
98   proc->sz = sz;
99   proc->tf->eip = elf.entry;  // main
100   proc->tf->esp = sp;
101   switchuvm(proc);
102   freevm(oldpgdir);
103   cprintf("exec succeeded\n");
104   return 0;
105 
106  bad:
107   if(pgdir)
108     freevm(pgdir);
109   if(ip){
110     iunlockput(ip);
111     end_op();
112   }
113   return -1;
114 }
115