From 5755206f9f632aa8d5794d44de7e5ec675eeddd1 Mon Sep 17 00:00:00 2001
From: TianhuaTao <taotianhua@outlook.com>
Date: Sat, 10 Apr 2021 21:25:15 +0800
Subject: [PATCH] add lab6-smp

---
 os/console.c          |   6 +-
 os/defs.h             |  16 ++-
 os/file.c             |  53 ++++++++++
 os/file.h             |  42 ++++++++
 os/kalloc.c           |   3 +-
 os/loader.c           |   2 +-
 os/log.h              |  12 +--
 os/main.c             |   7 ++
 os/pipe.c             | 113 ++++++++++++++++++++
 os/proc.c             |  62 +++++++++--
 os/proc.h             |   6 +-
 os/syscall.c          | 239 ++++++++++++++++++++++++++++++++++++++----
 os/syscall_ids.h      |   2 +
 os/timer.c            |   2 +-
 os/vm.c               |  22 ++--
 user/include/unistd.h |   5 +-
 user/lib/stdio.c      |   5 +-
 user/lib/syscall.c    |   8 +-
 user/src/pipetest.c   |  43 ++++++++
 user/src/user_shell.c |   3 +
 20 files changed, 594 insertions(+), 57 deletions(-)
 create mode 100644 os/file.c
 create mode 100644 os/file.h
 create mode 100644 os/pipe.c
 create mode 100644 user/src/pipetest.c

diff --git a/os/console.c b/os/console.c
index 83d96dc..1989295 100644
--- a/os/console.c
+++ b/os/console.c
@@ -2,4 +2,8 @@
 
 void consputc(int c) {
     console_putchar(c);
-}
\ No newline at end of file
+}
+
+char consgetc() {
+    return console_getchar();
+}
diff --git a/os/defs.h b/os/defs.h
index 76bcd24..66ab11e 100644
--- a/os/defs.h
+++ b/os/defs.h
@@ -4,6 +4,8 @@
 #include "types.h"
 struct context;
 struct proc;
+struct file;
+struct pipe;
 
 // panic.c
 void loop();
@@ -16,7 +18,7 @@ void shutdown();
 void set_timer(uint64 stime);
 
 // console.c
-
+void consoleinit(void);
 void consputc(int);
 
 // printf.c
@@ -65,6 +67,7 @@ int exec(char*);
 int wait(int, int*);
 struct proc* allocproc();
 void init_scheduler();
+int fdalloc(struct file *);
 
 
 // kalloc.c
@@ -93,12 +96,23 @@ int map1page(pagetable_t pagetable, uint64 va, uint64 pa, int perm);
 pte_t *walk(pagetable_t pagetable, uint64 va, int alloc);
 void
 kvminithart();
+void debugwalk(pagetable_t, int);
+
 
 // timer.c
 uint64 get_cycle();
 void timerinit();
 void set_next_timer();
 uint64 get_time_ms();
+// pipe.c
+int pipealloc(struct file *, struct file *);
+void pipeclose(struct pipe *, int);
+int piperead(struct pipe *, uint64, int);
+int pipewrite(struct pipe *, uint64, int);
+
+// file.c
+void fileclose(struct file *);
+struct file* filealloc();
 
 // number of elements in fixed-size array
 #define NELEM(x) (sizeof(x) / sizeof((x)[0]))
diff --git a/os/file.c b/os/file.c
new file mode 100644
index 0000000..48b7c9c
--- /dev/null
+++ b/os/file.c
@@ -0,0 +1,53 @@
+#include "types.h"
+#include "file.h"
+#include "proc.h"
+#include "defs.h"
+
+#define FILE_MAX (128*16)
+struct file filepool[FILE_MAX];
+
+void
+fileclose(struct file *f)
+{
+    if(f->ref < 1)
+        panic("fileclose");
+    if(--f->ref > 0) {
+        return;
+    }
+
+    if(f->type == FD_PIPE){
+        pipeclose(f->pipe, f->writable);
+    }
+    f->off = 0;
+    f->readable = 0;
+    f->writable = 0;
+    f->ref = 0;
+    f->type = FD_NONE;
+}
+
+struct file* filealloc() {
+    for(int i = 0; i < FILE_MAX; ++i) {
+        if(filepool[i].ref == 0) {
+            filepool[i].ref = 1;
+            return &filepool[i];
+        }
+    }
+    return 0;
+}
+
+int init_mailbox(struct mailbox* mb){
+    void* buf_pa = kalloc();
+    if(buf_pa == 0 ){
+        return 0;
+    }
+    init_spin_lock(&mb->lock);
+    mb->mailbuf  =buf_pa;
+    for (int i = 0; i < MAX_MAIL_IN_BOX; i++)
+    {
+        mb->length[i] = 0;
+        mb->valid[i] = 0;
+    }
+    mb->head = 0;
+    return 1;
+}
+
diff --git a/os/file.h b/os/file.h
new file mode 100644
index 0000000..dd7fad9
--- /dev/null
+++ b/os/file.h
@@ -0,0 +1,42 @@
+#ifndef __FILE_H__
+#define __FILE_H__
+
+#include "types.h"
+#include "lock.h"
+// pipe.h
+#define PIPESIZE 512
+
+struct pipe {
+    char data[PIPESIZE];
+    uint nread;     // number of bytes read
+    uint nwrite;    // number of bytes written
+    int readopen;   // read fd is still open
+    int writeopen;  // write fd is still open
+    struct spinlock lock;
+};
+
+// file.h
+struct file {
+    enum { FD_NONE = 0, FD_PIPE} type;
+    int ref; // reference count
+    char readable;
+    char writable;
+    struct pipe *pipe; // FD_PIPE
+    uint off;          // FD_INODE
+};
+
+typedef char mail_t[256];
+# define MAX_MAIL_IN_BOX (16)
+struct mailbox{
+    mail_t* mailbuf;    // 4KB, 16 mail
+    int valid[MAX_MAIL_IN_BOX];
+    int length[MAX_MAIL_IN_BOX];
+    int head;
+    struct spinlock lock;
+};
+
+int init_mailbox(struct mailbox* mb);
+
+extern struct file filepool[128 * 16];
+
+#endif //!__FILE_H__
\ No newline at end of file
diff --git a/os/kalloc.c b/os/kalloc.c
index fd3e09b..d97560c 100644
--- a/os/kalloc.c
+++ b/os/kalloc.c
@@ -68,8 +68,9 @@ kalloc(void)
     if (l)
     {
         kmem.freelist = l->next;
-        memset((char *)l, 5, PGSIZE); // fill with junk
     }
     release(&kmem.lock);
+    if(l)
+        memset((char *)l, 5, PGSIZE); // fill with junk
     return (void *)l;
 }
\ No newline at end of file
diff --git a/os/loader.c b/os/loader.c
index fb9cf2b..9af4b6f 100644
--- a/os/loader.c
+++ b/os/loader.c
@@ -7,7 +7,7 @@ static int app_cur, app_num;
 static uint64 *app_info_ptr;
 extern char _app_num[], _app_names[];
 const uint64 BASE_ADDRESS = 0x1000; // user text start
-char names[20][100];
+char names[40][100];
 
 
 void batchinit() {
diff --git a/os/log.h b/os/log.h
index 9045dc5..1c8bf12 100644
--- a/os/log.h
+++ b/os/log.h
@@ -58,23 +58,23 @@ enum LOG_COLOR
 
 #if defined(USE_LOG_WARN)
 
-#define warnf(fmt, ...) printf("\x1b[%dm[%s] " fmt "\x1b[0m\n", YELLOW, "WARN", ##__VA_ARGS__);
+#define warnf(fmt, ...) printf("\x1b[%dm[%s] " fmt "\x1b[0m\n", YELLOW, "WARN", ##__VA_ARGS__)
 #else
 #define warnf(fmt, ...)
 #endif //
 
 #if defined(USE_LOG_ERROR)
 
-#define errorf(fmt, ...) printf("\x1b[%dm[%s] " fmt "\x1b[0m\n", RED, "ERROR", ##__VA_ARGS__);
+#define errorf(fmt, ...) printf("\x1b[%dm[%s] " fmt "\x1b[0m\n", RED, "ERROR", ##__VA_ARGS__)
 #else
 #define errorf(fmt, ...)
 #endif //
 
 #if defined(USE_LOG_DEBUG)
 
-#define debugf(fmt, ...) printf("\x1b[%dm[%s] " fmt "\x1b[0m\n", GREEN, "DEBUG", ##__VA_ARGS__);
+#define debugf(fmt, ...) printf("\x1b[%dm[%s] " fmt "\x1b[0m\n", GREEN, "DEBUG", ##__VA_ARGS__)
 
-#define debugcore(fmt, ...) printf("\x1b[%dm[%s %d] " fmt "\x1b[0m\n", GREEN, "DEBUG", cpuid(), ##__VA_ARGS__);
+#define debugcore(fmt, ...) printf("\x1b[%dm[%s %d] " fmt "\x1b[0m\n", GREEN, "DEBUG", cpuid(), ##__VA_ARGS__)
 #define phex(var_name) debugf(#var_name "=%p", var_name)
 
 #else
@@ -84,14 +84,14 @@ enum LOG_COLOR
 
 #if defined(USE_LOG_TRACE)
 
-#define tracef(fmt, ...) printf("\x1b[%dm[%s] " fmt "\x1b[0m\n", GRAY, "TRACE", ##__VA_ARGS__);
+#define tracef(fmt, ...) printf("\x1b[%dm[%s] " fmt "\x1b[0m\n", GRAY, "TRACE", ##__VA_ARGS__)
 #else
 #define tracef(fmt, ...)
 #endif //
 
 #if defined(USE_LOG_INFO)
 
-#define infof(fmt, ...) printf("\x1b[%dm[%s] " fmt "\x1b[0m\n", BLUE, "INFO", ##__VA_ARGS__);
+#define infof(fmt, ...) printf("\x1b[%dm[%s] " fmt "\x1b[0m\n", BLUE, "INFO", ##__VA_ARGS__)
 #else
 #define infof(fmt, ...)
 #endif //
diff --git a/os/main.c b/os/main.c
index 69830e6..f09f004 100644
--- a/os/main.c
+++ b/os/main.c
@@ -19,6 +19,7 @@ void clean_bss()
 }
 
 volatile static int first_hart = 1;
+volatile static int all_started = 0;
 void start_hart(uint64 hartid, uint64 start_addr, uint64 a1);
 void hart_bootcamp(uint64 hartid, uint64 a1)
 {
@@ -39,6 +40,7 @@ void wait_all_boot()
         while (!booted[i])
             ;
     }
+    all_started = 1;
 }
 void init_booted()
 {
@@ -103,6 +105,11 @@ void main(uint64 hartid, uint64 a1)
     {
         hart_bootcamp(hartid, a1);
     }
+    while (!all_started)
+    {
+        ;   // wait until all hard started
+    }
+    
     tracef("start scheduler!");
     scheduler();
     debugf("core %d halt", cpuid());
diff --git a/os/pipe.c b/os/pipe.c
new file mode 100644
index 0000000..10a9aad
--- /dev/null
+++ b/os/pipe.c
@@ -0,0 +1,113 @@
+#include "riscv.h"
+#include "defs.h"
+#include "proc.h"
+#include "file.h"
+
+int
+pipealloc(struct file *f0, struct file *f1)
+{
+    struct pipe *pi;
+    pi = 0;
+    if((pi = (struct pipe*)kalloc()) == 0)
+        goto bad;
+    pi->readopen = 1;
+    pi->writeopen = 1;
+    pi->nwrite = 0;
+    pi->nread = 0;
+    init_spin_lock(&pi->lock);
+    f0->type = FD_PIPE;
+    f0->readable = 1;
+    f0->writable = 0;
+    f0->pipe = pi;
+    f1->type = FD_PIPE;
+    f1->readable = 0;
+    f1->writable = 1;
+    f1->pipe = pi;
+    return 0;
+bad:
+    if(pi)
+        kfree((char*)pi);
+    return -1;
+}
+
+void
+pipeclose(struct pipe *pi, int writable)
+{
+    acquire(&pi->lock);
+    if(writable){
+        pi->writeopen = 0;
+    } else {
+        pi->readopen = 0;
+    }
+    if(pi->readopen == 0 && pi->writeopen == 0){
+        release(&pi->lock);
+        kfree((char*)pi);
+    }else
+        release(&pi->lock);
+}
+
+int
+pipewrite(struct pipe *pi, uint64 addr, int n)
+{
+    int w = 0;
+    uint64 size;
+    struct proc *p = curr_proc();
+    if(n <= 0) {
+        panic("invalid read num");
+    }
+    acquire(&pi->lock);
+    while(w < n){
+        if(pi->readopen == 0){
+            return -1;
+        }
+        if(pi->nwrite == pi->nread + PIPESIZE){ //DOC: pipewrite-full
+            release(&pi->lock);
+            yield();
+            acquire(&pi->lock);
+        } else {
+            size = MIN(MIN(n - w, pi->nread + PIPESIZE - pi->nwrite), PIPESIZE - (pi->nwrite % PIPESIZE));
+            if(copyin(p->pagetable, &pi->data[pi->nwrite % PIPESIZE], addr + w, size) < 0) {
+                panic("copyin");
+            }
+            pi->nwrite += size;
+            w += size;
+        }
+    }
+    release(&pi->lock);
+
+    return w;
+}
+
+int
+piperead(struct pipe *pi, uint64 addr, int n)
+{
+    int r = 0;
+    uint64 size = -1;
+    struct proc *p = curr_proc();
+    if(n <= 0) {
+        panic("invalid read num");
+    }
+    acquire(&pi->lock);
+    while(pi->nread == pi->nwrite) {
+        if(pi->writeopen)
+        {
+            release(&pi->lock);
+            yield();
+            acquire(&pi->lock);
+        }
+        else
+            return -1;
+    }
+    while(r < n && size != 0) {  //DOC: piperead-copy
+        if(pi->nread == pi->nwrite)
+            break;
+        size = MIN(MIN(n - r, pi->nwrite - pi->nread), PIPESIZE - (pi->nread % PIPESIZE));
+        if(copyout(p->pagetable, addr + r, &pi->data[pi->nread % PIPESIZE], size) < 0) {
+            panic("copyout");
+        }
+        pi->nread += size;
+        r += size;
+    }
+    release(&pi->lock);
+    return r;
+}
diff --git a/os/proc.c b/os/proc.c
index 4fca0ba..ebfa68f 100644
--- a/os/proc.c
+++ b/os/proc.c
@@ -4,6 +4,7 @@
 #include "timer.h"
 #include "log.h"
 #include "riscv.h"
+#include "file.h"
 #include "memory_layout.h"
 struct proc pool[NPROC];
 
@@ -21,6 +22,20 @@ struct proc *curr_proc()
 }
 // struct proc idle[NCPU];
 
+struct proc* findproc(int pid)
+{
+    struct proc *p = NULL;
+    acquire(&pool_lock);
+    for(p = pool; p < &pool[NPROC]; p++) {
+        if(p->state != UNUSED && p->pid == pid) {
+            break;
+        }
+    }
+    release(&pool_lock);
+    return p;
+}
+
+
 void procinit(void)
 {
     struct proc *p;
@@ -41,6 +56,7 @@ void procinit(void)
 
 int allocpid()
 {
+    // TODO: add lock
     static int PID = 1;
     return PID++;
 }
@@ -93,6 +109,12 @@ freeproc(struct proc *p)
         proc_freepagetable(p->pagetable, p->sz);
     p->pagetable = 0;
     p->state = UNUSED;
+    for(int i = 0; i < FD_MAX; ++i) {
+        if(p->files[i] != 0) {
+            fileclose(p->files[i]);
+            p->files[i] = 0;
+        }
+    }
 }
 
 
@@ -127,7 +149,7 @@ found:
     }
     memset(&p->context, 0, sizeof(p->context));
     memset((void *)p->kstack, 0, KSTACK_SIZE);
-    debugf("memset done");
+    // debugf("memset done");
     p->context.ra = (uint64)usertrapret;    // used in swtch()
         p->context.sp = p->kstack + KSTACK_SIZE;
 
@@ -136,7 +158,10 @@ found:
     p->priority = 16;
     p->cpu_time = 0;
     p->last_start_time = 0;
-    debugf("before return");
+    if(init_mailbox(&p->mb)==0){
+        panic("init mailbox failed");
+    } 
+    // debugf("before return");
     return p;
 }
 // Return this CPU's cpu struct.
@@ -234,7 +259,7 @@ void scheduler(void)
         }
         else
         {
-            debugcore("no proc to run");
+            // debugcore("no proc to run");
             // break;
         }
     }
@@ -263,7 +288,7 @@ void sched(void)
     //     p->state = UNUSED;
     //     // exit(-1);
     // }
-    infof("before swtch");
+    // infof("before swtch");
     swtch(&p->context, &mycpu()->context);
 }
 
@@ -279,16 +304,17 @@ fork(void)
     int pid;
     struct proc *np;
     struct proc *p = curr_proc();
-    debugf("inside fork");
+    // debugf("inside fork");
 
     // Allocate process.
     if((np = allocproc()) == 0){
         panic("allocproc\n");
     }
-    debugf("inside fork allocproc done");
+    // debugf("inside fork allocproc done");
     
     // Copy user memory from parent to child.
     if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){
+        release(&np->lock);
         panic("uvmcopy\n");
     }
     np->sz = p->sz;
@@ -296,6 +322,11 @@ fork(void)
     // copy saved user registers.
     *(np->trapframe) = *(p->trapframe);
 
+    for(int i = 0; i < FD_MAX; ++i)
+        if(p->files[i] != 0 && p->files[i]->type != FD_NONE) {
+            p->files[i]->ref++;
+            np->files[i] = p->files[i];
+        }
     // Cause fork to return 0 in the child.
     np->trapframe->a0 = 0;
     pid = np->pid;
@@ -303,6 +334,8 @@ fork(void)
 
 
     np->parent = p;
+
+
     np->state = RUNNABLE;
     release(&np->lock);
     return pid;
@@ -367,6 +400,7 @@ int spawn(char* filename){
     }
     // info("load\n");
     loader(id, np);
+    release(&np->lock);
     return pid;
 }
 
@@ -398,7 +432,7 @@ wait(int pid, int* code)
             return -1;
         }
 
-        debugf("pid %d keep waiting", p->pid);
+        // debugf("pid %d keep waiting", p->pid);
         p->state = RUNNABLE;
         sched();
     }
@@ -415,4 +449,16 @@ void exit(int code) {
     }
     debugf("before sched");
     sched();
-}
\ No newline at end of file
+}
+
+int fdalloc(struct file* f) {
+    struct proc* p = curr_proc();
+    // fd = 0 is reserved for stdio/stdout
+    for(int i = 1; i < FD_MAX; ++i) {
+        if(p->files[i] == 0) {
+            p->files[i] = f;
+            return i;
+        }
+    }
+    return -1;
+}
diff --git a/os/proc.h b/os/proc.h
index 61ac685..3da3081 100644
--- a/os/proc.h
+++ b/os/proc.h
@@ -4,11 +4,12 @@
 #include "ucore.h"
 
 #include "lock.h"
-
+#include "file.h"
 #define NPROC (256)
 #define KSTACK_SIZE (4096)
 #define USTACK_SIZE (4096)
 #define TRAPFRAME_SIZE (4096)
+#define FD_MAX (16)
 enum procstate
 {
   UNUSED,
@@ -43,7 +44,10 @@ struct proc
   uint64 priority;
   uint64 cpu_time;        // ms, user and kernel
   uint64 last_start_time; // ms
+  struct file* files[16];
+  struct mailbox mb;
 };
+struct proc* findproc(int pid);
 
 struct proc *curr_proc();
 int spawn(char* filename);
diff --git a/os/syscall.c b/os/syscall.c
index 1122410..8016814 100644
--- a/os/syscall.c
+++ b/os/syscall.c
@@ -5,34 +5,20 @@
 #include "log.h"
 #include "timer.h"
 #include "riscv.h"
+#include "file.h"
 #define min(a, b) a < b ? a : b;
 
-/**
- * return TRUE if [sout, eout) contains [sin, ein)
- */
-inline int contains(char *sout, char *eout, char *sin, char *ein)
-{
-    return (sout <= sin && sin < eout) && (sout <= ein && ein <= eout) && sin <= ein;
-}
-
-uint64 sys_write(int fd, uint64 va, uint len) 
-{
-    if (fd != 1)
-        return -1;
+uint64 console_write(uint64 va, uint64 len) {
     struct proc *p = curr_proc();
     char str[200];
     int size = copyinstr(p->pagetable, str, va, MIN(len, 200));
-    // debug("size = %d\n", size);
     for(int i = 0; i < size; ++i) {
         console_putchar(str[i]);
     }
     return size;
 }
 
-uint64 sys_read(int fd, uint64 va, uint64 len) {
-    if (fd != 0)
-        return -1;
-    // read from stdin is blocking
+uint64 console_read(uint64 va, uint64 len) {
     struct proc *p = curr_proc();
     char str[200];
     for(int i = 0; i < len; ++i) {
@@ -47,6 +33,84 @@ uint64 sys_read(int fd, uint64 va, uint64 len) {
     return len;
 }
 
+/**
+ * return TRUE if [sout, eout) contains [sin, ein)
+ */
+inline int contains(char *sout, char *eout, char *sin, char *ein)
+{
+    return (sout <= sin && sin < eout) && (sout <= ein && ein <= eout) && sin <= ein;
+}
+
+uint64 sys_write(int fd, uint64 va, uint64 len) {
+    if(fd == 1) {
+        return console_write(va, len);
+    }
+    if(fd>=FD_MAX){
+        return -1;
+    }
+    infof("fd=%d\n", fd);
+    struct proc *p = curr_proc();
+    struct file *f = p->files[fd];
+    if(f==0){
+        return -1;
+    }
+    if(f->type == FD_PIPE) {
+        debugf("write to pipe at %p\n", f->pipe);
+        return pipewrite(f->pipe, va, len);
+    }
+    errorf("unknown file type %d\n", f->type);
+    panic("syswrite: unknown file type\n");
+    return -1;
+}
+
+uint64 sys_read(int fd, uint64 va, uint64 len) {
+    if(fd == 0) {
+        return console_read(va, len);
+    }
+    if(fd>=FD_MAX){
+        return -1;
+    }
+    struct proc *p = curr_proc();
+    struct file *f = p->files[fd];
+    if(f==0){
+        return -1;
+    }
+    if(f->type == FD_PIPE) {
+        debugf("read to pipe at %p\n", f->pipe);
+        return piperead(f->pipe, va, len);
+    }
+    errorf("unknown file type %d\n", f->type);
+    panic("sysread: unknown file type\n");
+    return -1;
+}
+
+uint64
+sys_pipe(uint64 fdarray) {
+    infof("init pipe\n");
+    struct proc *p = curr_proc();
+    uint64 fd0, fd1;
+    struct file* f0, *f1;
+    if(f0 < 0 || f1 < 0) {
+        return -1;
+    }
+    f0 = filealloc();
+    f1 = filealloc();
+    if(pipealloc(f0, f1) < 0)
+        return -1;
+    fd0 = fdalloc(f0);
+    fd1 = fdalloc(f1);
+    if(copyout(p->pagetable, fdarray, (char*)&fd0, sizeof(fd0)) < 0 ||
+       copyout(p->pagetable, fdarray+sizeof(uint64), (char *)&fd1, sizeof(fd1)) < 0){
+        fileclose(f0);
+        fileclose(f1);
+        p->files[fd0] = 0;
+        p->files[fd1] = 0;
+        return -1;
+    }
+    return 0;
+}
+
+
 
 uint64 sys_exit(int code)
 {
@@ -108,7 +172,19 @@ int64 sys_gettimeofday(uint64 *timeval, int tz){
 
     return 0;
 }
-
+uint64 sys_close(int fd) {
+    if(fd == 0)
+        return 0;
+    struct proc *p = curr_proc();
+    struct file *f = p->files[fd];
+    if(f->type != FD_PIPE) {
+        errorf("unknown file type %d\n", f->type);
+        panic("fileclose: unknown file type\n");
+    }
+    fileclose(f);
+    p->files[fd] = 0;
+    return 0;
+}
 int64 sys_mmap(void* start, uint64 len, int prot){
     if(len ==0) return 0;
 
@@ -191,13 +267,124 @@ int64 sys_munmap(void* start, uint64 len){
 int sys_spawn(char* filename){
     return spawn(filename);
 }
+int sys_mailread(void* buf, int len){
+    infof("mailread\n");
+    if(len>256){
+        len = 256;
+    }
+    if(len<0){
+        return -1;
+    }
+    struct proc* p = curr_proc();
+    
+    struct mailbox *inbox = &(p->mb);
+
+    acquire(&inbox->lock);
+    if(len == 0){
+        for (int i = 0; i < MAX_MAIL_IN_BOX; i++)
+        {
+            if(inbox->valid[i]){
+                release(&inbox->lock);
+                return 0;
+            }
+        }
+        release(&inbox->lock);
+        return -1;
+    }
+
+
+    // read head mail
+    int head_idx = inbox->head;
+    if (inbox->valid[head_idx]){
+        int msg_len = inbox->length[head_idx];
+        int copy_len = min(msg_len, len);
+        int eret = copyout(p->pagetable, (uint64)buf, inbox->mailbuf[head_idx], copy_len);
+        if (eret <0){
+            infof("copyout failed\n");
+            release(&inbox->lock);
+            return -1;
+        }
+        inbox->valid[inbox->head] = 0;
+        inbox->head+=1;
+        inbox->head = (inbox->head) % MAX_MAIL_IN_BOX;
+        release(&inbox->lock)
+        infof("read mail %d bytes\n", copy_len);
+        return copy_len;
+    }else{
+        // mail box is empty
+        release(&inbox->lock);
+        infof("mail box is empty\n");
+        return -1;
+    }
+
+
+}
+
+int sys_mailwrite(int pid, void*buf, int len){
+    infof("mailwrite\n");
+    if(len>256){
+        len = 256;
+    }
+    if(len<0){
+        return -1;
+    }
+    struct proc* cur_p = curr_proc();
+
+    struct proc* p = findproc(pid);
+    if( p == 0 ){return -1;}
+    struct mailbox *dest = &(p->mb);
+
+    acquire(&dest->lock);
+
+    if (len == 0 ){
+        for (int i = 0; i < MAX_MAIL_IN_BOX; i++)
+        {
+            if(!(dest->valid[i])){
+                // empty slot
+                release(&dest->lock);
+                return 0;
+            }
+        }
+        release(&dest->lock);
+        return -1;
+    }
+
+
+    // write mail
+    int head_idx = dest->head;
+    for (int j = 0; j < MAX_MAIL_IN_BOX; j++)
+    {
+        if (dest->valid[j] != 0){
+            // not empty, find next
+        }else{
+            // empty, write to this one
+            int eret = copyin(cur_p->pagetable, dest->mailbuf[j], (uint64)buf, len);
+            if(eret <0){
+                infof("copyin failed\n");
+                release(&dest->lock);
+                return -1;
+            }
+            dest->valid[j] = 1;
+            dest->length[j]=len;
+            release(&dest->lock);
+            return len;
+        }
+        head_idx+=1;
+        head_idx = head_idx % MAX_MAIL_IN_BOX;
+    }
+
+    // all filled
+    release(&dest->lock);
+    return -1;
+    
+}
 
 void syscall() {
     struct proc *p = curr_proc();
     struct trapframe *trapframe = p->trapframe;
     int id = trapframe->a7, ret;
     uint64 args[7] = {trapframe->a0, trapframe->a1, trapframe->a2, trapframe->a3, trapframe->a4, trapframe->a5, trapframe->a6};
-    if (id != SYS_write){
+    if (id != SYS_write && id != SYS_read){
     debugf("syscall %d args:%p %p %p %p %p %p %p\n", id, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);}
     switch (id) {
         case SYS_write:
@@ -247,10 +434,22 @@ void syscall() {
         case SYS_spawn:
             ret = sys_spawn((char*)args[0]);
             break;
+        case SYS_pipe2:
+            ret = sys_pipe(args[0]);
+            break;
+        case SYS_close:
+            ret = sys_close(args[0]);
+            break;
+        case SYS_mailread:
+            ret = sys_mailread((void*)args[0], args[1]);
+            break;
+        case SYS_mailwrite:
+            ret = sys_mailwrite(args[0], (void*)args[1], args[2]);
+            break;
         default:
             ret = -1;
             warnf("unknown syscall %d\n", id);
     }
     trapframe->a0 = ret;
-    if (id != SYS_write){debugf("syscall ret %d\n", ret);}
+    if (id != SYS_write && id != SYS_read){debugf("syscall ret %d\n", ret);}
 }
\ No newline at end of file
diff --git a/os/syscall_ids.h b/os/syscall_ids.h
index 5fdca9a..4e40da4 100644
--- a/os/syscall_ids.h
+++ b/os/syscall_ids.h
@@ -282,6 +282,8 @@
 #define SYS_rseq 293
 #define SYS_kexec_file_load 294
 #define SYS_spawn 400
+#define SYS_mailread 401
+#define SYS_mailwrite 402
 #define SYS_pidfd_send_signal 424
 #define SYS_io_uring_setup 425
 #define SYS_io_uring_enter 426
diff --git a/os/timer.c b/os/timer.c
index d3696fc..6de2300 100644
--- a/os/timer.c
+++ b/os/timer.c
@@ -19,7 +19,7 @@ void timerinit() {
 /// Set the next timer interrupt
 void set_next_timer() {
     // 100Hz @ QEMU
-    uint64 timebase = CPU_FREQ / TICKS_PER_SEC; 
+    const uint64 timebase = CPU_FREQ / TICKS_PER_SEC; 
     set_timer(get_cycle() + timebase);
 }
 
diff --git a/os/vm.c b/os/vm.c
index dcc83c6..74f81b6 100644
--- a/os/vm.c
+++ b/os/vm.c
@@ -144,11 +144,11 @@ int mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
     uint64 a, last;
     pte_t *pte;
 
-    debugf("va=%p->pa=%p, size=%p, UXWR=%d%d%d%d", va, pa, size,
-           HAS_BIT(perm, PTE_U),
-           HAS_BIT(perm, PTE_X),
-           HAS_BIT(perm, PTE_W),
-           HAS_BIT(perm, PTE_R));
+    // debugf("va=%p->pa=%p, size=%p, UXWR=%d%d%d%d", va, pa, size,
+    //        HAS_BIT(perm, PTE_U),
+    //        HAS_BIT(perm, PTE_X),
+    //        HAS_BIT(perm, PTE_W),
+    //        HAS_BIT(perm, PTE_R));
     a = PGROUNDDOWN(va);
     last = PGROUNDDOWN(va + size - 1);
     // int cnt =0 ;
@@ -178,11 +178,11 @@ int map1page(pagetable_t pagetable, uint64 va, uint64 pa, int perm)
     uint64 a;
     pte_t *pte;
     uint64 size = PGSIZE;
-    debugf("va=%p->pa=%p, size=%p, UXWR=%d%d%d%d", va, pa, size,
-           HAS_BIT(perm, PTE_U),
-           HAS_BIT(perm, PTE_X),
-           HAS_BIT(perm, PTE_W),
-           HAS_BIT(perm, PTE_R));
+    // debugf("va=%p->pa=%p, size=%p, UXWR=%d%d%d%d", va, pa, size,
+    //        HAS_BIT(perm, PTE_U),
+    //        HAS_BIT(perm, PTE_X),
+    //        HAS_BIT(perm, PTE_W),
+    //        HAS_BIT(perm, PTE_R));
     a = PGROUNDDOWN(va);
 
     if ((pte = walk(pagetable, a, 1)) == 0)
@@ -243,7 +243,7 @@ uvmcreate()
     //     uvmfree(pagetable, 0);
     //     return 0;
     // }
-    debugf("map user trampoline\n");
+    // debugf("map user trampoline\n");
     return pagetable;
 }
 
diff --git a/user/include/unistd.h b/user/include/unistd.h
index 826f134..65b73cd 100644
--- a/user/include/unistd.h
+++ b/user/include/unistd.h
@@ -5,8 +5,8 @@
 
 int open(const char*, int, int);
 
-ssize_t read(int, void*, size_t);
-ssize_t write(int, const void*, size_t);
+ssize_t read(int, void*, unsigned long long);
+ssize_t write(int, const void*, unsigned long long);
 
 int close(int);
 pid_t getpid(void);
@@ -15,6 +15,7 @@ void exit(int);
 int fork(void);
 int exec(char*);
 int wait(int, int*);
+int pipe(void*);
 uint64 get_time();
 int sleep(unsigned long long);
 #endif // __UNISTD_H__
diff --git a/user/lib/stdio.c b/user/lib/stdio.c
index cb11643..d5196b8 100644
--- a/user/lib/stdio.c
+++ b/user/lib/stdio.c
@@ -11,8 +11,9 @@ int getchar() {
 
 int putchar(int c)
 {
-    char byte = c;
-    return write(stdout, &byte, 1);
+    static char put[2] = {0, 0};
+    put[0] = c;
+    return write(stdout, put, 1);
 }
 
 int puts(const char* s)
diff --git a/user/lib/syscall.c b/user/lib/syscall.c
index 6dd236a..d562224 100644
--- a/user/lib/syscall.c
+++ b/user/lib/syscall.c
@@ -11,11 +11,11 @@ int close(int fd) {
     return syscall(SYS_close, fd);
 }
 
-ssize_t read(int fd, void *buf, size_t len) {
+ssize_t read(int fd, void *buf, unsigned long long len) {
     return syscall(SYS_read, fd, buf, len);
 }
 
-ssize_t write(int fd, const void *buf, size_t len) {
+ssize_t write(int fd, const void *buf, unsigned long long len) {
     return syscall(SYS_write, fd, buf, len);
 }
 
@@ -53,4 +53,8 @@ int sleep(unsigned long long time) {
         sched_yield();
     }
     return 0;
+}
+
+int pipe(void* p) {
+    return syscall(SYS_pipe2, p);
 }
\ No newline at end of file
diff --git a/user/src/pipetest.c b/user/src/pipetest.c
new file mode 100644
index 0000000..dac6d81
--- /dev/null
+++ b/user/src/pipetest.c
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+char STR[] = "hello pipe!";
+
+int main() {
+    // create pipe
+    uint64 pipe_fd[2];
+    int ret = pipe((void*)&pipe_fd);
+    assert(ret == 0, -2);
+    printf("[parent] read end = %p, write end = %p\n", pipe_fd[0], pipe_fd[1]);
+    if (fork() == 0) {
+        // child process, read from parent
+        // close write_end
+        close(pipe_fd[1]);
+        puts("[child] close write end");
+        char buffer[32 + 1];
+        int len_read = read(pipe_fd[0], buffer, 32);
+        puts("[chile] read over");
+        // assert(len_read < 32);
+        buffer[len_read] = 0;
+        assert(strncmp(buffer, STR, strlen(STR)) == 0, -3);
+        puts("Read OK, child process exited!");
+        return 0;
+    } else {
+        // parent process, write to child
+        // close read end
+        close(pipe_fd[0]);
+        printf("[parent] close read end\n");
+        assert(write(pipe_fd[1], STR, strlen(STR)) == strlen(STR), -3);
+        printf("[parent] write over\n");
+        // close write end
+        close(pipe_fd[1]);
+        int exit_code = 0;
+        wait(-1, &exit_code);
+        assert(exit_code == 0, -2);
+        puts("pipetest passed!");
+    }
+    return 0;
+}
+
diff --git a/user/src/user_shell.c b/user/src/user_shell.c
index 678df6e..f023091 100644
--- a/user/src/user_shell.c
+++ b/user/src/user_shell.c
@@ -2,12 +2,14 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+
 const unsigned char LF = 0x0a;
 const unsigned char CR = 0x0d;
 const unsigned char DL = 0x7f;
 const unsigned char BS = 0x08;
 
 char line[100] = {};
+
 int top = 0;
 
 void push(char c) {
@@ -68,6 +70,7 @@ int main() {
             default:
                 putchar(c);
                 push(c);
+                break;
         }
     }
     return 0;
-- 
GitLab