From c25c94b469aeee2b28ca2118dfee4e8ff5e82fd5 Mon Sep 17 00:00:00 2001
From: Oliver Ford <oliford@NervousEnergy.(none)>
Date: Sat, 19 Apr 2008 18:59:55 +0100
Subject: [PATCH]     Initial MMU level 1 table merging.

    Adds the vars MMUMergeStart and MMUMergeCount.
    The specified entries of the level 1 table are watched and the number of
    times they change recorded. The last non-unmapped entry is reported.

    Used to find virtual address when windows keeps hiding MMU entries.
---
 include/irq.h |   17 +++++++++
 src/irq.cpp   |  103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 120 insertions(+), 0 deletions(-)

diff --git a/include/irq.h b/include/irq.h
index ed3b8ac..f27b2f6 100644
--- a/include/irq.h
+++ b/include/irq.h
@@ -97,6 +97,14 @@ struct irqData {
     uint32 clock;
     uint32 exitEarly;
     struct traceitem traces[NR_TRACE];
+
+    //
+    // MMU L1 table merging (see bottom of irq.cpp)
+    //
+    uint32 mergeTableCount;
+    uint32 mergeTableStart;
+    uint32 l1Copy[4096];
+    uint32 l1Changed[4096];
 };
 
 // Add an item to the trace buffer.
@@ -205,3 +213,12 @@ void L1_resume_handler(struct irqData *data, struct irqregs *regs);
 void startL1traps(struct irqData *data);
 void stopL1traps(struct irqData *data);
 int prepL1traps(struct irqData *data);
+
+
+/****************************************************************
+ * MMU L1 table merging (see bottom of irq.cpp)
+ ****************************************************************/
+void startMMUMerge(struct irqData *data);
+void __irq stopMMUMerge(struct irqData *data);
+int prepMMUMerge(struct irqData *data);
+void dumpMMUMerge(struct irqData *data);
diff --git a/src/irq.cpp b/src/irq.cpp
index b89905c..a655f95 100644
--- a/src/irq.cpp
+++ b/src/irq.cpp
@@ -75,6 +75,7 @@ postPoll(struct irqData *data, int isPXA) {
         set_DBCON(data->dbcon);
 }
 
+static void __irq checkMMUMerge(struct irqData *data ); //prototype for mmu checks and merging  (bottom of irq.cpp)
 
 /****************************************************************
  * C part of exception handlers
@@ -124,6 +125,7 @@ irq_handler(struct irqData *data, struct irqregs *regs)
     prePoll(data, isPXA);
     checkPolls(data, &data->irqpoll);
     checkPolls(data, &data->tracepoll);
+    checkMMUMerge(data);
     postPoll(data, isPXA);
 }
 
@@ -142,6 +144,7 @@ abort_handler(struct irqData *data, struct irqregs *regs)
     // Trace time memory polling.
     prePoll(data, isPXA);
     checkPolls(data, &data->tracepoll);
+    checkMMUMerge(data);
     postPoll(data, isPXA);
 
     return ret;
@@ -162,6 +165,7 @@ prefetch_handler(struct irqData *data, struct irqregs *regs)
     // Trace time memory polling.
     prePoll(data, isPXA);
     checkPolls(data, &data->tracepoll);
+    checkMMUMerge(data);
     postPoll(data, isPXA);
 
     return ret;
@@ -434,6 +438,10 @@ cmd_wirq(const char *cmd, const char *args)
     if (ret)
         goto abort;
 
+    ret = prepMMUMerge(data);
+    if (ret)
+        goto abort;
+
     ret = hookResume(
         memVirtToPhys((uint32)&code->cCode[offset_cResumeHandler()])
         , memVirtToPhys((uint32)data)
@@ -447,6 +455,7 @@ cmd_wirq(const char *cmd, const char *args)
     take_control();
     startPXAtraps(data);
     startL1traps(data);
+    startMMUMerge(data);
     Mach->flushCache();
     *irq_loc = newIrqHandler;
     *abort_loc = newAbortHandler;
@@ -462,6 +471,7 @@ cmd_wirq(const char *cmd, const char *args)
     take_control();
     stopPXAtraps(data);
     stopL1traps(data);
+    stopMMUMerge(data);
     Mach->flushCache();
     *irq_loc = asmVars->winceIrqHandler;
     *abort_loc = asmVars->winceAbortHandler;
@@ -471,6 +481,7 @@ cmd_wirq(const char *cmd, const char *args)
 
     unhookResume();
 
+    dumpMMUMerge(data);
     postLoop(data);
 abort:
     if (rawCode)
@@ -479,3 +490,95 @@ abort:
 REG_CMD(testWirqAvail, "WI|RQ", cmd_wirq,
         "WIRQ <seconds>\n"
         "  Watch which IRQ occurs for some period of time and report them.")
+
+
+
+// MMU Table merging
+//
+// Idea is to make a copy of the l1 table and at the start every IRQ we compare it to the current one.
+// Any changes are just written to copy of the table except for writing type 0 (unmapped).
+// We should end up with a table which is the merged copy of anything windows tries to hide.
+// The counts represent the number of times something actually different gets mapped there, so
+// if winCE is just turning it on and off, he count will be 1.
+//
+
+static uint32 MMUMergeStart;
+REG_VAR_INT(testWirqAvail,"MMUMergeStart",MMUMergeStart,
+            "First entry of MMU level 1 table to watch.")
+static uint32 MMUMergeCount;
+REG_VAR_INT(testWirqAvail,"MMUMergeCount",MMUMergeCount,
+            "Number of MMU level 1 table entries to watch. Making this too big (~> 512) may seriously slow/crash your system!")
+
+
+// setup
+int prepMMUMerge(struct irqData *data)
+{
+	data->mergeTableStart = MMUMergeStart;
+	data->mergeTableCount = MMUMergeCount;
+
+	if( !data->mergeTableCount ){
+		Output("MMU Table merging disabled");
+		return 0;
+	}
+	
+	//make sure we have the mmu table address
+	if( !data->mmuVAddr ){
+		data->mmuVAddr = (uint32*)memPhysMap(cpuGetMMU());
+		if (! data->mmuVAddr) {
+			Output("Unable to map MMU table");
+			data->mergeTableCount = 0; 
+			return -1;
+		}
+	}
+	Output("MMU L1 table merging enabled, watching %i entries starting at entry %i",
+		data->mergeTableCount,data->mergeTableStart);
+	
+	return 0;
+}
+
+// start
+void startMMUMerge(struct irqData *data)
+{ 
+	if( !data->mergeTableCount ) return;
+	
+	//make the initial copy
+	memcpy(data->l1Copy,data->mmuVAddr + data->mergeTableStart,0x4000); //make initial copy now (after harets modifications)
+	memset(data->l1Changed,0,sizeof(data->l1Changed)); //clear all change flags
+}
+
+// stop
+void __irq stopMMUMerge(struct irqData *data)
+{
+	if( !data->mergeTableCount ) return;	
+	//anything to do?
+}
+
+void dumpMMUMerge(struct irqData *data){
+	if( !data->mergeTableCount ) return;
+
+	Output("MMU Merge table:");
+	Output("Index  ( vAddr  ) = Last entry  x Change count");
+	for(uint i=0;i < data->mergeTableCount;i++)
+		if(data->l1Changed[i]){
+			uint idx = data->mergeTableStart + i;
+			Output("%5i  (%08x) = %08x   x %i",idx,(idx << 20), data->l1Copy[i],data->l1Changed[i]);
+		}	
+}
+
+// perform check and merge
+static void __irq checkMMUMerge(struct irqData *data )
+{
+	if( !data->mergeTableCount ) return; 	
+	
+	uint32 *tableEntry;
+	for(uint i=0; i< data->mergeTableCount; i++){ //for each mmu entry
+		tableEntry = data->mmuVAddr + (data->mergeTableStart + i);
+		if(data->l1Copy[i] != *tableEntry){
+			//only interested if its changing to another map, not to unmapped
+			if(*tableEntry != 0){
+				data->l1Changed[i]++; //count actual changes
+				data->l1Copy[i] = *tableEntry;
+			}
+		}
+	}
+}
-- 
1.5.2.5

