From 18998096701a1d4695b2097006d7afc2a539bd89 Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Fri, 8 Sep 2023 09:24:27 -0400 Subject: 3rd lab --- kernel/memlayout.h | 17 ++++++++++++++++- kernel/syscall.c | 15 +++++++++++++++ kernel/syscall.h | 11 +++++++++++ kernel/sysproc.c | 15 ++++++++++++--- 4 files changed, 54 insertions(+), 4 deletions(-) (limited to 'kernel') diff --git a/kernel/memlayout.h b/kernel/memlayout.h index cac3cb1..74d2fd4 100644 --- a/kernel/memlayout.h +++ b/kernel/memlayout.h @@ -25,6 +25,10 @@ #define VIRTIO0 0x10001000 #define VIRTIO0_IRQ 1 +#ifdef LAB_NET +#define E1000_IRQ 33 +#endif + // core local interruptor (CLINT), which contains the timer. #define CLINT 0x2000000L #define CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 8*(hartid)) @@ -34,8 +38,11 @@ #define PLIC 0x0c000000L #define PLIC_PRIORITY (PLIC + 0x0) #define PLIC_PENDING (PLIC + 0x1000) +#define PLIC_MENABLE(hart) (PLIC + 0x2000 + (hart)*0x100) #define PLIC_SENABLE(hart) (PLIC + 0x2080 + (hart)*0x100) +#define PLIC_MPRIORITY(hart) (PLIC + 0x200000 + (hart)*0x2000) #define PLIC_SPRIORITY(hart) (PLIC + 0x201000 + (hart)*0x2000) +#define PLIC_MCLAIM(hart) (PLIC + 0x200004 + (hart)*0x2000) #define PLIC_SCLAIM(hart) (PLIC + 0x201004 + (hart)*0x2000) // the kernel expects there to be RAM @@ -50,7 +57,7 @@ // map kernel stacks beneath the trampoline, // each surrounded by invalid guard pages. -#define KSTACK(p) (TRAMPOLINE - ((p)+1)* 2*PGSIZE) +#define KSTACK(p) (TRAMPOLINE - (p)*2*PGSIZE - 3*PGSIZE) // User memory layout. // Address zero first: @@ -59,6 +66,14 @@ // fixed-size stack // expandable heap // ... +// USYSCALL (shared with kernel) // TRAPFRAME (p->trapframe, used by the trampoline) // TRAMPOLINE (the same page as in the kernel) #define TRAPFRAME (TRAMPOLINE - PGSIZE) +#ifdef LAB_PGTBL +#define USYSCALL (TRAPFRAME - PGSIZE) + +struct usyscall { + int pid; // Process ID +}; +#endif diff --git a/kernel/syscall.c b/kernel/syscall.c index ed65409..beea0ef 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -102,6 +102,13 @@ extern uint64 sys_link(void); extern uint64 sys_mkdir(void); extern uint64 sys_close(void); +#ifdef LAB_NET +extern uint64 sys_connect(void); +#endif +#ifdef LAB_PGTBL +extern uint64 sys_pgaccess(void); +#endif + // An array mapping syscall numbers from syscall.h // to the function that handles the system call. static uint64 (*syscalls[])(void) = { @@ -126,8 +133,16 @@ static uint64 (*syscalls[])(void) = { [SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close, +#ifdef LAB_NET +[SYS_connect] sys_connect, +#endif +#ifdef LAB_PGTBL +[SYS_pgaccess] sys_pgaccess, +#endif }; + + void syscall(void) { diff --git a/kernel/syscall.h b/kernel/syscall.h index bc5f356..8da572e 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -20,3 +20,14 @@ #define SYS_link 19 #define SYS_mkdir 20 #define SYS_close 21 + +// System calls for labs +#define SYS_trace 22 +#define SYS_sysinfo 23 +#define SYS_sigalarm 24 +#define SYS_sigreturn 25 +#define SYS_symlink 26 +#define SYS_mmap 27 +#define SYS_munmap 28 +#define SYS_connect 29 +#define SYS_pgaccess 30 diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 3b4d5bd..88644b2 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -1,7 +1,7 @@ #include "types.h" #include "riscv.h" -#include "defs.h" #include "param.h" +#include "defs.h" #include "memlayout.h" #include "spinlock.h" #include "proc.h" @@ -54,9 +54,8 @@ sys_sleep(void) int n; uint ticks0; + argint(0, &n); - if(n < 0) - n = 0; acquire(&tickslock); ticks0 = ticks; while(ticks - ticks0 < n){ @@ -70,6 +69,16 @@ sys_sleep(void) return 0; } + +#ifdef LAB_PGTBL +int +sys_pgaccess(void) +{ + // lab pgtbl: your code here. + return 0; +} +#endif + uint64 sys_kill(void) { -- cgit v1.2.3 From 283d5ab4c964ab525e45fcade06d6fd7e977c43e Mon Sep 17 00:00:00 2001 From: Mole Shang <135e2@135e2.dev> Date: Thu, 18 Jan 2024 17:35:27 +0800 Subject: lab syscall: finish Conflicts: kernel/syscall.c kernel/syscall.h user/user.h user/usys.pl --- kernel/defs.h | 6 ++++++ kernel/kalloc.c | 14 ++++++++++++++ kernel/proc.c | 20 ++++++++++++++++++++ kernel/proc.h | 1 + kernel/syscall.c | 38 ++++++++++++++++++++++++++++++++++++++ kernel/syscall.h | 2 ++ kernel/sysinfo.c | 24 ++++++++++++++++++++++++ kernel/sysinfo.h | 4 ++++ kernel/sysproc.c | 18 ++++++++++++++++++ 9 files changed, 127 insertions(+) create mode 100644 kernel/sysinfo.c create mode 100644 kernel/sysinfo.h (limited to 'kernel') diff --git a/kernel/defs.h b/kernel/defs.h index a3c962b..c8eeef3 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -8,6 +8,7 @@ struct spinlock; struct sleeplock; struct stat; struct superblock; +struct sysinfo; // bio.c void binit(void); @@ -63,6 +64,7 @@ void ramdiskrw(struct buf*); void* kalloc(void); void kfree(void *); void kinit(void); +int get_freemem(void); // log.c void initlog(int, struct superblock*); @@ -106,6 +108,7 @@ void yield(void); int either_copyout(int user_dst, uint64 dst, void *src, uint64 len); int either_copyin(void *dst, int user_src, uint64 src, uint64 len); void procdump(void); +int get_nproc(void); // swtch.S void swtch(struct context*, struct context*); @@ -141,6 +144,9 @@ int fetchstr(uint64, char*, int); int fetchaddr(uint64, uint64*); void syscall(); +// sysinfo.c +int sys_info(uint64); + // trap.c extern uint ticks; void trapinit(void); diff --git a/kernel/kalloc.c b/kernel/kalloc.c index 0699e7e..c2fdb86 100644 --- a/kernel/kalloc.c +++ b/kernel/kalloc.c @@ -80,3 +80,17 @@ kalloc(void) memset((char*)r, 5, PGSIZE); // fill with junk return (void*)r; } + +int +get_freemem(void) +{ + int n; + struct run *r; + + acquire(&kmem.lock); + for (n = 0, r = kmem.freelist; r; r = r->next) + n++; + release(&kmem.lock); + + return n * PGSIZE; +} diff --git a/kernel/proc.c b/kernel/proc.c index 58a8a0b..5aa616f 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -299,6 +299,9 @@ fork(void) // copy saved user registers. *(np->trapframe) = *(p->trapframe); + // inherit trace_mask + np->trace_mask = p->trace_mask; + // Cause fork to return 0 in the child. np->trapframe->a0 = 0; @@ -686,3 +689,20 @@ procdump(void) printf("\n"); } } + +int +get_nproc(void) +{ + int n = 0; + struct proc *p; + + for(int i = 0; i < NPROC; i++) { + p = &proc[i]; + acquire(&p->lock); + if(p->state != UNUSED) + n++; + release(&p->lock); + } + + return n; +} diff --git a/kernel/proc.h b/kernel/proc.h index d021857..4a2ca6c 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -91,6 +91,7 @@ struct proc { int killed; // If non-zero, have been killed int xstate; // Exit status to be returned to parent's wait int pid; // Process ID + int trace_mask; // SYS_trace mask (1 << SYS_xxx) // wait_lock must be held when using this: struct proc *parent; // Parent process diff --git a/kernel/syscall.c b/kernel/syscall.c index beea0ef..4907f0f 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -101,6 +101,8 @@ extern uint64 sys_unlink(void); extern uint64 sys_link(void); extern uint64 sys_mkdir(void); extern uint64 sys_close(void); +extern uint64 sys_trace(void); +extern uint64 sys_sysinfo(void); #ifdef LAB_NET extern uint64 sys_connect(void); @@ -139,6 +141,35 @@ static uint64 (*syscalls[])(void) = { #ifdef LAB_PGTBL [SYS_pgaccess] sys_pgaccess, #endif +[SYS_trace] sys_trace, +[SYS_sysinfo] sys_sysinfo, +}; + +// syscall name maps for SYS_trace: +static char *syscall_names[] = { +[SYS_fork] "fork", +[SYS_exit] "exit", +[SYS_wait] "wait", +[SYS_pipe] "pipe", +[SYS_read] "read", +[SYS_kill] "kill", +[SYS_exec] "exec", +[SYS_fstat] "fstat", +[SYS_chdir] "chdir", +[SYS_dup] "dup", +[SYS_getpid] "getpid", +[SYS_sbrk] "sbrk", +[SYS_sleep] "sleep", +[SYS_uptime] "uptime", +[SYS_open] "open", +[SYS_write] "write", +[SYS_mknod] "mknod", +[SYS_unlink] "unlink", +[SYS_link] "link", +[SYS_mkdir] "mkdir", +[SYS_close] "close", +[SYS_trace] "trace", +[SYS_sysinfo] "sysinfo", }; @@ -154,6 +185,13 @@ syscall(void) // Use num to lookup the system call function for num, call it, // and store its return value in p->trapframe->a0 p->trapframe->a0 = syscalls[num](); + + // SYS_trace: match all the syscalls which number < mask asked + // p->trace_mask == 1 << SYS_xxx + if(p->trace_mask >> num) { + printf("%d: syscall %s -> %d\n", p->pid, syscall_names[num], p->trapframe->a0); + } + } else { printf("%d %s: unknown sys call %d\n", p->pid, p->name, num); diff --git a/kernel/syscall.h b/kernel/syscall.h index 8da572e..d930252 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -31,3 +31,5 @@ #define SYS_munmap 28 #define SYS_connect 29 #define SYS_pgaccess 30 +#define SYS_trace 22 +#define SYS_sysinfo 23 diff --git a/kernel/sysinfo.c b/kernel/sysinfo.c new file mode 100644 index 0000000..c66324d --- /dev/null +++ b/kernel/sysinfo.c @@ -0,0 +1,24 @@ +#include "types.h" +#include "riscv.h" +#include "param.h" +#include "spinlock.h" +#include "defs.h" +#include "sysinfo.h" +#include "proc.h" + +// Get current system info +// addr is a user virtual address, pointing to a struct sysinfo. +int +sys_info(uint64 addr) { + struct proc *p = myproc(); + struct sysinfo info; + + // Fill nums into the sysinfo struct + info.freemem = get_freemem(); + info.nproc = get_nproc(); + + if(copyout(p->pagetable, addr, (char *)&info, sizeof(info)) < 0) + return -1; + return 0; +} + diff --git a/kernel/sysinfo.h b/kernel/sysinfo.h new file mode 100644 index 0000000..fb878e6 --- /dev/null +++ b/kernel/sysinfo.h @@ -0,0 +1,4 @@ +struct sysinfo { + uint64 freemem; // amount of free memory (bytes) + uint64 nproc; // number of process +}; diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 88644b2..4cf0697 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -100,3 +100,21 @@ sys_uptime(void) release(&tickslock); return xticks; } + +uint64 +sys_trace(void) +{ + argint(0, &myproc()->trace_mask); + + return -(myproc()->trace_mask <= 1); +} + +uint64 +sys_sysinfo(void) +{ + uint64 si; // user pointer to struct sysinfo + + argaddr(0, &si); + return sys_info(si); +} + -- cgit v1.2.3 From c9284cd93525436cc823258ab309c1b27eeec714 Mon Sep 17 00:00:00 2001 From: Mole Shang <135e2@135e2.dev> Date: Sat, 10 Feb 2024 13:08:26 +0800 Subject: lab pgtbl: finish --- kernel/defs.h | 2 ++ kernel/exec.c | 4 ++++ kernel/proc.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- kernel/proc.h | 1 + kernel/riscv.h | 1 + kernel/syscall.c | 7 +++++++ kernel/syscall.h | 2 -- kernel/sysproc.c | 10 ++++++++-- kernel/vm.c | 27 +++++++++++++++++++++++++++ 9 files changed, 94 insertions(+), 5 deletions(-) (limited to 'kernel') diff --git a/kernel/defs.h b/kernel/defs.h index c8eeef3..bd85d1f 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -109,6 +109,7 @@ int either_copyout(int user_dst, uint64 dst, void *src, uint64 len); int either_copyin(void *dst, int user_src, uint64 src, uint64 len); void procdump(void); int get_nproc(void); +int pgaccess(uint64 base, int len, uint64 mask); // swtch.S void swtch(struct context*, struct context*); @@ -179,6 +180,7 @@ uint64 walkaddr(pagetable_t, uint64); int copyout(pagetable_t, uint64, char *, uint64); int copyin(pagetable_t, char *, uint64, uint64); int copyinstr(pagetable_t, char *, uint64, uint64); +void vmprint(pagetable_t); // plic.c void plicinit(void); diff --git a/kernel/exec.c b/kernel/exec.c index e18bbb6..35b35f5 100644 --- a/kernel/exec.c +++ b/kernel/exec.c @@ -128,6 +128,10 @@ exec(char *path, char **argv) p->trapframe->sp = sp; // initial stack pointer proc_freepagetable(oldpagetable, oldsz); + if(p->pid == 1){ + vmprint(p->pagetable); + } + return argc; // this ends up in a0, the first argument to main(argc, argv) bad: diff --git a/kernel/proc.c b/kernel/proc.c index 5aa616f..3d215a5 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -132,6 +132,14 @@ found: return 0; } + // Allocate a usyscall page and fill pid. + if((p->usyscall = (struct usyscall *)kalloc()) == 0){ + freeproc(p); + release(&p->lock); + return 0; + } + p->usyscall->pid = p->pid; + // An empty user page table. p->pagetable = proc_pagetable(p); if(p->pagetable == 0){ @@ -158,6 +166,9 @@ freeproc(struct proc *p) if(p->trapframe) kfree((void*)p->trapframe); p->trapframe = 0; + if(p->usyscall) + kfree((void*)p->usyscall); + p->usyscall = 0; if(p->pagetable) proc_freepagetable(p->pagetable, p->sz); p->pagetable = 0; @@ -172,7 +183,7 @@ freeproc(struct proc *p) } // Create a user page table for a given process, with no user memory, -// but with trampoline and trapframe pages. +// but with trampoline, trapframe and usyscall pages. pagetable_t proc_pagetable(struct proc *p) { @@ -202,6 +213,14 @@ proc_pagetable(struct proc *p) return 0; } + // map the usyscall page below the trapframe page, for + // ugetpid(). + if(mappages(pagetable, USYSCALL, PGSIZE, + (uint64)(p->usyscall), PTE_R | PTE_U) < 0){ + uvmunmap(pagetable, USYSCALL, 1, 0); + uvmfree(pagetable, 0); + return 0; + } return pagetable; } @@ -212,6 +231,7 @@ proc_freepagetable(pagetable_t pagetable, uint64 sz) { uvmunmap(pagetable, TRAMPOLINE, 1, 0); uvmunmap(pagetable, TRAPFRAME, 1, 0); + uvmunmap(pagetable, USYSCALL, 1, 0); uvmfree(pagetable, sz); } @@ -706,3 +726,26 @@ get_nproc(void) return n; } + +// lab pagetable: report which pages have been accessed (r/w) +// according to PTE_A and store it in a bit mask (3rd param) +int +pgaccess(uint64 base, int len, uint64 mask_addr) +{ + struct proc *p = myproc(); + pagetable_t pgtbl = p->pagetable; + pte_t *pte; + int mask = 0; + + // iterater thru pages + for(int i = 0; i < len; i++) { + pte = walk(pgtbl, base + i * PGSIZE, 0); + if(*pte & PTE_A) { + *pte &= (~PTE_A); // clear PTE_A to avoid setting it forever + mask |= (1L << i); + } + } + + // now copyout the mask to user memory + return copyout(pgtbl, mask_addr, (char *)&mask, sizeof(mask)); +} diff --git a/kernel/proc.h b/kernel/proc.h index 4a2ca6c..c816ae2 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -101,6 +101,7 @@ struct proc { uint64 sz; // Size of process memory (bytes) pagetable_t pagetable; // User page table struct trapframe *trapframe; // data page for trampoline.S + struct usyscall *usyscall; // data page for usyscall struct context context; // swtch() here to run process struct file *ofile[NOFILE]; // Open files struct inode *cwd; // Current directory diff --git a/kernel/riscv.h b/kernel/riscv.h index 20a01db..33fa9ee 100644 --- a/kernel/riscv.h +++ b/kernel/riscv.h @@ -343,6 +343,7 @@ typedef uint64 *pagetable_t; // 512 PTEs #define PTE_W (1L << 2) #define PTE_X (1L << 3) #define PTE_U (1L << 4) // user can access +#define PTE_A (1L << 6) // riscv access bit // shift a physical address to the right place for a PTE. #define PA2PTE(pa) ((((uint64)pa) >> 12) << 10) diff --git a/kernel/syscall.c b/kernel/syscall.c index 4907f0f..394b980 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -168,6 +168,12 @@ static char *syscall_names[] = { [SYS_link] "link", [SYS_mkdir] "mkdir", [SYS_close] "close", +#ifdef LAB_NET +[SYS_connect] "connect", +#endif +#ifdef LAB_PGTBL +[SYS_pgaccess] "pgaccess", +#endif [SYS_trace] "trace", [SYS_sysinfo] "sysinfo", }; @@ -198,3 +204,4 @@ syscall(void) p->trapframe->a0 = -1; } } + diff --git a/kernel/syscall.h b/kernel/syscall.h index d930252..8da572e 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -31,5 +31,3 @@ #define SYS_munmap 28 #define SYS_connect 29 #define SYS_pgaccess 30 -#define SYS_trace 22 -#define SYS_sysinfo 23 diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 4cf0697..bd9d0f0 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -74,8 +74,14 @@ sys_sleep(void) int sys_pgaccess(void) { - // lab pgtbl: your code here. - return 0; + uint64 base, mask; + int len; + + + argaddr(0, &base); + argint(1, &len); + argaddr(2, &mask); + return pgaccess(base, len, mask); } #endif diff --git a/kernel/vm.c b/kernel/vm.c index 5c31e87..9c17fe7 100644 --- a/kernel/vm.c +++ b/kernel/vm.c @@ -449,3 +449,30 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max) return -1; } } + +static void +walkprint(pagetable_t pgtbl, int level) +{ + for(int i = 0; i < 512; i++){ + pte_t pte = pgtbl[i]; + if(pte & PTE_V){ + for(int j = 0; j < level; j++){ + printf(" .."); + } + printf("%d: pte %p pa %p\n", i, pte, PTE2PA(pte)); + if((pte & (PTE_R|PTE_W|PTE_X)) == 0){ + // this PTE points to a lower-level page table. + walkprint((pagetable_t)PTE2PA(pte), level+1); + } + } + } +} + +// Print the contents of a page table +void +vmprint(pagetable_t pgtbl) +{ + printf("page table %p\n", pgtbl); + + walkprint(pgtbl, 1); +} -- cgit v1.2.3 From 48a5e34fcd07852b4a68825ce8e37feb6f6d04d7 Mon Sep 17 00:00:00 2001 From: Mole Shang <135e2@135e2.dev> Date: Sun, 11 Feb 2024 14:41:35 +0800 Subject: lab traps: finish --- kernel/defs.h | 1 + kernel/printf.c | 17 +++++++++++++++++ kernel/proc.c | 19 +++++++++++++++++++ kernel/proc.h | 5 +++++ kernel/riscv.h | 9 +++++++++ kernel/syscall.c | 6 ++++++ kernel/sysproc.c | 26 ++++++++++++++++++++++++++ kernel/trap.c | 23 +++++++++++++++++++++-- 8 files changed, 104 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/defs.h b/kernel/defs.h index bd85d1f..04a0276 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -82,6 +82,7 @@ int pipewrite(struct pipe*, uint64, int); void printf(char*, ...); void panic(char*) __attribute__((noreturn)); void printfinit(void); +void backtrace(void); // proc.c int cpuid(void); diff --git a/kernel/printf.c b/kernel/printf.c index 1a50203..509c1c5 100644 --- a/kernel/printf.c +++ b/kernel/printf.c @@ -122,6 +122,8 @@ panic(char *s) printf("panic: "); printf(s); printf("\n"); + backtrace(); + panicked = 1; // freeze uart output from other CPUs for(;;) ; @@ -133,3 +135,18 @@ printfinit(void) initlock(&pr.lock, "pr"); pr.locking = 1; } + +void +backtrace(void) +{ + uint64 fp = r_fp(); + printf("backtrace:\n"); + uint64 stackpg = PGROUNDDOWN(fp); + // Whereever fp points to should always live in the stack page + while(PGROUNDDOWN(fp) == stackpg){ + // print the return addr (stored in fp-8) + printf("%p\n", *(uint64 *)(fp-8)); + // load previous (upper stack) fp + fp = *(uint64 *)(fp-16); + } +} diff --git a/kernel/proc.c b/kernel/proc.c index 3d215a5..9a9bae9 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -39,6 +39,7 @@ proc_mapstacks(pagetable_t kpgtbl) if(pa == 0) panic("kalloc"); uint64 va = KSTACK((int) (p - proc)); + p->alarm_tickspassed = 0; kvmmap(kpgtbl, va, (uint64)pa, PGSIZE, PTE_R | PTE_W); } } @@ -140,6 +141,17 @@ found: } p->usyscall->pid = p->pid; + // reset sigalarm props + p->alarm_interval = 0; + p->alarm_handler = 0; + p->alarm_tickspassed = 0; + p->alarm_caninvoke = 1; + if((p->atpfm = (struct trapframe *)kalloc()) == 0){ + freeproc(p); + release(&p->lock); + return 0; + } + // An empty user page table. p->pagetable = proc_pagetable(p); if(p->pagetable == 0){ @@ -171,6 +183,13 @@ freeproc(struct proc *p) p->usyscall = 0; if(p->pagetable) proc_freepagetable(p->pagetable, p->sz); + if(p->atpfm) + kfree((void*)p->atpfm); + p->atpfm = 0; + p->alarm_interval = 0; + p->alarm_handler = 0; + p->alarm_tickspassed = 0; + p->alarm_caninvoke = 1; p->pagetable = 0; p->sz = 0; p->pid = 0; diff --git a/kernel/proc.h b/kernel/proc.h index c816ae2..a195b02 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -106,4 +106,9 @@ struct proc { struct file *ofile[NOFILE]; // Open files struct inode *cwd; // Current directory char name[16]; // Process name (debugging) + int alarm_interval; // sigalarm syscall interval + uint64 alarm_handler; // sigalarm syscall handler + int alarm_tickspassed; // record how many ticks passed since last sigalarm handler call + int alarm_caninvoke; // prevent re-entrant calls to handler + struct trapframe *atpfm; // trapframe to resume after handling, must hold p->lock }; diff --git a/kernel/riscv.h b/kernel/riscv.h index 33fa9ee..5ede50a 100644 --- a/kernel/riscv.h +++ b/kernel/riscv.h @@ -327,6 +327,15 @@ sfence_vma() asm volatile("sfence.vma zero, zero"); } +// read the frame pointer of currently executing func +static inline uint64 +r_fp() +{ + uint64 x; + asm volatile("mv %0, s0" : "=r" (x) ); + return x; +} + typedef uint64 pte_t; typedef uint64 *pagetable_t; // 512 PTEs diff --git a/kernel/syscall.c b/kernel/syscall.c index 394b980..8392eb4 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -110,6 +110,8 @@ extern uint64 sys_connect(void); #ifdef LAB_PGTBL extern uint64 sys_pgaccess(void); #endif +extern uint64 sys_sigalarm(void); +extern uint64 sys_sigreturn(void); // An array mapping syscall numbers from syscall.h // to the function that handles the system call. @@ -143,6 +145,8 @@ static uint64 (*syscalls[])(void) = { #endif [SYS_trace] sys_trace, [SYS_sysinfo] sys_sysinfo, +[SYS_sigalarm] sys_sigalarm, +[SYS_sigreturn] sys_sigreturn, }; // syscall name maps for SYS_trace: @@ -176,6 +180,8 @@ static char *syscall_names[] = { #endif [SYS_trace] "trace", [SYS_sysinfo] "sysinfo", +[SYS_sigalarm] "sigalarm", +[SYS_sigreturn] "sigreturn", }; diff --git a/kernel/sysproc.c b/kernel/sysproc.c index bd9d0f0..fac1d83 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -65,6 +65,9 @@ sys_sleep(void) } sleep(&ticks, &tickslock); } + + backtrace(); + release(&tickslock); return 0; } @@ -124,3 +127,26 @@ sys_sysinfo(void) return sys_info(si); } +uint64 +sys_sigalarm(void) +{ + struct proc *p = myproc(); + uint64 handler; + + argint(0, &p->alarm_interval); + argaddr(1, &handler); + p->alarm_handler = handler; + + return 0; +} + +uint64 sys_sigreturn(void) +{ + struct proc *p = myproc(); + // retore saved trapframe to resume + memmove(p->trapframe, p->atpfm, sizeof(struct trapframe)); + p->alarm_tickspassed = 0; + p->alarm_caninvoke = 1; + // make sure return the original a0 in trapframe to pass test3 + return p->trapframe->a0; +} diff --git a/kernel/trap.c b/kernel/trap.c index 512c850..eb8009f 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -6,6 +6,12 @@ #include "proc.h" #include "defs.h" +/* + * Always remember that RISC-V disables interrupts when it starts to take a trap, + * so there's no need to call intr_off() at the beginning of trap handling. + * Reference: xv6-riscv-book 4.5 + */ + struct spinlock tickslock; uint ticks; @@ -76,9 +82,22 @@ usertrap(void) if(killed(p)) exit(-1); - // give up the CPU if this is a timer interrupt. - if(which_dev == 2) + if(which_dev == 2){ + // timer interrupt + if(p->alarm_interval > 0 && p->alarm_caninvoke){ + // record sigalarm + p->alarm_tickspassed++; + if(p->alarm_tickspassed == p->alarm_interval){ + // store original trapframe in p->atpfm + memmove(p->atpfm, p->trapframe, sizeof(struct trapframe)); + p->alarm_tickspassed = 0; + p->alarm_caninvoke = 0; + p->trapframe->epc = p->alarm_handler; + } + } + // give up the CPU. yield(); + } usertrapret(); } -- cgit v1.2.3 From 4a6593f1a6f666c618d303a4858c4c6d31b41c63 Mon Sep 17 00:00:00 2001 From: Mole Shang <135e2@135e2.dev> Date: Sun, 11 Feb 2024 17:51:28 +0800 Subject: lab cow: finish --- kernel/cow.c | 30 ++++++++++++++++++++++++++++++ kernel/defs.h | 5 +++++ kernel/kalloc.c | 43 ++++++++++++++++++++++++++++++++++++++++++- kernel/riscv.h | 1 + kernel/sysproc.c | 2 +- kernel/trap.c | 7 +++++++ kernel/vm.c | 27 ++++++++++++++++++++------- 7 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 kernel/cow.c (limited to 'kernel') diff --git a/kernel/cow.c b/kernel/cow.c new file mode 100644 index 0000000..b3634fc --- /dev/null +++ b/kernel/cow.c @@ -0,0 +1,30 @@ +// COW pagefault handler +#include "types.h" +#include "riscv.h" +#include "defs.h" + +int +cow_handler(pagetable_t pagetable, uint64 va) +{ + // you can't really write to rediculous pointers + if(va >= MAXVA || PGROUNDDOWN(va) == 0) + return -1; + pte_t *pte = walk(pagetable, va, 0); + if(pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0) + return -1; + if(*pte & PTE_C){ + uint64 pa_orig = PTE2PA(*pte); + uint64 pa_new = (uint64)kalloc(); + if(pa_new == 0){ + printf("cow pagefault: kalloc failed\n"); + return -1; + } + // copy the page and add write permission + memmove((void*)pa_new, (void*)pa_orig, PGSIZE); + uint64 flags = (PTE_FLAGS(*pte) | PTE_W) & ~PTE_C; + *pte = PA2PTE(pa_new) | flags; + kfree((void*)pa_orig); + } else if ((*pte & PTE_W) == 0) + return -1; + return 0; +} diff --git a/kernel/defs.h b/kernel/defs.h index 04a0276..870c984 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -23,6 +23,9 @@ void consoleinit(void); void consoleintr(int); void consputc(int); +// cow.c +int cow_handler(pagetable_t, uint64); + // exec.c int exec(char*, char**); @@ -61,6 +64,8 @@ void ramdiskintr(void); void ramdiskrw(struct buf*); // kalloc.c +int refcnt_inc(uint64); +int refcnt_dec(uint64); void* kalloc(void); void kfree(void *); void kinit(void); diff --git a/kernel/kalloc.c b/kernel/kalloc.c index c2fdb86..581f0f6 100644 --- a/kernel/kalloc.c +++ b/kernel/kalloc.c @@ -23,10 +23,41 @@ struct { struct run *freelist; } kmem; +int phypg_refcnt[PHYSTOP/PGSIZE]; + +// Increase the refcnt +int +refcnt_inc(uint64 pa) +{ + acquire(&kmem.lock); + int *prefcnt = &phypg_refcnt[pa/PGSIZE]; + if(pa > PHYSTOP || *prefcnt < 1) + panic("increase refcnt"); + (*prefcnt)++; + release(&kmem.lock); + return *prefcnt; +} + +// Decrease the refcnt +int +refcnt_dec(uint64 pa) +{ + acquire(&kmem.lock); + int *prefcnt = &phypg_refcnt[pa/PGSIZE]; + if(pa > PHYSTOP || *prefcnt < 1) + panic("decrease refcnt"); + (*prefcnt)--; + release(&kmem.lock); + return *prefcnt; +} + void kinit() { initlock(&kmem.lock, "kmem"); + // init all refcnt to 1, which would later be freed to 0 by kfree() + for(uint64 p = PGROUNDUP((uint64)end); p + PGSIZE <= PHYSTOP; p += PGSIZE) + phypg_refcnt[p/PGSIZE] = 1; freerange(end, (void*)PHYSTOP); } @@ -51,6 +82,12 @@ kfree(void *pa) if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP) panic("kfree"); + refcnt_dec((uint64)pa); + + if(phypg_refcnt[(uint64)pa/PGSIZE] > 0) + // We still have refs to this phy page, do not actually free it + return; + // Fill with junk to catch dangling refs. memset(pa, 1, PGSIZE); @@ -72,8 +109,12 @@ kalloc(void) acquire(&kmem.lock); r = kmem.freelist; - if(r) + if(r){ + if(phypg_refcnt[(uint64)r/PGSIZE]) + panic("kalloc: invalid refcnt"); + phypg_refcnt[(uint64)r/PGSIZE] = 1; kmem.freelist = r->next; + } release(&kmem.lock); if(r) diff --git a/kernel/riscv.h b/kernel/riscv.h index 5ede50a..7d6eb6e 100644 --- a/kernel/riscv.h +++ b/kernel/riscv.h @@ -353,6 +353,7 @@ typedef uint64 *pagetable_t; // 512 PTEs #define PTE_X (1L << 3) #define PTE_U (1L << 4) // user can access #define PTE_A (1L << 6) // riscv access bit +#define PTE_C (1L << 8) // RSW low bit, use it to mark whether a page is COW // shift a physical address to the right place for a PTE. #define PA2PTE(pa) ((((uint64)pa) >> 12) << 10) diff --git a/kernel/sysproc.c b/kernel/sysproc.c index fac1d83..715a511 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -66,7 +66,7 @@ sys_sleep(void) sleep(&ticks, &tickslock); } - backtrace(); + // backtrace(); release(&tickslock); return 0; diff --git a/kernel/trap.c b/kernel/trap.c index eb8009f..bd3b100 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -73,9 +73,16 @@ usertrap(void) syscall(); } else if((which_dev = devintr()) != 0){ // ok + } else if(r_scause() == 13 || r_scause() == 15){ + // deal with page fault + uint64 va = r_stval(); + if(cow_handler(p->pagetable, va) < 0) + goto err; } else { printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid); printf(" sepc=%p stval=%p\n", r_sepc(), r_stval()); + err: + printf("killing the process...\n"); setkilled(p); } diff --git a/kernel/vm.c b/kernel/vm.c index 9c17fe7..11f9e0a 100644 --- a/kernel/vm.c +++ b/kernel/vm.c @@ -315,20 +315,26 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz) pte_t *pte; uint64 pa, i; uint flags; - char *mem; + // char *mem; for(i = 0; i < sz; i += PGSIZE){ if((pte = walk(old, i, 0)) == 0) panic("uvmcopy: pte should exist"); if((*pte & PTE_V) == 0) panic("uvmcopy: page not present"); - pa = PTE2PA(*pte); - flags = PTE_FLAGS(*pte); + // do not do the actual copy, just increase the refcnt and mark pages readonly COW + /* if((mem = kalloc()) == 0) goto err; memmove(mem, (char*)pa, PGSIZE); - if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){ - kfree(mem); + */ + *pte &= ~PTE_W; + *pte |= PTE_C; + pa = PTE2PA(*pte); + refcnt_inc(pa); + flags = PTE_FLAGS(*pte); + if(mappages(new, i, PGSIZE, (uint64)pa, flags) != 0){ + // kfree(mem); goto err; } } @@ -359,17 +365,24 @@ int copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len) { uint64 n, va0, pa0; - pte_t *pte; + // pte_t *pte; while(len > 0){ va0 = PGROUNDDOWN(dstva); - if(va0 >= MAXVA) + + if(cow_handler(pagetable, va0) < 0) return -1; + + /* pte = walk(pagetable, va0, 0); if(pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0 || (*pte & PTE_W) == 0) return -1; pa0 = PTE2PA(*pte); + */ + pa0 = walkaddr(pagetable, va0); + if(pa0 == 0) + return -1; n = PGSIZE - (dstva - va0); if(n > len) n = len; -- cgit v1.2.3