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