From 0498bfd15937d64599b8c63948907a8b60e5d6ae Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Mon, 1 Jul 2019 13:46:11 -0400 Subject: timer interrupt in the kernel -> yield --- kernel/kernelvec.S | 2 +- kernel/trap.c | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'kernel') 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/trap.c b/kernel/trap.c index 586f123..06fc4b3 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -121,12 +121,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 +137,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, -- cgit v1.2.3 From 9b99f007434ea3af0c4834a91f19952d5670e16b Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Mon, 1 Jul 2019 14:15:18 -0400 Subject: oops, don't hold mycpu() result across intr_off() --- kernel/spinlock.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'kernel') diff --git a/kernel/spinlock.c b/kernel/spinlock.c index 557a86c..5a44a46 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c @@ -87,13 +87,12 @@ holding(struct spinlock *lk) void push_off(void) { - struct cpu *c = mycpu(); int old = intr_get(); intr_off(); - if(c->noff == 0) - c->intena = old; - c->noff += 1; + if(mycpu()->noff == 0) + mycpu()->intena = old; + mycpu()->noff += 1; } void -- cgit v1.2.3 From 18e76a6c47b0f62b2458430d4357f3eb68bfd759 Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Mon, 1 Jul 2019 17:01:50 -0400 Subject: sbrk() returns a pointer, so it should be 64 bits --- kernel/syscall.c | 46 +++++++++++++++++++++++----------------------- kernel/sysfile.c | 26 +++++++++++++------------- kernel/sysproc.c | 16 ++++++++-------- 3 files changed, 44 insertions(+), 44 deletions(-) (limited to 'kernel') diff --git a/kernel/syscall.c b/kernel/syscall.c index ca34f2c..ff10f9c 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -116,29 +116,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 7788de3..77e273f 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 e57e045..93ea9bc 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -6,32 +6,32 @@ #include "memlayout.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; @@ -45,7 +45,7 @@ sys_sbrk(void) return addr; } -int +uint64 sys_sleep(void) { int n; @@ -66,7 +66,7 @@ sys_sleep(void) return 0; } -int +uint64 sys_kill(void) { int pid; @@ -78,7 +78,7 @@ sys_kill(void) // return how many clock tick interrupts have occurred // since start. -int +uint64 sys_uptime(void) { uint xticks; -- cgit v1.2.3 From abfe9999f447c15d904b3c11f32d4a22a45470a0 Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Mon, 1 Jul 2019 17:46:06 -0400 Subject: have fork() fail, not panic, if not enough phys mem --- kernel/defs.h | 2 +- kernel/proc.c | 42 +++++++++++++++++++++++++++++------------- kernel/vm.c | 11 +++++++++-- 3 files changed, 39 insertions(+), 16 deletions(-) (limited to 'kernel') diff --git a/kernel/defs.h b/kernel/defs.h index 1b397fe..1c0b39a 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -185,7 +185,7 @@ 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); void unmappages(pagetable_t, uint64, uint64, int); diff --git a/kernel/proc.c b/kernel/proc.c index 4ae34c8..e0ee965 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -109,6 +109,28 @@ 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->pid = 0; + p->parent = 0; + p->name[0] = 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 @@ -145,7 +167,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") @@ -223,7 +246,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; @@ -319,17 +345,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(&ptable.lock); return pid; } diff --git a/kernel/vm.c b/kernel/vm.c index 580669f..7d67464 100644 --- a/kernel/vm.c +++ b/kernel/vm.c @@ -273,7 +273,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 +291,15 @@ 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); } + return 0; + + err: + unmappages(new, 0, i, 1); + return -1; } // Copy from kernel to user. -- cgit v1.2.3 From 40f1041a0a7cd8a1902371cf459989c19f1dc718 Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Tue, 2 Jul 2019 05:20:11 -0400 Subject: don't enable interrupts until done with sstatus, scause, &c --- kernel/trap.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'kernel') diff --git a/kernel/trap.c b/kernel/trap.c index 06fc4b3..835a3b0 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; } -- cgit v1.2.3 From 1540c8b15ac35de9027e60804a786d23703d383d Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Tue, 2 Jul 2019 11:04:35 -0400 Subject: COW tests --- kernel/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/vm.c b/kernel/vm.c index 7d67464..d5ff594 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) { -- cgit v1.2.3 From b27f275014cb473960b9e4d36b03455e404116a7 Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Tue, 2 Jul 2019 11:17:50 -0400 Subject: avoid allocproc() returning a struct proc with non-zero p->sz --- kernel/proc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'kernel') diff --git a/kernel/proc.c b/kernel/proc.c index e0ee965..20d5085 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -124,9 +124,11 @@ freeproc(struct proc *p) 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; } -- cgit v1.2.3 From f59c1bf1d82da4b445c1cff10c228ea55fa035d4 Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Tue, 2 Jul 2019 11:45:06 -0400 Subject: try to continue from walk() failing to allocate a page-table page --- kernel/defs.h | 4 ++-- kernel/vm.c | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) (limited to 'kernel') diff --git a/kernel/defs.h b/kernel/defs.h index 1c0b39a..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); -int 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/vm.c b/kernel/vm.c index d5ff594..bdb53c2 100644 --- a/kernel/vm.c +++ b/kernel/vm.c @@ -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; } @@ -293,7 +299,10 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz) if((mem = kalloc()) == 0) 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; -- cgit v1.2.3