mirror of https://github.com/PCSX2/pcsx2.git
newHostVM: (WIP, may not run!) -- Applied host virtual memory mapping to the EE/IOP/VU main and on-chip memory banks. Added a new OO-based system allocator object for handling said virtual memory resources. Plus many code cleanups, and some added mess that needs to be cleaned up.
git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@4020 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
f1024dad91
commit
be1a590464
|
@ -189,6 +189,7 @@ static const s64 _32mb = _1mb * 32;
|
|||
static const s64 _64mb = _1mb * 64;
|
||||
static const s64 _256mb = _1mb * 256;
|
||||
static const s64 _1gb = _256mb * 4;
|
||||
static const s64 _4gb = _1gb * 4;
|
||||
|
||||
|
||||
// ===========================================================================================
|
||||
|
|
|
@ -62,7 +62,7 @@ protected:
|
|||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EventListener_PageFault
|
||||
// EventListener_PageFault / EventListenerHelper_PageFault
|
||||
// --------------------------------------------------------------------------------------
|
||||
class EventListener_PageFault : public IEventListener_PageFault
|
||||
{
|
||||
|
@ -71,6 +71,36 @@ public:
|
|||
virtual ~EventListener_PageFault() throw();
|
||||
};
|
||||
|
||||
template< typename TypeToDispatchTo >
|
||||
class EventListenerHelper_PageFault : public EventListener_PageFault
|
||||
{
|
||||
public:
|
||||
TypeToDispatchTo* Owner;
|
||||
|
||||
public:
|
||||
EventListenerHelper_PageFault( TypeToDispatchTo& dispatchTo )
|
||||
{
|
||||
Owner = &dispatchTo;
|
||||
}
|
||||
|
||||
EventListenerHelper_PageFault( TypeToDispatchTo* dispatchTo )
|
||||
{
|
||||
Owner = dispatchTo;
|
||||
}
|
||||
|
||||
virtual ~EventListenerHelper_PageFault() throw() {}
|
||||
|
||||
protected:
|
||||
virtual void OnPageFaultEvent( const PageFaultInfo& info, bool& handled )
|
||||
{
|
||||
OnPageFaultEvent( info, handled );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SrcType_PageFault
|
||||
// --------------------------------------------------------------------------------------
|
||||
class SrcType_PageFault : public EventSource<IEventListener_PageFault>
|
||||
{
|
||||
protected:
|
||||
|
@ -90,57 +120,68 @@ protected:
|
|||
virtual void _DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt );
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseVirtualMemoryReserve (WIP!!)
|
||||
// VirtualMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class BaseVirtualMemoryReserve : public EventListener_PageFault
|
||||
class VirtualMemoryReserve
|
||||
{
|
||||
DeclareNoncopyableObject( BaseVirtualMemoryReserve );
|
||||
DeclareNoncopyableObject( VirtualMemoryReserve );
|
||||
|
||||
public:
|
||||
wxString Name;
|
||||
|
||||
protected:
|
||||
// Default size of the reserve, in bytes. Can be specified when the object is contructed.
|
||||
// Is used as the reserve size when Reserve() is called, unless an override is specified
|
||||
// in the Reserve parameters.
|
||||
size_t m_defsize;
|
||||
|
||||
void* m_baseptr;
|
||||
|
||||
// reserved memory (in pages).
|
||||
uptr m_reserved;
|
||||
|
||||
// Incremental size by which the buffer grows (in pages)
|
||||
uptr m_blocksize;
|
||||
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_commited;
|
||||
uptr m_pages_commited;
|
||||
|
||||
public:
|
||||
BaseVirtualMemoryReserve( const wxString& name );
|
||||
virtual ~BaseVirtualMemoryReserve() throw()
|
||||
VirtualMemoryReserve( const wxString& name, size_t size = 0 );
|
||||
virtual ~VirtualMemoryReserve() throw()
|
||||
{
|
||||
Free();
|
||||
Release();
|
||||
}
|
||||
|
||||
virtual void* Reserve( uint size, uptr base = 0, uptr upper_bounds = 0 );
|
||||
virtual void Reset();
|
||||
virtual void Free();
|
||||
virtual bool TryResize( uint newsize );
|
||||
virtual void* Reserve( size_t size = 0, uptr base = 0, uptr upper_bounds = 0 );
|
||||
virtual void* ReserveAt( uptr base = 0, uptr upper_bounds = 0 )
|
||||
{
|
||||
return Reserve(m_defsize, base, upper_bounds);
|
||||
}
|
||||
|
||||
virtual void CommitBlocks( uptr page, uint blocks );
|
||||
virtual void Reset();
|
||||
virtual void Release();
|
||||
virtual bool TryResize( uint newsize );
|
||||
virtual bool Commit();
|
||||
|
||||
bool IsOk() const { return m_baseptr != NULL; }
|
||||
wxString GetName() const { return Name; }
|
||||
|
||||
uptr GetReserveSizeInBytes() const { return m_reserved * __pagesize; }
|
||||
uptr GetReserveSizeInPages() const { return m_reserved; }
|
||||
uptr GetReserveSizeInBytes() const { return m_pages_reserved * __pagesize; }
|
||||
uptr GetReserveSizeInPages() const { return m_pages_reserved; }
|
||||
uint GetCommittedPageCount() const { return m_pages_commited; }
|
||||
uint GetCommittedBytes() const { return m_pages_commited * __pagesize; }
|
||||
|
||||
u8* GetPtr() { return (u8*)m_baseptr; }
|
||||
const u8* GetPtr() const { return (u8*)m_baseptr; }
|
||||
u8* GetPtrEnd() { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); }
|
||||
const u8* GetPtrEnd() const { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); }
|
||||
|
||||
u8* GetPtrEnd() { return (u8*)m_baseptr + (m_reserved * __pagesize); }
|
||||
const u8* GetPtrEnd() const { return (u8*)m_baseptr + (m_reserved * __pagesize); }
|
||||
VirtualMemoryReserve& SetBaseAddr( uptr newaddr );
|
||||
VirtualMemoryReserve& SetPageAccessOnCommit( const PageProtectionMode& mode );
|
||||
|
||||
operator void*() { return m_baseptr; }
|
||||
operator const void*() const { return m_baseptr; }
|
||||
|
@ -150,16 +191,45 @@ public:
|
|||
|
||||
u8& operator[](uint idx)
|
||||
{
|
||||
pxAssume(idx < (m_reserved * __pagesize));
|
||||
pxAssume(idx < (m_pages_reserved * __pagesize));
|
||||
return *((u8*)m_baseptr + idx);
|
||||
}
|
||||
|
||||
const u8& operator[](uint idx) const
|
||||
{
|
||||
pxAssume(idx < (m_reserved * __pagesize));
|
||||
pxAssume(idx < (m_pages_reserved * __pagesize));
|
||||
return *((u8*)m_baseptr + idx);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseVmReserveListener
|
||||
// --------------------------------------------------------------------------------------
|
||||
class BaseVmReserveListener : public VirtualMemoryReserve
|
||||
{
|
||||
DeclareNoncopyableObject( BaseVmReserveListener );
|
||||
|
||||
typedef VirtualMemoryReserve _parent;
|
||||
|
||||
protected:
|
||||
EventListenerHelper_PageFault<BaseVmReserveListener> m_pagefault_listener;
|
||||
|
||||
// Incremental size by which the buffer grows (in pages)
|
||||
uptr m_blocksize;
|
||||
|
||||
public:
|
||||
BaseVmReserveListener( const wxString& name, size_t size = 0 );
|
||||
virtual ~BaseVmReserveListener() throw() { }
|
||||
|
||||
operator void*() { return m_baseptr; }
|
||||
operator const void*() const { return m_baseptr; }
|
||||
|
||||
operator u8*() { return (u8*)m_baseptr; }
|
||||
operator const u8*() const { return (u8*)m_baseptr; }
|
||||
|
||||
using _parent::operator[];
|
||||
|
||||
protected:
|
||||
void OnPageFaultEvent( const PageFaultInfo& info, bool& handled );
|
||||
|
||||
|
@ -175,6 +245,8 @@ protected:
|
|||
|
||||
// This function is called for every committed block.
|
||||
virtual void OnCommittedBlock( void* block )=0;
|
||||
|
||||
virtual void CommitBlocks( uptr page, uint blocks );
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -202,9 +274,9 @@ protected:
|
|||
// By default, the base block size is based on a heuristic that balances the size of the spatial
|
||||
// array reserve against a best-guess performance profile for the target platform.
|
||||
//
|
||||
class SpatialArrayReserve : public BaseVirtualMemoryReserve
|
||||
class SpatialArrayReserve : public BaseVmReserveListener
|
||||
{
|
||||
typedef BaseVirtualMemoryReserve __parent;
|
||||
typedef BaseVmReserveListener _parent;
|
||||
|
||||
protected:
|
||||
uint m_numblocks;
|
||||
|
@ -218,7 +290,7 @@ protected:
|
|||
public:
|
||||
SpatialArrayReserve( const wxString& name );
|
||||
|
||||
virtual void* Reserve( uint size, uptr base = 0, uptr upper_bounds = 0 );
|
||||
virtual void* Reserve( size_t size = 0, uptr base = 0, uptr upper_bounds = 0 );
|
||||
virtual void Reset();
|
||||
virtual bool TryResize( uint newsize );
|
||||
|
||||
|
@ -234,7 +306,7 @@ public:
|
|||
operator u8*() { return (u8*)m_baseptr; }
|
||||
operator const u8*() const { return (u8*)m_baseptr; }
|
||||
|
||||
using __parent::operator[];
|
||||
using _parent::operator[];
|
||||
|
||||
protected:
|
||||
void DoCommitAndProtect( uptr page );
|
||||
|
@ -258,7 +330,8 @@ extern int SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps);
|
|||
# error PCSX2 - Unsupported operating system platform.
|
||||
#endif
|
||||
|
||||
extern void InstallSignalHandler();
|
||||
extern void pxInstallSignalHandler();
|
||||
extern void _platform_InstallSignalHandler();
|
||||
|
||||
extern SrcType_PageFault* Source_PageFault;
|
||||
|
||||
|
|
|
@ -15,11 +15,64 @@
|
|||
|
||||
|
||||
#include "../PrecompiledHeader.h"
|
||||
#include "PageFaultSource.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
extern void SignalExit(int sig);
|
||||
|
||||
static const uptr m_pagemask = getpagesize()-1;
|
||||
|
||||
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
|
||||
static void SysPageFaultSignalFilter( int signal, siginfo_t *siginfo, void * )
|
||||
{
|
||||
// [TODO] : Add a thread ID filter to the Linux Signal handler here.
|
||||
// Rationale: On windows, the __try/__except model allows per-thread specific behavior
|
||||
// for page fault handling. On linux, there is a single signal handler for the whole
|
||||
// process, but the handler is executed by the thread that caused the exception.
|
||||
|
||||
|
||||
// Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done
|
||||
// from the context of the current thread and stackframe. So long as the thread is not
|
||||
// the main/ui thread, use of the px assertion system should be safe. Use of stdio should
|
||||
// be safe even on the main thread.
|
||||
// (in other words, stdio limitations only really apply to process-level asynchronous
|
||||
// signals)
|
||||
|
||||
// Note: Use of stdio functions isn't safe here. Avoid console logs,
|
||||
// assertions, file logs, or just about anything else useful.
|
||||
|
||||
Source_PageFault->Dispatch( PageFaultInfo( (uptr)siginfo->si_addr & ~m_pagemask ) );
|
||||
|
||||
// resumes execution right where we left off (re-executes instruction that
|
||||
// caused the SIGSEGV).
|
||||
if (Source_PageFault->WasHandled()) return;
|
||||
|
||||
if (!wxThread::IsMain())
|
||||
{
|
||||
pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr));
|
||||
}
|
||||
|
||||
// Bad mojo! Completely invalid address.
|
||||
// Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
|
||||
|
||||
wxTrap();
|
||||
if (!IsDebugBuild) raise( SIGKILL );
|
||||
}
|
||||
|
||||
void _platform_InstallSignalHandler()
|
||||
{
|
||||
Console.WriteLn("Installing POSIX SIGSEGV handler...");
|
||||
struct sigaction sa;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = SysPageFaultSignalFilter;
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
}
|
||||
|
||||
static __ri void PageSizeAssertionTest( size_t size )
|
||||
{
|
||||
pxAssertMsg( (__pagesize == getpagesize()), pxsFmt(
|
||||
|
|
|
@ -27,6 +27,21 @@ template class EventSource< IEventListener_PageFault >;
|
|||
|
||||
SrcType_PageFault* Source_PageFault = NULL;
|
||||
|
||||
void pxInstallSignalHandler()
|
||||
{
|
||||
if (!Source_PageFault)
|
||||
{
|
||||
Source_PageFault = new SrcType_PageFault();
|
||||
}
|
||||
|
||||
_platform_InstallSignalHandler();
|
||||
|
||||
// NOP on Win32 systems -- we use __try{} __except{} instead.
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EventListener_PageFault (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
EventListener_PageFault::EventListener_PageFault()
|
||||
{
|
||||
pxAssume(Source_PageFault);
|
||||
|
@ -53,50 +68,78 @@ void SrcType_PageFault::_DispatchRaw( ListenerIterator iter, const ListenerItera
|
|||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseVirtualMemoryReserve (implementations)
|
||||
// VirtualMemoryReserve (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
BaseVirtualMemoryReserve::BaseVirtualMemoryReserve( const wxString& name )
|
||||
VirtualMemoryReserve::VirtualMemoryReserve( const wxString& name, size_t size )
|
||||
: Name( name )
|
||||
{
|
||||
m_commited = 0;
|
||||
m_reserved = 0;
|
||||
m_baseptr = NULL;
|
||||
m_blocksize = __pagesize;
|
||||
m_prot_mode = PageAccess_None();
|
||||
m_defsize = size;
|
||||
|
||||
m_pages_commited = 0;
|
||||
m_pages_reserved = 0;
|
||||
m_baseptr = NULL;
|
||||
m_prot_mode = PageAccess_None();
|
||||
}
|
||||
|
||||
VirtualMemoryReserve& VirtualMemoryReserve::SetBaseAddr( uptr newaddr )
|
||||
{
|
||||
if (!pxAssertDev(!m_pages_reserved, "Invalid object state: you must release the virtual memory reserve prior to changing its base address!")) return *this;
|
||||
|
||||
m_baseptr = (void*)newaddr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
VirtualMemoryReserve& VirtualMemoryReserve::SetPageAccessOnCommit( const PageProtectionMode& mode )
|
||||
{
|
||||
m_prot_mode = mode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Notes:
|
||||
// * This method should be called if the object is already in an released (unreserved) state.
|
||||
// Subsequent calls will be ignored, and the existing reserve will be returned.
|
||||
//
|
||||
// Parameters:
|
||||
// size - size of the reserve, in bytes. (optional)
|
||||
// If not specified (or zero), then the default size specified in the constructor for the
|
||||
// object instance is used.
|
||||
//
|
||||
// upper_bounds - criteria that must be met for the allocation to be valid.
|
||||
// If the OS refuses to allocate the memory below the specified address, the
|
||||
// object will fail to initialize and an exception will be thrown.
|
||||
void* BaseVirtualMemoryReserve::Reserve( uint size, uptr base, uptr upper_bounds )
|
||||
void* VirtualMemoryReserve::Reserve( size_t size, uptr base, uptr upper_bounds )
|
||||
{
|
||||
if (!pxAssertDev( m_baseptr == NULL, "(VirtualMemoryReserve) Invalid object state; object has already been reserved." ))
|
||||
return m_baseptr;
|
||||
|
||||
m_reserved = (size + __pagesize-4) / __pagesize;
|
||||
uptr reserved_bytes = m_reserved * __pagesize;
|
||||
if (!size) size = m_defsize;
|
||||
if (!size) return NULL;
|
||||
|
||||
m_pages_reserved = (size + __pagesize-4) / __pagesize;
|
||||
uptr reserved_bytes = m_pages_reserved * __pagesize;
|
||||
|
||||
m_baseptr = (void*)HostSys::MmapReserve(base, reserved_bytes);
|
||||
|
||||
if (!m_baseptr && (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)))
|
||||
if (!m_baseptr || (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)))
|
||||
{
|
||||
DevCon.Warning( L"%s: host memory @ 0x%08x -> 0x%08x is unavailable; attempting to map elsewhere...",
|
||||
Name.c_str(), base, base + size );
|
||||
|
||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||
|
||||
if (base)
|
||||
{
|
||||
DevCon.Warning( L"%s: address 0x%08x is unavailable; trying OS-selected address instead.", Name.c_str(), base );
|
||||
|
||||
// Let's try again at an OS-picked memory area, and then hope it meets needed
|
||||
// boundschecking criteria below.
|
||||
SafeSysMunmap( m_baseptr, reserved_bytes );
|
||||
m_baseptr = HostSys::MmapReserve( 0, reserved_bytes );
|
||||
}
|
||||
|
||||
if ((upper_bounds != 0) && (((uptr)m_baseptr + reserved_bytes) > upper_bounds))
|
||||
{
|
||||
SafeSysMunmap( m_baseptr, reserved_bytes );
|
||||
// returns null, caller should throw an exception or handle appropriately.
|
||||
}
|
||||
}
|
||||
|
||||
if ((upper_bounds != 0) && (((uptr)m_baseptr + reserved_bytes) > upper_bounds))
|
||||
{
|
||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||
// returns null, caller should throw an exception or handle appropriately.
|
||||
}
|
||||
|
||||
if (!m_baseptr) return NULL;
|
||||
|
@ -108,20 +151,30 @@ void* BaseVirtualMemoryReserve::Reserve( uint size, uptr base, uptr upper_bounds
|
|||
}
|
||||
|
||||
// Clears all committed blocks, restoring the allocation to a reserve only.
|
||||
void BaseVirtualMemoryReserve::Reset()
|
||||
void VirtualMemoryReserve::Reset()
|
||||
{
|
||||
if (!m_commited) return;
|
||||
|
||||
HostSys::MemProtect(m_baseptr, m_commited*__pagesize, PageAccess_None());
|
||||
HostSys::MmapResetPtr(m_baseptr, m_commited*__pagesize);
|
||||
m_commited = 0;
|
||||
if (!m_pages_commited) return;
|
||||
|
||||
HostSys::MemProtect(m_baseptr, m_pages_commited*__pagesize, PageAccess_None());
|
||||
HostSys::MmapResetPtr(m_baseptr, m_pages_commited*__pagesize);
|
||||
m_pages_commited = 0;
|
||||
}
|
||||
|
||||
void BaseVirtualMemoryReserve::Free()
|
||||
void VirtualMemoryReserve::Release()
|
||||
{
|
||||
HostSys::Munmap((uptr)m_baseptr, m_reserved*__pagesize);
|
||||
SafeSysMunmap(m_baseptr, m_pages_reserved*__pagesize);
|
||||
}
|
||||
|
||||
bool VirtualMemoryReserve::Commit()
|
||||
{
|
||||
if (!m_pages_reserved) return false;
|
||||
if (!pxAssert(!m_pages_commited)) return true;
|
||||
|
||||
m_pages_commited = m_pages_reserved;
|
||||
return HostSys::MmapCommitPtr(m_baseptr, m_pages_reserved*__pagesize, m_prot_mode);
|
||||
}
|
||||
|
||||
|
||||
// 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
|
||||
// of the reserve.
|
||||
|
@ -131,13 +184,13 @@ void BaseVirtualMemoryReserve::Free()
|
|||
//
|
||||
// Parameters:
|
||||
// newsize - new size of the reserved buffer, in bytes.
|
||||
bool BaseVirtualMemoryReserve::TryResize( uint newsize )
|
||||
bool VirtualMemoryReserve::TryResize( uint newsize )
|
||||
{
|
||||
uint newPages = (newsize + __pagesize - 1) / __pagesize;
|
||||
|
||||
if (newPages > m_reserved)
|
||||
if (newPages > m_pages_reserved)
|
||||
{
|
||||
uint toReservePages = newPages - m_reserved;
|
||||
uint toReservePages = newPages - m_pages_reserved;
|
||||
uint toReserveBytes = toReservePages * __pagesize;
|
||||
|
||||
DevCon.WriteLn( L"%-32s is being expanded by %u pages.", Name.c_str(), toReservePages);
|
||||
|
@ -153,11 +206,11 @@ bool BaseVirtualMemoryReserve::TryResize( uint newsize )
|
|||
DevCon.WriteLn( Color_Blue, L"%-32s @ 0x%08X -> 0x%08X [%umb]", Name.c_str(),
|
||||
m_baseptr, (uptr)m_baseptr+toReserveBytes, toReserveBytes / _1mb);
|
||||
}
|
||||
else if (newPages < m_reserved)
|
||||
else if (newPages < m_pages_reserved)
|
||||
{
|
||||
if (m_commited > newsize) return false;
|
||||
if (m_pages_commited > newsize) return false;
|
||||
|
||||
uint toRemovePages = m_reserved - newPages;
|
||||
uint toRemovePages = m_pages_reserved - newPages;
|
||||
uint toRemoveBytes = toRemovePages * __pagesize;
|
||||
|
||||
DevCon.WriteLn( L"%-32s is being shrunk by %u pages.", Name.c_str(), toRemovePages);
|
||||
|
@ -171,8 +224,18 @@ bool BaseVirtualMemoryReserve::TryResize( uint newsize )
|
|||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseVmReserveListener (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
void BaseVirtualMemoryReserve::CommitBlocks( uptr page, uint blocks )
|
||||
BaseVmReserveListener::BaseVmReserveListener( const wxString& name, size_t size )
|
||||
: VirtualMemoryReserve( name, size )
|
||||
, m_pagefault_listener( this )
|
||||
{
|
||||
m_blocksize = __pagesize;
|
||||
}
|
||||
|
||||
void BaseVmReserveListener::CommitBlocks( uptr page, uint blocks )
|
||||
{
|
||||
const uptr blocksbytes = blocks * m_blocksize * __pagesize;
|
||||
void* blockptr = (u8*)m_baseptr + (page * __pagesize);
|
||||
|
@ -190,13 +253,13 @@ void BaseVirtualMemoryReserve::CommitBlocks( uptr page, uint blocks )
|
|||
for( ; init<endpos; init += m_blocksize*__pagesize )
|
||||
OnCommittedBlock(init);
|
||||
|
||||
m_commited += m_blocksize * blocks;
|
||||
m_pages_commited += m_blocksize * blocks;
|
||||
}
|
||||
|
||||
void BaseVirtualMemoryReserve::OnPageFaultEvent(const PageFaultInfo& info, bool& handled)
|
||||
void BaseVmReserveListener::OnPageFaultEvent(const PageFaultInfo& info, bool& handled)
|
||||
{
|
||||
sptr offset = (info.addr - (uptr)m_baseptr) / __pagesize;
|
||||
if ((offset < 0) || ((uptr)offset >= m_reserved)) return;
|
||||
if ((offset < 0) || ((uptr)offset >= m_pages_reserved)) 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.
|
||||
|
@ -238,7 +301,7 @@ void BaseVirtualMemoryReserve::OnPageFaultEvent(const PageFaultInfo& info, bool&
|
|||
// --------------------------------------------------------------------------------------
|
||||
|
||||
SpatialArrayReserve::SpatialArrayReserve( const wxString& name ) :
|
||||
__parent( name )
|
||||
_parent( name )
|
||||
{
|
||||
m_prot_mode = PageAccess_ReadWrite();
|
||||
}
|
||||
|
@ -250,9 +313,9 @@ uint SpatialArrayReserve::_calcBlockBitArrayLength() const
|
|||
return (((m_numblocks + 7) / 8) + 15) & ~15;
|
||||
}
|
||||
|
||||
void* SpatialArrayReserve::Reserve( uint size, uptr base, uptr upper_bounds )
|
||||
void* SpatialArrayReserve::Reserve( size_t size, uptr base, uptr upper_bounds )
|
||||
{
|
||||
void* addr = __parent::Reserve( size, base, upper_bounds );
|
||||
void* addr = _parent::Reserve( size, base, upper_bounds );
|
||||
if (!addr) return NULL;
|
||||
|
||||
if (m_blocksize) SetBlockSizeInPages( m_blocksize );
|
||||
|
@ -264,7 +327,7 @@ void* SpatialArrayReserve::Reserve( uint size, uptr base, uptr upper_bounds )
|
|||
// Resets/clears the spatial array, reducing the memory commit pool overhead to zero (0).
|
||||
void SpatialArrayReserve::Reset()
|
||||
{
|
||||
if (m_commited)
|
||||
if (m_pages_commited)
|
||||
{
|
||||
u8* curptr = GetPtr();
|
||||
const uint blockBytes = m_blocksize * __pagesize;
|
||||
|
@ -299,7 +362,7 @@ bool SpatialArrayReserve::TryResize( uint newsize )
|
|||
uint pages_in_use = i * m_blocksize;
|
||||
if (newpages < pages_in_use) return false;
|
||||
|
||||
if (!__parent::TryResize( newsize )) return false;
|
||||
if (!_parent::TryResize( newsize )) return false;
|
||||
|
||||
// On success, we must re-calibrate the internal blockbits array.
|
||||
|
||||
|
@ -317,12 +380,12 @@ bool SpatialArrayReserve::TryResize( uint newsize )
|
|||
// in debug builds.
|
||||
SpatialArrayReserve& SpatialArrayReserve::SetBlockCount( uint blocks )
|
||||
{
|
||||
pxAssumeDev( !m_commited, "Invalid object state: SetBlockCount must be called prior to reserved memory accesses." );
|
||||
pxAssumeDev( !m_pages_commited, "Invalid object state: SetBlockCount must be called prior to reserved memory accesses." );
|
||||
|
||||
// Calculate such that the last block extends past the end of the array, if necessary.
|
||||
|
||||
m_numblocks = blocks;
|
||||
m_blocksize = (m_reserved + m_numblocks-1) / m_numblocks;
|
||||
m_blocksize = (m_pages_reserved + m_numblocks-1) / m_numblocks;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -334,10 +397,10 @@ SpatialArrayReserve& SpatialArrayReserve::SetBlockCount( uint blocks )
|
|||
// a modified buffer will be ignored (and generate an assertion in dev/debug modes).
|
||||
SpatialArrayReserve& SpatialArrayReserve::SetBlockSizeInPages( uint pages )
|
||||
{
|
||||
if (pxAssertDev(!m_commited, "Invalid object state: Block size can only be changed prior to accessing or modifying the reserved buffer contents."))
|
||||
if (pxAssertDev(!m_pages_commited, "Invalid object state: Block size can only be changed prior to accessing or modifying the reserved buffer contents."))
|
||||
{
|
||||
m_blocksize = pages;
|
||||
m_numblocks = (m_reserved + m_blocksize - 1) / m_blocksize;
|
||||
m_numblocks = (m_pages_reserved + m_blocksize - 1) / m_blocksize;
|
||||
m_blockbits.Alloc( _calcBlockBitArrayLength() );
|
||||
}
|
||||
return *this;
|
||||
|
|
|
@ -15,8 +15,25 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "Utilities/RedtapeWindows.h"
|
||||
#include "PageFaultSource.h"
|
||||
|
||||
#include <winnt.h>
|
||||
|
||||
int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
|
||||
{
|
||||
if( eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION )
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
Source_PageFault->Dispatch( PageFaultInfo( (uptr)eps->ExceptionRecord->ExceptionInformation[1] ) );
|
||||
return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
void _platform_InstallSignalHandler()
|
||||
{
|
||||
// NOP on Win32 systems -- we use __try{} __except{} instead.
|
||||
}
|
||||
|
||||
|
||||
static DWORD ConvertToWinApi( const PageProtectionMode& mode )
|
||||
{
|
||||
DWORD winmode = PAGE_NOACCESS;
|
||||
|
@ -94,7 +111,7 @@ void* HostSys::Mmap(uptr base, size_t size)
|
|||
void HostSys::Munmap(uptr base, size_t size)
|
||||
{
|
||||
if (!base) return;
|
||||
VirtualFree((void*)base, size, MEM_DECOMMIT);
|
||||
//VirtualFree((void*)base, size, MEM_DECOMMIT);
|
||||
VirtualFree((void*)base, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,26 +24,38 @@ IopVM_MemoryAllocMess* iopMem = NULL;
|
|||
|
||||
__pagealigned u8 iopHw[Ps2MemSize::IopHardware];
|
||||
|
||||
void psxMemAlloc()
|
||||
// --------------------------------------------------------------------------------------
|
||||
// iopMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
iopMemoryReserve::iopMemoryReserve()
|
||||
: _parent( L"IOP Main Memory (2mb)", sizeof(*iopMem) )
|
||||
{
|
||||
if( iopMem == NULL )
|
||||
iopMem = (IopVM_MemoryAllocMess*)vtlb_malloc( sizeof(*iopMem), 4096 );
|
||||
}
|
||||
|
||||
psxMemWLUT = (uptr*)_aligned_malloc(0x2000 * sizeof(uptr) * 2, 16);
|
||||
psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
|
||||
void iopMemoryReserve::Reserve()
|
||||
{
|
||||
_parent::Reserve(HostMemoryMap::IOPmem);
|
||||
//_parent::Reserve(EmuConfig.HostMap.IOP);
|
||||
iopMem = (IopVM_MemoryAllocMess*)m_reserve.GetPtr();
|
||||
}
|
||||
|
||||
// Note! Resetting the IOP's memory state is dependent on having *all* psx memory allocated,
|
||||
// which is performed by MemInit and PsxMemInit()
|
||||
void psxMemReset()
|
||||
void iopMemoryReserve::Reset()
|
||||
{
|
||||
pxAssume( psxMemWLUT != NULL );
|
||||
pxAssume( iopMem != NULL );
|
||||
_parent::Reset();
|
||||
|
||||
DbgCon.WriteLn( "IOP Resetting physical ram..." );
|
||||
pxAssume( iopMem );
|
||||
|
||||
if (!psxMemWLUT)
|
||||
{
|
||||
psxMemWLUT = (uptr*)_aligned_malloc(0x2000 * sizeof(uptr) * 2, 16);
|
||||
psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
|
||||
}
|
||||
|
||||
DbgCon.WriteLn("IOP resetting main memory...");
|
||||
|
||||
memzero_ptr<0x2000 * sizeof(uptr) * 2>( psxMemWLUT ); // clears both allocations, RLUT and WLUT
|
||||
memzero( *iopMem );
|
||||
|
||||
// Trick! We're accessing RLUT here through WLUT, since it's the non-const pointer.
|
||||
// So the ones with a 0x2000 prefixed are RLUT tables.
|
||||
|
@ -87,15 +99,21 @@ void psxMemReset()
|
|||
//for (i=0; i<0x0008; i++) psxMemWLUT[i + 0xbfc0] = (uptr)&psR[i << 16];
|
||||
}
|
||||
|
||||
void psxMemShutdown()
|
||||
void iopMemoryReserve::Shutdown()
|
||||
{
|
||||
vtlb_free( iopMem, sizeof(*iopMem) );
|
||||
iopMem = NULL;
|
||||
_parent::Shutdown();
|
||||
|
||||
safe_aligned_free(psxMemWLUT);
|
||||
psxMemRLUT = NULL;
|
||||
}
|
||||
|
||||
void iopMemoryReserve::Release()
|
||||
{
|
||||
_parent::Release();
|
||||
iopMem = NULL;
|
||||
}
|
||||
|
||||
|
||||
u8 __fastcall iopMemRead8(u32 mem)
|
||||
{
|
||||
mem &= 0x1fffffff;
|
||||
|
|
|
@ -71,6 +71,7 @@ static __fi u8* iopPhysMem( u32 addr )
|
|||
#define psxHu16(mem) (*(u16*)&iopHw[(mem) & 0xffff])
|
||||
#define psxHu32(mem) (*(u32*)&iopHw[(mem) & 0xffff])
|
||||
|
||||
extern void psxMemReserve();
|
||||
extern void psxMemAlloc();
|
||||
extern void psxMemReset();
|
||||
extern void psxMemShutdown();
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <signal.h>
|
||||
#include "Common.h"
|
||||
|
||||
#include "Utilities/PageFaultSource.h"
|
||||
|
||||
extern void SignalExit(int sig);
|
||||
|
||||
static const uptr m_pagemask = getpagesize()-1;
|
||||
|
||||
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
|
||||
static void SysPageFaultSignalFilter( int signal, siginfo_t *siginfo, void * )
|
||||
{
|
||||
// Note: Use of most stdio functions isn't safe here. Avoid console logs,
|
||||
// assertions, file logs, or just about anything else useful.
|
||||
|
||||
Source_PageFault->Dispatch( PageFaultInfo( (uptr)siginfo->si_addr & ~m_pagemask ) );
|
||||
|
||||
// resumes execution right where we left off (re-executes instruction that
|
||||
// caused the SIGSEGV).
|
||||
if( Source_PageFault->WasHandled() ) return;
|
||||
|
||||
// Bad mojo! Completely invalid address.
|
||||
// Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
|
||||
|
||||
wxTrap();
|
||||
if( !IsDebugBuild ) raise( SIGKILL );
|
||||
}
|
||||
|
||||
void InstallSignalHandler()
|
||||
{
|
||||
Console.WriteLn("Installing POSIX SIGSEGV handler...");
|
||||
struct sigaction sa;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = SysPageFaultSignalFilter;
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
}
|
||||
|
||||
void NTFS_CompressFile( const wxString& file, bool compressStatus ) {}
|
|
@ -20,6 +20,8 @@
|
|||
#include <gdk/gdkkeysyms.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
void NTFS_CompressFile( const wxString& file, bool compressStatus ) {}
|
||||
|
||||
// Returns a WXK_* keycode, given some kinda GDK input mess!
|
||||
int TranslateGDKtoWXK( u32 keysym )
|
||||
{
|
||||
|
|
|
@ -586,30 +586,8 @@ protected:
|
|||
static mmap_PageFaultHandler* mmap_faultHandler = NULL;
|
||||
|
||||
EEVM_MemoryAllocMess* eeMem = NULL;
|
||||
|
||||
__pagealigned u8 eeHw[Ps2MemSize::Hardware];
|
||||
|
||||
void memAlloc()
|
||||
{
|
||||
if( eeMem == NULL )
|
||||
eeMem = (EEVM_MemoryAllocMess*)vtlb_malloc( sizeof(*eeMem), 4096 );
|
||||
|
||||
if( eeMem == NULL)
|
||||
throw Exception::OutOfMemory( L"PS2 Main Memory (VTLB)" )
|
||||
.SetUserMsg(L"Could not allocate memory needed for the PS2 virtual machine's main memory (approx. 42mb).");
|
||||
|
||||
pxAssume(Source_PageFault);
|
||||
mmap_faultHandler = new mmap_PageFaultHandler();
|
||||
}
|
||||
|
||||
void memShutdown()
|
||||
{
|
||||
safe_delete(mmap_faultHandler);
|
||||
|
||||
vtlb_free( eeMem, sizeof(*eeMem) );
|
||||
eeMem = NULL;
|
||||
vtlb_Term();
|
||||
}
|
||||
|
||||
void memBindConditionalHandlers()
|
||||
{
|
||||
|
@ -639,19 +617,39 @@ void memBindConditionalHandlers()
|
|||
}
|
||||
}
|
||||
|
||||
// Resets memory mappings, unmaps TLBs, reloads bios roms, etc.
|
||||
void memReset()
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// eeMemoryReserve (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
eeMemoryReserve::eeMemoryReserve()
|
||||
: _parent( L"EE Main Memory", sizeof(*eeMem) )
|
||||
{
|
||||
// VTLB Protection Preparations.
|
||||
//HostSys::MemProtect( m_psAllMem, m_allMemSize, Protect_ReadWrite );
|
||||
}
|
||||
|
||||
void eeMemoryReserve::Reserve()
|
||||
{
|
||||
_parent::Reserve(HostMemoryMap::EEmem);
|
||||
//_parent::Reserve(EmuConfig.HostMap.IOP);
|
||||
eeMem = (EEVM_MemoryAllocMess*)m_reserve.GetPtr();
|
||||
}
|
||||
|
||||
// Resets memory mappings, unmaps TLBs, reloads bios roms, etc.
|
||||
void eeMemoryReserve::Reset()
|
||||
{
|
||||
if (!mmap_faultHandler)
|
||||
{
|
||||
pxAssume(Source_PageFault);
|
||||
mmap_faultHandler = new mmap_PageFaultHandler();
|
||||
}
|
||||
|
||||
_parent::Reset();
|
||||
|
||||
// Note!! Ideally the vtlb should only be initialized once, and then subsequent
|
||||
// resets of the system hardware would only clear vtlb mappings, but since the
|
||||
// rest of the emu is not really set up to support a "soft" reset of that sort
|
||||
// we opt for the hard/safe version.
|
||||
|
||||
pxAssume( eeMem != NULL );
|
||||
memzero( *eeMem );
|
||||
pxAssume( eeMem );
|
||||
|
||||
#ifdef ENABLECACHE
|
||||
memset(pCache,0,sizeof(_cacheS)*64);
|
||||
|
@ -764,9 +762,18 @@ void memReset()
|
|||
LoadBIOS();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory Protection and Block Checking, vtlb Style!
|
||||
//
|
||||
void eeMemoryReserve::Release()
|
||||
{
|
||||
safe_delete(mmap_faultHandler);
|
||||
_parent::Release();
|
||||
eeMem = NULL;
|
||||
vtlb_Term();
|
||||
}
|
||||
|
||||
|
||||
// ===========================================================================================
|
||||
// Memory Protection and Block Checking, vtlb Style!
|
||||
// ===========================================================================================
|
||||
// For the first time code is recompiled (executed), the PS2 ram page for that code is
|
||||
// protected using Virtual Memory (mprotect). If the game modifies its own code then this
|
||||
// protection causes an *exception* to be raised (signal in Linux), which is handled by
|
||||
|
|
|
@ -107,9 +107,7 @@ static __fi void ZeroQWC( u128& dest )
|
|||
#define psSu64(mem) (*(u64 *)&eeMem->Scratch[(mem) & 0x3fff])
|
||||
#define psSu128(mem) (*(u128*)&eeMem->Scratch[(mem) & 0x3fff])
|
||||
|
||||
extern void memAlloc();
|
||||
extern void memReset(); // clears PS2 ram and loads the bios. Throws Exception::FileNotFound on error.
|
||||
extern void memShutdown();
|
||||
|
||||
extern void memSetKernelMode();
|
||||
//extern void memSetSupervisorMode();
|
||||
extern void memSetUserMode();
|
||||
|
|
|
@ -17,18 +17,18 @@
|
|||
|
||||
namespace Ps2MemSize
|
||||
{
|
||||
static const uint MainRam = 0x02000000; // 32 MB main memory!
|
||||
static const uint Rom = 0x00400000; // 4 MB main rom
|
||||
static const uint Rom1 = 0x00040000; // DVD player
|
||||
static const uint Rom2 = 0x00080000; // Chinese rom extension (?)
|
||||
static const uint ERom = 0x001C0000; // DVD player extensions (?)
|
||||
static const uint Hardware = 0x00010000;
|
||||
static const uint Scratch = 0x00004000;
|
||||
static const uint MainRam = _32mb; // 32 MB main memory!
|
||||
static const uint Rom = _1mb * 4; // 4 MB main rom
|
||||
static const uint Rom1 = 0x00040000; // DVD player
|
||||
static const uint Rom2 = 0x00080000; // Chinese rom extension (?)
|
||||
static const uint ERom = 0x001C0000; // DVD player extensions (?)
|
||||
static const uint Hardware = _64kb;
|
||||
static const uint Scratch = _16kb;
|
||||
|
||||
static const uint IopRam = 0x00200000; // 2MB main ram on the IOP.
|
||||
static const uint IopHardware = 0x00010000;
|
||||
static const uint IopRam = _1mb * 2; // 2MB main ram on the IOP.
|
||||
static const uint IopHardware = _64kb;
|
||||
|
||||
static const uint GSregs = 0x00002000; // 8k for the GS registers and stuff.
|
||||
static const uint GSregs = 0x00002000; // 8k for the GS registers and stuff.
|
||||
}
|
||||
|
||||
typedef u8 mem8_t;
|
||||
|
@ -53,6 +53,9 @@ typedef u128 mem128_t;
|
|||
// memory, such as hardware registers or scratchpad, the access will generate a page fault, the
|
||||
// compiled block will be cleared and re-compiled using "full" VTLB translation logic.
|
||||
//
|
||||
// Note that support for this feature may not be doable under x86/32 platforms, due to the
|
||||
// 2gb/3gb limit of Windows XP (the 3gb feature will make it slightly more feasible at least).
|
||||
//
|
||||
#define VTLB_UsePageFaulting 0
|
||||
|
||||
#if VTLB_UsePageFaulting
|
||||
|
@ -101,7 +104,7 @@ struct EEVM_MemoryAllocMess
|
|||
struct IopVM_MemoryAllocMess
|
||||
{
|
||||
u8 Main[Ps2MemSize::IopRam]; // Main memory (hard-wired to 2MB)
|
||||
u8 P[0x00010000]; // I really have no idea what this is... --air
|
||||
u8 P[_64kb]; // I really have no idea what this is... --air
|
||||
u8 Sif[0x100]; // a few special SIF/SBUS registers (likely not needed)
|
||||
};
|
||||
|
||||
|
|
|
@ -50,14 +50,14 @@ static const uint eeWaitCycles = 3072;
|
|||
|
||||
bool eeEventTestIsActive = false;
|
||||
|
||||
extern SysMainMemory& GetVmMemory();
|
||||
|
||||
void cpuReset()
|
||||
{
|
||||
if( GetMTGS().IsOpen() )
|
||||
if (GetMTGS().IsOpen())
|
||||
GetMTGS().WaitGS(); // GS better be done processing before we reset the EE, just in case.
|
||||
|
||||
memReset();
|
||||
psxMemReset();
|
||||
vuMicroMemReset();
|
||||
GetVmMemory().ResetAll();
|
||||
|
||||
memzero(cpuRegs);
|
||||
memzero(fpuRegs);
|
||||
|
|
111
pcsx2/System.cpp
111
pcsx2/System.cpp
|
@ -41,7 +41,7 @@ extern void resetNewVif(int idx);
|
|||
// Parameters:
|
||||
// name - a nice long name that accurately describes the contents of this reserve.
|
||||
RecompiledCodeReserve::RecompiledCodeReserve( const wxString& name, uint defCommit )
|
||||
: BaseVirtualMemoryReserve( name )
|
||||
: BaseVmReserveListener( name )
|
||||
{
|
||||
m_blocksize = (1024 * 128) / __pagesize;
|
||||
m_prot_mode = PageAccess_Any();
|
||||
|
@ -73,9 +73,9 @@ uint RecompiledCodeReserve::_calcDefaultCommitInBlocks() const
|
|||
return (m_def_commit + m_blocksize - 1) / m_blocksize;
|
||||
}
|
||||
|
||||
void* RecompiledCodeReserve::Reserve( uint size, uptr base, uptr upper_bounds )
|
||||
void* RecompiledCodeReserve::Reserve( size_t size, uptr base, uptr upper_bounds )
|
||||
{
|
||||
if (!__parent::Reserve(size, base, upper_bounds)) return NULL;
|
||||
if (!_parent::Reserve(size, base, upper_bounds)) return NULL;
|
||||
_registerProfiler();
|
||||
return m_baseptr;
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ RecompiledCodeReserve& RecompiledCodeReserve::SetProfilerName( const wxString& s
|
|||
|
||||
void RecompiledCodeReserve::DoCommitAndProtect( uptr page )
|
||||
{
|
||||
CommitBlocks(page, (m_commited || !m_def_commit) ? 1 : _calcDefaultCommitInBlocks() );
|
||||
CommitBlocks(page, (m_pages_commited || !m_def_commit) ? 1 : _calcDefaultCommitInBlocks() );
|
||||
}
|
||||
|
||||
void RecompiledCodeReserve::OnCommittedBlock( void* block )
|
||||
|
@ -333,84 +333,71 @@ static wxString GetMemoryErrorVM()
|
|||
// --------------------------------------------------------------------------------------
|
||||
// SysReserveVM (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
SysReserveVM::SysReserveVM()
|
||||
SysMainMemory::SysMainMemory()
|
||||
{
|
||||
if (!Source_PageFault) Source_PageFault = new SrcType_PageFault();
|
||||
|
||||
// [TODO] : Reserve memory addresses for PS2 virtual machine
|
||||
//DevCon.WriteLn( "Reserving memory addresses for the PS2 virtual machine..." );
|
||||
}
|
||||
|
||||
void SysReserveVM::CleanupMess() throw()
|
||||
SysMainMemory::~SysMainMemory() throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
safe_delete(Source_PageFault);
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
ShutdownAll();
|
||||
ReleaseAll();
|
||||
}
|
||||
|
||||
SysReserveVM::~SysReserveVM() throw()
|
||||
void SysMainMemory::ReserveAll()
|
||||
{
|
||||
CleanupMess();
|
||||
pxInstallSignalHandler();
|
||||
|
||||
DevCon.WriteLn( "PS2vm: Mapping host memory for all virtual systems..." );
|
||||
|
||||
m_ee.Reserve();
|
||||
m_iop.Reserve();
|
||||
m_vu.Reserve();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysAllocVM (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
SysAllocVM::SysAllocVM()
|
||||
void SysMainMemory::CommitAll()
|
||||
{
|
||||
InstallSignalHandler();
|
||||
if (m_ee.IsCommitted() && m_iop.IsCommitted() && m_vu.IsCommitted()) return;
|
||||
|
||||
Console.WriteLn( "Allocating memory for the PS2 virtual machine..." );
|
||||
DevCon.WriteLn( "PS2vm: Allocating host memory for all virtual systems..." );
|
||||
|
||||
try
|
||||
{
|
||||
vtlb_Core_Alloc();
|
||||
memAlloc();
|
||||
psxMemAlloc();
|
||||
vuMicroMemAlloc();
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::OutOfMemory& ex )
|
||||
{
|
||||
ex.UserMsg() += L"\n\n" + GetMemoryErrorVM();
|
||||
CleanupMess();
|
||||
throw;
|
||||
}
|
||||
catch( std::bad_alloc& ex )
|
||||
{
|
||||
CleanupMess();
|
||||
|
||||
// re-throw std::bad_alloc as something more friendly. This is needed since
|
||||
// much of the code uses new/delete internally, which throw std::bad_alloc on fail.
|
||||
|
||||
throw Exception::OutOfMemory()
|
||||
.SetDiagMsg(
|
||||
L"std::bad_alloc caught while trying to allocate memory for the PS2 Virtual Machine.\n"
|
||||
L"Error Details: " + fromUTF8( ex.what() )
|
||||
)
|
||||
.SetUserMsg(GetMemoryErrorVM()); // translated
|
||||
}
|
||||
m_ee.Commit();
|
||||
m_iop.Commit();
|
||||
m_vu.Commit();
|
||||
}
|
||||
|
||||
void SysAllocVM::CleanupMess() throw()
|
||||
|
||||
void SysMainMemory::ResetAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
vuMicroMemShutdown();
|
||||
psxMemShutdown();
|
||||
memShutdown();
|
||||
vtlb_Core_Shutdown();
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
CommitAll();
|
||||
|
||||
DevCon.WriteLn( "PS2vm: Resetting host memory for all virtual systems..." );
|
||||
|
||||
m_ee.Reset();
|
||||
m_iop.Reset();
|
||||
m_vu.Reset();
|
||||
}
|
||||
|
||||
SysAllocVM::~SysAllocVM() throw()
|
||||
void SysMainMemory::ShutdownAll()
|
||||
{
|
||||
CleanupMess();
|
||||
Console.WriteLn( "PS2vm: Shutting down host memory for all virtual systems..." );
|
||||
|
||||
m_ee.Shutdown();
|
||||
m_iop.Shutdown();
|
||||
m_vu.Shutdown();
|
||||
}
|
||||
|
||||
void SysMainMemory::ReleaseAll()
|
||||
{
|
||||
Console.WriteLn( "PS2vm: Releasing host memory maps for all virtual systems..." );
|
||||
|
||||
m_ee.Shutdown();
|
||||
m_iop.Shutdown();
|
||||
m_vu.Shutdown();
|
||||
|
||||
safe_delete(Source_PageFault);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysCpuProviderPack (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "Utilities/Threading.h" // to use threading stuff, include the Threading namespace in your file.
|
||||
#include "CDVD/CDVDaccess.h"
|
||||
|
||||
#include "vtlb.h"
|
||||
|
||||
typedef SafeArray<u8> VmStateBuffer;
|
||||
|
||||
class BaseVUmicroCPU;
|
||||
|
@ -30,49 +32,62 @@ class RecompiledCodeReserve;
|
|||
// are provided and used to assist in debugging and possibly hacking; as it makes it possible
|
||||
// for a programmer to know exactly where to look (consistently!) for the base address of
|
||||
// the various virtual machine components. These addresses can be keyed directly into the
|
||||
// debugger's disasm window to get disassembl of recompiled code, and they can be used to help
|
||||
// debugger's disasm window to get disassembly of recompiled code, and they can be used to help
|
||||
// identify recompiled code addresses in the callstack.
|
||||
|
||||
// All of these areas should be reserved as soon as possible during program startup, and its
|
||||
// important that none of the areas overlap. In all but superVU's case, failure due to overlap
|
||||
// or other conflict will result in the operating system picking a preferred address for the mapping.
|
||||
|
||||
namespace HostMemoryMap
|
||||
{
|
||||
// superVU is OLD SCHOOL, and it requires its allocation to be in the lower 256mb
|
||||
// of the virtual memory space. (8mb each)
|
||||
static const uptr sVU0rec = _256mb - (_16mb*2);
|
||||
static const uptr sVU1rec = _256mb - (_16mb*1);
|
||||
static const uptr sVU0rec = _256mb - (_8mb*3);
|
||||
static const uptr sVU1rec = _256mb - (_8mb*2);
|
||||
|
||||
// PS2 main memory, SPR, and ROMs
|
||||
static const uptr EEmem = 0x20000000;
|
||||
static const uptr EEmem = 0x30000000;
|
||||
|
||||
// IOP main memory and ROMs
|
||||
static const uptr IOPmem = 0x28000000;
|
||||
static const uptr IOPmem = 0x34000000;
|
||||
|
||||
// VU0 and VU1 memory.
|
||||
static const uptr VUmem = 0x38000000;
|
||||
|
||||
// EE recompiler code cache area (64mb)
|
||||
static const uptr EErec = 0x30000000;
|
||||
static const uptr EErec = 0x40000000;
|
||||
|
||||
// IOP recompiler code cache area (16 or 32mb)
|
||||
static const uptr IOPrec = 0x34000000;
|
||||
static const uptr IOPrec = 0x44000000;
|
||||
|
||||
// microVU1 recompiler code cache area (64mb)
|
||||
static const uptr mVU0rec = 0x38000000;
|
||||
// microVU1 recompiler code cache area (32 or 64mb)
|
||||
static const uptr mVU0rec = 0x48000000;
|
||||
|
||||
// microVU0 recompiler code cache area (64mb)
|
||||
static const uptr mVU1rec = 0x40000000;
|
||||
static const uptr mVU1rec = 0x50000000;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysReserveVM
|
||||
// SysMainMemory
|
||||
// --------------------------------------------------------------------------------------
|
||||
class SysReserveVM
|
||||
// This class provides the main memory for the virtual machines.
|
||||
class SysMainMemory
|
||||
{
|
||||
public:
|
||||
SysReserveVM();
|
||||
virtual ~SysReserveVM() throw();
|
||||
|
||||
protected:
|
||||
void CleanupMess() throw();
|
||||
eeMemoryReserve m_ee;
|
||||
iopMemoryReserve m_iop;
|
||||
vuMemoryReserve m_vu;
|
||||
|
||||
public:
|
||||
SysMainMemory();
|
||||
virtual ~SysMainMemory() throw();
|
||||
|
||||
virtual void ReserveAll();
|
||||
virtual void CommitAll();
|
||||
virtual void ResetAll();
|
||||
virtual void ShutdownAll();
|
||||
virtual void ReleaseAll();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -142,6 +157,8 @@ extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true );
|
|||
|
||||
extern wxString SysGetDiscID();
|
||||
|
||||
extern SysMainMemory& GetVmMemory();
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PCSX2_SEH - Defines existence of "built in" Structured Exception Handling support.
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
// A recompiled code reserve is a simple sequential-growth block of memory which is auto-
|
||||
// cleared to INT 3 (0xcc) as needed.
|
||||
//
|
||||
class RecompiledCodeReserve : public BaseVirtualMemoryReserve
|
||||
class RecompiledCodeReserve : public BaseVmReserveListener
|
||||
{
|
||||
typedef BaseVirtualMemoryReserve __parent;
|
||||
typedef BaseVmReserveListener _parent;
|
||||
|
||||
protected:
|
||||
// Specifies the number of blocks that should be committed automatically when the
|
||||
|
@ -40,7 +40,7 @@ public:
|
|||
RecompiledCodeReserve( const wxString& name, uint defCommit = 0 );
|
||||
virtual ~RecompiledCodeReserve() throw();
|
||||
|
||||
virtual void* Reserve( uint size, uptr base=0, uptr upper_bounds=0 );
|
||||
virtual void* Reserve( size_t size, uptr base=0, uptr upper_bounds=0 );
|
||||
virtual void OnCommittedBlock( void* block );
|
||||
|
||||
virtual RecompiledCodeReserve& SetProfilerName( const wxString& shortname );
|
||||
|
|
|
@ -111,13 +111,24 @@ void SysCoreThread::SetElfOverride( const wxString& elf )
|
|||
Hle_SetElfPath(elf.ToUTF8());
|
||||
}
|
||||
|
||||
void SysCoreThread::Reset()
|
||||
// Performs a quicker reset that does not deallocate memory associated with PS2 virtual machines
|
||||
// or cpu providers (recompilers).
|
||||
void SysCoreThread::ResetQuick()
|
||||
{
|
||||
Suspend();
|
||||
|
||||
m_resetVirtualMachine = true;
|
||||
m_hasActiveMachine = false;
|
||||
}
|
||||
|
||||
void SysCoreThread::Reset()
|
||||
{
|
||||
ResetQuick();
|
||||
GetVmMemory().ShutdownAll();
|
||||
SysClearExecutionCache();
|
||||
}
|
||||
|
||||
|
||||
// Applies a full suite of new settings, which will automatically facilitate the necessary
|
||||
// resets of the core and components (including plugins, if needed). The scope of resetting
|
||||
// is determined by comparing the current settings against the new settings, so that only
|
||||
|
@ -159,6 +170,8 @@ void SysCoreThread::_reset_stuff_as_needed()
|
|||
// because of changes to the TLB. We don't actually support the TLB, however, so rec
|
||||
// resets aren't in fact *needed* ... yet. But might as well, no harm. --air
|
||||
|
||||
GetVmMemory().CommitAll();
|
||||
|
||||
if( m_resetVirtualMachine || m_resetRecompilers || m_resetProfilers )
|
||||
{
|
||||
SysClearExecutionCache();
|
||||
|
|
|
@ -184,6 +184,7 @@ public:
|
|||
|
||||
virtual void OnResumeReady();
|
||||
virtual void Reset();
|
||||
virtual void ResetQuick();
|
||||
virtual void Cancel( bool isBlocking=true );
|
||||
virtual bool Cancel( const wxTimeSpan& timeout );
|
||||
|
||||
|
|
|
@ -19,15 +19,15 @@
|
|||
#include "VUops.h"
|
||||
#include "R5900.h"
|
||||
|
||||
static const uint VU0_MEMSIZE = 0x1000;
|
||||
static const uint VU0_PROGSIZE = 0x1000;
|
||||
static const uint VU1_MEMSIZE = 0x4000;
|
||||
static const uint VU1_PROGSIZE = 0x4000;
|
||||
static const uint VU0_MEMSIZE = 0x1000; // 4kb
|
||||
static const uint VU0_PROGSIZE = 0x1000; // 4kb
|
||||
static const uint VU1_MEMSIZE = 0x4000; // 16kb
|
||||
static const uint VU1_PROGSIZE = 0x4000; // 16kb
|
||||
|
||||
static const uint VU0_MEMMASK = VU0_MEMSIZE-1;
|
||||
static const uint VU0_PROGMASK = VU0_PROGSIZE-1;
|
||||
static const uint VU1_MEMMASK = VU1_MEMSIZE-1;
|
||||
static const uint VU1_PROGMASK = VU1_PROGSIZE-1;
|
||||
static const uint VU0_MEMMASK = VU0_MEMSIZE-1;
|
||||
static const uint VU0_PROGMASK = VU0_PROGSIZE-1;
|
||||
static const uint VU1_MEMMASK = VU1_MEMSIZE-1;
|
||||
static const uint VU1_PROGMASK = VU1_PROGSIZE-1;
|
||||
|
||||
#define vuRunCycles (512*12) // Cycles to run ExecuteBlockJIT() for (called from within recs)
|
||||
#define vu0RunCycles (512*12) // Cycles to run vu0 for whenever ExecuteBlock() is called
|
||||
|
@ -287,10 +287,6 @@ extern BaseVUmicroCPU* CpuVU0;
|
|||
extern BaseVUmicroCPU* CpuVU1;
|
||||
|
||||
|
||||
extern void vuMicroMemAlloc();
|
||||
extern void vuMicroMemShutdown();
|
||||
extern void vuMicroMemReset();
|
||||
|
||||
// VU0
|
||||
extern void vu0ResetRegs();
|
||||
extern void __fastcall vu0ExecMicro(u32 addr);
|
||||
|
|
|
@ -18,43 +18,41 @@
|
|||
#include "Common.h"
|
||||
#include "VUmicro.h"
|
||||
|
||||
|
||||
__aligned16 VURegs vuRegs[2];
|
||||
|
||||
static u8* m_vuAllMem = NULL;
|
||||
static const uint m_vuMemSize =
|
||||
0x1000 + // VU0micro memory
|
||||
0x4000 + // VU0 memory
|
||||
0x4000 + // VU1 memory
|
||||
0x4000;
|
||||
|
||||
void vuMicroMemAlloc()
|
||||
vuMemoryReserve::vuMemoryReserve()
|
||||
: _parent( L"VU0/1 on-chip memory", VU1_PROGSIZE + VU1_MEMSIZE + VU0_PROGSIZE + VU0_MEMSIZE )
|
||||
{
|
||||
if( m_vuAllMem == NULL )
|
||||
m_vuAllMem = vtlb_malloc( m_vuMemSize, 16 );
|
||||
}
|
||||
|
||||
if( m_vuAllMem == NULL )
|
||||
throw Exception::OutOfMemory( L"VU0 and VU1 on-chip memory" );
|
||||
void vuMemoryReserve::Reserve()
|
||||
{
|
||||
_parent::Reserve(HostMemoryMap::VUmem);
|
||||
//_parent::Reserve(EmuConfig.HostMemMap.VUmem);
|
||||
|
||||
u8* curpos = m_vuAllMem;
|
||||
u8* curpos = m_reserve.GetPtr();
|
||||
VU0.Micro = curpos; curpos += 0x1000;
|
||||
VU0.Mem = curpos; curpos += 0x4000;
|
||||
VU1.Micro = curpos; curpos += 0x4000;
|
||||
VU1.Mem = curpos;
|
||||
//curpos += 0x4000;
|
||||
}
|
||||
|
||||
void vuMicroMemShutdown()
|
||||
void vuMemoryReserve::Release()
|
||||
{
|
||||
// -- VTLB Memory Allocation --
|
||||
_parent::Release();
|
||||
|
||||
vtlb_free( m_vuAllMem, m_vuMemSize );
|
||||
m_vuAllMem = NULL;
|
||||
VU0.Micro = VU0.Mem = NULL;
|
||||
VU1.Micro = VU1.Mem = NULL;
|
||||
}
|
||||
|
||||
void vuMicroMemReset()
|
||||
void vuMemoryReserve::Reset()
|
||||
{
|
||||
pxAssume( VU0.Mem != NULL );
|
||||
pxAssume( VU1.Mem != NULL );
|
||||
_parent::Reset();
|
||||
|
||||
pxAssume( VU0.Mem );
|
||||
pxAssume( VU1.Mem );
|
||||
|
||||
memMapVUmicro();
|
||||
|
||||
|
@ -67,8 +65,6 @@ void vuMicroMemReset()
|
|||
VU0.VF[0].f.z = 0.0f;
|
||||
VU0.VF[0].f.w = 1.0f;
|
||||
VU0.VI[0].UL = 0;
|
||||
memzero_ptr<4*1024>(VU0.Mem);
|
||||
memzero_ptr<4*1024>(VU0.Micro);
|
||||
|
||||
// === VU1 Initialization ===
|
||||
memzero(VU1.ACC);
|
||||
|
@ -79,8 +75,6 @@ void vuMicroMemReset()
|
|||
VU1.VF[0].f.z = 0.0f;
|
||||
VU1.VF[0].f.w = 1.0f;
|
||||
VU1.VI[0].UL = 0;
|
||||
memzero_ptr<16*1024>(VU1.Mem);
|
||||
memzero_ptr<16*1024>(VU1.Micro);
|
||||
}
|
||||
|
||||
void SaveStateBase::vuMicroFreeze()
|
||||
|
|
|
@ -476,8 +476,7 @@ public:
|
|||
// blocked threads stalling the GUI.
|
||||
ExecutorThread SysExecutorThread;
|
||||
ScopedPtr<SysCpuProviderPack> m_CpuProviders;
|
||||
ScopedPtr<SysReserveVM> m_VmReserve;
|
||||
ScopedPtr<SysAllocVM> m_VmAllocs;
|
||||
ScopedPtr<SysMainMemory> m_VmReserve;
|
||||
|
||||
protected:
|
||||
wxWindowID m_id_MainFrame;
|
||||
|
@ -499,6 +498,8 @@ public:
|
|||
void SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override=wxEmptyString );
|
||||
void LogicalVsync();
|
||||
|
||||
SysMainMemory& GetVmReserve();
|
||||
|
||||
GSFrame& GetGsFrame() const;
|
||||
MainEmuFrame& GetMainFrame() const;
|
||||
|
||||
|
@ -528,8 +529,6 @@ public:
|
|||
void StartPendingSave();
|
||||
void ClearPendingSave();
|
||||
|
||||
void AllocateVM();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// App-wide Resources
|
||||
// --------------------------------------------------------------------------
|
||||
|
|
|
@ -109,6 +109,17 @@ void AppCoreThread::Reset()
|
|||
_parent::Reset();
|
||||
}
|
||||
|
||||
void AppCoreThread::ResetQuick()
|
||||
{
|
||||
if( !GetSysExecutorThread().IsSelf() )
|
||||
{
|
||||
GetSysExecutorThread().PostEvent( SysExecEvent_InvokeCoreThreadMethod(&AppCoreThread::ResetQuick) );
|
||||
return;
|
||||
}
|
||||
|
||||
_parent::ResetQuick();
|
||||
}
|
||||
|
||||
ExecutorThread& GetSysExecutorThread()
|
||||
{
|
||||
return wxGetApp().SysExecutorThread;
|
||||
|
@ -183,7 +194,6 @@ void Pcsx2App::SysApplySettings()
|
|||
void AppCoreThread::OnResumeReady()
|
||||
{
|
||||
wxGetApp().SysApplySettings();
|
||||
wxGetApp().AllocateVM();
|
||||
wxGetApp().PostMethod( AppSaveSettings );
|
||||
_parent::OnResumeReady();
|
||||
}
|
||||
|
|
|
@ -134,6 +134,7 @@ public:
|
|||
virtual void Suspend( bool isBlocking=false );
|
||||
virtual void Resume();
|
||||
virtual void Reset();
|
||||
virtual void ResetQuick();
|
||||
virtual void Cancel( bool isBlocking=true );
|
||||
virtual bool StateCheckInThread();
|
||||
virtual void ChangeCdvdSource();
|
||||
|
|
|
@ -163,6 +163,12 @@ public:
|
|||
// this second layer class to act as a bridge between the event system and the class's
|
||||
// handler implementations.
|
||||
//
|
||||
// Explained in detail: The class that wants to listen to shit will implement its expected
|
||||
// virtual overrides from the listener classes (OnCoreThread_Started, for example), and then
|
||||
// it adds an instance of the EventListenerHelper_CoreThread class to itself, instead of
|
||||
// *inheriting* from it. Thusly, the Helper gets initialized when the class is created,
|
||||
// and when events are dispatched to the listener, it forwards the event to the main class.
|
||||
// --air
|
||||
|
||||
template< typename TypeToDispatchTo >
|
||||
class EventListenerHelper_CoreThread : public EventListener_CoreThread
|
||||
|
@ -212,9 +218,9 @@ public:
|
|||
protected:
|
||||
void CorePlugins_OnLoaded() { Owner.OnCorePlugins_Loaded(); }
|
||||
void CorePlugins_OnInit() { Owner.OnCorePlugins_Init(); }
|
||||
void CorePlugins_OnOpening() { Owner.OnCorePlugins_Opening(); }
|
||||
void CorePlugins_OnOpening() { Owner.OnCorePlugins_Opening(); }
|
||||
void CorePlugins_OnOpened() { Owner.OnCorePlugins_Opened(); }
|
||||
void CorePlugins_OnClosing() { Owner.OnCorePlugins_Closing(); }
|
||||
void CorePlugins_OnClosing() { Owner.OnCorePlugins_Closing(); }
|
||||
void CorePlugins_OnClosed() { Owner.OnCorePlugins_Closed(); }
|
||||
void CorePlugins_OnShutdown() { Owner.OnCorePlugins_Shutdown(); }
|
||||
void CorePlugins_OnUnloaded() { Owner.OnCorePlugins_Unloaded(); }
|
||||
|
|
|
@ -238,12 +238,6 @@ void Pcsx2App::OpenProgramLog()
|
|||
if( m_current_focus ) m_current_focus->SetFocus();
|
||||
}
|
||||
|
||||
void Pcsx2App::AllocateVM()
|
||||
{
|
||||
if (m_VmAllocs) return;
|
||||
m_VmAllocs = new SysAllocVM();
|
||||
}
|
||||
|
||||
void Pcsx2App::AllocateCoreStuffs()
|
||||
{
|
||||
if( AppRpc_TryInvokeAsync( &Pcsx2App::AllocateCoreStuffs ) ) return;
|
||||
|
@ -252,7 +246,7 @@ void Pcsx2App::AllocateCoreStuffs()
|
|||
SysLogMachineCaps();
|
||||
AppApplySettings();
|
||||
|
||||
if (!m_VmReserve) m_VmReserve = new SysReserveVM();
|
||||
GetVmReserve().ReserveAll();
|
||||
|
||||
if( !m_CpuProviders )
|
||||
{
|
||||
|
@ -820,12 +814,12 @@ void Pcsx2App::CleanUp()
|
|||
|
||||
__fi wxString AddAppName( const wxChar* fmt )
|
||||
{
|
||||
return wxsFormat( fmt, pxGetAppName().c_str() );
|
||||
return pxsFmt( fmt, pxGetAppName().c_str() );
|
||||
}
|
||||
|
||||
__fi wxString AddAppName( const char* fmt )
|
||||
{
|
||||
return wxsFormat( fromUTF8(fmt), pxGetAppName().c_str() );
|
||||
return pxsFmt( fromUTF8(fmt), pxGetAppName().c_str() );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -702,6 +702,12 @@ void Pcsx2App::PostIdleAppMethod( FnPtr_Pcsx2App method )
|
|||
AddIdleEvent( evt );
|
||||
}
|
||||
|
||||
SysMainMemory& Pcsx2App::GetVmReserve()
|
||||
{
|
||||
if (!m_VmReserve) m_VmReserve = new SysMainMemory();
|
||||
return *m_VmReserve;
|
||||
}
|
||||
|
||||
void Pcsx2App::OpenGsPanel()
|
||||
{
|
||||
if( AppRpc_TryInvoke( &Pcsx2App::OpenGsPanel ) ) return;
|
||||
|
@ -851,7 +857,7 @@ protected:
|
|||
|
||||
DbgCon.WriteLn( Color_Gray, "(SysExecute) received." );
|
||||
|
||||
CoreThread.Reset();
|
||||
CoreThread.ResetQuick();
|
||||
|
||||
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
|
||||
if( m_UseCDVDsrc )
|
||||
|
@ -930,6 +936,11 @@ MainEmuFrame* GetMainFramePtr()
|
|||
return wxTheApp ? wxGetApp().GetMainFramePtr() : NULL;
|
||||
}
|
||||
|
||||
SysMainMemory& GetVmMemory()
|
||||
{
|
||||
return wxGetApp().GetVmReserve();
|
||||
}
|
||||
|
||||
SysCoreThread& GetCoreThread()
|
||||
{
|
||||
return CoreThread;
|
||||
|
|
107
pcsx2/vtlb.cpp
107
pcsx2/vtlb.cpp
|
@ -33,9 +33,10 @@
|
|||
#include "Common.h"
|
||||
#include "vtlb.h"
|
||||
#include "COP0.h"
|
||||
|
||||
#include "R5900Exceptions.h"
|
||||
|
||||
#include "Utilities\MemsetFast.inl"
|
||||
|
||||
using namespace R5900;
|
||||
using namespace vtlb_private;
|
||||
|
||||
|
@ -46,7 +47,7 @@ namespace vtlb_private
|
|||
__aligned(64) MapData vtlbdata;
|
||||
}
|
||||
|
||||
static vtlbHandler vtlbHandlerCount=0;
|
||||
static vtlbHandler vtlbHandlerCount = 0;
|
||||
|
||||
static vtlbHandler DefaultPhyHandler;
|
||||
static vtlbHandler UnmappedVirtHandler0;
|
||||
|
@ -565,69 +566,67 @@ void vtlb_Term()
|
|||
// [TODO] basemem - request allocating memory at the specified virtual location, which can allow
|
||||
// for easier debugging and/or 3rd party cheat programs. If 0, the operating system
|
||||
// default is used.
|
||||
void vtlb_Core_Alloc( /*uptr basemem*/ )
|
||||
void vtlb_Core_Alloc()
|
||||
{
|
||||
if( vtlbdata.alloc_base != NULL ) return;
|
||||
|
||||
vtlbdata.alloc_current = 0;
|
||||
vtlbdata.alloc_base = SysMmapEx( HostMemoryMap::EEmem, VTLB_ALLOC_SIZE, 0x80000000, "Vtlb" );
|
||||
|
||||
#ifndef __WXMSW__
|
||||
// [TODO] Win32 can fall back on this, since malloc always maps below 2GB. (but we need to
|
||||
// make sure we flag it and call the right free -- and really it should never fail anyway
|
||||
// since SysMmapEx should still grab addresses below the 2gb line when given the 0 param
|
||||
// (OS picks the location).
|
||||
|
||||
//if (!vtlbdata.alloc_base)
|
||||
// vtlbdata.alloc_base = (u8*)_aligned_malloc( VTLB_ALLOC_SIZE, 4096 );
|
||||
#endif
|
||||
|
||||
if (!vtlbdata.alloc_base)
|
||||
throw Exception::OutOfMemory( pxsFmt(L"PS2 mappable system ram (%u megs)", VTLB_ALLOC_SIZE / _1mb) );
|
||||
|
||||
vtlbdata.vmap = (s32*)_aligned_malloc( VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap), 16 );
|
||||
if (!vtlbdata.vmap)
|
||||
throw Exception::OutOfMemory( pxsFmt(L"VTLB virtual LUT (%u megs)", VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap) / _1mb) );
|
||||
throw Exception::OutOfMemory( L"VTLB Virtual Address Translation LUT" )
|
||||
.SetDiagMsg(pxsFmt("(%u megs)", VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap) / _1mb)
|
||||
);
|
||||
}
|
||||
|
||||
void vtlb_Core_Shutdown()
|
||||
void vtlb_Core_Free()
|
||||
{
|
||||
safe_aligned_free( vtlbdata.vmap );
|
||||
|
||||
if (!vtlbdata.alloc_base) return;
|
||||
|
||||
SafeSysMunmap( vtlbdata.alloc_base, VTLB_ALLOC_SIZE );
|
||||
|
||||
#ifdef __WXMSW__
|
||||
// Make sure and unprotect memory first, since CrtDebug will try to write to it.
|
||||
//HostSys::MemProtect( vtlbdata.alloc_base, VTLB_ALLOC_SIZE, Protect_ReadWrite );
|
||||
//safe_aligned_free( vtlbdata.alloc_base );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// This function allocates memory block with are compatible with the Vtlb's requirements
|
||||
// for memory locations. The Vtlb requires the topmost bit (Sign bit) of the memory
|
||||
// pointer to be cleared. Some operating systems and/or implementations of malloc do that,
|
||||
// but others do not. So use this instead to allocate the memory correctly for your
|
||||
// platform.
|
||||
//
|
||||
u8* vtlb_malloc( uint size, uint align )
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VtlbMemoryReserve (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
VtlbMemoryReserve::VtlbMemoryReserve( const wxString& name, size_t size )
|
||||
: m_reserve( name, size )
|
||||
{
|
||||
vtlbdata.alloc_current += align-1;
|
||||
vtlbdata.alloc_current &= ~(align-1);
|
||||
|
||||
int rv = vtlbdata.alloc_current;
|
||||
vtlbdata.alloc_current += size;
|
||||
|
||||
pxAssertDev( vtlbdata.alloc_current < VTLB_ALLOC_SIZE, "(vtlb_malloc) memory overflow! Please increase the size of VTLB_ALLOC_SIZE!" );
|
||||
return &vtlbdata.alloc_base[rv];
|
||||
m_reserve.SetPageAccessOnCommit( PageAccess_ReadWrite() );
|
||||
}
|
||||
|
||||
void vtlb_free( void* pmem, uint size )
|
||||
void VtlbMemoryReserve::SetBaseAddr( uptr newaddr )
|
||||
{
|
||||
if (!pmem) return;
|
||||
|
||||
vtlbdata.alloc_current -= size;
|
||||
pxAssertDev( vtlbdata.alloc_current >= 0, "(vtlb_free) mismatched calls to vtlb_malloc and free detected via memory underflow." );
|
||||
m_reserve.SetBaseAddr( newaddr );
|
||||
}
|
||||
|
||||
void VtlbMemoryReserve::Reserve( sptr hostptr )
|
||||
{
|
||||
m_reserve.Reserve();
|
||||
if (!m_reserve.IsOk())
|
||||
throw Exception::OutOfMemory( m_reserve.GetName() );
|
||||
}
|
||||
|
||||
void VtlbMemoryReserve::Commit()
|
||||
{
|
||||
if (IsCommitted()) return;
|
||||
if (!m_reserve.Commit())
|
||||
throw Exception::OutOfMemory( m_reserve.GetName() );
|
||||
}
|
||||
|
||||
void VtlbMemoryReserve::Reset()
|
||||
{
|
||||
if (!m_reserve.Commit())
|
||||
throw Exception::OutOfMemory( m_reserve.GetName() );
|
||||
|
||||
memzero_sse_a(m_reserve.GetPtr(), m_reserve.GetCommittedBytes());
|
||||
}
|
||||
|
||||
void VtlbMemoryReserve::Shutdown()
|
||||
{
|
||||
m_reserve.Reset();
|
||||
}
|
||||
|
||||
void VtlbMemoryReserve::Release()
|
||||
{
|
||||
m_reserve.Release();
|
||||
}
|
||||
|
||||
bool VtlbMemoryReserve::IsCommitted() const
|
||||
{
|
||||
return !!m_reserve.GetCommittedPageCount();
|
||||
}
|
105
pcsx2/vtlb.h
105
pcsx2/vtlb.h
|
@ -17,6 +17,10 @@
|
|||
|
||||
#include "MemoryTypes.h"
|
||||
|
||||
#include "Utilities/PageFaultSource.h"
|
||||
|
||||
static const uptr VTLB_AllocUpperBounds = _1gb * 2;
|
||||
|
||||
// Specialized function pointers for each read type
|
||||
typedef mem8_t __fastcall vtlbMemR8FP(u32 addr);
|
||||
typedef mem16_t __fastcall vtlbMemR16FP(u32 addr);
|
||||
|
@ -34,12 +38,10 @@ typedef void __fastcall vtlbMemW128FP(u32 addr,const mem128_t* data);
|
|||
typedef u32 vtlbHandler;
|
||||
|
||||
extern void vtlb_Core_Alloc();
|
||||
extern void vtlb_Core_Shutdown();
|
||||
extern void vtlb_Core_Free();
|
||||
extern void vtlb_Init();
|
||||
extern void vtlb_Reset();
|
||||
extern void vtlb_Term();
|
||||
extern u8* vtlb_malloc( uint size, uint align );
|
||||
extern void vtlb_free( void* pmem, uint size );
|
||||
|
||||
|
||||
extern vtlbHandler vtlb_NewHandler();
|
||||
|
@ -85,19 +87,100 @@ extern void vtlb_DynGenWrite_Const( u32 bits, u32 addr_const );
|
|||
extern void vtlb_DynGenRead64_Const( u32 bits, u32 addr_const );
|
||||
extern void vtlb_DynGenRead32_Const( u32 bits, bool sign, u32 addr_const );
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VtlbMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class VtlbMemoryReserve
|
||||
{
|
||||
protected:
|
||||
VirtualMemoryReserve m_reserve;
|
||||
|
||||
public:
|
||||
VtlbMemoryReserve( const wxString& name, size_t size );
|
||||
virtual ~VtlbMemoryReserve() throw()
|
||||
{
|
||||
m_reserve.Release();
|
||||
}
|
||||
|
||||
virtual void Reserve( sptr hostptr );
|
||||
virtual void Release();
|
||||
|
||||
virtual void Commit();
|
||||
virtual void Reset();
|
||||
virtual void Shutdown();
|
||||
virtual void SetBaseAddr( uptr newaddr );
|
||||
|
||||
bool IsCommitted() const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// eeMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class eeMemoryReserve : public VtlbMemoryReserve
|
||||
{
|
||||
typedef VtlbMemoryReserve _parent;
|
||||
|
||||
public:
|
||||
eeMemoryReserve();
|
||||
virtual ~eeMemoryReserve() throw()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
void Reserve();
|
||||
void Release();
|
||||
void Reset();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// iopMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class iopMemoryReserve : public VtlbMemoryReserve
|
||||
{
|
||||
typedef VtlbMemoryReserve _parent;
|
||||
|
||||
public:
|
||||
iopMemoryReserve();
|
||||
virtual ~iopMemoryReserve() throw()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
void Reserve();
|
||||
void Release();
|
||||
void Reset();
|
||||
void Shutdown();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// vuMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class vuMemoryReserve : public VtlbMemoryReserve
|
||||
{
|
||||
typedef VtlbMemoryReserve _parent;
|
||||
|
||||
public:
|
||||
vuMemoryReserve();
|
||||
virtual ~vuMemoryReserve() throw()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
virtual void Reserve();
|
||||
virtual void Release();
|
||||
|
||||
void Reset();
|
||||
};
|
||||
|
||||
namespace vtlb_private
|
||||
{
|
||||
// Allocate enough memory for EE, IOP, and VU, memory space (IOP + VU is roughly
|
||||
// 2.5mb, so we alloc 4mb for now -- a little more than is needed).
|
||||
static const uint VTLB_ALLOC_SIZE = sizeof(*eeMem) + (_1mb*4);
|
||||
|
||||
static const uint VTLB_PAGE_BITS = 12;
|
||||
static const uint VTLB_PAGE_MASK = 4095;
|
||||
static const uint VTLB_PAGE_SIZE = 4096;
|
||||
|
||||
static const uint VTLB_PMAP_ITEMS = 0x20000000 / VTLB_PAGE_SIZE;
|
||||
static const uint VTLB_PMAP_SZ = 0x20000000;
|
||||
static const uint VTLB_VMAP_ITEMS = 0x100000000ULL / VTLB_PAGE_SIZE;
|
||||
static const uint VTLB_PMAP_ITEMS = _256mb / VTLB_PAGE_SIZE;
|
||||
static const uint VTLB_PMAP_SZ = _256mb;
|
||||
static const uint VTLB_VMAP_ITEMS = _4gb / VTLB_PAGE_SIZE;
|
||||
|
||||
struct MapData
|
||||
{
|
||||
|
@ -110,6 +193,8 @@ namespace vtlb_private
|
|||
|
||||
s32* vmap; //4MB (allocated by vtlb_init)
|
||||
|
||||
u8* reserve_base; //base of the memory array
|
||||
|
||||
u8* alloc_base; //base of the memory array
|
||||
int alloc_current; //current base
|
||||
};
|
||||
|
|
|
@ -19,17 +19,3 @@
|
|||
|
||||
#include "Common.h"
|
||||
#include "Utilities/PageFaultSource.h"
|
||||
|
||||
int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
|
||||
{
|
||||
if( eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION )
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
Source_PageFault->Dispatch( PageFaultInfo( (uptr)eps->ExceptionRecord->ExceptionInformation[1] ) );
|
||||
return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
void InstallSignalHandler()
|
||||
{
|
||||
// NOP on Win32 systems -- we use __try{} __except{} instead.
|
||||
}
|
||||
|
|
|
@ -65,11 +65,11 @@ bool g_cpuFlushedPC, g_cpuFlushedCode, g_recompilingDelaySlot, g_maySignalExcept
|
|||
// --------------------------------------------------------------------------------------
|
||||
class R5900LutReserve_RAM : public SpatialArrayReserve
|
||||
{
|
||||
typedef SpatialArrayReserve __parent;
|
||||
typedef SpatialArrayReserve _parent;
|
||||
|
||||
public:
|
||||
R5900LutReserve_RAM( const wxString& name )
|
||||
: __parent( name )
|
||||
: _parent( name )
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -567,7 +567,7 @@ static __ri void ClearRecLUT(BASEBLOCK* base, int memsize)
|
|||
|
||||
void R5900LutReserve_RAM::OnCommittedBlock( void* block )
|
||||
{
|
||||
__parent::OnCommittedBlock(block);
|
||||
_parent::OnCommittedBlock(block);
|
||||
ClearRecLUT((BASEBLOCK*)block, __pagesize * m_blocksize);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue