kernel/eka/memmodel/epoc/flexible/mmu/mmu.cpp
changeset 11 329ab0095843
parent 9 96e5fb8b040d
child 13 46fffbe7b5a7
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mmu.cpp	Thu Jan 07 13:38:45 2010 +0200
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mmu.cpp	Mon Jan 18 21:31:10 2010 +0200
@@ -701,6 +701,7 @@
 	//   which has a reference on it's process, which should own the address space!
 
 #ifdef __BROADCAST_CACHE_MAINTENANCE__
+	TInt aliasAsid = -1;
 	if (thread->iAliasLinAddr)
 		{
 		// If an alias is in effect, the the thread will be locked to the current CPU,
@@ -713,6 +714,12 @@
 			__KTRACE_OPT2(KPAGING,KPANIC,Kern::Printf("Fault with thread locked to current CPU! addr=0x%08x (%O pc=%x)",aFaultAddress,thread,aPc));
 			Exc::Fault(aExceptionInfo);
 			}
+		// Open a reference on the aliased process's os asid before removing the alias
+		// so that the address space can't be freed while we try to access its members.
+		aliasAsid = thread->iAliasProcess->TryOpenOsAsid();
+		// This should never fail as until we remove the alias there will 
+		// always be at least one reference on the os asid.
+		__NK_ASSERT_DEBUG(aliasAsid >= 0);
 		thread->RemoveAlias();
 		}
 #endif
@@ -783,6 +790,15 @@
 		DMemModelThread::RestoreAddressSpace();
 		}
 
+#ifdef __BROADCAST_CACHE_MAINTENANCE__
+	// Close any reference on the aliased process's os asid before we leave the
+	// critical section.
+	if (aliasAsid >= 0)
+		{
+		thread->iAliasProcess->CloseOsAsid();
+		}
+#endif
+
 	NKern::ThreadLeaveCS();  // thread will die now if CheckRealtimeThreadFault caused a panic
 
 	// deal with XTRAP_PAGING...
@@ -1284,6 +1300,56 @@
 	iCount = 0;
 	}
 
+#ifdef __SMP__
+/**
+Dummy IPI to be invoked when a thread's alias pde members are updated remotely
+by another thread.
+
+@internalComponent
+*/
+class TAliasIPI : public TGenericIPI
+	{
+public:
+	static void RefreshIsr(TGenericIPI*);
+	void RefreshAlias();
+	};
+
+
+/**
+Dummy isr method.
+*/
+void TAliasIPI::RefreshIsr(TGenericIPI*)
+	{
+	TRACE2(("TAliasIPI"));
+	}
+
+
+/**
+Queue the dummy IPI on all other processors.  This ensures that DoProcessSwitch will
+have completed updating iAliasPdePtr once this method returns.
+*/
+void TAliasIPI::RefreshAlias()
+	{
+	NKern::Lock();
+	QueueAllOther(&RefreshIsr);
+	NKern::Unlock();
+	WaitCompletion();
+	}
+
+
+/** 
+Perform a dummy ipi on all the other processors to ensure if any of them are 
+executing DoProcessSwitch they will see the new value of iAliasPde before they 
+update iAliasPdePtr or will finish updating iAliasPdePtr before we continue.  
+This works as DoProcessSwitch() has interrupts disabled while reading iAliasPde 
+and updating iAliasPdePtr.
+*/
+void BroadcastAliasRefresh()
+	{
+	TAliasIPI ipi;
+	ipi.RefreshAlias();
+	}
+#endif //__SMP__
 
 /**
 Remove any thread IPC aliases which use the specified page table.
@@ -1311,11 +1377,12 @@
 			TRACE2(("Thread %O RemoveAliasesForPageTable", this));
 			thread->iAliasPde = KPdeUnallocatedEntry;
 #ifdef __SMP__ // we need to also unmap the page table in case thread is running on another core...
-			// need Data Memory Barrier (DMB) here to make sure iAliasPde change is
-			// seen before we set the PDE entry, otherwise 'thread' may read old value
-			// and put it back
-			__e32_memory_barrier();
+
+			// Ensure other processors see the update to iAliasPde.
+			BroadcastAliasRefresh();
+
 			*thread->iAliasPdePtr = KPdeUnallocatedEntry;
+
 			SinglePdeUpdated(thread->iAliasPdePtr);
 			__NK_ASSERT_DEBUG((thread->iAliasLinAddr&KPageMask)==0);
 			// Invalidate the tlb for the page using os asid of the process that created the alias
@@ -1325,9 +1392,6 @@
 			// note, race condition with 'thread' updating its iAliasLinAddr is
 			// not a problem because 'thread' will not the be accessing the aliased
 			// region and will take care of invalidating the TLB.
-			// FIXME: There is still a race here. If the thread owning the alias reads the
-			// PDE before we clear thread->iAliasPde and writes it after we clear
-			// *thread->iAliasPdePtr the alias still ends up restored when it shouldn't be.
 #endif
 			}
 		MmuLock::Flash();