From ce9cb0d6c0b3d967f6b5ce4a884acefea9b508e6 Mon Sep 17 00:00:00 2001 From: whatever Date: Thu, 19 Dec 2024 15:19:42 +0800 Subject: [PATCH] all done --- Makefile | 3 +- ] | 582 +++++++++++++++++++++++++++++++++++++++++++++++ gradelib.py | 2 +- kernel/bio.c | 2 - kernel/defs.h | 1 + kernel/fs.c | 1 - kernel/proc.c | 58 ++++- kernel/proc.h | 12 +- kernel/syscall.c | 5 +- kernel/syscall.h | 2 + kernel/sysfile.c | 183 +++++++++++++++ kernel/sysproc.c | 49 ++-- kernel/trap.c | 19 +- time.txt | 1 + user/mmaptest.c | 4 - user/user.h | 5 + user/usys.pl | 2 + 17 files changed, 871 insertions(+), 60 deletions(-) create mode 100644 ] create mode 100644 time.txt diff --git a/Makefile b/Makefile index b7fb22d..76bfe92 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ endif # riscv64-unknown-elf- or riscv64-linux-gnu- # perhaps in /opt/riscv/bin -#TOOLPREFIX = +TOOLPREFIX = /opt/riscv/bin/riscv64-unknown-elf- # Try to infer the correct TOOLPREFIX if not set ifndef TOOLPREFIX @@ -197,7 +197,6 @@ UPROGS=\ - ifeq ($(LAB),syscall) UPROGS += \ $U/_attack\ diff --git a/] b/] new file mode 100644 index 0000000..c4dfbec --- /dev/null +++ b/] @@ -0,0 +1,582 @@ +// +// File-system system calls. +// Mostly argument checking, since we don't trust +// user code, and calls into file.c and fs.c. +// + +#include "types.h" +#include "riscv.h" +#include "defs.h" +#include "param.h" +#include "stat.h" +#include "spinlock.h" +#include "proc.h" +#include "fs.h" +#include "sleeplock.h" +#include "file.h" +#include "fcntl.h" + +// Fetch the nth word-sized system call argument as a file descriptor +// and return both the descriptor and the corresponding struct file. +static int +argfd(int n, int *pfd, struct file **pf) +{ + int fd; + struct file *f; + + argint(n, &fd); + if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0) + return -1; + if(pfd) + *pfd = fd; + if(pf) + *pf = f; + return 0; +} + +// Allocate a file descriptor for the given file. +// Takes over file reference from caller on success. +static int +fdalloc(struct file *f) +{ + int fd; + struct proc *p = myproc(); + + for(fd = 0; fd < NOFILE; fd++){ + if(p->ofile[fd] == 0){ + p->ofile[fd] = f; + return fd; + } + } + return -1; +} + +uint64 +sys_dup(void) +{ + struct file *f; + int fd; + + if(argfd(0, 0, &f) < 0) + return -1; + if((fd=fdalloc(f)) < 0) + return -1; + filedup(f); + return fd; +} + +uint64 +sys_read(void) +{ + struct file *f; + int n; + uint64 p; + + argaddr(1, &p); + argint(2, &n); + if(argfd(0, 0, &f) < 0) + return -1; + return fileread(f, p, n); +} + +uint64 +sys_write(void) +{ + struct file *f; + int n; + uint64 p; + + argaddr(1, &p); + argint(2, &n); + if(argfd(0, 0, &f) < 0) + return -1; + + return filewrite(f, p, n); +} + +uint64 +sys_close(void) +{ + int fd; + struct file *f; + + if(argfd(0, &fd, &f) < 0) + return -1; + myproc()->ofile[fd] = 0; + fileclose(f); + return 0; +} + +uint64 +sys_fstat(void) +{ + struct file *f; + uint64 st; // user pointer to struct stat + + argaddr(1, &st); + if(argfd(0, 0, &f) < 0) + return -1; + return filestat(f, st); +} + +// Create the path new as a link to the same inode as old. +uint64 +sys_link(void) +{ + char name[DIRSIZ], new[MAXPATH], old[MAXPATH]; + struct inode *dp, *ip; + + if(argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0) + return -1; + + begin_op(); + if((ip = namei(old)) == 0){ + end_op(); + return -1; + } + + ilock(ip); + if(ip->type == T_DIR){ + iunlockput(ip); + end_op(); + return -1; + } + + ip->nlink++; + iupdate(ip); + iunlock(ip); + + if((dp = nameiparent(new, name)) == 0) + goto bad; + ilock(dp); + if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){ + iunlockput(dp); + goto bad; + } + iunlockput(dp); + iput(ip); + + end_op(); + + return 0; + +bad: + ilock(ip); + ip->nlink--; + iupdate(ip); + iunlockput(ip); + end_op(); + return -1; +} + +// Is the directory dp empty except for "." and ".." ? +static int +isdirempty(struct inode *dp) +{ + int off; + struct dirent de; + + for(off=2*sizeof(de); offsize; off+=sizeof(de)){ + if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de)) + panic("isdirempty: readi"); + if(de.inum != 0) + return 0; + } + return 1; +} + +uint64 +sys_unlink(void) +{ + struct inode *ip, *dp; + struct dirent de; + char name[DIRSIZ], path[MAXPATH]; + uint off; + + if(argstr(0, path, MAXPATH) < 0) + return -1; + + begin_op(); + if((dp = nameiparent(path, name)) == 0){ + end_op(); + return -1; + } + + ilock(dp); + + // Cannot unlink "." or "..". + if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0) + goto bad; + + if((ip = dirlookup(dp, name, &off)) == 0) + goto bad; + ilock(ip); + + if(ip->nlink < 1) + panic("unlink: nlink < 1"); + if(ip->type == T_DIR && !isdirempty(ip)){ + iunlockput(ip); + goto bad; + } + + memset(&de, 0, sizeof(de)); + if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de)) + panic("unlink: writei"); + if(ip->type == T_DIR){ + dp->nlink--; + iupdate(dp); + } + iunlockput(dp); + + ip->nlink--; + iupdate(ip); + iunlockput(ip); + + end_op(); + + return 0; + +bad: + iunlockput(dp); + end_op(); + return -1; +} + +static struct inode* +create(char *path, short type, short major, short minor) +{ + struct inode *ip, *dp; + char name[DIRSIZ]; + + if((dp = nameiparent(path, name)) == 0) + return 0; + + ilock(dp); + + if((ip = dirlookup(dp, name, 0)) != 0){ + iunlockput(dp); + ilock(ip); + if(type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE)) + return ip; + iunlockput(ip); + return 0; + } + + if((ip = ialloc(dp->dev, type)) == 0){ + iunlockput(dp); + return 0; + } + + ilock(ip); + ip->major = major; + ip->minor = minor; + ip->nlink = 1; + iupdate(ip); + + if(type == T_DIR){ // Create . and .. entries. + // No ip->nlink++ for ".": avoid cyclic ref count. + if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) + goto fail; + } + + if(dirlink(dp, name, ip->inum) < 0) + goto fail; + + if(type == T_DIR){ + // now that success is guaranteed: + dp->nlink++; // for ".." + iupdate(dp); + } + + iunlockput(dp); + + return ip; + + fail: + // something went wrong. de-allocate ip. + ip->nlink = 0; + iupdate(ip); + iunlockput(ip); + iunlockput(dp); + return 0; +} + +uint64 +sys_open(void) +{ + char path[MAXPATH]; + int fd, omode; + struct file *f; + struct inode *ip; + int n; + + argint(1, &omode); + if((n = argstr(0, path, MAXPATH)) < 0) + return -1; + + begin_op(); + + if(omode & O_CREATE){ + ip = create(path, T_FILE, 0, 0); + if(ip == 0){ + end_op(); + return -1; + } + } else { + if((ip = namei(path)) == 0){ + end_op(); + return -1; + } + ilock(ip); + if(ip->type == T_DIR && omode != O_RDONLY){ + iunlockput(ip); + end_op(); + return -1; + } + } + + if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){ + iunlockput(ip); + end_op(); + return -1; + } + + if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){ + if(f) + fileclose(f); + iunlockput(ip); + end_op(); + return -1; + } + + if(ip->type == T_DEVICE){ + f->type = FD_DEVICE; + f->major = ip->major; + } else { + f->type = FD_INODE; + f->off = 0; + } + f->ip = ip; + f->readable = !(omode & O_WRONLY); + f->writable = (omode & O_WRONLY) || (omode & O_RDWR); + + if((omode & O_TRUNC) && ip->type == T_FILE){ + itrunc(ip); + } + + iunlock(ip); + end_op(); + + return fd; +} + +uint64 +sys_mkdir(void) +{ + char path[MAXPATH]; + struct inode *ip; + + begin_op(); + if(argstr(0, path, MAXPATH) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){ + end_op(); + return -1; + } + iunlockput(ip); + end_op(); + return 0; +} + +uint64 +sys_mknod(void) +{ + struct inode *ip; + char path[MAXPATH]; + int major, minor; + + begin_op(); + argint(1, &major); + argint(2, &minor); + if((argstr(0, path, MAXPATH)) < 0 || + (ip = create(path, T_DEVICE, major, minor)) == 0){ + end_op(); + return -1; + } + iunlockput(ip); + end_op(); + return 0; +} + +uint64 +sys_chdir(void) +{ + char path[MAXPATH]; + struct inode *ip; + struct proc *p = myproc(); + + begin_op(); + if(argstr(0, path, MAXPATH) < 0 || (ip = namei(path)) == 0){ + end_op(); + return -1; + } + ilock(ip); + if(ip->type != T_DIR){ + iunlockput(ip); + end_op(); + return -1; + } + iunlock(ip); + iput(p->cwd); + end_op(); + p->cwd = ip; + return 0; +} + +uint64 +sys_exec(void) +{ + char path[MAXPATH], *argv[MAXARG]; + int i; + uint64 uargv, uarg; + + argaddr(1, &uargv); + if(argstr(0, path, MAXPATH) < 0) { + return -1; + } + memset(argv, 0, sizeof(argv)); + for(i=0;; i++){ + if(i >= NELEM(argv)){ + goto bad; + } + if(fetchaddr(uargv+sizeof(uint64)*i, (uint64*)&uarg) < 0){ + goto bad; + } + if(uarg == 0){ + argv[i] = 0; + break; + } + argv[i] = kalloc(); + if(argv[i] == 0) + goto bad; + if(fetchstr(uarg, argv[i], PGSIZE) < 0) + goto bad; + } + + int ret = exec(path, argv); + + for(i = 0; i < NELEM(argv) && argv[i] != 0; i++) + kfree(argv[i]); + + return ret; + + bad: + for(i = 0; i < NELEM(argv) && argv[i] != 0; i++) + kfree(argv[i]); + return -1; +} + +uint64 +sys_pipe(void) +{ + uint64 fdarray; // user pointer to array of two integers + struct file *rf, *wf; + int fd0, fd1; + struct proc *p = myproc(); + + argaddr(0, &fdarray); + if(pipealloc(&rf, &wf) < 0) + return -1; + fd0 = -1; + if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ + if(fd0 >= 0) + p->ofile[fd0] = 0; + fileclose(rf); + fileclose(wf); + return -1; + } + if(copyout(p->pagetable, fdarray, (char*)&fd0, sizeof(fd0)) < 0 || + copyout(p->pagetable, fdarray+sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0){ + p->ofile[fd0] = 0; + p->ofile[fd1] = 0; + fileclose(rf); + fileclose(wf); + return -1; + } + return 0; +} + +const struct vma Null= {.addr=0,.len=0,.prot=0,.flags=0,.file=(struct file*)0,.offset=0}; +uint64 sys_mmap(void) { + uint64 addr,len; + int prot, flags, fd, offset; + argaddr(0, &addr); + argaddr(1, &len), argint(2, &prot), argint(3, &flags), argint(4, &fd), argint(5, &offset); + struct proc *p = myproc(); + struct vma *vma = p->vma; + uint64 ret = p->sz; + for (int i = 0; i < NVMA; ++i) // don't process when it's full + if (vma[i].len == Null.len) { // getting a mem size of 0 seems crazy + vma[i].addr=ret;//addr is always 0, and ret is the position + vma[i].len=len; + vma[i].prot=prot; + vma[i].flags=flags;// which is MAP flags + vma[i].file=p->ofile[fd]; + filedup(vma[i].file);//increased ref here + vma[i].offset=offset; + break; + } + p->sz += len; + return ret; +} +uint64 sys_munmap(void) { + uint64 addr,len; + argaddr(0,&addr),argaddr(1,&len); + // well it's possible that the passed addr and len does not match a munmap + + return 0; +} +int lazymap(){ + struct proc *p=myproc(); + uint64 va=PGROUNDDOWN(r_stval()); + if(va>=p->sz) + goto err1; + for(int i=0;ivma[i].addr; + const int vma_flag=p->vma[i].prot; + const int offset=p->vma[i].offset; + struct file *file=p->vma[i].file; + struct inode *ip=file->ip; + const int len=p->vma[i].len; + // each addr and len won't intersect with each other, it's defined by sys_mmap process + if(PGROUNDDOWN(addr) + len>= va){// it's considered that addr is page-aligned + char *mem=kalloc(); + memset(mem,0,PGSIZE); + if(mem==0) + goto err1; + int pte_flag=0; + if(vma_flag & PROT_READ) + pte_flag|=PTE_R; + if(vma_flag & PROT_WRITE) + pte_flag|=PTE_W; + if(vma_flag & PROT_EXEC) + pte_flag|=PTE_X; + pte_flag|=PTE_U; + if(mappages(p->pagetable,va,PGSIZE,(uint64)mem,pte_flag)<0){ + kfree(mem); + goto err1; + } + ilock(ip); + // readi won't increase inode ref + if(!readi(ip,0,(uint64)mem,offset + (va-addr),PGSIZE)) + goto err2; + DEBUG(); + // file pointer handles ref to inode, so don't increase inode ref there + iunlock(ip); + return 0; + err2: + iunlock(ip); + goto err1; + } + } +err1: + return -1; +} diff --git a/gradelib.py b/gradelib.py index f0d4934..21dd2bc 100644 --- a/gradelib.py +++ b/gradelib.py @@ -238,7 +238,7 @@ def make(*target): post_make() def show_command(cmd): - from pipes import quote + from shlex import quote print("\n$", " ".join(map(quote, cmd))) def maybe_unlink(*paths): diff --git a/kernel/bio.c b/kernel/bio.c index 60d91a6..b52403e 100644 --- a/kernel/bio.c +++ b/kernel/bio.c @@ -118,9 +118,7 @@ brelse(struct buf *b) { if(!holdingsleep(&b->lock)) panic("brelse"); - releasesleep(&b->lock); - acquire(&bcache.lock); b->refcnt--; if (b->refcnt == 0) { diff --git a/kernel/defs.h b/kernel/defs.h index d133cd3..ecf7a52 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -237,3 +237,4 @@ void netinit(void); void net_rx(char *buf, int len); #endif +#define DEBUG() printf("File %s, Line %d, Function %s\n",__FILE__,__LINE__,__func__); diff --git a/kernel/fs.c b/kernel/fs.c index c6bab15..748e3fd 100644 --- a/kernel/fs.c +++ b/kernel/fs.c @@ -478,7 +478,6 @@ readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n) return 0; if(off + n > ip->size) n = ip->size - off; - for(tot=0; totsz = sz; return 0; } - +extern int lazymap(uint64); // Create a new process, copying the parent. // Sets up child kernel stack to return as if from fork() system call. int @@ -282,12 +282,35 @@ fork(void) int i, pid; struct proc *np; struct proc *p = myproc(); - // Allocate process. if((np = allocproc()) == 0){ return -1; } - + // not lazy anymore, forcefully alloc all pages in VMA + release(&np->lock); + for(int i=0;ivma[i]=p->vma[i]; + if(p->vma[i].len==0) + continue; + const int addr=p->vma[i].addr; + const int len=p->vma[i].len; + const int vis=p->vma[i].vis; + filedup(np->vma[i].file); + for(int j=0;jpagetable,cur,0); + if(pte!=0 &&(*pte & PTE_V)!=0) + continue; + if(lazymap(cur)<0){ + freeproc(np); + return -1; + } + } + } + acquire(&np->lock); // Copy user memory from parent to child. if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){ freeproc(np); @@ -321,7 +344,6 @@ fork(void) acquire(&np->lock); np->state = RUNNABLE; release(&np->lock); - return pid; } @@ -343,6 +365,7 @@ reparent(struct proc *p) // Exit the current process. Does not return. // An exited process remains in the zombie state // until its parent calls wait(). +extern int munmap(uint64,uint64); void exit(int status) { @@ -364,7 +387,30 @@ exit(int status) iput(p->cwd); end_op(); p->cwd = 0; - + #ifdef CHECK_IF_VALID_ADDR + int cnt=0; + #endif + for(int i=0;ivma[j].addr>p->vma[x].addr) + x=j; + if(p->vma[x].len==0) + break; + #ifdef CHECK_IF_VALID_ADDR + printf("current sz=%lu\n",p->sz); + if(p->vma[x].addr+p->vma[x].len!=p->sz){ + printf("addr=%lu,len=%d,cnt=%d\n",p->vma[x].addr,p->vma[x].len,cnt); + panic("invalid addr"); + } + ++cnt; + #endif + if(p->vma[x].len) + munmap(p->vma[x].addr,p->vma[x].len); + } + #ifdef CHECK_IF_VALID_ADDR + printf("it's still alive, sz=%lu\n",p->sz); + #endif acquire(&wait_lock); // Give any children to init. @@ -379,7 +425,6 @@ exit(int status) p->state = ZOMBIE; release(&wait_lock); - // Jump into the scheduler, never to return. sched(); panic("zombie exit"); @@ -446,7 +491,6 @@ scheduler(void) { struct proc *p; struct cpu *c = mycpu(); - c->proc = 0; for(;;){ // The most recent process to run may have had interrupts diff --git a/kernel/proc.h b/kernel/proc.h index d021857..a7ad853 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -20,7 +20,7 @@ struct context { // Per-CPU state. struct cpu { - struct proc *proc; // The process running on this cpu, or null. + struct proc *proc; // The process running on this cpu, or Null. struct context context; // swtch() here to enter scheduler(). int noff; // Depth of push_off() nesting. int intena; // Were interrupts enabled before push_off()? @@ -80,7 +80,14 @@ struct trapframe { }; enum procstate { UNUSED, USED, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; - +#define NVMA 16 +struct vma{ + uint64 addr; + int len,prot,flags,offset; + struct file *file; + int vis;// validity bitmask used, bit 1 stands for being unmapped, init be 0 + // the 0-th bit stands for addr, then 1-st bit stands for addr+PGSIZE, etc +}; // Per-process state struct proc { struct spinlock lock; @@ -104,4 +111,5 @@ struct proc { struct file *ofile[NOFILE]; // Open files struct inode *cwd; // Current directory char name[16]; // Process name (debugging) + struct vma vma[NVMA]; }; diff --git a/kernel/syscall.c b/kernel/syscall.c index ed65409..d3f567e 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -101,7 +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_mmap(void); +extern uint64 sys_munmap(void); // An array mapping syscall numbers from syscall.h // to the function that handles the system call. static uint64 (*syscalls[])(void) = { @@ -126,6 +127,8 @@ static uint64 (*syscalls[])(void) = { [SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close, +[SYS_mmap] sys_mmap, +[SYS_munmap] sys_munmap }; void diff --git a/kernel/syscall.h b/kernel/syscall.h index bc5f356..4e24fd5 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -20,3 +20,5 @@ #define SYS_link 19 #define SYS_mkdir 20 #define SYS_close 21 +#define SYS_mmap 22 +#define SYS_munmap 23 diff --git a/kernel/sysfile.c b/kernel/sysfile.c index 16b668c..ee038b5 100644 --- a/kernel/sysfile.c +++ b/kernel/sysfile.c @@ -503,3 +503,186 @@ sys_pipe(void) } return 0; } + +const struct vma Null= {.addr=0,.len=0,.prot=0,.flags=0,.file=(struct file*)0,.offset=0,.vis=0}; +uint64 sys_mmap(void) { + uint64 addr,len; + int prot, flags, fd, offset; + argaddr(0, &addr); + argaddr(1, &len), argint(2, &prot), argint(3, &flags), argint(4, &fd), argint(5, &offset); + struct proc *p = myproc(); + struct vma *vma = p->vma; + if((!p->ofile[fd]->readable) && (prot & PROT_READ)) + goto err1; + if((!p->ofile[fd]->writable) && (prot &PROT_WRITE) && (flags & MAP_SHARED)) + goto err1; + uint64 ret = p->sz; + for (int i = 0; i < NVMA; ++i) // don't process when it's full + if (vma[i].len == Null.len) { // getting a mem size of 0 seems crazy + vma[i].addr=ret;//addr is always 0, and ret is the position + vma[i].len=len; + vma[i].prot=prot; + vma[i].flags=flags;// which is MAP flags + vma[i].file=p->ofile[fd]; + filedup(vma[i].file);//increased ref here + vma[i].offset=offset; + vma[i].vis=0; + p->sz+=len; + return ret; + } +err1: + return -1; +} +void shrink_vma(){ + struct proc *p=myproc(); + //DEBUG(); + while(1){ + int found=0; + int i; + for(i=0;ivma[i].vis==-1 && p->vma[i].addr+p->vma[i].len==p->sz){ + found=1; + break; + } + if(!found) + break; + #ifdef CHECK_IF_EXISTS + printf("current sz=%lu\n",p->sz); + #endif + p->sz-=p->vma[i].len; + p->vma[i]=Null; + } +} +int munmap(uint64 Argaddr,uint64 Arglen){ + struct proc *p=myproc(); + // well it's possible that the passed addr and len does not match a munmap + // how do I know that all of the pages of an mmap zone has been removed --using vis + // don't do crazy things like unmap two different mmap area at same time --it's fine, no such operation in test + for(int i=0;ivma[i].addr; + const int offset=p->vma[i].offset; + struct file *file=p->vma[i].file; + struct inode *ip=file->ip; + const int len=p->vma[i].len; + int *vis=&p->vma[i].vis; + const int map_flag=p->vma[i].flags; + if(*vis!=-1 && len >0 && PGROUNDDOWN(addr) + len >= Argaddr+Arglen && PGROUNDDOWN(addr) <= Argaddr){ + // for(int i=0;ipagetable,cur,0); + if(pte!=0 && (*pte & PTE_V)!=0){ + // this page may not actually allocated + // wait what happens for uvmunmap, if there's a mmap page between normal pages... --I bet this won't happen + if(map_flag & (MAP_SHARED)){// write back + begin_op(); // don't forget begin_op + ilock(ip); + const uint sz=ip->size; + const int pos=offset+(cur-addr); + const uint remain=sz-pos; + if(writei(ip,1,cur,pos,PGSIZEpagetable,cur,1,1); + } + *vis |= 1<>i; + if(all_clear){ // clear this vma + // wait, what happens if this vma is the highest address? + // and, it's responsible for exit, to call munmap in a dereasing order + //if(p->sz == addr+len) + //p->sz-=len; + // release the file + fileclose(file); + // clean this vma + //p->vma[i]=Null;// well, I don't need those pointers at all... + p->vma[i].vis=-1; + shrink_vma(); + } + return 0; + err2: + iunlock(ip); + goto err1; + } + } +err1: + // hey! why did a uint64 func return -1?? + return -1; //default not found +} +uint64 sys_munmap(void) { + uint64 Argaddr,Arglen; + argaddr(0,&Argaddr),argaddr(1,&Arglen); + return munmap(Argaddr,Arglen); +} +int lazymap(uint64 va){ + struct proc *p=myproc(); + if(va>=p->sz) + goto err1; + uint64 scause=r_scause(); + for(int i=0;ivma[i].addr; + const int vma_flag=p->vma[i].prot; + const int offset=p->vma[i].offset; + struct file *file=p->vma[i].file; + struct inode *ip=file->ip; + const int len=p->vma[i].len; + const int vis=p->vma[i].vis; + // each addr and len won't intersect with each other, it's defined by sys_mmap process + // it's > not >=, however + // we must make sure that this va is within the range + if(vis!=-1 && len > 0 && PGROUNDDOWN(addr) + len>va && PGROUNDDOWN(addr)<=va){// it's considered that addr is page-aligned + const int x=(va-addr)/PGSIZE; + if((1<pagetable,va,PGSIZE,(uint64)mem,pte_flag)<0){ + kfree(mem); + goto err1; + } + // why I need to call readi?? + // oh, that's because I can't get file+offset directly... + ilock(ip); + // readi won't increase inode ref + if(readi(ip,0,(uint64)mem,offset + (va-addr),PGSIZE)<=0) + goto err2; + // file pointer handles ref to inode, so don't increase inode ref there + iunlock(ip); + return 0; + err2: + uvmunmap(p->pagetable,va,1,1); + iunlock(ip); + goto err1; + } + } +err1: + return -1; +} diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 3b4d5bd..06b4eb3 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -5,62 +5,45 @@ #include "memlayout.h" #include "spinlock.h" #include "proc.h" - -uint64 -sys_exit(void) -{ +uint64 sys_exit(void) { int n; argint(0, &n); exit(n); - return 0; // not reached + return 0; // not reached } -uint64 -sys_getpid(void) -{ - return myproc()->pid; -} +uint64 sys_getpid(void) { return myproc()->pid; } -uint64 -sys_fork(void) -{ - return fork(); -} +uint64 sys_fork(void) { return fork(); } -uint64 -sys_wait(void) -{ +uint64 sys_wait(void) { uint64 p; argaddr(0, &p); return wait(p); } -uint64 -sys_sbrk(void) -{ +uint64 sys_sbrk(void) { uint64 addr; int n; argint(0, &n); addr = myproc()->sz; - if(growproc(n) < 0) + if (growproc(n) < 0) return -1; return addr; } -uint64 -sys_sleep(void) -{ +uint64 sys_sleep(void) { int n; uint ticks0; argint(0, &n); - if(n < 0) + if (n < 0) n = 0; acquire(&tickslock); ticks0 = ticks; - while(ticks - ticks0 < n){ - if(killed(myproc())){ + while (ticks - ticks0 < n) { + if (killed(myproc())) { release(&tickslock); return -1; } @@ -70,20 +53,17 @@ sys_sleep(void) return 0; } -uint64 -sys_kill(void) -{ +uint64 sys_kill(void) { int pid; argint(0, &pid); return kill(pid); } + // return how many clock tick interrupts have occurred // since start. -uint64 -sys_uptime(void) -{ +uint64 sys_uptime(void) { uint xticks; acquire(&tickslock); @@ -91,3 +71,4 @@ sys_uptime(void) release(&tickslock); return xticks; } + diff --git a/kernel/trap.c b/kernel/trap.c index d454a7d..9136943 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -15,7 +15,7 @@ extern char trampoline[], uservec[], userret[]; void kernelvec(); extern int devintr(); - +extern int lazymap(uint64); void trapinit(void) { @@ -65,7 +65,14 @@ usertrap(void) intr_on(); syscall(); - } else if((which_dev = devintr()) != 0){ + }else if(r_scause() == 13 || r_scause() == 15){ //on handling page fault + if(killed(p)) + exit(-1);// for sure? + if(lazymap(PGROUNDDOWN(r_stval()))<0) + setkilled(p); + // kill will call exit(), and exit() will handle munmap + // do I need to call intr_on()? no + }else if((which_dev = devintr()) != 0){ // ok } else { printf("usertrap(): unexpected scause 0x%lx pid=%d\n", r_scause(), p->pid); @@ -77,9 +84,9 @@ usertrap(void) exit(-1); // give up the CPU if this is a timer interrupt. - if(which_dev == 2) + if(which_dev == 2){ yield(); - + } usertrapret(); } @@ -151,9 +158,9 @@ kerneltrap() } // give up the CPU if this is a timer interrupt. - if(which_dev == 2 && myproc() != 0) + if(which_dev == 2 && myproc() != 0){ 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); diff --git a/time.txt b/time.txt new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/time.txt @@ -0,0 +1 @@ +12 diff --git a/user/mmaptest.c b/user/mmaptest.c index 2f995ea..8949dbd 100644 --- a/user/mmaptest.c +++ b/user/mmaptest.c @@ -169,16 +169,13 @@ mmap_test(void) err("mmap (4)"); if (close(fd) == -1) err("close (3)"); - // check that the mapping still works after close(fd). _v1(p); - // write the mapped memory. for (i = 0; i < PGSIZE; i++) p[i] = 'B'; for (i = PGSIZE; i < PGSIZE*2; i++) p[i] = 'C'; - // unmap just the first two of three pages of mapped memory. if (munmap(p, PGSIZE*2) == -1) err("munmap (3)"); @@ -425,7 +422,6 @@ more_test() printf("test writes to read-only mapped memory\n"); makefile(f); - pid = fork(); if(pid < 0) err("fork"); if(pid == 0){ diff --git a/user/user.h b/user/user.h index 0e9bd4a..e1c74e3 100644 --- a/user/user.h +++ b/user/user.h @@ -1,6 +1,9 @@ #ifdef LAB_MMAP + typedef unsigned long size_t; typedef long int off_t; +void *mmap(void*,size_t,int,int,int,off_t); +int munmap(void*,size_t); #endif struct stat; @@ -59,3 +62,5 @@ int statistics(void*, int); // umalloc.c void* malloc(uint); void free(void*); + +#define DEBUG() printf("File %s, Line %d, Function %s\n",__FILE__,__LINE__,__func__); diff --git a/user/usys.pl b/user/usys.pl index 01e426e..d23b9cc 100755 --- a/user/usys.pl +++ b/user/usys.pl @@ -36,3 +36,5 @@ entry("getpid"); entry("sbrk"); entry("sleep"); entry("uptime"); +entry("mmap"); +entry("munmap");