diff --git a/defs.h b/defs.h
index 02da96f545789b2bdc61a56f7470f04ee95ff202..ca7367d2480cbe8bcc22d577c9d182388ddf90ca 100644
--- a/defs.h
+++ b/defs.h
@@ -60,9 +60,8 @@ extern uchar    ioapicid;
 void            ioapicinit(void);
 
 // kalloc.c
-extern int      nfreemem;
-char*           kalloc(int);
-void            kfree(char*, int);
+char*           kalloc(void);
+void            kfree(char*);
 void            kinit(char*,uint);
 
 // kbd.c
diff --git a/kalloc.c b/kalloc.c
index ca87018f17b572d529affcdb0ffcb2823eeda508..65de759b99c10d091b789dc491b4ac28e0278eb3 100644
--- a/kalloc.c
+++ b/kalloc.c
@@ -1,8 +1,6 @@
 // Physical memory allocator, intended to allocate
-// memory for user processes. Allocates in 4096-byte pages.
-// Free list is kept sorted and combines adjacent pages into
-// long runs, to make it easier to allocate big segments.
-// This combining is not useful now that xv6 uses paging.
+// memory for user processes, kernel stacks, page table pages,
+// and pipe buffers. Allocates 4096-byte pages.
 
 #include "types.h"
 #include "defs.h"
@@ -12,7 +10,6 @@
 
 struct run {
   struct run *next;
-  int len; // bytes
 };
 
 struct {
@@ -20,92 +17,52 @@ struct {
   struct run *freelist;
 } kmem;
 
-int nfreemem;
-
 // Initialize free list of physical pages.
 void
 kinit(char *p, uint len)
 {
   initlock(&kmem.lock, "kmem");
-  nfreemem = 0;
-  kfree(p, len);
+  char *p1 = (char*)PGROUNDUP((uint)p);
+  char *p2 = PGROUNDDOWN(p + len);
+  for( ; p1 < p2; p1 += 4096)
+    kfree(p1);
 }
 
-// Free the len bytes of memory pointed at by v,
+// Free the page of physical memory pointed at by v,
 // which normally should have been returned by a
-// call to kalloc(len).  (The exception is when
+// call to kalloc().  (The exception is when
 // initializing the allocator; see kinit above.)
 void
-kfree(char *v, int len)
+kfree(char *v)
 {
-  struct run *r, *rend, **rp, *p, *pend;
+  struct run *r;
 
-  if(len <= 0 || len % PGSIZE)
+  if(((uint) v) % PGSIZE || (uint)v < 1024*1024 || (uint)v >= PHYSTOP) 
     panic("kfree");
 
   // Fill with junk to catch dangling refs.
-  memset(v, 1, len);
+  memset(v, 1, PGSIZE);
 
   acquire(&kmem.lock);
-  nfreemem += len;
-  p = (struct run*)v;
-  pend = (struct run*)(v + len);
-  for(rp=&kmem.freelist; (r=*rp) != 0 && r <= pend; rp=&r->next){
-    rend = (struct run*)((char*)r + r->len);
-    if(r <= p && p < rend) {
-      cprintf("freeing a free page: r = 0x%x p = 0x%x rend = 0x%x\n", 
-	      r, p, rend);
-      panic("freeing free page");
-    }
-    if(rend == p){  // r before p: expand r to include p
-      r->len += len;
-      if(r->next && r->next == pend){  // r now next to r->next?
-        r->len += r->next->len;
-        r->next = r->next->next;
-      }
-      goto out;
-    }
-    if(pend == r){  // p before r: expand p to include, replace r
-      p->len = len + r->len;
-      p->next = r->next;
-      *rp = p;
-      goto out;
-    }
-  }
-  // Insert p before r in list.
-  p->len = len;
-  p->next = r;
-  *rp = p;
-
- out:
+  r = (struct run *) v;
+  r->next = kmem.freelist;
+  kmem.freelist = r;
   release(&kmem.lock);
 }
 
-// Allocate n bytes of physical memory.
-// Returns a kernel-segment pointer.
+// Allocate one 4096-byte page of physical memory.
+// Returns a pointer that the kernel can use.
 // Returns 0 if the memory cannot be allocated.
 char*
-kalloc(int n)
+kalloc()
 {
-  char *p;
-  struct run *r, **rp;
-
-  if(n % PGSIZE || n <= 0)
-    panic("kalloc");
+  struct run *r;
 
   acquire(&kmem.lock);
-  for(rp=&kmem.freelist; (r=*rp) != 0; rp=&r->next){
-    if(r->len >= n){
-      r->len -= n;
-      p = (char*)r + r->len;
-      if(r->len == 0)
-        *rp = r->next;
-      nfreemem -= n;
-      release(&kmem.lock);
-      return p;
-    }
-  }
+  r = kmem.freelist;
+  if(r)
+    kmem.freelist = r->next;
   release(&kmem.lock);
-  return 0;
+  return (char*) r;
 }
 
diff --git a/main.c b/main.c
index 1a49bc609e7ff8ee68349129888d05da9b755af9..878ea36b974efc22500227ab5ca182c02ca011c0 100644
--- a/main.c
+++ b/main.c
@@ -28,7 +28,7 @@ main(void)
 void
 jkstack(void)
 {
-  char *kstack = kalloc(PGSIZE);
+  char *kstack = kalloc();
   if (!kstack)
     panic("jkstack\n");
   char *top = kstack + PGSIZE;
@@ -92,7 +92,7 @@ bootothers(void)
       continue;
 
     // Fill in %esp, %eip and start code on cpu.
-    stack = kalloc(KSTACKSIZE);
+    stack = kalloc();
     *(void**)(code-4) = stack + KSTACKSIZE;
     *(void**)(code-8) = mpmain;
     lapicstartap(c->id, (uint)code);
diff --git a/mmu.h b/mmu.h
index f4fc7327a4452175b8465bc371e024f4aa74c663..db40f2588f964fb5e8b4bbdba9a6bbb77591fc4c 100644
--- a/mmu.h
+++ b/mmu.h
@@ -112,7 +112,7 @@ struct segdesc {
 #define PDXSHIFT	22		// offset of PDX in a linear address
 
 #define PGROUNDUP(sz)  (((sz)+PGSIZE-1) & ~(PGSIZE-1))
-#define PGROUNDDOWN(a) ((char*)((((unsigned int)a) & ~(PGSIZE-1))))
+#define PGROUNDDOWN(a) ((char*)((((unsigned int)(a)) & ~(PGSIZE-1))))
 
 // Page table/directory entry flags.
 #define PTE_P		0x001	// Present
diff --git a/param.h b/param.h
index c1959d1890fc959a90d1d577cb62b8fcfecee5f4..48c3352c5d8fd3024cf6d3b36b656bb77e1b9176 100644
--- a/param.h
+++ b/param.h
@@ -1,6 +1,5 @@
 #define NPROC        64  // maximum number of processes
-#define PAGE       4096  // conveniently chosen to be equal to PGSIZE
-#define KSTACKSIZE PAGE  // size of per-process kernel stack
+#define KSTACKSIZE 4096  // size of per-process kernel stack
 #define NCPU          8  // maximum number of CPUs
 #define NOFILE       16  // open files per process
 #define NFILE       100  // open files per system
@@ -8,3 +7,4 @@
 #define NINODE       50  // maximum number of active i-nodes
 #define NDEV         10  // maximum major device number
 #define ROOTDEV       1  // device number of file system root disk
+#define PHYSTOP  0x1000000 // use phys mem up to here as free pool
diff --git a/pipe.c b/pipe.c
index 4a1857c1d7acb9626f1f9629adb957515d1b3406..bc847b9e8afdd08c6b54061e49b039fce12a57ea 100644
--- a/pipe.c
+++ b/pipe.c
@@ -27,7 +27,7 @@ pipealloc(struct file **f0, struct file **f1)
   *f0 = *f1 = 0;
   if((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0)
     goto bad;
-  if((p = (struct pipe*)kalloc(PAGE)) == 0)
+  if((p = (struct pipe*)kalloc()) == 0)
     goto bad;
   p->readopen = 1;
   p->writeopen = 1;
@@ -47,7 +47,7 @@ pipealloc(struct file **f0, struct file **f1)
 //PAGEBREAK: 20
  bad:
   if(p)
-    kfree((char*)p, PAGE);
+    kfree((char*)p);
   if(*f0)
     fileclose(*f0);
   if(*f1)
@@ -68,7 +68,7 @@ pipeclose(struct pipe *p, int writable)
   }
   if(p->readopen == 0 && p->writeopen == 0) {
     release(&p->lock);
-    kfree((char*)p, PAGE);
+    kfree((char*)p);
   } else
     release(&p->lock);
 }
diff --git a/proc.c b/proc.c
index e69bacf0920414e46be20ad7010198005800bd8e..5ac27800edf2bf639b35266fae78f5cb05f32ca5 100644
--- a/proc.c
+++ b/proc.c
@@ -84,7 +84,7 @@ found:
   release(&ptable.lock);
 
   // Allocate kernel stack if possible.
-  if((p->kstack = kalloc(KSTACKSIZE)) == 0){
+  if((p->kstack = kalloc()) == 0){
     p->state = UNUSED;
     return 0;
   }
@@ -169,7 +169,7 @@ fork(void)
 
   // Copy process state from p.
   if (!(np->pgdir = copyuvm(proc->pgdir, proc->sz))) {
-    kfree(np->kstack, KSTACKSIZE);
+    kfree(np->kstack);
     np->kstack = 0;
     np->state = UNUSED;
     return -1;
@@ -418,7 +418,7 @@ wait(void)
       if(p->state == ZOMBIE){
         // Found one.
         pid = p->pid;
-        kfree(p->kstack, KSTACKSIZE);
+        kfree(p->kstack);
         p->kstack = 0;
         freevm(p->pgdir);
         p->state = UNUSED;
diff --git a/umalloc.c b/umalloc.c
index afc86a5db18ef339f033a5a03d384108b38fe531..4984591218e1a45a587459e4362cfea7c2e47307 100644
--- a/umalloc.c
+++ b/umalloc.c
@@ -49,8 +49,8 @@ morecore(uint nu)
   char *p;
   Header *hp;
 
-  if(nu < PAGE)
-    nu = PAGE;
+  if(nu < 4096)
+    nu = 4096;
   p = sbrk(nu * sizeof(Header));
   if(p == (char*) -1)
     return 0;
diff --git a/vm.c b/vm.c
index 262f079e8b5d22692571d19f15510b750632a0c0..46d18fcd7315124e76cab8fd185699cdf4dbe577 100644
--- a/vm.c
+++ b/vm.c
@@ -29,7 +29,6 @@
 // (both in physical memory and in the kernel's virtual address
 // space).
 
-#define PHYSTOP  0x1000000
 #define USERTOP  0xA0000
 
 static uint kerntext;  // Linker starts kernel at 1MB
@@ -53,7 +52,7 @@ walkpgdir(pde_t *pgdir, const void *va, int create)
   pde = &pgdir[PDX(va)];
   if (*pde & PTE_P) {
     pgtab = (pte_t*) PTE_ADDR(*pde);
-  } else if (!create || !(r = (uint) kalloc(PGSIZE)))
+  } else if (!create || !(r = (uint) kalloc()))
     return 0;
   else {
     pgtab = (pte_t*) r;
@@ -156,7 +155,7 @@ setupkvm(void)
   pde_t *pgdir;
 
   // Allocate page directory
-  if (!(pgdir = (pde_t *) kalloc(PGSIZE)))
+  if (!(pgdir = (pde_t *) kalloc()))
     return 0;
   memset(pgdir, 0, PGSIZE);
   // Map IO space from 640K to 1Mbyte
@@ -206,7 +205,7 @@ allocuvm(pde_t *pgdir, char *addr, uint sz)
   for(a = first; a <= last; a += PGSIZE){
     pte_t *pte = walkpgdir(pgdir, a, 0);
     if(pte == 0 || (*pte & PTE_P) == 0){
-      char *mem = kalloc(PGSIZE);
+      char *mem = kalloc();
       if(mem == 0){
         // XXX clean up?
         return 0;
@@ -235,7 +234,7 @@ deallocuvm(pde_t *pgdir, char *addr, uint sz)
       uint pa = PTE_ADDR(*pte);
       if(pa == 0)
         panic("deallocuvm");
-      kfree((void *) pa, PGSIZE);
+      kfree((void *) pa);
       *pte = 0;
     }
   }
@@ -260,15 +259,15 @@ freevm(pde_t *pgdir)
 	  uint pa = PTE_ADDR(pgtab[j]);
 	  uint va = PGADDR(i, j, 0);
 	  if (va < USERTOP)   // user memory
-            kfree((void *) pa, PGSIZE);
+            kfree((void *) pa);
 	  pgtab[j] = 0;
 	}
       }
-      kfree((void *) da, PGSIZE);
+      kfree((void *) da);
       pgdir[i] = 0;
     }
   }
-  kfree((void *) pgdir, PGSIZE);
+  kfree((void *) pgdir);
 }
 
 int
@@ -324,7 +323,7 @@ copyuvm(pde_t *pgdir, uint sz)
       panic("copyuvm: pte should exist\n");
     if(*pte & PTE_P){
       pa = PTE_ADDR(*pte);
-      if (!(mem = kalloc(PGSIZE)))
+      if (!(mem = kalloc()))
         return 0;
       memmove(mem, (char *)pa, PGSIZE);
       if (!mappages(d, (void *)i, PGSIZE, PADDR(mem), PTE_W|PTE_U))