mirror of https://github.com/PCSX2/pcsx2.git
* Fix for Issue 493 -- non-standard SYSTEM.CNF contents are handled better now.
* Some minor exception/error handling fixes and improvements. DevNote: the BOOT2 elf loader fix is still a hackfix. I documented the proper fix for mimicking PS2 BOOT2 parsing, but not in a mood to do the full proper implementation right now. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3442 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
9d5a1b44ba
commit
d36bb19612
|
@ -306,17 +306,34 @@ s32 cdvdWriteConfig(const u8* config)
|
|||
static MutexRecursive Mutex_NewDiskCB;
|
||||
|
||||
// Sets ElfCRC to the CRC of the game bound to the CDVD plugin.
|
||||
static __forceinline ElfObject *loadElf( const wxString filename )
|
||||
static __forceinline ElfObject* loadElf( const wxString filename )
|
||||
{
|
||||
if (filename.StartsWith(L"host"))
|
||||
return new ElfObject(filename.After(':'), Path::GetFileSize(filename.After(':')));
|
||||
|
||||
// Mimic PS2 behavior!
|
||||
// Much trial-and-error with changing the ISOFS and BOOT2 contents of an image have shown that
|
||||
// the PS2 BIOS performs the peculiar task of *ignoring* the version info from the parsed BOOT2
|
||||
// filename *and* the ISOFS, when loading the game's ELF image. What this means is:
|
||||
//
|
||||
// 1. a valid PS2 ELF can have any version (ISOFS), and the version need not match the one in SYSTEM.CNF.
|
||||
// 2. the version info on the file in the BOOT2 parameter of SYSTEM.CNF can be missing, 10 chars long,
|
||||
// or anything else. Its all ignored.
|
||||
// 3. Games loading their own files do *not* exhibit this behavior; likely due to using newer IOP modules
|
||||
// or lower level filesystem APIs (fortunately that doesn't affect us).
|
||||
//
|
||||
// FIXME: Properly mimicing this behavior is troublesome since we need to add support for "ignoring"
|
||||
// version information when doing file searches. I'll add this later. For now, assuming a ;1 should
|
||||
// be sufficient (no known games have their ELF binary as anything but version ;1)
|
||||
|
||||
const wxString fixedname( wxStringTokenizer(filename, L';').GetNextToken() + L";1" );
|
||||
|
||||
if( fixedname != filename )
|
||||
Console.WriteLn( Color_Blue, "(LoadELF) Non-conforming version suffix detected and replaced." );
|
||||
|
||||
IsoFSCDVD isofs;
|
||||
IsoFile file(isofs, filename);
|
||||
ElfObject *elfptr;
|
||||
|
||||
elfptr = new ElfObject(filename, file);
|
||||
return elfptr;
|
||||
return new ElfObject(filename, file);
|
||||
}
|
||||
|
||||
static __forceinline void _reloadElfInfo(wxString elfpath)
|
||||
|
@ -339,7 +356,6 @@ static __forceinline void _reloadElfInfo(wxString elfpath)
|
|||
if (fname.Matches(L"????_???.??*"))
|
||||
DiscSerial = fname(0,4) + L"-" + fname(5,3) + fname(9,2);
|
||||
|
||||
Console.WriteLn("Disc ID = %s", DiscSerial.ToUTF8().data());
|
||||
elfptr = loadElf(elfpath);
|
||||
|
||||
ElfCRC = elfptr->getCRC();
|
||||
|
@ -348,47 +364,54 @@ static __forceinline void _reloadElfInfo(wxString elfpath)
|
|||
ElfEntry = elfptr->header.e_entry;
|
||||
Console.WriteLn("Entry point = 0x%08x", ElfEntry);
|
||||
|
||||
elfptr.Delete();
|
||||
|
||||
// Set the Game DataBase to the correct game based on Game Serial Code...
|
||||
if (IGameDatabase* GameDB = AppHost_GetGameDatabase()) {
|
||||
wxString gameSerial( SysGetDiscID() );
|
||||
wxString serialMsg;
|
||||
if(!DiscSerial.IsEmpty())
|
||||
serialMsg = L"serial=" + DiscSerial + L" ";
|
||||
|
||||
Game_Data game;
|
||||
if (GameDB->findGame(game, gameSerial))
|
||||
{
|
||||
Console.WriteLn(L"(GameDB) Found Game! %s [CRC=%8.8x]", serialMsg.c_str(), ElfCRC );
|
||||
// [TODO] Display lots of other info from the database here!
|
||||
}
|
||||
else
|
||||
Console.Warning(L"(GameDB) Game not found! %s [CRC=%8.8x]", serialMsg.c_str(), ElfCRC );
|
||||
}
|
||||
// Note: Do not load game database info here. This code is generic and called from
|
||||
// BIOS key encryption as well as eeloadReplaceOSDSYS. The first is actually still executing
|
||||
// BIOS code, and patches and cheats should not be applied yet. (they are applied when
|
||||
// eeGameStarting is invoked, which is when the VM starts executing the actual game ELF
|
||||
// binary).
|
||||
}
|
||||
|
||||
void cdvdReloadElfInfo(wxString elfoverride)
|
||||
{
|
||||
if (!elfoverride.IsEmpty())
|
||||
// called from context of executing VM code (recompilers), so we need to trap exceptions
|
||||
// and route them through the VM's exception handler. (needed for non-SEH platforms, such
|
||||
// as Linux/GCC)
|
||||
|
||||
try
|
||||
{
|
||||
_reloadElfInfo(elfoverride);
|
||||
return;
|
||||
if (!elfoverride.IsEmpty())
|
||||
{
|
||||
_reloadElfInfo(elfoverride);
|
||||
return;
|
||||
}
|
||||
|
||||
wxString elfpath;
|
||||
u32 discType = GetPS2ElfName(elfpath);
|
||||
|
||||
if(discType==1)
|
||||
{
|
||||
// Is a PS1 disc.
|
||||
if (!ENABLE_LOADING_PS1_GAMES)
|
||||
Cpu->ThrowException( Exception::RuntimeError()
|
||||
.SetDiagMsg(L"PSX game discs are not supported by PCSX2.")
|
||||
.SetUserMsg(pxE( "Error:PsxDisc",
|
||||
L"Playstation game discs are not supported by PCSX2. If you want to emulate PSX games "
|
||||
L"then you'll have to download a PSX-specific emulator, such as ePSXe or PCSX.")
|
||||
)
|
||||
);
|
||||
//Console.Error( "Playstation1 game discs are not supported by PCSX2." );
|
||||
}
|
||||
|
||||
// Isn't a disc we recognize?
|
||||
if(discType == 0) return;
|
||||
|
||||
// Recognized and PS2 (BOOT2). Good job, user.
|
||||
_reloadElfInfo(elfpath);
|
||||
}
|
||||
|
||||
wxString elfpath;
|
||||
u32 discType = GetPS2ElfName(elfpath);
|
||||
|
||||
switch (discType)
|
||||
{
|
||||
case 2: // Is a PS2 disc.
|
||||
_reloadElfInfo(elfpath);
|
||||
break;
|
||||
case 1: // Is a PS1 disc.
|
||||
if (ENABLE_LOADING_PS1_GAMES) _reloadElfInfo(elfpath);
|
||||
break;
|
||||
default: // Isn't a disc we recognise.
|
||||
break;
|
||||
catch (Exception::FileNotFound& e)
|
||||
{
|
||||
pxFail( "Not in my back yard!" );
|
||||
Cpu->ThrowException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -434,13 +434,13 @@ int GetPS2ElfName( wxString& name )
|
|||
|
||||
while( !file.eof() )
|
||||
{
|
||||
wxString original( fromUTF8(file.readLine().c_str()) );
|
||||
ParsedAssignmentString parts( original );
|
||||
const wxString original( fromUTF8(file.readLine().c_str()) );
|
||||
const ParsedAssignmentString parts( original );
|
||||
|
||||
if( parts.lvalue.IsEmpty() && parts.rvalue.IsEmpty() ) continue;
|
||||
if( parts.rvalue.IsEmpty() )
|
||||
{
|
||||
Console.Error( "(GetElfName) Unusual or malformed entry in SYSTEM.CNF ignored:" );
|
||||
Console.Warning( "(SYSTEM.CNF) Unusual or malformed entry in SYSTEM.CNF ignored:" );
|
||||
Console.Indent().WriteLn( original );
|
||||
continue;
|
||||
}
|
||||
|
@ -448,22 +448,22 @@ int GetPS2ElfName( wxString& name )
|
|||
if( parts.lvalue == L"BOOT2" )
|
||||
{
|
||||
name = parts.rvalue;
|
||||
Console.WriteLn( Color_StrongBlue, L"(GetElfName) Detected PS2 Disc = " + name );
|
||||
Console.WriteLn( Color_StrongBlue, L"(SYSTEM.CNF) Detected PS2 Disc = " + name );
|
||||
retype = 2;
|
||||
}
|
||||
else if( parts.lvalue == L"BOOT" )
|
||||
{
|
||||
name = parts.rvalue;
|
||||
Console.WriteLn( Color_StrongBlue, L"(GetElfName) Detected PSX/PSone Disc = " + name );
|
||||
Console.WriteLn( Color_StrongBlue, L"(SYSTEM.CNF) Detected PSX/PSone Disc = " + name );
|
||||
retype = 1;
|
||||
}
|
||||
else if( parts.lvalue == L"VMODE" )
|
||||
{
|
||||
Console.WriteLn( Color_StrongBlue, L"(GetElfName) Disc region type = " + parts.rvalue );
|
||||
Console.WriteLn( Color_Blue, L"(SYSTEM.CNF) Disc region type = " + parts.rvalue );
|
||||
}
|
||||
else if( parts.lvalue == L"VER" )
|
||||
{
|
||||
Console.WriteLn( Color_StrongBlue, L"(GetElfName) Software version = " + parts.rvalue );
|
||||
Console.WriteLn( Color_Blue, L"(SYSTEM.CNF) Software version = " + parts.rvalue );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -478,9 +478,9 @@ int GetPS2ElfName( wxString& name )
|
|||
Console.Error(ex.FormatDiagnosticMessage());
|
||||
return 0; // ISO error
|
||||
}
|
||||
catch( Exception::FileNotFound& ex )
|
||||
catch( Exception::FileNotFound& )
|
||||
{
|
||||
Console.Warning(ex.FormatDiagnosticMessage());
|
||||
//Console.Warning(ex.FormatDiagnosticMessage());
|
||||
return 0; // no SYSTEM.CNF, not a PS1/PS2 disc.
|
||||
}
|
||||
|
||||
|
|
|
@ -423,6 +423,12 @@ static void intThrowException( const BaseR5900Exception& ex )
|
|||
ex.Rethrow();
|
||||
}
|
||||
|
||||
static void intThrowException( const BaseException& ex )
|
||||
{
|
||||
// No tricks needed; C++ stack unwnding shoud suffice for MSW and GCC alike.
|
||||
ex.Rethrow();
|
||||
}
|
||||
|
||||
R5900cpu intCpu =
|
||||
{
|
||||
intAlloc,
|
||||
|
@ -434,5 +440,6 @@ R5900cpu intCpu =
|
|||
|
||||
intCheckExecutionState,
|
||||
intThrowException,
|
||||
intThrowException,
|
||||
intClear,
|
||||
};
|
||||
|
|
|
@ -581,10 +581,10 @@ void __fastcall eeGameStarting()
|
|||
{
|
||||
if (!g_GameStarted)
|
||||
{
|
||||
Console.WriteLn( Color_Green, "(R5900) ELF Entry point! [addr=0x%08X]", ElfEntry );
|
||||
//Console.WriteLn( Color_Green, "(R5900) ELF Entry point! [addr=0x%08X]", ElfEntry );
|
||||
g_GameStarted = true;
|
||||
GetCoreThread().GameStartingInThread();
|
||||
|
||||
|
||||
// GameStartingInThread may issue a reset of the cpu and/or recompilers. Check for and
|
||||
// handle such things here:
|
||||
Cpu->CheckExecutionState();
|
||||
|
@ -607,7 +607,7 @@ void __fastcall eeloadReplaceOSDSYS()
|
|||
else
|
||||
cdvdReloadElfInfo();
|
||||
|
||||
// didn't recognise an ELF
|
||||
// didn't recognize an ELF
|
||||
if (ElfEntry == -1) {
|
||||
eeGameStarting();
|
||||
return;
|
||||
|
|
|
@ -279,7 +279,7 @@ struct R5900cpu
|
|||
// Can be called from any thread. Execute status must be suspended or stopped
|
||||
// to prevent multi-thread race conditions.
|
||||
//
|
||||
// Notable Exception Throws:
|
||||
// Exception Throws:
|
||||
// OutOfMemory - Not enough memory, or the memory areas required were already
|
||||
// reserved.
|
||||
//
|
||||
|
@ -303,7 +303,7 @@ struct R5900cpu
|
|||
// Can be called from any thread. Execute status must be suspended or stopped
|
||||
// to prevent multi-thread race conditions.
|
||||
//
|
||||
// Exception Throws: Emulator-defined. Common exception types to look for:
|
||||
// Exception Throws: Emulator-defined. Common exception types to expect are
|
||||
// OutOfMemory, Stream Exceptions
|
||||
//
|
||||
void (*Reset)();
|
||||
|
@ -322,7 +322,9 @@ struct R5900cpu
|
|||
// call to return at the nearest state check (typically handled internally using
|
||||
// either C++ exceptions or setjmp/longjmp).
|
||||
//
|
||||
// Exception Throws: [TODO] (possible execution-related throws to be added)
|
||||
// Exception Throws:
|
||||
// Throws BaseR5900Exception and all derivatives.
|
||||
// Throws FileNotFound or other Streaming errors (typically related to BIOS MEC/NVM)
|
||||
//
|
||||
void (*Execute)();
|
||||
|
||||
|
@ -333,23 +335,28 @@ struct R5900cpu
|
|||
//
|
||||
// Implementation note: Because of the nuances of recompiled code execution, setjmp
|
||||
// may be used in place of thread cancellation or C++ exceptions (non-SEH exceptions
|
||||
// cannot unwind through the recompiled code stackframes).
|
||||
// cannot unwind through the recompiled code stackframes, thus longjmp must be used).
|
||||
//
|
||||
// Thread Affinity:
|
||||
// Must be called on the same thread as Execute only.
|
||||
// Must be called on the same thread as Execute.
|
||||
//
|
||||
// Exception Throws:
|
||||
// May throw threading/Pthreads cancellations if the compiler supports SEH.
|
||||
// ThreadTimedOut - For canceling VM execution in response to MTGS deadlock. (if the
|
||||
// core emulator does not support multithreaded GS then this will not be a throw
|
||||
// exception).
|
||||
// May throw Execution/Pthreads cancellations if the compiler supports SEH.
|
||||
//
|
||||
void (*CheckExecutionState)();
|
||||
|
||||
// Safely throws host exceptions from executing code (either recompiled or interpreted).
|
||||
// If this function is called outside the context of the CPU's code execution, then the
|
||||
// given exception will be re-thrown automatically.
|
||||
void (*ThrowException)( const BaseR5900Exception& ex );
|
||||
//
|
||||
// Exception Throws:
|
||||
// (SEH) Rethrows the given exception immediately.
|
||||
// (setjmp) Re-throws immediately if called from outside the context of dynamically
|
||||
// generated code (either non-executing contexts or interpreters). Does not throw
|
||||
// otherwise.
|
||||
//
|
||||
void (*ThrowException)( const BaseException& ex );
|
||||
void (*ThrowCpuException)( const BaseR5900Exception& ex );
|
||||
|
||||
// Manual recompiled code cache clear; typically useful to recompilers only. Size is
|
||||
// in MIPS words (32 bits). Dev note: this callback is nearly obsolete, and might be
|
||||
|
|
|
@ -260,6 +260,8 @@ void SysCoreThread::OnResumeInThread( bool isSuspended )
|
|||
// Invoked by the pthread_exit or pthread_cancel.
|
||||
void SysCoreThread::OnCleanupInThread()
|
||||
{
|
||||
m_ExecMode = ExecMode_Closing;
|
||||
|
||||
m_hasActiveMachine = false;
|
||||
m_resetVirtualMachine = true;
|
||||
|
||||
|
@ -269,5 +271,7 @@ void SysCoreThread::OnCleanupInThread()
|
|||
_mm_setcsr( m_mxcsr_saved.bitmask );
|
||||
Threading::DisableHiresScheduler();
|
||||
_parent::OnCleanupInThread();
|
||||
|
||||
m_ExecMode = ExecMode_NoThreadYet;
|
||||
}
|
||||
|
||||
|
|
|
@ -95,13 +95,16 @@ public:
|
|||
}
|
||||
|
||||
bool IsClosed() const { return !IsOpen(); }
|
||||
|
||||
bool IsPaused() const { return !IsRunning() || (m_ExecMode <= ExecMode_Paused); }
|
||||
|
||||
bool IsClosing() const
|
||||
{
|
||||
return !IsRunning() || (m_ExecMode <= ExecMode_Closed) || (m_ExecMode == ExecMode_Closing);
|
||||
}
|
||||
|
||||
bool HasPendingStateChangeRequest() const
|
||||
{
|
||||
ExecutionMode mode = m_ExecMode;
|
||||
return (mode == ExecMode_Closing) || (mode == ExecMode_Pausing);
|
||||
return m_ExecMode >= ExecMode_Closing;
|
||||
}
|
||||
|
||||
ExecutionMode GetExecutionMode() const { return m_ExecMode; }
|
||||
|
|
|
@ -384,6 +384,7 @@ void AppCoreThread::OnSuspendInThread()
|
|||
// the new (lack of) thread status, so this posts a message to the App to do so.
|
||||
void AppCoreThread::OnCleanupInThread()
|
||||
{
|
||||
m_ExecMode = ExecMode_Closing;
|
||||
PostCoreStatus( CoreThread_Stopped );
|
||||
_parent::OnCleanupInThread();
|
||||
}
|
||||
|
|
|
@ -541,7 +541,7 @@ void MainEmuFrame::ApplyCoreStatus()
|
|||
|
||||
if( susres )
|
||||
{
|
||||
if( CoreThread.IsOpen() )
|
||||
if( !CoreThread.IsClosing() )
|
||||
{
|
||||
susres->Enable();
|
||||
susres->SetText(_("Suspend"));
|
||||
|
|
|
@ -233,7 +233,7 @@ void __fastcall vtlb_memWrite128(u32 mem, const mem128_t *value)
|
|||
static __forceinline void vtlb_Miss(u32 addr,u32 mode)
|
||||
{
|
||||
if( IsDevBuild )
|
||||
Cpu->ThrowException( R5900Exception::TLBMiss( addr, !!mode ) );
|
||||
Cpu->ThrowCpuException( R5900Exception::TLBMiss( addr, !!mode ) );
|
||||
else
|
||||
Console.Error( R5900Exception::TLBMiss( addr, !!mode ).FormatMessage() );
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ static __forceinline void vtlb_BusError(u32 addr,u32 mode)
|
|||
// the PC prior to invoking the indirect handlers.
|
||||
|
||||
if( IsDevBuild )
|
||||
Cpu->ThrowException( R5900Exception::BusError( addr, !!mode ) );
|
||||
Cpu->ThrowCpuException( R5900Exception::BusError( addr, !!mode ) );
|
||||
else
|
||||
Console.Error( R5900Exception::TLBMiss( addr, !!mode ).FormatMessage() );
|
||||
}
|
||||
|
|
|
@ -63,8 +63,6 @@ bool g_cpuFlushedPC, g_cpuFlushedCode, g_recompilingDelaySlot, g_maySignalExcept
|
|||
#define X86
|
||||
static const int RECCONSTBUF_SIZE = 16384 * 2; // 64 bit consts in 32 bit units
|
||||
|
||||
static ScopedPtr<BaseR5900Exception> m_vmException;
|
||||
|
||||
static u8 *recMem = NULL; // the recompiled blocks will be here
|
||||
static u32* recConstBuf = NULL; // 64-bit pseudo-immediates
|
||||
static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here
|
||||
|
@ -714,7 +712,15 @@ void recStep( void )
|
|||
{
|
||||
}
|
||||
|
||||
static jmp_buf m_SetJmp_StateCheck;
|
||||
#if !PCSX2_SEH
|
||||
# define SETJMP_CODE(x) x
|
||||
static jmp_buf m_SetJmp_StateCheck;
|
||||
static ScopedPtr<BaseR5900Exception> m_cpuException;
|
||||
static ScopedPtr<BaseException> m_Exception;
|
||||
#else
|
||||
# define SETJMP_CODE(x)
|
||||
#endif
|
||||
|
||||
|
||||
static void recExitExecution()
|
||||
{
|
||||
|
@ -732,7 +738,7 @@ static void recExitExecution()
|
|||
|
||||
static void recCheckExecutionState()
|
||||
{
|
||||
if( eeRecIsReset || m_vmException || GetCoreThread().HasPendingStateChangeRequest() )
|
||||
if( SETJMP_CODE(m_cpuException || m_Exception ||) eeRecIsReset || GetCoreThread().HasPendingStateChangeRequest() )
|
||||
{
|
||||
recExitExecution();
|
||||
}
|
||||
|
@ -747,7 +753,6 @@ static void recExecute()
|
|||
|
||||
#if PCSX2_SEH
|
||||
eeRecIsReset = false;
|
||||
m_vmException = NULL;
|
||||
ScopedBool executing(m_recExecutingCode);
|
||||
|
||||
try {
|
||||
|
@ -758,6 +763,8 @@ static void recExecute()
|
|||
#else
|
||||
|
||||
int oldstate;
|
||||
m_cpuException = NULL;
|
||||
m_Exception = NULL;
|
||||
|
||||
if( !setjmp( m_SetJmp_StateCheck ) )
|
||||
{
|
||||
|
@ -777,9 +784,10 @@ static void recExecute()
|
|||
{
|
||||
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
|
||||
}
|
||||
#endif
|
||||
|
||||
if(m_vmException) m_vmException->Rethrow();
|
||||
if(m_cpuException) m_cpuException->Rethrow();
|
||||
if(m_Exception) m_Exception->Rethrow();
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
@ -1838,12 +1846,25 @@ StartRecomp:
|
|||
// SEH unwind (MSW) or setjmp/longjmp (GCC).
|
||||
static void recThrowException( const BaseR5900Exception& ex )
|
||||
{
|
||||
#if PCSX2_SEH
|
||||
ex.Rethrow();
|
||||
#else
|
||||
if (!m_recExecutingCode) ex.Rethrow();
|
||||
|
||||
m_vmException = ex.Clone();
|
||||
m_cpuException = ex.Clone();
|
||||
recExitExecution();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void recThrowException( const BaseException& ex )
|
||||
{
|
||||
#if PCSX2_SEH
|
||||
ex.Rethrow();
|
||||
#else
|
||||
if (!m_recExecutingCode) ex.Rethrow();
|
||||
m_Exception = ex.Clone();
|
||||
recExitExecution();
|
||||
#endif
|
||||
}
|
||||
|
||||
R5900cpu recCpu =
|
||||
{
|
||||
|
@ -1856,5 +1877,6 @@ R5900cpu recCpu =
|
|||
|
||||
recCheckExecutionState,
|
||||
recThrowException,
|
||||
recThrowException,
|
||||
recClear,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue