root/kernel/exec.c

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

DEFINITIONS

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

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