Index: arch/ppc32/include/mm/tlb.h
===================================================================
--- arch/ppc32/include/mm/tlb.h	(revision 16dad0326d5098846c35e2175b8768aef9de8b36)
+++ arch/ppc32/include/mm/tlb.h	(revision 9a68b34d997aee7a6bb46e96ef6da51cb260bcaf)
@@ -33,5 +33,22 @@
 #include <typedefs.h>
 
-extern void pht_refill(istate_t *istate);
+#define PHT_BITS	16
+#define PHT_ORDER	4
+
+typedef struct {
+	unsigned v : 1;          /**< Valid */
+	unsigned vsid : 24;      /**< Virtual Segment ID */
+	unsigned h : 1;          /**< Primary/secondary hash */
+	unsigned api : 6;        /**< Abbreviated Page Index */
+	unsigned rpn : 20;       /**< Real Page Number */
+	unsigned reserved0 : 3;
+	unsigned r : 1;          /**< Reference */
+	unsigned c : 1;          /**< Change */
+	unsigned wimg : 4;       /**< Access control */
+	unsigned reserved1 : 1;
+	unsigned pp : 2;         /**< Page protection */
+} phte_t;
+
+extern void pht_refill(bool data, istate_t *istate);
 
 #endif
Index: arch/ppc32/src/drivers/cuda.c
===================================================================
--- arch/ppc32/src/drivers/cuda.c	(revision 16dad0326d5098846c35e2175b8768aef9de8b36)
+++ arch/ppc32/src/drivers/cuda.c	(revision 9a68b34d997aee7a6bb46e96ef6da51cb260bcaf)
@@ -72,4 +72,8 @@
 #ifdef CONFIG_POWEROFF
 	cuda_packet(CUDA_POWERDOWN);
+#else
+	asm volatile (
+		"b 0\n"
+	);
 #endif
 	cpu_sleep();
Index: arch/ppc32/src/exception.S
===================================================================
--- arch/ppc32/src/exception.S	(revision 16dad0326d5098846c35e2175b8768aef9de8b36)
+++ arch/ppc32/src/exception.S	(revision 9a68b34d997aee7a6bb46e96ef6da51cb260bcaf)
@@ -139,5 +139,6 @@
 	
 	addis sp, sp, 0x8000
-	mr r3, sp
+	li r3, 1
+	mr r4, sp
 	rfi
 
@@ -160,5 +161,6 @@
 	
 	addis sp, sp, 0x8000
-	mr r3, sp
+	li r3, 0
+	mr r4, sp
 	rfi
 
Index: arch/ppc32/src/mm/tlb.c
===================================================================
--- arch/ppc32/src/mm/tlb.c	(revision 16dad0326d5098846c35e2175b8768aef9de8b36)
+++ arch/ppc32/src/mm/tlb.c	(revision 9a68b34d997aee7a6bb46e96ef6da51cb260bcaf)
@@ -30,4 +30,5 @@
 #include <arch/types.h>
 #include <mm/tlb.h>
+#include <mm/frame.h>
 #include <mm/page.h>
 #include <mm/as.h>
@@ -37,4 +38,7 @@
 
 
+static phte_t *phte;
+
+
 /** Initialize Page Hash Table.
  *
@@ -44,4 +48,16 @@
 void tlb_arch_init(void)
 {
+	phte_t *physical_phte = (phte_t *) PFN2ADDR(frame_alloc(PHT_ORDER, FRAME_KA | FRAME_PANIC));
+	phte =(phte_t *) PA2KA((__address) physical_phte);
+	
+	ASSERT((__address) physical_phte % (1 << PHT_BITS) == 0);
+	
+	memsetb((__address) phte, 1 << PHT_BITS, 0);
+	
+	asm volatile (
+		"mtsdr1 %0\n"
+		:
+		: "r" ((__address) physical_phte)
+	);
 }
 
@@ -104,24 +120,33 @@
 	if (s)
 		sym2 = s;
-	panic("%X: PHT Refill Exception at %X(%s<-%s)\n", badvaddr, istate->pc, symbol, sym2);
-}
-
-
-/** Process Data Storage Interrupt
- *
+	panic("%p: PHT Refill Exception at %p (%s<-%s)\n", badvaddr, istate->pc, symbol, sym2);
+}
+
+
+/** Process Instruction/Data Storage Interrupt
+ *
+ * @param data   True if Data Storage Interrupt.
  * @param istate Interrupted register context.
  *
  */
-void pht_refill(istate_t *istate)
+void pht_refill(bool data, istate_t *istate)
 {
 	asid_t asid;
 	__address badvaddr;
 	pte_t *pte;
-	
-	__asm__ volatile (
-		"mfdar %0\n"
-		: "=r" (badvaddr)
-	);
-	
+	__u32 page;
+	__u32 api;
+	__u32 vsid;
+	__u32 hash;
+	__u32 i;
+	
+	if (data) {
+		asm volatile (
+			"mfdar %0\n"
+			: "=r" (badvaddr)
+		);
+	} else
+		badvaddr = istate->pc;
+		
 	spinlock_lock(&AS->lock);
 	asid = AS->asid;
@@ -134,11 +159,38 @@
 		goto fail;
 
-	/*
-	 * Record access to PTE.
-	 */
+	/* Record access to PTE */
 	pte->a = 1;
 	
-	// FIXME: Insert entry into PHT
-
+	page = ADDR2PFN(badvaddr);
+	api = (badvaddr >> 22) & 0x3f;
+	asm volatile (
+		"mfsrin %0, %1\n"
+		: "=r" (vsid)
+		: "r" (badvaddr >> 28)
+	);
+	
+	/* Primary hash (xor) */
+	hash = ((vsid ^ page) & 0x3ff) << 3;
+	
+	/* Find invalid PTE in PTEG */
+	for (i = 0; i < 8; i++) {
+		if (!phte[hash + i].v)
+			break;
+	}
+	
+	// TODO: Check access/change bits, secondary hash
+	
+	if (i == 8)
+		i = page % 8;
+	
+	phte[hash + i].v = 1;
+	phte[hash + i].vsid = vsid;
+	phte[hash + i].h = 0;
+	phte[hash + i].api = api;
+	phte[hash + i].rpn = pte->pfn;
+	phte[hash + i].r = 0;
+	phte[hash + i].c = 0;
+	phte[hash + i].pp = 2; // FIXME
+	
 	page_table_unlock(AS, true);
 	return;
Index: generic/src/mm/frame.c
===================================================================
--- generic/src/mm/frame.c	(revision 16dad0326d5098846c35e2175b8768aef9de8b36)
+++ generic/src/mm/frame.c	(revision 9a68b34d997aee7a6bb46e96ef6da51cb260bcaf)
@@ -435,9 +435,13 @@
  *
  * Assume zone is locked
- * Panics, if allocation is impossible.
+ * Panics if allocation is impossible.
+ *
+ * @param zone  Zone to allocate from.
+ * @param order Allocate exactly 2^order frames.
  *
  * @return Frame index in zone
- */
-static pfn_t zone_frame_alloc(zone_t *zone,__u8 order)
+ *
+ */
+static pfn_t zone_frame_alloc(zone_t *zone, __u8 order)
 {
 	pfn_t v;
@@ -892,11 +896,13 @@
 /** Allocate power-of-two frames of physical memory.
  *
- * @param flags Flags for host zone selection and address processing.
- * @param order Allocate exactly 2^order frames.
- * @param pzone Preferred zone
+ * @param order  Allocate exactly 2^order frames.
+ * @param flags  Flags for host zone selection and address processing.
+ * @param status Allocation status (FRAME_OK on success), unused if NULL.
+ * @param pzone  Preferred zone
  *
  * @return Allocated frame.
- */
-pfn_t frame_alloc_generic(__u8 order, int flags, int * status, int *pzone) 
+ *
+ */
+pfn_t frame_alloc_generic(__u8 order, int flags, int *status, int *pzone) 
 {
 	ipl_t ipl;
@@ -907,8 +913,10 @@
 loop:
 	ipl = interrupts_disable();
+	
 	/*
 	 * First, find suitable frame zone.
 	 */
-	zone = find_free_zone_lock(order,pzone);
+	zone = find_free_zone_lock(order, pzone);
+	
 	/* If no memory, reclaim some slab memory,
 	   if it does not help, reclaim all */
@@ -916,9 +924,9 @@
 		freed = slab_reclaim(0);
 		if (freed)
-			zone = find_free_zone_lock(order,pzone);
+			zone = find_free_zone_lock(order, pzone);
 		if (!zone) {
 			freed = slab_reclaim(SLAB_RECLAIM_ALL);
 			if (freed)
-				zone = find_free_zone_lock(order,pzone);
+				zone = find_free_zone_lock(order, pzone);
 		}
 	}
@@ -942,5 +950,6 @@
 		goto loop;
 	}
-	v = zone_frame_alloc(zone,order);
+	
+	v = zone_frame_alloc(zone, order);
 	v += zone->base;
 
