summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/defs.h4
-rw-r--r--kernel/kernelvec.S2
-rw-r--r--kernel/proc.c44
-rw-r--r--kernel/syscall.c46
-rw-r--r--kernel/sysfile.c26
-rw-r--r--kernel/sysproc.c16
-rw-r--r--kernel/trap.c27
-rw-r--r--kernel/vm.c32
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.