+ Debug("Done");
+}
+
+// NOTE: Runs in abort context, not much difference, just a smaller stack
+void MM_PageFault(Uint32 PC, Uint32 Addr, Uint32 DFSR, int bPrefetch)
+{
+ int rv;
+ tMM_PageInfo pi;
+
+ rv = MM_int_GetPageInfo(Addr, &pi);
+
+ // Check for COW
+ if( rv == 0 && pi.AP == AP_RO_BOTH )
+ {
+ pi.AP = AP_RW_BOTH;
+ if( giMM_ZeroPage && pi.PhysAddr == giMM_ZeroPage )
+ {
+ tPAddr newpage;
+ newpage = MM_AllocPhys();
+ if( !newpage ) {
+ Log_Error("MMVirt", "Unable to allocate new page for COW of ZERO");
+ for(;;);
+ }
+
+ #if TRACE_COW
+ Log_Notice("MMVirt", "COW %p caused by %p, ZERO duped to %P (RefCnt(%i)--)", Addr, PC,
+ newpage, MM_GetRefCount(pi.PhysAddr));
+ #endif
+
+ MM_DerefPhys(pi.PhysAddr);
+ pi.PhysAddr = newpage;
+ pi.AP = AP_RW_BOTH;
+ MM_int_SetPageInfo(Addr, &pi);
+
+ memset( (void*)(Addr & ~(PAGE_SIZE-1)), 0, PAGE_SIZE );
+
+ return ;
+ }
+ else if( MM_GetRefCount(pi.PhysAddr) > 1 )
+ {
+ // Duplicate the page
+ tPAddr newpage;
+ void *dst, *src;
+
+ newpage = MM_AllocPhys();
+ if(!newpage) {
+ Log_Error("MMVirt", "Unable to allocate new page for COW");
+ for(;;);
+ }
+ dst = (void*)MM_MapTemp(newpage);
+ src = (void*)(Addr & ~(PAGE_SIZE-1));
+ memcpy( dst, src, PAGE_SIZE );
+ MM_FreeTemp( (tVAddr)dst );
+
+ #if TRACE_COW
+ Log_Notice("MMVirt", "COW %p caused by %p, %P duped to %P (RefCnt(%i)--)", Addr, PC,
+ pi.PhysAddr, newpage, MM_GetRefCount(pi.PhysAddr));
+ #endif
+
+ MM_DerefPhys(pi.PhysAddr);
+ pi.PhysAddr = newpage;
+ }
+ #if TRACE_COW
+ else {
+ Log_Notice("MMVirt", "COW %p caused by %p, took last reference to %P",
+ Addr, PC, pi.PhysAddr);
+ }
+ #endif
+ // Unset COW
+ pi.AP = AP_RW_BOTH;
+ MM_int_SetPageInfo(Addr, &pi);
+ return ;
+ }
+
+
+ Log_Error("MMVirt", "Code at %p accessed %p (DFSR = 0x%x)%s", PC, Addr, DFSR,
+ (bPrefetch ? " - Prefetch" : "")
+ );
+ if( Addr < 0x80000000 )
+ MM_DumpTables(0, 0x80000000);
+ else
+ MM_DumpTables(0x80000000, -1);
+ for(;;);