Index: kernel/genarch/src/mm/as_pt.c
===================================================================
--- kernel/genarch/src/mm/as_pt.c	(revision 07525cdba517a318677cef4eb379adaea132443a)
+++ kernel/genarch/src/mm/as_pt.c	(revision de3d15b46ea8377d7efda8dc4e9bdea54653c3f2)
@@ -113,5 +113,5 @@
 void ptl0_destroy(pte_t *page_table)
 {
-	frame_free((uintptr_t) page_table);
+	frame_free((uintptr_t) page_table, PTL0_FRAMES);
 }
 
Index: kernel/genarch/src/mm/page_pt.c
===================================================================
--- kernel/genarch/src/mm/page_pt.c	(revision 07525cdba517a318677cef4eb379adaea132443a)
+++ kernel/genarch/src/mm/page_pt.c	(revision de3d15b46ea8377d7efda8dc4e9bdea54653c3f2)
@@ -219,5 +219,5 @@
 		memsetb(&ptl0[PTL0_INDEX(page)], sizeof(pte_t), 0);
 #endif
-		frame_free(KA2PA((uintptr_t) ptl3));
+		frame_free(KA2PA((uintptr_t) ptl3), PTL3_FRAMES);
 	} else {
 		/*
@@ -253,5 +253,5 @@
 		memsetb(&ptl0[PTL0_INDEX(page)], sizeof(pte_t), 0);
 #endif
-		frame_free(KA2PA((uintptr_t) ptl2));
+		frame_free(KA2PA((uintptr_t) ptl2), PTL2_FRAMES);
 	} else {
 		/*
@@ -284,5 +284,5 @@
 
 		memsetb(&ptl0[PTL0_INDEX(page)], sizeof(pte_t), 0);
-		frame_free(KA2PA((uintptr_t) ptl1));
+		frame_free(KA2PA((uintptr_t) ptl1), PTL1_FRAMES);
 	}
 #endif /* PTL1_ENTRIES != 0 */
Index: kernel/generic/include/mm/frame.h
===================================================================
--- kernel/generic/include/mm/frame.h	(revision 07525cdba517a318677cef4eb379adaea132443a)
+++ kernel/generic/include/mm/frame.h	(revision de3d15b46ea8377d7efda8dc4e9bdea54653c3f2)
@@ -134,7 +134,7 @@
 extern uintptr_t frame_alloc(size_t, frame_flags_t, uintptr_t);
 extern uintptr_t frame_alloc_noreserve(size_t, frame_flags_t, uintptr_t);
-extern void frame_free_generic(uintptr_t, frame_flags_t);
-extern void frame_free(uintptr_t);
-extern void frame_free_noreserve(uintptr_t);
+extern void frame_free_generic(uintptr_t, size_t, frame_flags_t);
+extern void frame_free(uintptr_t, size_t);
+extern void frame_free_noreserve(uintptr_t, size_t);
 extern void frame_reference_add(pfn_t);
 extern size_t frame_total_free_get(void);
Index: kernel/generic/src/ddi/ddi.c
===================================================================
--- kernel/generic/src/ddi/ddi.c	(revision 07525cdba517a318677cef4eb379adaea132443a)
+++ kernel/generic/src/ddi/ddi.c	(revision de3d15b46ea8377d7efda8dc4e9bdea54653c3f2)
@@ -339,5 +339,5 @@
 	if (!as_area_create(TASK->as, map_flags, size,
 	    AS_AREA_ATTR_NONE, &phys_backend, &backend_data, virt, bound)) {
-		frame_free_noreserve(*phys);
+		frame_free_noreserve(*phys, frames);
 		return ENOMEM;
 	}
Index: kernel/generic/src/mm/as.c
===================================================================
--- kernel/generic/src/mm/as.c	(revision 07525cdba517a318677cef4eb379adaea132443a)
+++ kernel/generic/src/mm/as.c	(revision de3d15b46ea8377d7efda8dc4e9bdea54653c3f2)
@@ -907,5 +907,5 @@
 			
 			for (i = 0; i < node->keys; i++)
-				frame_free((uintptr_t) node->value[i]);
+				frame_free((uintptr_t) node->value[i], 1);
 		}
 		
Index: kernel/generic/src/mm/backend_anon.c
===================================================================
--- kernel/generic/src/mm/backend_anon.c	(revision 07525cdba517a318677cef4eb379adaea132443a)
+++ kernel/generic/src/mm/backend_anon.c	(revision de3d15b46ea8377d7efda8dc4e9bdea54653c3f2)
@@ -294,5 +294,5 @@
 		 * the normal unreserving frame_free().
 		 */
-		frame_free(frame);
+		frame_free(frame, 1);
 	} else {
 		/*
@@ -301,5 +301,5 @@
 		 * manipulate the reserve or it would be given back twice.
 		 */
-		frame_free_noreserve(frame);
+		frame_free_noreserve(frame, 1);
 	}
 }
Index: kernel/generic/src/mm/backend_elf.c
===================================================================
--- kernel/generic/src/mm/backend_elf.c	(revision 07525cdba517a318677cef4eb379adaea132443a)
+++ kernel/generic/src/mm/backend_elf.c	(revision de3d15b46ea8377d7efda8dc4e9bdea54653c3f2)
@@ -429,5 +429,5 @@
 			 * data.
 			 */
-			frame_free_noreserve(frame);
+			frame_free_noreserve(frame, 1);
 		}
 	} else {
@@ -437,5 +437,5 @@
 		 * anonymous). In any case, a frame needs to be freed.
 		 */
-		frame_free_noreserve(frame);
+		frame_free_noreserve(frame, 1);
 	}
 }
Index: kernel/generic/src/mm/frame.c
===================================================================
--- kernel/generic/src/mm/frame.c	(revision 07525cdba517a318677cef4eb379adaea132443a)
+++ kernel/generic/src/mm/frame.c	(revision de3d15b46ea8377d7efda8dc4e9bdea54653c3f2)
@@ -348,5 +348,4 @@
 	
 	frame_t *frame = zone_get_frame(zone, index);
-	size_t size = 0;
 	
 	ASSERT(frame->refcount > 0);
@@ -359,8 +358,8 @@
 		zone->busy_count--;
 		
-		size = FRAME_SIZE;
-	}
-	
-	return size;
+		return 1;
+	}
+	
+	return 0;
 }
 
@@ -891,28 +890,33 @@
 }
 
-/** Free a frame.
- *
- * Find respective frame structure for supplied physical frame address.
- * Decrement frame reference count. If it drops to zero, move the frame
- * structure to free list.
- *
- * @param frame Physical Address of of the frame to be freed.
+/** Free frames of physical memory.
+ *
+ * Find respective frame structures for supplied physical frames.
+ * Decrement each frame reference count. If it drops to zero, mark
+ * the frames as available.
+ *
+ * @param start Physical Address of the first frame to be freed.
+ * @param count Number of frames to free.
  * @param flags Flags to control memory reservation.
  *
  */
-void frame_free_generic(uintptr_t frame, frame_flags_t flags)
-{
+void frame_free_generic(uintptr_t start, size_t count, frame_flags_t flags)
+{
+	size_t freed = 0;
+	
 	irq_spinlock_lock(&zones.lock, true);
 	
-	/*
-	 * First, find host frame zone for addr.
-	 */
-	pfn_t pfn = ADDR2PFN(frame);
-	size_t znum = find_zone(pfn, 1, 0);
-	
-	ASSERT(znum != (size_t) -1);
-	
-	size_t size =
-	    zone_frame_free(&zones.info[znum], pfn - zones.info[znum].base);
+	for (size_t i = 0; i < count; i++) {
+		/*
+		 * First, find host frame zone for addr.
+		 */
+		pfn_t pfn = ADDR2PFN(start) + i;
+		size_t znum = find_zone(pfn, 1, 0);
+		
+		ASSERT(znum != (size_t) -1);
+		
+		freed += zone_frame_free(&zones.info[znum],
+		    pfn - zones.info[znum].base);
+	}
 	
 	irq_spinlock_unlock(&zones.lock, true);
@@ -920,10 +924,7 @@
 	/*
 	 * Signal that some memory has been freed.
-	 */
-	
-	
-	/*
-	 * Since the mem_avail_mtx is an active mutex, we need to disable interrupts
-	 * to prevent deadlock with TLB shootdown.
+	 * Since the mem_avail_mtx is an active mutex,
+	 * we need to disable interruptsto prevent deadlock
+	 * with TLB shootdown.
 	 */
 	
@@ -932,5 +933,5 @@
 	
 	if (mem_avail_req > 0)
-		mem_avail_req -= min(mem_avail_req, size);
+		mem_avail_req -= min(mem_avail_req, freed);
 	
 	if (mem_avail_req == 0) {
@@ -943,15 +944,15 @@
 	
 	if (!(flags & FRAME_NO_RESERVE))
-		reserve_free(size);
-}
-
-void frame_free(uintptr_t frame)
-{
-	frame_free_generic(frame, 0);
-}
-
-void frame_free_noreserve(uintptr_t frame)
-{
-	frame_free_generic(frame, FRAME_NO_RESERVE);
+		reserve_free(freed);
+}
+
+void frame_free(uintptr_t frame, size_t count)
+{
+	frame_free_generic(frame, count, 0);
+}
+
+void frame_free_noreserve(uintptr_t frame, size_t count)
+{
+	frame_free_generic(frame, count, FRAME_NO_RESERVE);
 }
 
Index: kernel/generic/src/mm/slab.c
===================================================================
--- kernel/generic/src/mm/slab.c	(revision 07525cdba517a318677cef4eb379adaea132443a)
+++ kernel/generic/src/mm/slab.c	(revision de3d15b46ea8377d7efda8dc4e9bdea54653c3f2)
@@ -193,5 +193,5 @@
 		slab = slab_alloc(slab_extern_cache, flags);
 		if (!slab) {
-			frame_free(KA2PA(data));
+			frame_free(KA2PA(data), cache->frames);
 			return NULL;
 		}
@@ -225,5 +225,5 @@
 NO_TRACE static size_t slab_space_free(slab_cache_t *cache, slab_t *slab)
 {
-	frame_free(KA2PA(slab->start));
+	frame_free(KA2PA(slab->start), slab->cache->frames);
 	if (!(cache->flags & SLAB_CACHE_SLINSIDE))
 		slab_free(slab_extern_cache, slab);
Index: kernel/generic/src/proc/thread.c
===================================================================
--- kernel/generic/src/proc/thread.c	(revision 07525cdba517a318677cef4eb379adaea132443a)
+++ kernel/generic/src/proc/thread.c	(revision de3d15b46ea8377d7efda8dc4e9bdea54653c3f2)
@@ -217,5 +217,5 @@
 	thr_destructor_arch(thread);
 	
-	frame_free(KA2PA(thread->kstack));
+	frame_free(KA2PA(thread->kstack), STACK_FRAMES);
 	
 #ifdef CONFIG_FPU
Index: kernel/test/mm/falloc1.c
===================================================================
--- kernel/test/mm/falloc1.c	(revision 07525cdba517a318677cef4eb379adaea132443a)
+++ kernel/test/mm/falloc1.c	(revision de3d15b46ea8377d7efda8dc4e9bdea54653c3f2)
@@ -84,5 +84,5 @@
 			
 			for (unsigned int i = 0; i < allocated; i++)
-				frame_free(KA2PA(frames[i]));
+				frame_free(KA2PA(frames[i]), count);
 			
 			TPRINTF("done.\n");
Index: kernel/test/mm/falloc2.c
===================================================================
--- kernel/test/mm/falloc2.c	(revision 07525cdba517a318677cef4eb379adaea132443a)
+++ kernel/test/mm/falloc2.c	(revision de3d15b46ea8377d7efda8dc4e9bdea54653c3f2)
@@ -100,5 +100,5 @@
 					}
 				}
-				frame_free(KA2PA(frames[i]));
+				frame_free(KA2PA(frames[i]), count);
 			}
 			
Index: kernel/test/mm/mapping1.c
===================================================================
--- kernel/test/mm/mapping1.c	(revision 07525cdba517a318677cef4eb379adaea132443a)
+++ kernel/test/mm/mapping1.c	(revision de3d15b46ea8377d7efda8dc4e9bdea54653c3f2)
@@ -65,5 +65,5 @@
 			km_unmap(page0, PAGE_SIZE);
 			km_unmap(page1, PAGE_SIZE);
-			frame_free(frame);
+			frame_free(frame, 1);
 			return "Criss-cross read does not match the value written.";
 		}
@@ -80,5 +80,5 @@
 			km_unmap(page0, PAGE_SIZE);
 			km_unmap(page1, PAGE_SIZE);
-			frame_free(frame);
+			frame_free(frame, 1);
 			return "Criss-cross read does not match the value written.";
 		}
@@ -87,5 +87,5 @@
 	km_unmap(page0, PAGE_SIZE);
 	km_unmap(page1, PAGE_SIZE);
-	frame_free(frame);
+	frame_free(frame, 1);
 	
 	return NULL;
