diff --git a/Kernel/arch/x86/include/proc.h b/Kernel/arch/x86/include/proc.h
index e449a0fa05c61abdba2570da84806ae6339a18d9..73bddbb9758233ae4bab1a605785d5ad9f715b4d 100644
--- a/Kernel/arch/x86/include/proc.h
+++ b/Kernel/arch/x86/include/proc.h
@@ -23,4 +23,6 @@ typedef struct sTSS {
 	Uint16	Resvd, IOPB;	// IO Permissions Bitmap
 } __attribute__((packed)) tTSS;
 
+#define USER_MAX	KERNEL_BASE
+
 #endif
diff --git a/Kernel/arch/x86/start.asm b/Kernel/arch/x86/start.asm
index 8c7d9a64008e469209a3bd7b3a2b459476ba7780..d504a5df5f5df718196e11011eab2c01a122e4ee 100644
--- a/Kernel/arch/x86/start.asm
+++ b/Kernel/arch/x86/start.asm
@@ -70,7 +70,7 @@ start:
 	mov cr3, ecx
 	
 	mov ecx, cr0
-	or	ecx, 0x80010000	; PG and WP
+	or ecx, 0x80010000	; PG and WP
 	mov cr0, ecx
 	
 	mov WORD [0xB8002], 0x0763	; 'c'
diff --git a/Kernel/arch/x86_64/main.c b/Kernel/arch/x86_64/main.c
index d3b79c673a8f09e43412f13d72387587d61d2d94..c154870610a74eb697a26a458e718b1f33cf8921 100644
--- a/Kernel/arch/x86_64/main.c
+++ b/Kernel/arch/x86_64/main.c
@@ -41,8 +41,6 @@ void kmain(Uint MbMagic, void *MbInfoPtr)
 		// Adjust Multiboot structure address
 		mbInfo = (void*)( (Uint)MbInfoPtr + KERNEL_BASE );
 		gsBootCmdLine = (char*)( (Uint)mbInfo->CommandLine + KERNEL_BASE);
-		Log("gsBootCmdLine = '%s'", gsBootCmdLine);
-		
 		MM_InitPhys_Multiboot( mbInfo );	// Set up physical memory manager
 		break;
 	default:
@@ -57,14 +55,13 @@ void kmain(Uint MbMagic, void *MbInfoPtr)
 	Heap_Install();
 	
 	*(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'E';
-	Log_Log("Arch", "Starting threading...");
 	Threads_Init();
 	
 	Time_Setup();
 	*(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'F';
 	
-	Log_Log("Arch", "Starting VFS...");
 	// Load Virtual Filesystem
+	Log_Log("Arch", "Starting VFS...");
 	VFS_Init();
 	
 	*(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'Z';
diff --git a/Kernel/arch/x86_64/mm_phys.c b/Kernel/arch/x86_64/mm_phys.c
index 064622f8273361d45254193be2b2197a3a94fde2..c2c215b3b99603d96146a1044d4451cedfbc2919 100644
--- a/Kernel/arch/x86_64/mm_phys.c
+++ b/Kernel/arch/x86_64/mm_phys.c
@@ -183,7 +183,7 @@ void MM_InitPhys_Multiboot(tMBoot_Info *MBoot)
 				paddr = ent->Base;
 			}
 			
-			Log(" MM_InitPhys_Multiboot: paddr=0x%x, avail=%i", paddr, avail);
+			Log("MM_InitPhys_Multiboot: paddr=0x%x, avail=0x%x pg", paddr, avail);
 			
 			// Map
 			while( todo && avail --)
@@ -509,7 +509,7 @@ void MM_RefPhys(tPAddr PAddr)
 				return ;
 			}
 			// Fill block
-			Log("Allocated references for %P-%P", page_base << 12, (page_base+pages_per_refpage-1)<<12);
+			Log("Allocated references for %P-%P", page_base << 12, (page_base+pages_per_refpage)<<12);
 			for( i = 0; i < pages_per_refpage; i ++ ) {
 				 int	pg = page_base + i;
 				gaiPageReferences[pg] = !!PAGE_ALLOC_TEST(pg);
diff --git a/Kernel/arch/x86_64/mm_virt.c b/Kernel/arch/x86_64/mm_virt.c
index 1bb890c60abc499ec31ecf39615987e402764a51..12bb3a47da50ec66db9d1c3bcf6f7f7497e1b569 100644
--- a/Kernel/arch/x86_64/mm_virt.c
+++ b/Kernel/arch/x86_64/mm_virt.c
@@ -80,7 +80,7 @@ tPAddr	gMM_ZeroPage;
 // === CODE ===
 void MM_InitVirt(void)
 {
-	Log_Debug("MMVirt", "&PAGEMAPLVL4(0) = %p", &PAGEMAPLVL4(0));
+//	Log_Debug("MMVirt", "&PAGEMAPLVL4(0) = %p", &PAGEMAPLVL4(0));
 //	MM_DumpTables(0, -1L);
 }
 
@@ -106,6 +106,7 @@ void MM_int_ClonePageEnt( Uint64 *Ent, void *NextLevel, tVAddr Addr, int bTable
 	{
 		*Ent &= ~PF_COW;
 		*Ent |= PF_PRESENT|PF_WRITE;
+//		Log_Debug("MMVirt", "COW ent at %p (%p) only %P", Ent, NextLevel, curpage);
 	}
 	else
 	{
@@ -820,18 +821,21 @@ tPAddr MM_Clone(void)
 		if( TMPMAPLVL4(i) & 1 )
 			MM_RefPhys( TMPMAPLVL4(i) & PADDR_MASK );
 	}
+
+	// Mark Per-Process data as COW
+	TMPMAPLVL4(MM_PPD_BASE>>39) |= PF_COW;
+	TMPMAPLVL4(MM_PPD_BASE>>39) &= ~PF_WRITE;
 	
 	// #5 Set fractal mapping
-	TMPMAPLVL4(508) = ret | 3;	// Main
-	TMPMAPLVL4(509) = 0;	// Temp
+	TMPMAPLVL4(MM_FRACTAL_BASE>>39) = ret | 3;	// Main
+	TMPMAPLVL4(MM_TMPFRAC_BASE>>39) = 0;	// Temp
 	
 	// #6 Create kernel stack
 	//  tThread->KernelStack is the top
 	//  There is 1 guard page below the stack
 	kstackbase = Proc_GetCurThread()->KernelStack - KERNEL_STACK_SIZE;
 
-	Log("MM_Clone: kstackbase = %p", kstackbase);
-	
+	// Clone stack
 	TMPMAPLVL4(MM_KSTACK_BASE >> PML4_SHIFT) = 0;
 	for( i = 1; i < KERNEL_STACK_SIZE/0x1000; i ++ )
 	{
@@ -839,9 +843,6 @@ tPAddr MM_Clone(void)
 		tVAddr	tmpmapping;
 		MM_MapEx(kstackbase+i*0x1000, phys, 1, 0);
 		
-		Log_Debug("MM", "MM_Clone: Cloning stack page %p from %P to %P",
-			kstackbase+i*0x1000, MM_GetPhysAddr( kstackbase+i*0x1000 ), phys
-			);
 		tmpmapping = MM_MapTemp(phys);
 		if( MM_GetPhysAddr( kstackbase+i*0x1000 ) )
 			memcpy((void*)tmpmapping, (void*)(kstackbase+i*0x1000), 0x1000);
@@ -867,7 +868,7 @@ void MM_int_ClearTableLevel(tVAddr VAddr, int LevelBits, int MaxEnts)
 	Uint64	* const table_bases[] = {&PAGETABLE(0), &PAGEDIR(0), &PAGEDIRPTR(0), &PAGEMAPLVL4(0)};
 	Uint64	*table = table_bases[(LevelBits-12)/9] + (VAddr >> LevelBits);
 	 int	i;
-	Log("MM_int_ClearTableLevel: (VAddr=%p, LevelBits=%i, MaxEnts=%i)", VAddr, LevelBits, MaxEnts);
+//	Log("MM_int_ClearTableLevel: (VAddr=%p, LevelBits=%i, MaxEnts=%i)", VAddr, LevelBits, MaxEnts);
 	for( i = 0; i < MaxEnts; i ++ )
 	{
 		// Skip non-present tables
diff --git a/Kernel/arch/x86_64/proc.c b/Kernel/arch/x86_64/proc.c
index 50f712fb989c99abcf411f485a450268803e9584..415901fc8b8529c549aaf46dc5a271b4110f019a 100644
--- a/Kernel/arch/x86_64/proc.c
+++ b/Kernel/arch/x86_64/proc.c
@@ -16,7 +16,7 @@
 #include <hal_proc.h>
 
 // === FLAGS ===
-#define DEBUG_TRACE_SWITCH	1
+#define DEBUG_TRACE_SWITCH	0
 #define BREAK_ON_SWITCH 	0	// Break into bochs debugger on a task switch
 
 // === CONSTANTS ===
@@ -413,7 +413,7 @@ void Proc_Start(void)
 	__asm__ __volatile__("sti");
 	#endif
 	MM_FinishVirtualInit();
-	Log("Multithreading started");
+	Log_Log("Proc", "Multithreading started");
 }
 
 /**
@@ -490,13 +490,15 @@ int Proc_Clone(Uint Flags)
 	newThread->KernelStack = cur->KernelStack;
 	newThread->SavedState.RIP = rip;
 
-	// DEBUG	
+	// DEBUG
+	#if 0
 	Log("New (Clone) %p, rsp = %p, cr3 = %p", rip, newThread->SavedState.RSP, newThread->MemState.CR3);
 	{
 		Uint cr3;
 		__asm__ __volatile__ ("mov %%cr3, %0" : "=r" (cr3));
 		Log("Current CR3 = 0x%x, PADDR(RSP) = 0x%x", cr3, MM_GetPhysAddr(newThread->SavedState.RSP));
 	}
+	#endif
 	// /DEBUG
 	
 	// Lock list and add to active
@@ -573,7 +575,6 @@ Uint Proc_MakeUserStack(void)
 	for( ; i < USER_STACK_SZ/0x1000; i++ )
 	{
 		tPAddr	alloc = MM_Allocate( base + (i<<12) );
-		Log_Debug("Proc", "Proc_MakeUserStack: alloc = %P", alloc);
 		if( !alloc )
 		{
 			// Error
@@ -634,9 +635,8 @@ void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP)
 			CS, SS);
 		Threads_Exit(0, -1);
 	}
-	Log("Proc_StartProcess: (SS=%x, Stack=%p, Flags=%x, CS=%x, IP=%p)",
-		SS, Stack, Flags, CS, IP);
-	MM_DumpTables(0, USER_MAX);
+//	Log("Proc_StartProcess: (SS=%x, Stack=%p, Flags=%x, CS=%x, IP=%p)", SS, Stack, Flags, CS, IP);
+//	MM_DumpTables(0, USER_MAX);
 	if(CS == 0x1B)
 	{
 		// 32-bit return
@@ -724,12 +724,12 @@ void Proc_Reschedule(void)
 		return ;
 
 	#if DEBUG_TRACE_SWITCH
-	LogF("\nSwitching to task %i, CR3 = 0x%x, RIP = %p, RSP = %p, KStack = %p\n",
-		nextthread->TID,
+	LogF("\nSwitching to task CR3 = 0x%x, RIP = %p, RSP = %p - %i (%s)\n",
 		nextthread->MemState.CR3,
 		nextthread->SavedState.RIP,
 		nextthread->SavedState.RSP,
-		nextthread->KernelStack
+		nextthread->TID,
+		nextthread->ThreadName
 		);
 	#endif
 
diff --git a/Kernel/arch/x86_64/start32.asm b/Kernel/arch/x86_64/start32.asm
index da0739b8d1763fb3d3e9797b9e3a4fac85518148..d38c993ee52f109bbdb2af49594bb001908902d3 100644
--- a/Kernel/arch/x86_64/start32.asm
+++ b/Kernel/arch/x86_64/start32.asm
@@ -70,7 +70,7 @@ start:
 
 	; Enable paging
 	mov eax, cr0
-	or eax, 0x80000000
+	or eax, 0x80010000	; PG & WP
 	mov cr0, eax
 
 	; Load GDT
diff --git a/Kernel/syscalls.c b/Kernel/syscalls.c
index 742b082a968540ad91864612dea2449d3ebb6bd0..e304b40e2a9c25a1b5fd0fddec6e820229b69b13 100644
--- a/Kernel/syscalls.c
+++ b/Kernel/syscalls.c
@@ -68,7 +68,6 @@ void SyscallHandler(tSyscallRegs *Regs)
 	case SYS_CLONE:
 		// Call clone system call
 		ret = Proc_Clone(Regs->Arg1);
-		Log("Proc_Clone returned %i", ret);
 		// Change user stack if a new stack address is passed
 		if(ret == 0 && Regs->Arg2)
 			Regs->StackPointer = Regs->Arg2;