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

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