diff --git a/Makefile b/Makefile
index 7415076..731a157 100644
--- a/Makefile
+++ b/Makefile
@@ -50,7 +50,7 @@ OBJCOPY = $(TOOLPREFIX)objcopy
 OBJDUMP = $(TOOLPREFIX)objdump
 
 # CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -ggdb -Werror -fno-omit-frame-pointer -O
-CFLAGS = -Wall -Werror -O
+CFLAGS = -Wall -Werror -O -fno-omit-frame-pointer -ggdb
 CFLAGS += -mcmodel=medany
 CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax
 CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
@@ -153,7 +153,7 @@ QEMUGDB = $(shell if $(QEMU) -help | grep -q '^-gdb'; \
 	then echo "-gdb tcp::$(GDBPORT)"; \
 	else echo "-s -p $(GDBPORT)"; fi)
 ifndef CPUS
-CPUS := 1
+CPUS := 3
 endif
 QEMUOPTS = -machine virt -kernel kernel -m 3G -smp $(CPUS) -nographic
 QEMUOPTS += -initrd fs.img
diff --git a/console.c b/console.c
index ca20842..b20d4a9 100644
--- a/console.c
+++ b/console.c
@@ -219,9 +219,15 @@ consolewrite(struct inode *ip, int user_src, uint64 src, int n)
 void
 consoleintr(int c)
 {
+  int doprocdump = 0;
+  
   acquire(&cons.lock);
 
   switch(c){
+  case C('P'):  // Process list.
+    // procdump() locks cons.lock indirectly; invoke later
+    doprocdump = 1;
+    break;
   case C('U'):  // Kill line.
     while(input.e != input.w &&
           input.buf[(input.e-1) % INPUT_BUF] != '\n'){
@@ -249,6 +255,9 @@ consoleintr(int c)
   }
   
   release(&cons.lock);
+
+  if(doprocdump)
+    procdump();
 }
 
 void
diff --git a/defs.h b/defs.h
index 2e991a1..597e5b6 100644
--- a/defs.h
+++ b/defs.h
@@ -124,6 +124,7 @@ void            wakeup(void*);
 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);
 
 // swtch.S
 void            swtch(struct context*, struct context*);
diff --git a/fs.h b/fs.h
index 56f0558..bc0805f 100644
--- a/fs.h
+++ b/fs.h
@@ -2,8 +2,8 @@
 // Both the kernel and user programs use this header file.
 
 
-#define ROOTINO 1  // root i-number
-#define BSIZE 512  // block size
+#define ROOTINO  1   // root i-number
+#define BSIZE 1024  // block size
 
 // Disk layout:
 // [ boot block | super block | log | inode blocks |
@@ -48,7 +48,7 @@ struct dinode {
 #define BPB           (BSIZE*8)
 
 // Block of free map containing bit for block b
-#define BBLOCK(b, sb) (b/BPB + sb.bmapstart)
+#define BBLOCK(b, sb) ((b)/BPB + sb.bmapstart)
 
 // Directory is a file containing a sequence of dirent structures.
 #define DIRSIZ 14
diff --git a/proc.c b/proc.c
index d23cb95..4ae34c8 100644
--- a/proc.c
+++ b/proc.c
@@ -560,3 +560,32 @@ either_copyin(void *dst, int user_src, uint64 src, uint64 len)
   }
 }
 
+// Print a process listing to console.  For debugging.
+// Runs when user types ^P on console.
+// No lock to avoid wedging a stuck machine further.
+void
+procdump(void)
+{
+  static char *states[] = {
+  [UNUSED]    "unused",
+  [EMBRYO]    "embryo",
+  [SLEEPING]  "sleep ",
+  [RUNNABLE]  "runble",
+  [RUNNING]   "run   ",
+  [ZOMBIE]    "zombie"
+  };
+  struct proc *p;
+  char *state;
+
+  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
+    if(p->state == UNUSED)
+      continue;
+    if(p->state >= 0 && p->state < NELEM(states) && states[p->state])
+      state = states[p->state];
+    else
+      state = "???";
+    printf("%d %s %s", p->pid, state, p->name);
+    printf("\n");
+  }
+}
+
diff --git a/spinlock.c b/spinlock.c
index 8b3c3f0..bbb7cb5 100644
--- a/spinlock.c
+++ b/spinlock.c
@@ -56,11 +56,13 @@ release(struct spinlock *lk)
   // section are visible to other cores before the lock is released.
   // Both the C compiler and the hardware may re-order loads and
   // stores; __sync_synchronize() tells them both not to.
+  // On RISC-V, this turns into a fence instruction.
   __sync_synchronize();
 
   // Release the lock, equivalent to lk->locked = 0.
   // This code can't use a C assignment, since it might
   // not be atomic. A real OS would use C atomics here.
+  // On RISC-V, use an amoswap instruction.
   //asm volatile("movl $0, %0" : "+m" (lk->locked) : );
   __sync_lock_release(&lk->locked);
 
@@ -73,7 +75,7 @@ holding(struct spinlock *lk)
 {
   int r;
   push_off();
-  r = lk->locked && lk->cpu == mycpu();
+  r = (lk->locked && lk->cpu == mycpu());
   pop_off();
   return r;
 }