+ tPAddr paddr = MM_AllocPhys();
+ if( MM_Map(VAddr, paddr) )
+ {
+ return paddr;
+ }
+
+ // Error of some form, either an overwrite or OOM
+ MM_DerefPhys(paddr);
+
+ // Check for overwrite
+ paddr = MM_GetPhysAddr(VAddr);
+ if( paddr != 0 ) {
+ Warning("MM_Allocate - Allocating to used address (%p)", VAddr);
+ return paddr;
+ }
+
+ // OOM
+ Warning("MM_Allocate - Out of Memory (Called by %p)", __builtin_return_address(0));
+ return 0;
+}
+
+void MM_AllocateZero(volatile void *VAddr)
+{
+ if( MM_GetPhysAddr(VAddr) ) {
+ Warning("MM_AllocateZero - Attempted overwrite at %p", VAddr);
+ return ;
+ }
+ if( !giMM_ZeroPage )
+ {
+ SHORTLOCK(&glMM_ZeroPage);
+ // Check again within the lock (just in case we lost the race)
+ if( giMM_ZeroPage == 0 )
+ {
+ giMM_ZeroPage = MM_Allocate(VAddr);
+ // - Reference a second time to prevent it from being freed
+ MM_RefPhys(giMM_ZeroPage);
+ memset((void*)VAddr, 0, PAGE_SIZE);
+ }
+ SHORTREL(&glMM_ZeroPage);
+ }
+ else
+ {
+ MM_Map(VAddr, giMM_ZeroPage);
+ MM_RefPhys(giMM_ZeroPage);
+ }
+ MM_SetFlags(VAddr, MM_PFLAG_COW, MM_PFLAG_COW);
+}
+
+/**
+ * \fn int MM_Map(tVAddr VAddr, tPAddr PAddr)
+ * \brief Map a physical page to a virtual one
+ */
+int MM_Map(volatile void *VAddr, tPAddr PAddr)
+{
+ Uint pagenum = (tVAddr)VAddr >> 12;
+
+ #if TRACE_MAPS
+ Debug("MM_Map(%p, %P)", VAddr, PAddr);
+ #endif
+
+ // Sanity check
+ if( (PAddr & 0xFFF) || ((tVAddr)VAddr & 0xFFF) ) {
+ Log_Warning("MM_Virt", "MM_Map - Physical or Virtual Addresses are not aligned (%P and %p) - %p",
+ PAddr, VAddr, __builtin_return_address(0));
+ //LEAVE('i', 0);
+ return 0;
+ }
+
+ bool is_user = ((tVAddr)VAddr < MM_USER_MAX);
+