root/kernel/exec.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. flags2perm
  2. kexec
  3. loadseg

   1 #include "types.h"
   2 #include "param.h"
   3 #include "memlayout.h"
   4 #include "riscv.h"
   5 #include "spinlock.h"
   6 #include "proc.h"
   7 #include "defs.h"
   8 #include "elf.h"
   9 
  10 static int loadseg(pde_t *, uint64, struct inode *, uint, uint);
  11 
  12 // map ELF permissions to PTE permission bits.
  13 int flags2perm(int flags)
  14 {
  15     int perm = 0;
  16     if(flags & 0x1)
  17       perm = PTE_X;
  18     if(flags & 0x2)
  19       perm |= PTE_W;
  20     return perm;
  21 }
  22 
  23 //
  24 // the implementation of the exec() system call
  25 //
  26 int
  27 kexec(char *path, char **argv)
  28 {
  29   char *s, *last;
  30   int i, off;
  31   uint64 argc, sz = 0, sp, ustack[MAXARG], stackbase;
  32   struct elfhdr elf;
  33   struct inode *ip;
  34   struct proghdr ph;
  35   pagetable_t pagetable = 0, oldpagetable;
  36   struct proc *p = myproc();
  37 
  38   begin_op();
  39 
  40   // Open the executable file.
  41   if((ip = namei(path)) == 0){
  42     end_op();
  43     return -1;
  44   }
  45   ilock(ip);
  46 
  47   // Read the ELF header.
  48   if(readi(ip, 0, (uint64)&elf, 0, sizeof(elf)) != sizeof(elf))
  49     goto bad;
  50 
  51   // Is this really an ELF file?
  52   if(elf.magic != ELF_MAGIC)
  53     goto bad;
  54 
  55   if((pagetable = proc_pagetable(p)) == 0)
  56     goto bad;
  57 
  58   // Load program into memory.
  59   for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
  60     if(readi(ip, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph))
  61       goto bad;
  62     if(ph.type != ELF_PROG_LOAD)
  63       continue;
  64     if(ph.memsz < ph.filesz)
  65       goto bad;
  66     if(ph.vaddr + ph.memsz < ph.vaddr)
  67       goto bad;
  68     if(ph.vaddr % PGSIZE != 0)
  69       goto bad;
  70     uint64 sz1;
  71     if((sz1 = uvmalloc(pagetable, sz, ph.vaddr + ph.memsz, flags2perm(ph.flags))) == 0)
  72       goto bad;
  73     sz = sz1;
  74     if(loadseg(pagetable, ph.vaddr, ip, ph.off, ph.filesz) < 0)
  75       goto bad;
  76   }
  77   iunlockput(ip);
  78   end_op();
  79   ip = 0;
  80 
  81   p = myproc();
  82   uint64 oldsz = p->sz;
  83 
  84   // Allocate some pages at the next page boundary.
  85   // Make the first inaccessible as a stack guard.
  86   // Use the rest as the user stack.
  87   sz = PGROUNDUP(sz);
  88   uint64 sz1;
  89   if((sz1 = uvmalloc(pagetable, sz, sz + (USERSTACK+1)*PGSIZE, PTE_W)) == 0)
  90     goto bad;
  91   sz = sz1;
  92   uvmclear(pagetable, sz-(USERSTACK+1)*PGSIZE);
  93   sp = sz;
  94   stackbase = sp - USERSTACK*PGSIZE;
  95 
  96   // Copy argument strings into new stack, remember their
  97   // addresses in ustack[].
  98   for(argc = 0; argv[argc]; argc++) {
  99     if(argc >= MAXARG)
 100       goto bad;
 101     sp -= strlen(argv[argc]) + 1;
 102     sp -= sp % 16; // riscv sp must be 16-byte aligned
 103     if(sp < stackbase)
 104       goto bad;
 105     if(copyout(pagetable, sp, argv[argc], strlen(argv[argc]) + 1) < 0)
 106       goto bad;
 107     ustack[argc] = sp;
 108   }
 109   ustack[argc] = 0;
 110 
 111   // push a copy of ustack[], the array of argv[] pointers.
 112   sp -= (argc+1) * sizeof(uint64);
 113   sp -= sp % 16;
 114   if(sp < stackbase)
 115     goto bad;
 116   if(copyout(pagetable, sp, (char *)ustack, (argc+1)*sizeof(uint64)) < 0)
 117     goto bad;
 118 
 119   // a0 and a1 contain arguments to user main(argc, argv)
 120   // argc is returned via the system call return
 121   // value, which goes in a0.
 122   p->trapframe->a1 = sp;
 123 
 124   // Save program name for debugging.
 125   for(last=s=path; *s; s++)
 126     if(*s == '/')
 127       last = s+1;
 128   safestrcpy(p->name, last, sizeof(p->name));
 129     
 130   // Commit to the user image.
 131   oldpagetable = p->pagetable;
 132   p->pagetable = pagetable;
 133   p->sz = sz;
 134   p->trapframe->epc = elf.entry;  // initial program counter = main
 135   p->trapframe->sp = sp; // initial stack pointer
 136   proc_freepagetable(oldpagetable, oldsz);
 137 
 138   return argc; // this ends up in a0, the first argument to main(argc, argv)
 139 
 140  bad:
 141   if(pagetable)
 142     proc_freepagetable(pagetable, sz);
 143   if(ip){
 144     iunlockput(ip);
 145     end_op();
 146   }
 147   return -1;
 148 }
 149 
 150 // Load an ELF program segment into pagetable at virtual address va.
 151 // va must be page-aligned
 152 // and the pages from va to va+sz must already be mapped.
 153 // Returns 0 on success, -1 on failure.
 154 static int
 155 loadseg(pagetable_t pagetable, uint64 va, struct inode *ip, uint offset, uint sz)
 156 {
 157   uint i, n;
 158   uint64 pa;
 159 
 160   for(i = 0; i < sz; i += PGSIZE){
 161     pa = walkaddr(pagetable, va + i);
 162     if(pa == 0)
 163       panic("loadseg: address should exist");
 164     if(sz - i < PGSIZE)
 165       n = sz - i;
 166     else
 167       n = PGSIZE;
 168     if(readi(ip, 0, (uint64)pa, offset+i, n) != n)
 169       return -1;
 170   }
 171   
 172   return 0;
 173 }

/* [<][>][^][v][top][bottom][index][help] */