diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/defs.h | 4 | ||||
| -rw-r--r-- | kernel/kernelvec.S | 2 | ||||
| -rw-r--r-- | kernel/proc.c | 44 | ||||
| -rw-r--r-- | kernel/syscall.c | 46 | ||||
| -rw-r--r-- | kernel/sysfile.c | 26 | ||||
| -rw-r--r-- | kernel/sysproc.c | 16 | ||||
| -rw-r--r-- | kernel/trap.c | 27 | ||||
| -rw-r--r-- | kernel/vm.c | 32 | 
8 files changed, 122 insertions, 75 deletions
| diff --git a/kernel/defs.h b/kernel/defs.h index 1b397fe..bd89af0 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -185,9 +185,9 @@ pagetable_t     uvmcreate(void);  void            uvminit(pagetable_t, uchar *, uint);  uint64          uvmalloc(pagetable_t, uint64, uint64);  uint64          uvmdealloc(pagetable_t, uint64, uint64); -void            uvmcopy(pagetable_t, pagetable_t, uint64); +int             uvmcopy(pagetable_t, pagetable_t, uint64);  void            uvmfree(pagetable_t, uint64); -void            mappages(pagetable_t, uint64, uint64, uint64, int); +int             mappages(pagetable_t, uint64, uint64, uint64, int);  void            unmappages(pagetable_t, uint64, uint64, int);  uint64          walkaddr(pagetable_t, uint64);  int             copyout(pagetable_t, uint64, char *, uint64); diff --git a/kernel/kernelvec.S b/kernel/kernelvec.S index 4f52688..e9b0ced 100644 --- a/kernel/kernelvec.S +++ b/kernel/kernelvec.S @@ -47,7 +47,7 @@ kernelvec:          ld ra, 0(sp)          ld sp, 8(sp)          ld gp, 16(sp) -        ld tp, 24(sp) +        // not this, in case we moved CPUs: ld tp, 24(sp)          ld t0, 32(sp)          ld t1, 40(sp)          ld t2, 48(sp) diff --git a/kernel/proc.c b/kernel/proc.c index c12d97e..8ea09b5 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -111,6 +111,30 @@ found:    return p;  } +// free a proc structure and the data hanging from it, +// including user pages. +// the proc lock must be held. +static void +freeproc(struct proc *p) +{ +  if(p->kstack) +    kfree(p->kstack); +  p->kstack = 0; +  if(p->tf) +    kfree((void*)p->tf); +  p->tf = 0; +  if(p->pagetable) +    proc_freepagetable(p->pagetable, p->sz); +  p->pagetable = 0; +  p->sz = 0; +  p->pid = 0; +  p->parent = 0; +  p->name[0] = 0; +  p->chan = 0; +  p->killed = 0; +  p->state = UNUSED; +} +  // Create a page table for a given process,  // with no users pages, but with trampoline pages.  // Called both when creating a process, and @@ -147,7 +171,8 @@ proc_freepagetable(pagetable_t pagetable, uint64 sz)  {    unmappages(pagetable, TRAMPOLINE, PGSIZE, 0);    unmappages(pagetable, TRAMPOLINE-PGSIZE, PGSIZE, 0); -  uvmfree(pagetable, sz); +  if(sz > 0) +    uvmfree(pagetable, sz);  }  // a user program that calls exec("/init") @@ -226,7 +251,10 @@ fork(void)    }    // Copy user memory from parent to child. -  uvmcopy(p->pagetable, np->pagetable, p->sz); +  if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){ +    freeproc(np); +    return -1; +  }    np->sz = p->sz;    np->parent = p; @@ -342,17 +370,7 @@ wait(void)        if(np->state == ZOMBIE){          // Found one.          pid = np->pid; -        kfree(np->kstack); -        np->kstack = 0; -        kfree((void*)np->tf); -        np->tf = 0; -        proc_freepagetable(np->pagetable, np->sz); -        np->pagetable = 0; -        np->pid = 0; -        np->parent = 0; -        np->name[0] = 0; -        np->killed = 0; -        np->state = UNUSED; +        freeproc(np);          release(&np->lock);          release(&p->lock);          return pid; diff --git a/kernel/syscall.c b/kernel/syscall.c index 8e9d51c..a054da2 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -117,29 +117,29 @@ argstr(int n, char *buf, int max)    return fetchstr(addr, buf, max);  } -extern int sys_chdir(void); -extern int sys_close(void); -extern int sys_dup(void); -extern int sys_exec(void); -extern int sys_exit(void); -extern int sys_fork(void); -extern int sys_fstat(void); -extern int sys_getpid(void); -extern int sys_kill(void); -extern int sys_link(void); -extern int sys_mkdir(void); -extern int sys_mknod(void); -extern int sys_open(void); -extern int sys_pipe(void); -extern int sys_read(void); -extern int sys_sbrk(void); -extern int sys_sleep(void); -extern int sys_unlink(void); -extern int sys_wait(void); -extern int sys_write(void); -extern int sys_uptime(void); - -static int (*syscalls[])(void) = { +extern uint64 sys_chdir(void); +extern uint64 sys_close(void); +extern uint64 sys_dup(void); +extern uint64 sys_exec(void); +extern uint64 sys_exit(void); +extern uint64 sys_fork(void); +extern uint64 sys_fstat(void); +extern uint64 sys_getpid(void); +extern uint64 sys_kill(void); +extern uint64 sys_link(void); +extern uint64 sys_mkdir(void); +extern uint64 sys_mknod(void); +extern uint64 sys_open(void); +extern uint64 sys_pipe(void); +extern uint64 sys_read(void); +extern uint64 sys_sbrk(void); +extern uint64 sys_sleep(void); +extern uint64 sys_unlink(void); +extern uint64 sys_wait(void); +extern uint64 sys_write(void); +extern uint64 sys_uptime(void); + +static uint64 (*syscalls[])(void) = {  [SYS_fork]    sys_fork,  [SYS_exit]    sys_exit,  [SYS_wait]    sys_wait, diff --git a/kernel/sysfile.c b/kernel/sysfile.c index 33f37f2..533e097 100644 --- a/kernel/sysfile.c +++ b/kernel/sysfile.c @@ -52,7 +52,7 @@ fdalloc(struct file *f)    return -1;  } -int +uint64  sys_dup(void)  {    struct file *f; @@ -66,7 +66,7 @@ sys_dup(void)    return fd;  } -int +uint64  sys_read(void)  {    struct file *f; @@ -78,7 +78,7 @@ sys_read(void)    return fileread(f, p, n);  } -int +uint64  sys_write(void)  {    struct file *f; @@ -91,7 +91,7 @@ sys_write(void)    return filewrite(f, p, n);  } -int +uint64  sys_close(void)  {    int fd; @@ -104,7 +104,7 @@ sys_close(void)    return 0;  } -int +uint64  sys_fstat(void)  {    struct file *f; @@ -116,7 +116,7 @@ sys_fstat(void)  }  // Create the path new as a link to the same inode as old. -int +uint64  sys_link(void)  {    char name[DIRSIZ], new[MAXPATH], old[MAXPATH]; @@ -182,7 +182,7 @@ isdirempty(struct inode *dp)  }  //PAGEBREAK! -int +uint64  sys_unlink(void)  {    struct inode *ip, *dp; @@ -284,7 +284,7 @@ create(char *path, short type, short major, short minor)    return ip;  } -int +uint64  sys_open(void)  {    char path[MAXPATH]; @@ -347,7 +347,7 @@ sys_open(void)    return fd;  } -int +uint64  sys_mkdir(void)  {    char path[MAXPATH]; @@ -363,7 +363,7 @@ sys_mkdir(void)    return 0;  } -int +uint64  sys_mknod(void)  {    struct inode *ip; @@ -383,7 +383,7 @@ sys_mknod(void)    return 0;  } -int +uint64  sys_chdir(void)  {    char path[MAXPATH]; @@ -408,7 +408,7 @@ sys_chdir(void)    return 0;  } -int +uint64  sys_exec(void)  {    char path[MAXPATH], *argv[MAXARG]; @@ -446,7 +446,7 @@ sys_exec(void)    return ret;  } -int +uint64  sys_pipe(void)  {    uint64 fdarray; // user pointer to array of two integers diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 65dde26..face81a 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -7,32 +7,32 @@  #include "spinlock.h"  #include "proc.h" -int +uint64  sys_exit(void)  {    exit();    return 0;  // not reached  } -int +uint64  sys_getpid(void)  {    return myproc()->pid;  } -int +uint64  sys_fork(void)  {    return fork();  } -int +uint64  sys_wait(void)  {    return wait();  } -int +uint64  sys_sbrk(void)  {    int addr; @@ -46,7 +46,7 @@ sys_sbrk(void)    return addr;  } -int +uint64  sys_sleep(void)  {    int n; @@ -67,7 +67,7 @@ sys_sleep(void)    return 0;  } -int +uint64  sys_kill(void)  {    int pid; @@ -79,7 +79,7 @@ sys_kill(void)  // return how many clock tick interrupts have occurred  // since start. -int +uint64  sys_uptime(void)  {    uint xticks; diff --git a/kernel/trap.c b/kernel/trap.c index 6c0d04b..018b7db 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -37,7 +37,7 @@ void  usertrap(void)  {    int which_dev = 0; -   +    if((r_sstatus() & SSTATUS_SPP) != 0)      panic("usertrap: not from user mode"); @@ -49,8 +49,6 @@ usertrap(void)    // save user program counter.    p->tf->epc = r_sepc(); - -  intr_on();    if(r_scause() == 8){      // system call @@ -59,11 +57,15 @@ usertrap(void)      // but we want to return to the next instruction.      p->tf->epc += 4; +    // an interrupt will change sstatus &c registers, +    // so don't enable until done with those registers. +    intr_on(); +      syscall();    } else if((which_dev = devintr()) != 0){      // ok    } else { -    printf("usertrap(): unexpected scause 0x%p pid=%d\n", r_scause(), p->pid); +    printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);      printf("            sepc=%p stval=%p\n", r_sepc(), r_stval());      p->killed = 1;    } @@ -121,12 +123,14 @@ usertrapret(void)    ((void (*)(uint64,uint64))TRAMPOLINE)(TRAMPOLINE - PGSIZE, satp);  } -// interrupts and exceptions from kernel code go here, +// interrupts and exceptions from kernel code go here via kernelvec,  // on whatever the current kernel stack is.  // must be 4-byte aligned to fit in stvec.  void   kerneltrap()  { +  int which_dev = 0; +  uint64 sepc = r_sepc();    uint64 sstatus = r_sstatus();    uint64 scause = r_scause(); @@ -135,11 +139,20 @@ kerneltrap()    if(intr_get() != 0)      panic("kerneltrap: interrupts enabled"); -  if(devintr() == 0){ -    printf("scause 0x%p\n", scause); +  if((which_dev = devintr()) == 0){ +    printf("scause %p\n", scause);      printf("sepc=%p stval=%p\n", r_sepc(), r_stval());      panic("kerneltrap");    } + +  // give up the CPU if this is a timer interrupt. +  if(which_dev == 2 && myproc() != 0 && myproc()->state == RUNNING) +    yield(); + +  // the yield() may have caused some traps to occur, +  // so restore trap registers for use by kernelvec.S's sepc instruction. +  w_sepc(sepc); +  w_sstatus(sstatus);  }  // check if it's an external interrupt or software interrupt, diff --git a/kernel/vm.c b/kernel/vm.c index 580669f..bdb53c2 100644 --- a/kernel/vm.c +++ b/kernel/vm.c @@ -97,8 +97,8 @@ walk(pagetable_t pagetable, uint64 va, int alloc)  }  // Look up a virtual address, return the physical address, -// Can only be used to look up user pages.  // or 0 if not mapped. +// Can only be used to look up user pages.  uint64  walkaddr(pagetable_t pagetable, uint64 va)  { @@ -119,8 +119,9 @@ walkaddr(pagetable_t pagetable, uint64 va)  // Create PTEs for virtual addresses starting at va that refer to  // physical addresses starting at pa. va and size might not -// be page-aligned. -void +// be page-aligned. Returns 0 on success, -1 if walk() couldn't +// allocate a needed page-table page. +int  mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)  {    uint64 a, last; @@ -130,7 +131,7 @@ mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)    last = PGROUNDDOWN(va + size - 1);    for(;;){      if((pte = walk(pagetable, a, 1)) == 0) -      panic("mappages: walk"); +      return -1;      if(*pte & PTE_V)        panic("remap");      *pte = PA2PTE(pa) | perm | PTE_V; @@ -139,6 +140,7 @@ mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)      a += PGSIZE;      pa += PGSIZE;    } +  return 0;  }  // Remove mappings from a page table. The mappings in @@ -222,7 +224,11 @@ uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz)        return 0;      }      memset(mem, 0, PGSIZE); -    mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U); +    if(mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0){ +      kfree(mem); +      uvmdealloc(pagetable, a, oldsz); +      return 0; +    }    }    return newsz;  } @@ -273,7 +279,9 @@ uvmfree(pagetable_t pagetable, uint64 sz)  // its memory into a child's page table.  // Copies both the page table and the  // physical memory. -void +// returns 0 on success, -1 on failure. +// frees any allocated pages on failure. +int  uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)  {    pte_t *pte; @@ -289,10 +297,18 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)      pa = PTE2PA(*pte);      flags = PTE_FLAGS(*pte);      if((mem = kalloc()) == 0) -      panic("uvmcopy: kalloc failed"); +      goto err;      memmove(mem, (char*)pa, PGSIZE); -    mappages(new, i, PGSIZE, (uint64)mem, flags); +    if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){ +      kfree(mem); +      goto err; +    }    } +  return 0; + + err: +  unmappages(new, 0, i, 1); +  return -1;  }  // Copy from kernel to user. | 
