xv6

port of xv6 to x86-64
git clone http://frotz.net/git/xv6.git
Log | Files | Refs | README | LICENSE

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 }