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:
Jake.Stine 2010-11-15 14:05:02 +00:00
parent f1024dad91
commit be1a590464
30 changed files with 691 additions and 414 deletions

View File

@ -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;
// ===========================================================================================

View File

@ -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;

View File

@ -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(

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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();

View File

@ -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 ) {}

View File

@ -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 )
{

View File

@ -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

View File

@ -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();

View File

@ -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)
};

View File

@ -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);

View File

@ -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)
// --------------------------------------------------------------------------------------

View File

@ -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.
// --------------------------------------------------------------------------------------

View File

@ -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 );

View File

@ -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();

View File

@ -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 );

View File

@ -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);

View File

@ -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()

View File

@ -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
// --------------------------------------------------------------------------

View File

@ -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();
}

View File

@ -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();

View File

@ -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(); }

View File

@ -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() );
}
// ------------------------------------------------------------------------------------------

View File

@ -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;

View File

@ -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();
}

View File

@ -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
};

View File

@ -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.
}

View File

@ -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);
}