diff --git a/common/include/Utilities/PageFaultSource.h b/common/include/Utilities/PageFaultSource.h index 41fd4c0924..0101d5c4af 100644 --- a/common/include/Utilities/PageFaultSource.h +++ b/common/include/Utilities/PageFaultSource.h @@ -130,7 +130,7 @@ class VirtualMemoryReserve protected: wxString m_name; - // Default size of the reserve, in bytes. Can be specified when the object is contructed. + // Default size of the reserve, in bytes. Can be specified when the object is constructed. // Is used as the reserve size when Reserve() is called, unless an override is specified // in the Reserve parameters. size_t m_defsize; @@ -140,13 +140,19 @@ protected: // reserved memory (in pages). uptr m_pages_reserved; - // Protection mode to be applied to committed blocks. - PageProtectionMode m_prot_mode; - // Records the number of pages committed to memory. // (metric for analysis of buffer usage) uptr m_pages_commited; + // Protection mode to be applied to committed blocks. + PageProtectionMode m_prot_mode; + + // Controls write access to the entire reserve. When true (the default), the reserve + // operates normally. When set to false, all committed blocks are re-protected with + // write disabled, and accesses to uncommitted blocks (read or write) will cause a GPF + // as well. + bool m_allow_writes; + public: VirtualMemoryReserve( const wxString& name=wxEmptyString, size_t size = 0 ); virtual ~VirtualMemoryReserve() throw() @@ -164,6 +170,9 @@ public: virtual void Release(); virtual bool TryResize( uint newsize ); virtual bool Commit(); + + virtual void ForbidModification(); + virtual void AllowModification(); bool IsOk() const { return m_baseptr != NULL; } wxString GetName() const { return m_name; } @@ -200,6 +209,8 @@ public: return *((u8*)m_baseptr + idx); } +protected: + virtual void ReprotectCommittedBlocks( const PageProtectionMode& newmode ); }; // -------------------------------------------------------------------------------------- @@ -231,6 +242,12 @@ public: void OnPageFaultEvent( const PageFaultInfo& info, bool& handled ); + virtual uptr SetBlockSize( uptr bytes ) + { + m_blocksize = (bytes + __pagesize - 1) / __pagesize; + return m_blocksize * __pagesize; + } + protected: // This function is called from OnPageFaultEvent after the address has been translated @@ -298,7 +315,8 @@ public: SpatialArrayReserve& SetBlockCount( uint blocks ); SpatialArrayReserve& SetBlockSizeInPages( uint bytes ); - uint SetBlockSize( uint bytes ); + + uptr SetBlockSize( uptr bytes ); operator void*() { return m_baseptr; } operator const void*() const { return m_baseptr; } @@ -309,6 +327,7 @@ public: using _parent::operator[]; protected: + void ReprotectCommittedBlocks( const PageProtectionMode& newmode ); void DoCommitAndProtect( uptr page ); uint _calcBlockBitArrayLength() const; }; diff --git a/common/src/Utilities/Exceptions.cpp b/common/src/Utilities/Exceptions.cpp index c1365d6b03..74d669ab42 100644 --- a/common/src/Utilities/Exceptions.cpp +++ b/common/src/Utilities/Exceptions.cpp @@ -218,8 +218,8 @@ wxString Exception::OutOfMemory::FormatDisplayMessage() const FastFormatUnicode retmsg; retmsg.Write( L"%s", _("Oh noes! Out of memory!") ); - if (!m_message_diag.IsEmpty()) - retmsg.Write(L"\n\n%s", m_message_diag.c_str()); + if (!m_message_user.IsEmpty()) + retmsg.Write(L"\n\n%s", m_message_user.c_str()); return retmsg; } diff --git a/common/src/Utilities/ThreadTools.cpp b/common/src/Utilities/ThreadTools.cpp index 3dd34302eb..10ef9ea0b4 100644 --- a/common/src/Utilities/ThreadTools.cpp +++ b/common/src/Utilities/ThreadTools.cpp @@ -405,7 +405,8 @@ void Threading::pxThread::RethrowException() const // after. ScopedExcept ptr( const_cast(this)->m_except.DetachPtr() ); - if( ptr ) ptr->Rethrow(); + if (ptr) + ptr->Rethrow(); } static bool m_BlockDeletions = false; diff --git a/common/src/Utilities/VirtualMemory.cpp b/common/src/Utilities/VirtualMemory.cpp index 50969186db..6a88233fa0 100644 --- a/common/src/Utilities/VirtualMemory.cpp +++ b/common/src/Utilities/VirtualMemory.cpp @@ -79,6 +79,7 @@ VirtualMemoryReserve::VirtualMemoryReserve( const wxString& name, size_t size ) m_pages_reserved = 0; m_baseptr = NULL; m_prot_mode = PageAccess_None(); + m_allow_writes = true; } VirtualMemoryReserve& VirtualMemoryReserve::SetName( const wxString& newname ) @@ -162,12 +163,18 @@ void* VirtualMemoryReserve::Reserve( size_t size, uptr base, uptr upper_bounds ) return m_baseptr; } +void VirtualMemoryReserve::ReprotectCommittedBlocks( const PageProtectionMode& newmode ) +{ + if (!m_pages_commited) return; + HostSys::MemProtect(m_baseptr, m_pages_commited*__pagesize, newmode); +} + // Clears all committed blocks, restoring the allocation to a reserve only. void VirtualMemoryReserve::Reset() { if (!m_pages_commited) return; - HostSys::MemProtect(m_baseptr, m_pages_commited*__pagesize, PageAccess_None()); + ReprotectCommittedBlocks(PageAccess_None()); HostSys::MmapResetPtr(m_baseptr, m_pages_commited*__pagesize); m_pages_commited = 0; } @@ -186,6 +193,18 @@ bool VirtualMemoryReserve::Commit() return HostSys::MmapCommitPtr(m_baseptr, m_pages_reserved*__pagesize, m_prot_mode); } +void VirtualMemoryReserve::AllowModification() +{ + m_allow_writes = true; + HostSys::MemProtect(m_baseptr, m_pages_commited*__pagesize, m_prot_mode); +} + +void VirtualMemoryReserve::ForbidModification() +{ + m_allow_writes = false; + HostSys::MemProtect(m_baseptr, m_pages_commited*__pagesize, PageProtectionMode(m_prot_mode).Write(false)); +} + // If growing the array, or if shrinking the array to some point that's still *greater* than the // committed memory range, then attempt a passive "on-the-fly" resize that maps/unmaps some portion @@ -273,6 +292,16 @@ void BaseVmReserveListener::OnPageFaultEvent(const PageFaultInfo& info, bool& ha sptr offset = (info.addr - (uptr)m_baseptr) / __pagesize; if ((offset < 0) || ((uptr)offset >= m_pages_reserved)) return; + if (!m_allow_writes) + { + pxFailRel( pxsFmt( + L"Memory Protection Fault @ %s (%s)\n" + L"Modification of this reserve has been disabled (m_allow_writes == false).", + pxsPtr(info.addr), m_name.c_str()) + ); + return; + } + // Linux Note! the SIGNAL handler is very limited in what it can do, and not only can't // we let the C++ exception try to unwind the stack, we may not be able to log it either. // (but we might as well try -- kernel/posix rules says not to do it, but Linux kernel @@ -336,23 +365,26 @@ void* SpatialArrayReserve::Reserve( size_t size, uptr base, uptr upper_bounds ) return addr; } +void SpatialArrayReserve::ReprotectCommittedBlocks( const PageProtectionMode& newmode ) +{ + if (!m_pages_commited) return; + + u8* curptr = GetPtr(); + const uint blockBytes = m_blocksize * __pagesize; + for (uint i=0; imicroVU0.IsAvailable(); } @@ -491,6 +497,12 @@ void SysCpuProviderPack::CleanupMess() throw() { psxRec.Shutdown(); recCpu.Shutdown(); + + if (newVifDynaRec) + { + dVifRelease(0); + dVifRelease(1); + } } DESTRUCTOR_CATCHALL } @@ -558,8 +570,11 @@ void SysClearExecutionCache() CpuVU0->Reset(); CpuVU1->Reset(); - resetNewVif(0); - resetNewVif(1); + if (newVifDynaRec) + { + dVifReset(0); + dVifReset(1); + } } // Maps a block of memory for use as a recompiled code buffer, and ensures that the diff --git a/pcsx2/x86/newVif.h b/pcsx2/x86/newVif.h index 1f77cc75a8..c1540ccbf4 100644 --- a/pcsx2/x86/newVif.h +++ b/pcsx2/x86/newVif.h @@ -39,6 +39,7 @@ extern void dVifReset (int idx); extern void dVifClose (int idx); extern void dVifRelease (int idx); extern void VifUnpackSSE_Init(); +extern void VifUnpackSSE_Destroy(); _vifT extern void dVifUnpack (const u8* data, bool isFill); diff --git a/pcsx2/x86/newVif_Dynarec.cpp b/pcsx2/x86/newVif_Dynarec.cpp index ecf814dfb1..6ec2f4a24d 100644 --- a/pcsx2/x86/newVif_Dynarec.cpp +++ b/pcsx2/x86/newVif_Dynarec.cpp @@ -32,24 +32,29 @@ void dVifReserve(int idx) void dVifReset(int idx) { - if( !nVif[idx].vifBlocks ) + pxAssumeDev(nVif[idx].recReserve, "Dynamic VIF recompiler reserve must be created prior to VIF use or reset!"); + + if (!nVif[idx].vifBlocks) nVif[idx].vifBlocks = new HashBucket<_tParams>(); else nVif[idx].vifBlocks->clear(); nVif[idx].recReserve->Reset(); + nVif[idx].numBlocks = 0; nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr(); } void dVifClose(int idx) { nVif[idx].numBlocks = 0; - nVif[idx].recReserve->Reset(); + if (nVif[idx].recReserve) + nVif[idx].recReserve->Reset(); safe_delete(nVif[idx].vifBlocks); } void dVifRelease(int idx) { + dVifClose(idx); safe_delete(nVif[idx].recReserve); } @@ -227,7 +232,9 @@ _vifT static __fi u8* dVifsetVUptr(uint cl, uint wl, bool isFill) { // it clears the buffer only. static __fi void dVifRecLimit(int idx) { if (nVif[idx].recWritePtr > (nVif[idx].recReserve->GetPtrEnd() - _256kb)) { - DevCon.WriteLn("nVif Recompiler Cache Reset! [0x%08x > 0x%08x]", nVif[idx].recWritePtr, nVif[idx].recReserve->GetPtrEnd()); + DevCon.WriteLn(L"nVif Recompiler Cache Reset! [%s > %s]", + pxsPtr(nVif[idx].recWritePtr), pxsPtr(nVif[idx].recReserve->GetPtrEnd()) + ); nVif[idx].recReserve->Reset(); nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr(); } diff --git a/pcsx2/x86/newVif_Unpack.cpp b/pcsx2/x86/newVif_Unpack.cpp index 02808d152f..713ca0ee61 100644 --- a/pcsx2/x86/newVif_Unpack.cpp +++ b/pcsx2/x86/newVif_Unpack.cpp @@ -80,7 +80,6 @@ nVifStruct::nVifStruct() void reserveNewVif(int idx) { - if (newVifDynaRec) dVifReserve(idx); } void resetNewVif(int idx) @@ -96,11 +95,9 @@ void resetNewVif(int idx) } void closeNewVif(int idx) { - if (newVifDynaRec) dVifClose(idx); } void releaseNewVif(int idx) { - if (newVifDynaRec) dVifRelease(idx); } static __fi u8* getVUptr(uint idx, int offset) { diff --git a/pcsx2/x86/newVif_UnpackSSE.cpp b/pcsx2/x86/newVif_UnpackSSE.cpp index dc7d7b595b..25a53d6a37 100644 --- a/pcsx2/x86/newVif_UnpackSSE.cpp +++ b/pcsx2/x86/newVif_UnpackSSE.cpp @@ -22,7 +22,9 @@ #define xMOV64(regX, loc) xMOVUPS(regX, loc) #define xMOV128(regX, loc) xMOVUPS(regX, loc) -static __pagealigned u8 nVifUpkExec[__pagesize*4]; +//static __pagealigned u8 nVifUpkExec[__pagesize*4]; +static RecompiledCodeReserve* nVifUpkExec = NULL; + // Merges xmm vectors without modifying source reg void mergeVectors(xRegisterSSE dest, xRegisterSSE src, xRegisterSSE temp, int xyzw) { @@ -288,17 +290,23 @@ static void nVifGen(int usn, int mask, int curCycle) { vpugen.xUnpack(i); vpugen.xMovDest(); xRET(); - - pxAssert( ((uptr)xGetPtr() - (uptr)nVifUpkExec) < sizeof(nVifUpkExec) ); } } void VifUnpackSSE_Init() { - HostSys::MemProtectStatic(nVifUpkExec, PageAccess_ReadWrite()); - memset8<0xcc>( nVifUpkExec ); + if (nVifUpkExec) return; - xSetPtr( nVifUpkExec ); + DevCon.WriteLn( "Generating SSE-optimized unpacking functions for VIF interpreters..." ); + + nVifUpkExec = new RecompiledCodeReserve(L"VIF SSE-optimized Unpacking Functions"); + nVifUpkExec->SetProfilerName("iVIF-SSE"); + nVifUpkExec->SetBlockSize( 1 ); + nVifUpkExec->Reserve( _64kb ); + + nVifUpkExec->ThrowIfNotOk(); + + xSetPtr( *nVifUpkExec ); for (int a = 0; a < 2; a++) { for (int b = 0; b < 2; b++) { @@ -306,5 +314,19 @@ void VifUnpackSSE_Init() nVifGen(a, b, c); }}} - HostSys::MemProtectStatic(nVifUpkExec, PageAccess_ExecOnly()); + nVifUpkExec->ForbidModification(); + + DevCon.WriteLn( "Unpack function generation complete. Generated function statistics:" ); + DevCon.Indent().WriteLn( + L"Reserved buffer : %u bytes @ %s\n" + L"x86 code generated : %u bytes\n", + (uint)nVifUpkExec->GetCommittedBytes(), + pxsPtr(nVifUpkExec->GetPtr()), + (uint)(nVifUpkExec->GetPtr() - xGetPtr()) + ); } + +void VifUnpackSSE_Destroy() +{ + safe_delete( nVifUpkExec ); +} \ No newline at end of file