diff --git a/Makefile b/Makefile
index a2784fd85a10e7b0aa44d17fc70491615b140e71..943d551556378b98a21fd768f63c7bba9901bcc8 100644
--- a/Makefile
+++ b/Makefile
@@ -144,7 +144,10 @@ UPROGS=\
 	$U/_mutest2\
 	$U/_rocky\
 	$U/_watchdog-panic\
-
+	$U/_sbrk-dealloc\
+	$U/_suicide\
+	$U/_rwtest\
+	$U/_naivefib\
 
 fs.img: mkfs/mkfs README $(UPROGS)
 	mkfs/mkfs fs.img README $(UPROGS)
diff --git a/kernel/defs.h b/kernel/defs.h
index df618ee9cfef725a67d08bc5499dca33db4eb697..1b78d7397937fd1c07fca7b1ac8505e2044d4815 100644
--- a/kernel/defs.h
+++ b/kernel/defs.h
@@ -94,7 +94,7 @@ int             cpuid(void);
 void            exit(int);
 int             fork(void);
 int             nice(int,int);
-int             growproc(int);
+int             growproc(long);
 pagetable_t     proc_pagetable(struct proc *);
 void            proc_freepagetable(pagetable_t, uint64);
 int             kill(int);
@@ -114,7 +114,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);
 void            priodump(void);
-
+void            proc_vmprint(struct proc* p);
 // swtch.S
 void            swtch(struct context*, struct context*);
 
@@ -183,13 +183,15 @@ 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 pt, uint64 pid, char* cmd);
 // plic.c
 void            plicinit(void);
 void            plicinithart(void);
 int             plic_claim(void);
 void            plic_complete(int);
 
+int allocate_if_possible(pagetable_t pagetable, struct proc*, uint64 addr);
+
 // virtio_disk.c
 void            virtio_disk_init(int);
 void            virtio_disk_rw(int, struct buf *, int);
@@ -219,4 +221,9 @@ void *lst_pop(struct list*);
 void lst_print(struct list*);
 int lst_empty(struct list*);
 
+#define ENOVMA     (-(1L << 1))
+#define ENOMEM     (-(1L << 2))
+#define ENOFILE    (-(1L << 3))
+#define EMAPFAILED (-(1L << 4))
+
 #endif
diff --git a/kernel/exec.c b/kernel/exec.c
index fb729251d872e673eedd1011f9234d3dc878009e..69f8b403e0dea2860080384e6a6d36cfccf7230c 100644
--- a/kernel/exec.c
+++ b/kernel/exec.c
@@ -32,31 +32,47 @@ exec(char *path, char **argv)
   ilock(ip);
 
   // Check ELF header
-  if(readi(ip, 0, (uint64)&elf, 0, sizeof(elf)) != sizeof(elf))
+  if(readi(ip, 0, (uint64)&elf, 0, sizeof(elf)) != sizeof(elf)){
+    printf("exec: readi error\n");
     goto bad;
-  if(elf.magic != ELF_MAGIC)
+  }
+  if(elf.magic != ELF_MAGIC){
+    printf("exec: bad number error\n");
     goto bad;
-
-  if((pagetable = proc_pagetable(p)) == 0)
+  }
+  if((pagetable = proc_pagetable(p)) == 0){
+    printf("exec: proc_pagetable error\n");
     goto bad;
+  }
 
   // Load program into memory.
   sz = 0;
   for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
-    if(readi(ip, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph))
-      goto bad;
+    if(readi(ip, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph)){
+      printf("exec: program header error\n");
+    }
     if(ph.type != ELF_PROG_LOAD)
       continue;
-    if(ph.memsz < ph.filesz)
+    if(ph.memsz < ph.filesz){
+      printf("exec: program header memsz < filesz\n");
       goto bad;
-    if(ph.vaddr + ph.memsz < ph.vaddr)
+    }
+    if(ph.vaddr + ph.memsz < ph.vaddr){
+      printf("exec: program header vaddr + memsz < vaddr\n");
       goto bad;
-    if((sz = uvmalloc(pagetable, sz, ph.vaddr + ph.memsz)) == 0)
+    }
+    if((sz = uvmalloc(pagetable, sz, ph.vaddr + ph.memsz)) == 0){
+      printf("exec: uvmalloc failed\n");
       goto bad;
-    if(ph.vaddr % PGSIZE != 0)
+    }
+    if(ph.vaddr % PGSIZE != 0){
+      printf("exec: vaddr not page aligned\n");
       goto bad;
-    if(loadseg(pagetable, ph.vaddr, ip, ph.off, ph.filesz) < 0)
+    }
+    if(loadseg(pagetable, ph.vaddr, ip, ph.off, ph.filesz) < 0){
+      printf("exec: loadseg failed\n");
       goto bad;
+    }
   }
   iunlockput(ip);
   end_op(ROOTDEV);
@@ -68,22 +84,30 @@ exec(char *path, char **argv)
   // Allocate two pages at the next page boundary.
   // Use the second as the user stack.
   sz = PGROUNDUP(sz);
-  if((sz = uvmalloc(pagetable, sz, sz + 2*PGSIZE)) == 0)
+  if((sz = uvmalloc(pagetable, sz, sz + 2*PGSIZE)) == 0){
+    printf("exec: uvmalloc failed for the stack\n");
     goto bad;
+  }
   uvmclear(pagetable, sz-2*PGSIZE);
   sp = sz;
   stackbase = sp - PGSIZE;
 
   // Push argument strings, prepare rest of stack in ustack.
   for(argc = 0; argv[argc]; argc++) {
-    if(argc >= MAXARG)
+    if(argc >= MAXARG){
+      printf("exec: too many args\n");
       goto bad;
+    }
     sp -= strlen(argv[argc]) + 1;
     sp -= sp % 16; // riscv sp must be 16-byte aligned
-    if(sp < stackbase)
+    if(sp < stackbase){
+      printf("exec: sp < stackbase\n");
       goto bad;
-    if(copyout(pagetable, sp, argv[argc], strlen(argv[argc]) + 1) < 0)
+    }
+    if(copyout(pagetable, sp, argv[argc], strlen(argv[argc]) + 1) < 0){
+      printf("exec: copy argument strings failed\n");
       goto bad;
+    }
     ustack[argc] = sp;
   }
   ustack[argc] = 0;
@@ -91,10 +115,14 @@ exec(char *path, char **argv)
   // push the array of argv[] pointers.
   sp -= (argc+1) * sizeof(uint64);
   sp -= sp % 16;
-  if(sp < stackbase)
+  if(sp < stackbase){
+    printf("exec: sp < stackbase, le retour\n");
     goto bad;
-  if(copyout(pagetable, sp, (char *)ustack, (argc+1)*sizeof(uint64)) < 0)
+  }
+  if(copyout(pagetable, sp, (char *)ustack, (argc+1)*sizeof(uint64)) < 0){
+    printf("exec: copy argument pointers failed\n");
     goto bad;
+  }
 
   // arguments to user main(argc, argv)
   // argc is returned via the system call return
diff --git a/kernel/kalloc.c b/kernel/kalloc.c
index 12e64af1a2567ad8763a88359fa86f4d5597c996..30c919ac3f5678dd5ab2ebddb6a2054d61fc4d3c 100644
--- a/kernel/kalloc.c
+++ b/kernel/kalloc.c
@@ -35,5 +35,7 @@ kfree(void *pa)
 void *
 kalloc(void)
 {
-  return bd_malloc(PGSIZE);
+  char* mem = bd_malloc(PGSIZE);
+  if(mem) memset(mem, 0, PGSIZE);
+  return mem;
 }
diff --git a/kernel/memlayout.h b/kernel/memlayout.h
index a9fc66cc5272d4431eb3669af688cff2a3662f12..d5a2f9a34a745f3f5f815543e80325054054eb47 100644
--- a/kernel/memlayout.h
+++ b/kernel/memlayout.h
@@ -70,4 +70,10 @@
 //   TRAMPOLINE (the same page as in the kernel)
 #define TRAPFRAME (TRAMPOLINE - PGSIZE)
 
+#define HEAP_THRESHOLD (8*1024*1024)
+
+#define USTACK_BOTTOM (256*1024*1024)
+#define USTACK_LIMIT (4 * 1024)
+#define USTACK_TOP (USTACK_BOTTOM + USTACK_LIMIT)
+
 #endif
diff --git a/kernel/proc.c b/kernel/proc.c
index 4efe499c7707456a47cffef30f114ddbba3e4871..a69b9fa578cfb89c25f4266c345986744d3767cf 100644
--- a/kernel/proc.c
+++ b/kernel/proc.c
@@ -14,7 +14,7 @@ struct cpu cpus[NCPU];
 struct proc proc[NPROC];
 
 struct list_proc* prio[NPRIO];
-struct spinlock prio_lock;
+struct spinlock prio_lock[NPRIO];
 
 struct proc *initproc;
 
@@ -26,60 +26,131 @@ static void wakeup1(struct proc *chan);
 
 extern char trampoline[]; // trampoline.S
 
-/* Solution insert et remove
+/* Ajoute une VMA à la liste de VMAs d'un processus.
+ * Prend le début et la fin de la VMA en paramètre.
+ * Retourne un pointeur vers la nouvelle entrée.
+ */
+struct vma* add_memory_area(struct proc* p,
+                            uint64 va_begin,
+                            uint64 va_end){
+  acquire(&p->vma_lock);
+  struct vma* entry = bd_malloc(sizeof(struct vma));
+  if(!entry){
+    panic("bd_malloc failed\n");
+  }
+  entry->va_begin = va_begin;
+  entry->va_end = va_end;
+  entry->next = p->memory_areas;
+  entry->file = 0;
+  entry->vma_flags = 0;
+  entry->file_offset = 0;
+  entry->file_nbytes = 0;
+  p->memory_areas = entry;
+  release(&p->vma_lock);
+  return entry;
+}
 
-// Needs lock on p and prio_lock[p->priority]
-void insert_into_prio_queue(struct proc* p){
-  struct list_proc* new = bd_malloc(sizeof(struct list_proc));
-  new->next = 0;
-  new->p = p;
-  if(!prio[p->priority]){
-    prio[p->priority] = new;
+/* Libère une liste de VMAs. Suppose qu'on tient un verrou sur cette liste. */
+void free_vma(struct vma* vmas){
+  struct vma* ma = vmas;
+  while(ma){
+    struct vma* old = ma;
+    ma = ma -> next;
+    bd_free(old);
   }
-  else {
-    struct list_proc* last = prio[p->priority];
-    while(last && last->next){
-      last = last->next;
+}
+
+/* Récupère la VMA associée à une adresse virtuelle, ou 0 si aucune VMA n'est
+ * associée à cette adresse.
+ * Nécessite que le verrou p->vma_lock soit tenu.
+ */
+struct vma* get_memory_area(struct proc* p, uint64 va){
+  if(!holding(&p->vma_lock)){
+    panic("get_memory_area: should hold vma_lock!\n");
+  }
+  struct vma* ma = p->memory_areas;
+  while(ma){
+    if (ma->va_begin <= va && va < ma->va_end){
+      return ma;
     }
-    last->next = new;
+    ma = ma -> next;
   }
+  return 0;
 }
 
-// Needs lock on p and prio_lock[p->priority]
-void remove_from_prio_queue(struct proc* p){
-  struct list_proc* old = prio[p->priority];
-  struct list_proc* prev = 0;
-  struct list_proc* head = old;
+/* Retourne l'adresse maximale utilisée par l'ensemble des VMAs. */
+uint64 max_addr_in_memory_areas(struct proc* p){
+  acquire(&p->vma_lock);
+  struct vma* ma = p->memory_areas;
+  uint64 max = 0;
+  while(ma){
+    if (ma->va_end > max) max =  ma->va_end;
+    ma = ma->next;
+  }
+  release(&p->vma_lock);
+  return max;
+}
 
-  while(old){
-    if(old->p == p) {
-      if(old == head){
-        head = old->next;
-      } else {
-        prev->next = old->next;
-      }
-      bd_free(old);
-      break;
-    }
-    prev = old;
-    old = old->next;
+/* Affiche une VMA. */
+void print_memory_area(struct proc* p, struct vma* ma){
+  printf("VA = [%p; %p[ RWX=%d%d%d",
+         ma->va_begin, ma->va_end,
+         (ma->vma_flags & VMA_R) != 0,
+         (ma->vma_flags & VMA_W) != 0,
+         (ma->vma_flags & VMA_X) != 0
+    );
+  if(ma->file){
+    printf(" file=%s off=0x%x n=0x%x", ma->file, ma->file_offset, ma->file_nbytes);
   }
+  if(ma == p->stack_vma) printf(" [stack]");
+  if(ma == p->heap_vma) printf(" [heap]");
+  printf("\n");
+}
 
-  prio[p->priority] = head;
+/* Affiche la liste de VMAs associée à un processus. */
+void print_memory_areas(struct proc* p){
+  struct vma* ma = p->memory_areas;
+  printf("Memory areas:\n");
+  while(ma){
+    print_memory_area(p, ma);
+    ma = ma -> next;
+  }
+  printf("==============\n");
 }
- */
+
+/* Copie les VMAs d'un processus [psrc] vers un processus [pdst]. */
+void vma_copy(struct proc * pdst, struct proc* psrc){
+  acquire(&psrc->vma_lock);
+  struct vma * ma = psrc->memory_areas;
+  while(ma){
+    struct vma* new_vma = add_memory_area(pdst, ma->va_begin, ma->va_end);
+    if(ma->file)
+      new_vma->file = strdup(ma->file);
+    else
+      new_vma->file = 0;
+    new_vma->file_offset = ma->file_offset;
+    new_vma->file_nbytes = ma->file_nbytes;
+    new_vma->vma_flags = ma->vma_flags;
+    if(ma == psrc->stack_vma) pdst->stack_vma = new_vma;
+    if(ma == psrc->heap_vma) pdst->heap_vma = new_vma;
+    ma = ma->next;
+  }
+  release(&psrc->vma_lock);
+}
+
 
 void
 procinit(void)
 {
   struct proc *p;
-  initlock(&prio_lock, "priolock");
   for(int i = 0; i < NPRIO; i++){
+    initlock(&prio_lock[i], "priolock");
     prio[i] = 0;
   }
   initlock(&pid_lock, "nextpid");
   for(p = proc; p < &proc[NPROC]; p++) {
       initlock(&p->lock, "proc");
+      initlock(&p->vma_lock, "vma");
 
       // Allocate a page for the process's kernel stack.
       // Map it high in memory, followed by an invalid
@@ -167,6 +238,7 @@ found:
   p->pagetable = proc_pagetable(p);
 
   p->priority = DEF_PRIO;
+  p->memory_areas = 0;
 
   // Set up new context to start executing at forkret,
   // which returns to user space.
@@ -193,6 +265,12 @@ freeproc(struct proc *p)
   p->cmd = 0;
   p->priority = 0;
   p->pagetable = 0;
+  acquire(&p->vma_lock);
+  free_vma(p->memory_areas);
+  release(&p->vma_lock);
+  p->memory_areas = 0;
+  p->stack_vma = 0;
+  p->heap_vma = 0;
   p->sz = 0;
   p->pid = 0;
   p->parent = 0;
@@ -279,9 +357,9 @@ userinit(void)
 // Grow or shrink user memory by n bytes.
 // Return 0 on success, -1 on failure.
 int
-growproc(int n)
+growproc(long n)
 {
-  uint sz;
+  uint64 sz;
   struct proc *p = myproc();
 
   sz = p->sz;
@@ -316,6 +394,7 @@ fork(void)
     release(&np->lock);
     return -1;
   }
+  vma_copy(np, p);
   np->sz = p->sz;
 
   np->parent = p;
@@ -764,3 +843,8 @@ void priodump(void){
     printf("\n");
   }
 }
+
+void proc_vmprint(struct proc* p){
+  vmprint(p->pagetable, p->pid, p->cmd);
+  print_memory_areas(p);
+}
diff --git a/kernel/proc.h b/kernel/proc.h
index 9d1def65df2dfb4a23245a8e562a4dee9197716a..30ef880fbfcb9b68536d22bb89211dea62f886ed 100644
--- a/kernel/proc.h
+++ b/kernel/proc.h
@@ -87,6 +87,45 @@ struct trapframe {
   /* 280 */ uint64 t6;
 };
 
+/* La structure qui représente une VMA (Virtual Memory Area). */
+struct vma {
+  /* C'est une structure de liste chaînée : le pointeur next pointe sur la
+   * prochaine VMA dans la liste. */
+  struct vma * next;
+
+  /* Le début et la fin de la VMA. */
+  uint64 va_begin;
+  uint64 va_end;
+
+  /* Éventuellement, cette VMA peut être peuplée par le contenu d'un fichier. Si
+   * c'est le cas, [file] donne le nom du fichier, [file_offset] le déplacement
+   * dans le fichier, et [file_nbytes] le nombre d'octets à lire dans le
+   * fichier.
+   *
+   * Par exemple, si [file_offset] vaut 0x300, [file_nbytes] vaut 0x60, [file]
+   * vaut "toto", [va_begin] vaut 0x1000 et [va_end] vaut 0x1fff, alors on
+   * chargera les octets 0x300-0x35f aux adresses virtuelles 0x1000-0x105f, et
+   * les adresses virtuelles 0x1060-0x1fff seront remplies de 0.
+   */
+  char* file;
+  uint64 file_offset;
+  uint64 file_nbytes;
+
+  /* Les permissions de cette VMA. (VMA_R, VMA_W, VMA_X) */
+  unsigned char vma_flags;
+};
+
+#define VMA_R (1 << 1)
+#define VMA_W (1 << 2)
+#define VMA_X (1 << 3)
+
+struct vma* add_memory_area(struct proc*, uint64, uint64);
+struct vma* get_memory_area(struct proc*, uint64);
+void print_memory_areas(struct proc*);
+void print_memory_area(struct proc*, struct vma*);
+uint64 max_addr_in_memory_areas(struct proc*);
+void free_vma(struct vma*);
+
 enum procstate { UNUSED, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
 
 // Per-process state
@@ -106,6 +145,10 @@ struct proc {
   // these are private to the process, so p->lock need not be held.
   uint64 kstack;               // Virtual address of kernel stack
   uint64 sz;                   // Size of process memory (bytes)
+  struct spinlock vma_lock;
+  struct vma * memory_areas;   // VMAs du processus
+  struct vma * stack_vma;      // Une VMA particulière pour la pile
+  struct vma * heap_vma;       // Une VMA particulière pour le tas
   pagetable_t pagetable;       // Page table
   struct trapframe *tf;        // data page for trampoline.S
   struct context context;      // swtch() here to run process
diff --git a/kernel/spinlock.c b/kernel/spinlock.c
index 56e08208624c70ac667940b6c32f88ccc0bafe3f..a4102577714b2aa3f903d8dfae958e48a055ef9a 100644
--- a/kernel/spinlock.c
+++ b/kernel/spinlock.c
@@ -28,7 +28,23 @@ initlock(struct spinlock *lk, char *name)
   nlock++;
 }
 
-#define MAXTRIES 100000
+
+void dump_locks(void){
+  printf_no_lock("LID\tLOCKED\tCPU\tPID\tNAME\t\tPC\n");
+  for(int i = 0; i < nlock; i++){
+    if(locks[i]->locked)
+      printf_no_lock("%d\t%d\t%d\t%d\t%s\t\t%p\n",
+                     i,
+                     locks[i]->locked,
+                     locks[i]->cpu - cpus,
+                     locks[i]->pid,
+                     locks[i]->name,
+                     locks[i]->pc
+        );
+  }
+}
+
+#define MAXTRIES 2000000
 
 // Acquire the lock.
 // Loops (spins) until the lock is acquired.
diff --git a/kernel/spinlock.h b/kernel/spinlock.h
index 1493600c8be481dfae25c422bebe5182193fbba5..45d12ed783305fa43c9e0400773cc0247e991c95 100644
--- a/kernel/spinlock.h
+++ b/kernel/spinlock.h
@@ -14,4 +14,6 @@ struct spinlock {
   uint nts;
 };
 
+void dump_locks(void);
+
 #endif
diff --git a/kernel/sysproc.c b/kernel/sysproc.c
index e4e45c863645dac54e0405a5d9fcc5aaf904278b..17587dc5f3599c7c38b53617898d937b380387eb 100644
--- a/kernel/sysproc.c
+++ b/kernel/sysproc.c
@@ -41,13 +41,13 @@ sys_wait(void)
 uint64
 sys_sbrk(void)
 {
-  int addr;
-  int n;
+  uint64 addr;
+  uint64 n;
 
-  if(argint(0, &n) < 0)
+  if(argaddr(0, &n) < 0)
     return -1;
   addr = myproc()->sz;
-  if(growproc(n) < 0)
+  if(growproc((long)n) < 0)
     return -1;
   return addr;
 }
diff --git a/kernel/trap.c b/kernel/trap.c
index 78c97a5a42116cc72852d9bb89eefe40c3d2704a..4a0dd922430f160eded85e55a3aa72c27976437e 100644
--- a/kernel/trap.c
+++ b/kernel/trap.c
@@ -33,6 +33,31 @@ trapinithart(void)
   w_stvec((uint64)kernelvec);
 }
 
+int handle_page_fault(struct proc* p, uint64 scause, uint64 stval, uint64 sepc){
+  uint64 addr = PGROUNDDOWN(stval);
+  acquire(&p->vma_lock);
+  int flags = allocate_if_possible(p->pagetable, p, addr);
+  release(&p->vma_lock);
+  if(flags < 0){
+    if(flags == ENOVMA){
+      printf("Could not find VMA associated with addr=%p\n", addr);
+    } else if (flags == ENOMEM){
+      printf("No more memory could be allocated from the kernel\n");
+    } else if (flags == ENOFILE){
+      printf("Could not read file associated with memory area\n");
+    } else if (flags == EMAPFAILED){
+      printf("mappages failed for an unknown reason\n");
+    }
+
+    proc_vmprint(p);
+    printf("unrecoverable page fault by pid=%d at sepc=%p stval=%p scause=%x\n",
+           p->pid, sepc, stval, scause);
+    p->killed = 1;
+    return -1;
+  }
+  return 0;
+}
+
 //
 // handle an interrupt, exception, or system call from user space.
 // called from trampoline.S
@@ -53,8 +78,10 @@ usertrap(void)
   
   // save user program counter.
   p->tf->epc = r_sepc();
-  
-  if(r_scause() == 8){
+
+  uint64 scause = r_scause();
+
+  if(scause == 8){
     // system call
 
     if(p->killed)
@@ -69,6 +96,8 @@ usertrap(void)
     intr_on();
 
     syscall();
+  } else if (scause == 0xf || scause == 0xd) {
+    handle_page_fault(p, scause, r_stval(), r_sepc());
   } else if((which_dev = devintr()) != 0){
     // ok
   } else {
diff --git a/kernel/vm.c b/kernel/vm.c
index dd651843f8e609edde41fdf446fc3834fdaf2d29..3d849fe16537a2642c0f8696a550a78abd57aaf4 100644
--- a/kernel/vm.c
+++ b/kernel/vm.c
@@ -182,11 +182,10 @@ uvmunmap(pagetable_t pagetable, uint64 va, uint64 size, int do_free)
 {
   uint64 a, last;
   pte_t *pte;
-  uint64 pa;
 
   a = PGROUNDDOWN(va);
   last = PGROUNDDOWN(va + size - 1);
-  for(;;){
+  for(; a <= last; a+=PGSIZE){
     if((pte = walk(pagetable, a, 0)) == 0)
       panic("uvmunmap: walk");
     if((*pte & PTE_V) == 0){
@@ -196,14 +195,9 @@ uvmunmap(pagetable_t pagetable, uint64 va, uint64 size, int do_free)
     if(PTE_FLAGS(*pte) == PTE_V)
       panic("uvmunmap: not a leaf");
     if(do_free){
-      pa = PTE2PA(*pte);
-      kfree((void*)pa);
+      kfree((void*)PTE2PA(*pte));
     }
     *pte = 0;
-    if(a == last)
-      break;
-    a += PGSIZE;
-    pa += PGSIZE;
   }
 }
 
@@ -359,6 +353,14 @@ uvmclear(pagetable_t pagetable, uint64 va)
   *pte &= ~PTE_U;
 }
 
+int allocate_if_possible(pagetable_t pagetable, struct proc* p, uint64 addr){
+  return 0;
+}
+
+int allocate_if_possible_range(pagetable_t pagetable, struct proc* p, uint64 addr, uint64 len){
+  return 0;
+}
+
 // Copy from kernel to user.
 // Copy len bytes from src to virtual address dstva in a given page table.
 // Return 0 on success, -1 on error.
@@ -367,6 +369,9 @@ copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
 {
   uint64 n, va0, pa0;
 
+  int f = allocate_if_possible_range(pagetable, myproc(), dstva, len);
+  if(f < 0) return -1;
+
   while(len > 0){
     va0 = PGROUNDDOWN(dstva);
     pa0 = walkaddr(pagetable, va0);
@@ -392,6 +397,9 @@ copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)
 {
   uint64 n, va0, pa0;
 
+  int f = allocate_if_possible_range(pagetable, myproc(), srcva, len);
+  if(f < 0) return -1;
+
   while(len > 0){
     va0 = PGROUNDDOWN(srcva);
     pa0 = walkaddr(pagetable, va0);
@@ -418,12 +426,21 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
 {
   uint64 n, va0, pa0;
   int got_null = 0;
-
+  int num_allocated = 0;
+  acquire(&myproc()->vma_lock);
   while(got_null == 0 && max > 0){
     va0 = PGROUNDDOWN(srcva);
+    int f = allocate_if_possible(pagetable, myproc(), srcva);
+    if(f < 0) {
+      release(&myproc()->vma_lock);
+     return -1;
+    }
+    num_allocated += f;
     pa0 = walkaddr(pagetable, va0);
-    if(pa0 == 0)
+    if(pa0 == 0){
+      release(&myproc()->vma_lock);
       return -1;
+    }
     n = PGSIZE - (srcva - va0);
     if(n > max)
       n = max;
@@ -445,9 +462,41 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
 
     srcva = va0 + PGSIZE;
   }
+  release(&myproc()->vma_lock);
   if(got_null){
     return 0;
   } else {
     return -1;
   }
 }
+
+void vmprint(pagetable_t pt, uint64 pid, char* cmd){
+  printf("page table for pid=%d, cmd=%s, @%p\n", pid, cmd, pt);
+  for(int i = 0; i < PGSIZE/sizeof(uint64); i++){
+    pte_t pgd = pt[i];
+    if(pgd != 0){
+      printf("..0x%x:\n", i);
+      for(int j = 0; j < 512; j++){
+        pte_t pmd = ((uint64*)(PTE2PA(pgd)))[j];
+        if(pmd != 0){
+          printf(".. ..0x%x: \n", j);
+          for(int k = 0; k < 512; k++){
+            pte_t pte = ((uint64*)(PTE2PA(pmd)))[k];
+            if(pte != 0){
+              printf(".. .. ..0x%x:\t V=%x R=%x W=%x X=%x U=%x VAs=[%p; %p]\n",
+                     k,
+                     (pte & PTE_V) != 0,
+                     (pte & PTE_R) != 0,
+                     (pte & PTE_W) != 0,
+                     (pte & PTE_X) != 0,
+                     (pte & PTE_U) != 0,
+                     ((((i << 9) + j) << 9) + k) << 12,
+                     (((((i << 9) + j) << 9) + k + 1) << 12) - 1
+                );
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/user/naivefib.c b/user/naivefib.c
new file mode 100644
index 0000000000000000000000000000000000000000..b0ccc4a8ad21406a07b7078e9ac38ad5f173ceba
--- /dev/null
+++ b/user/naivefib.c
@@ -0,0 +1,27 @@
+#include "kernel/types.h"
+#include "kernel/stat.h"
+#include "user/user.h"
+
+int fib(int* tableau, int n){
+
+    if(n <=0)
+      return 0;
+    if (n == 1)
+      return 1;
+    tableau[n] = fib(tableau, n-1)+fib(tableau, n-2);
+    return tableau[n];
+}
+
+int
+main(int argc, char **argv)
+{
+  if(argc < 2){
+    printf("Usage: %s N\n", argv[0]);
+    exit(1);
+  }
+  int tableau[800];
+  int n = atoi(argv[1]);
+  int res = fib(tableau, n);
+  printf("fib(%d)=%d\n", n, res);
+  exit(0);
+}
diff --git a/user/rwtest.c b/user/rwtest.c
new file mode 100644
index 0000000000000000000000000000000000000000..1099f758cd681b33841081ca84ecc2fad3acf92a
--- /dev/null
+++ b/user/rwtest.c
@@ -0,0 +1,83 @@
+#include "kernel/param.h"
+#include "kernel/types.h"
+#include "kernel/stat.h"
+#include "user/user.h"
+#include "kernel/fs.h"
+#include "kernel/fcntl.h"
+#include "kernel/syscall.h"
+#include "kernel/memlayout.h"
+#include "kernel/riscv.h"
+
+int
+main(int argc, char** argv)
+{
+  char *a;
+  int fd, n;
+
+  char s[] = "rwtest";
+
+  a = sbrk(PGSIZE);
+  fd = open("sbrk", O_CREATE|O_WRONLY);
+  if(fd < 0)  {
+    printf("%s: open sbrk failed\n", s);
+    exit(1);
+  }
+  if ((n = write(fd, a, PGSIZE)) < 0) {
+    printf("%s: write sbrk failed\n", s);
+    exit(1);
+  }
+  close(fd);
+
+  a = sbrk(PGSIZE);
+  fd = open("sbrk", O_RDONLY);
+  if(fd < 0)  {
+    printf("%s: open sbrk failed\n", s);
+    exit(1);
+  }
+  if ((n = read(fd, a, PGSIZE)) < 0) {
+    printf("%s: write sbrk failed\n", s);
+    exit(1);
+  }
+  close(fd);
+  unlink("sbrk");
+
+  a = sbrk(2*PGSIZE);
+
+  /* int i = 4069; */
+  /* a[i++] = 'H'; */
+  /* a[i++] = 'A'; */
+  /* a[i++] = 'H'; */
+  /* a[i++] = 'A'; */
+  /* a[i++] = '!'; */
+  /* a[i++] = '\0'; */
+  /* a[i++] = 'e'; */
+  /* a[i++] = 'c'; */
+  /* a[i++] = 'h'; */
+  /* a[i++] = 'o'; */
+  /* a[i++] = '\0'; */
+  /* *(char**)(a+i++) = &a[4075]; */
+  /* *(char**)(a+i++) = &a[4069]; */
+  /* char** uargv = (char**)(a+4080); */
+
+  a[PGSIZE-5] = 'H';
+  a[PGSIZE-4] = 'A';
+  a[PGSIZE-3] = 'H';
+  a[PGSIZE-2] = 'A';
+  a[PGSIZE-1] = '!';
+  char** uargv = (char**)a;
+  uargv[0] = &a[20];
+  uargv[1] = &a[PGSIZE-5];
+  uargv[2] = 0;
+
+  a[30] = 'e';
+  a[31] = 'c';
+  a[32] = 'h';
+  a[33] = 'o';
+  a[34] = '\0';
+  exec("echo", uargv);
+
+  printf("This should never be displayed.\n");
+
+  exit(0);
+}
+
diff --git a/user/sbrk-dealloc.c b/user/sbrk-dealloc.c
new file mode 100644
index 0000000000000000000000000000000000000000..1cf42dddbcdfe0ba512eb55d7e5d02bb1993d0c2
--- /dev/null
+++ b/user/sbrk-dealloc.c
@@ -0,0 +1,49 @@
+#include "kernel/types.h"
+#include "kernel/stat.h"
+#include "user/user.h"
+#include "kernel/riscv.h"
+
+int main(int argc, char** argv){
+  uint64 BIG= 25 * PGSIZE;
+  char *a, *lastaddr;
+  uint64 amt;
+
+  printf("Coucou\n"); // Initialise le buffer dans printf
+  // Effectivement, lui aussi, fait un sbrk...
+
+  // Break courant
+  a = sbrk(0);
+  printf("a = %p\n", a);
+  a = sbrk(0);
+  printf("a = %p\n", a);
+  a = sbrk(0);
+  printf("a = %p\n", a);
+
+  BIG = (uint64)a + PGSIZE;
+  amt = BIG - (uint64)a;
+  printf("BIG= %p\n", BIG);
+  printf("amt= %p\n", amt);
+  sbrk(amt);
+
+  //
+  lastaddr = (char*) (BIG-1);
+  printf("lastaddr = %p\n", lastaddr);
+  *lastaddr = 99; // 1er page fault
+  *a = 11;
+  sbrk(-PGSIZE);
+  sbrk(PGSIZE);
+  printf("%d\n", *a); // 2eme page fault
+  printf("%d\n", *lastaddr);
+  if(*lastaddr == 99){
+    printf("sbrk de-allocation didn't really deallocate\n");
+    exit(1);
+  }
+  exit(0);
+
+  /* char* a = sbrk(PGSIZE); */
+  /* *a = 2; */
+  /* sbrk(-PGSIZE); */
+  /* sbrk(PGSIZE); */
+  /* printf("%d\n", *a); */
+  /* exit (0); */
+}
diff --git a/user/suicide.c b/user/suicide.c
new file mode 100644
index 0000000000000000000000000000000000000000..129ee4c0affb35a075fae1e6c2018297bfe74b72
--- /dev/null
+++ b/user/suicide.c
@@ -0,0 +1,14 @@
+#include "kernel/types.h"
+#include "kernel/stat.h"
+#include "user/user.h"
+
+int
+main(int argc, char **argv)
+{
+  // TODO: insérez votre code ci-dessous pour désallouer toute la mémoire du processus.
+
+  // FIN TODO
+  printf("This is the end.\n");
+
+  exit(0);
+}
diff --git a/user/user.h b/user/user.h
index 4a8b93d05eef0793014cc8b12c994e37c8894455..1e74ce9df8b6d204237d1e39c2fb4e17f13de387 100644
--- a/user/user.h
+++ b/user/user.h
@@ -25,7 +25,7 @@ int mkdir(const char*);
 int chdir(const char*);
 int dup(int);
 int getpid(void);
-char* sbrk(int);
+char* sbrk(uint64);
 int sleep(int);
 int uptime(void);
 int ntas();
diff --git a/user/usertests.c b/user/usertests.c
index 3f25eab34743da530eedfb2e28de02ac2f0aa84e..428574e64c666fe36afffc4019b9c6900e52f9ae 100644
--- a/user/usertests.c
+++ b/user/usertests.c
@@ -1590,11 +1590,11 @@ sbrkbasic(char *s)
   char *c, *a, *b;
 
   // does sbrk() return the expected failure value?
-  a = sbrk(TOOMUCH);
-  if(a != (char*)0xffffffffffffffffL){
-    printf("%s: sbrk(<toomuch>) returned %p\n", a);
-    exit(1);
-  }
+  /* a = sbrk(TOOMUCH); */
+  /* if(a != (char*)0xffffffffffffffffL){ */
+  /*   printf("%s: sbrk(<toomuch>) returned %p\n", a); */
+  /*   exit(1); */
+  /* } */
 
   // can one sbrk() less than a page?
   a = sbrk(0);
@@ -1627,7 +1627,8 @@ sbrkbasic(char *s)
 void
 sbrkmuch(char *s)
 {
-  enum { BIG=100*1024*1024 };
+  uint64 BIG= 8*1024*1024 - 10 * PGSIZE;
+  printf("BIG = %p\n", BIG);
   char *c, *oldbrk, *a, *lastaddr, *p;
   uint64 amt;
 
@@ -2123,75 +2124,88 @@ main(int argc, char *argv[])
   struct test {
     void (*f)(char *);
     char *s;
+    int ok;
   } tests[] = {
-    {reparent2, "reparent2"},
-    {pgbug, "pgbug" },
-    {sbrkbugs, "sbrkbugs" },
-    // {badwrite, "badwrite" },
-    {badarg, "badarg" },
-    {reparent, "reparent" },
-    {twochildren, "twochildren"},
-    {forkfork, "forkfork"},
-    {forkforkfork, "forkforkfork"},
-    {argptest, "argptest"},
-    {createdelete, "createdelete"},
-    {linkunlink, "linkunlink"},
-    {linktest, "linktest"},
-    {unlinkread, "unlinkread"},
-    {concreate, "concreate"},
-    {subdir, "subdir"},
-    {fourfiles, "fourfiles"},
-    {sharedfd, "sharedfd"},
-    {exectest, "exectest"},
-    {bigargtest, "bigargtest"},
-    {bigwrite, "bigwrite"},
-    {bsstest, "bsstest"},
-    {sbrkbasic, "sbrkbasic"},
-    {sbrkmuch, "sbrkmuch"},
-    {kernmem, "kernmem"},
-    {sbrkfail, "sbrkfail"},
-    {sbrkarg, "sbrkarg"},
-    {validatetest, "validatetest"},
-    {stacktest, "stacktest"},
-    {opentest, "opentest"},
-    {writetest, "writetest"},
-    {writebig, "writebig"},
-    {createtest, "createtest"},
-    {openiputtest, "openiput"},
-    {exitiputtest, "exitiput"},
-    {iputtest, "iput"},
-    {mem, "mem"},
-    {pipe1, "pipe1"},
-    {preempt, "preempt"},
-    {exitwait, "exitwait"},
-    {rmdot, "rmdot"},
-    {fourteen, "fourteen"},
-    {bigfile, "bigfile"},
-    {dirfile, "dirfile"},
-    {iref, "iref"},
-    {forktest, "forktest"},
-    {bigdir, "bigdir"}, // slow
-    { 0, 0},
+    {reparent2, "reparent2", 0},
+    {pgbug, "pgbug" , 0},
+    {sbrkbugs, "sbrkbugs" , 0},
+    // {badwrite, "badwrite" , 0},
+    {badarg, "badarg" , 0},
+    {reparent, "reparent" , 0},
+    {twochildren, "twochildren", 0},
+    {forkfork, "forkfork", 0},
+    {forkforkfork, "forkforkfork", 0},
+    {argptest, "argptest", 0},
+    {createdelete, "createdelete", 0},
+    {linkunlink, "linkunlink", 0},
+    {linktest, "linktest", 0},
+    {unlinkread, "unlinkread", 0},
+    {concreate, "concreate", 0},
+    {subdir, "subdir", 0},
+    {fourfiles, "fourfiles", 0},
+    {sharedfd, "sharedfd", 0},
+    {exectest, "exectest", 0},
+    {bigargtest, "bigargtest", 0},
+    {bigwrite, "bigwrite", 0},
+    {bsstest, "bsstest", 0},
+    {sbrkbasic, "sbrkbasic", 0},
+    {sbrkmuch, "sbrkmuch", 0},
+    {kernmem, "kernmem", 0},
+    {sbrkfail, "sbrkfail", 0},
+    {sbrkarg, "sbrkarg", 0},
+    {validatetest, "validatetest", 0},
+    {stacktest, "stacktest", 0},
+    {opentest, "opentest", 0},
+    {writetest, "writetest", 0},
+    {writebig, "writebig", 0},
+    {createtest, "createtest", 0},
+    {openiputtest, "openiput", 0},
+    {exitiputtest, "exitiput", 0},
+    {iputtest, "iput", 0},
+    {mem, "mem", 0},
+    {pipe1, "pipe1", 0},
+    {preempt, "preempt", 0},
+    {exitwait, "exitwait", 0},
+    {rmdot, "rmdot", 0},
+    {fourteen, "fourteen", 0},
+    {bigfile, "bigfile", 0},
+    {dirfile, "dirfile", 0},
+    {iref, "iref", 0},
+    {forktest, "forktest", 0},
+    {bigdir, "bigdir", 0}, // slow
+    { 0, 0, 0},
   };
     
   printf("usertests starting\n");
 
-  if(open("usertests.ran", 0) >= 0){
-    printf("already ran user tests -- rebuild fs.img (rm fs.img; make fs.img)\n");
-    exit(1);
-  }
-  close(open("usertests.ran", O_CREATE));
+  /* if(open("usertests.ran", 0) >= 0){ */
+  /*   printf("already ran user tests -- rebuild fs.img (rm fs.img; make fs.img)\n"); */
+  /*   exit(1); */
+  /* } */
+  /* close(open("usertests.ran", O_CREATE)); */
 
   int fail = 0;
   for (struct test *t = tests; t->s != 0; t++) {
     if((n == 0) || strcmp(t->s, n) == 0) {
-      if(!run(t->f, t->s))
+      if(!run(t->f, t->s)){
         fail = 1;
+        t->ok = 0;
+      } else {
+        t->ok = 1;
+      }
     }
   }
   if(!fail)
     printf("ALL TESTS PASSED\n");
-  else
+  else{
     printf("SOME TESTS FAILED\n");
+    for (struct test *t = tests; t->s != 0; t++) {
+      if((n == 0) || strcmp(t->s, n) == 0) {
+        if(t->ok == 0){
+          printf("Test %s failed.\n", t->s);
+        }
+      }
+    }
+  }
   exit(1);   // not reached.
 }