kernel/exec.c

173 lines
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"910static int loadseg(pde_t *, uint64, struct inode *, uint, uint);1112// map ELF permissions to PTE permission bits.13int 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}2223//24// the implementation of the exec() system call25//26int27kexec(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();3738  begin_op();3940  // Open the executable file.41  if((ip = namei(path)) == 0){42    end_op();43    return -1;44  }45  ilock(ip);4647  // Read the ELF header.48  if(readi(ip, 0, (uint64)&elf, 0, sizeof(elf)) != sizeof(elf))49    goto bad;5051  // Is this really an ELF file?52  if(elf.magic != ELF_MAGIC)53    goto bad;5455  if((pagetable = proc_pagetable(p)) == 0)56    goto bad;5758  // 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;8081  p = myproc();82  uint64 oldsz = p->sz;8384  // 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;9596  // Copy argument strings into new stack, remember their97  // 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 aligned103    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;110111  // 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;118119  // a0 and a1 contain arguments to user main(argc, argv)120  // argc is returned via the system call return121  // value, which goes in a0.122  p->trapframe->a1 = sp;123124  // 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 = ulib.c:start()135  p->trapframe->sp = sp; // initial stack pointer136  proc_freepagetable(oldpagetable, oldsz);137138  return argc; // this ends up in a0, the first argument to main(argc, argv)139140 bad:141  if(pagetable)142    proc_freepagetable(pagetable, sz);143  if(ip){144    iunlockput(ip);145    end_op();146  }147  return -1;148}149150// Load an ELF program segment into pagetable at virtual address va.151// va must be page-aligned152// and the pages from va to va+sz must already be mapped.153// Returns 0 on success, -1 on failure.154static int155loadseg(pagetable_t pagetable, uint64 va, struct inode *ip, uint offset, uint sz)156{157  uint i, n;158  uint64 pa;159160  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    else167      n = PGSIZE;168    if(readi(ip, 0, (uint64)pa, offset+i, n) != n)169      return -1;170  }171  172  return 0;173}174