From be191c0473259da20cfbf514abb1a56b82c8f64e Mon Sep 17 00:00:00 2001 From: JosJuice Date: Wed, 30 Mar 2016 21:45:56 +0200 Subject: [PATCH] DVDInterface/DVDThread: Don't store CoreTiming event IDs in savestates CoreTiming event types aren't guaranteed to be stable across runs of Dolphin, so they shouldn't be in savestates. --- Source/Core/Core/HW/DVDInterface.cpp | 97 +++++++++++-------- Source/Core/Core/HW/DVDInterface.h | 5 +- Source/Core/Core/HW/DVDThread.cpp | 18 ++-- Source/Core/Core/HW/DVDThread.h | 2 +- .../Core/IPC_HLE/WII_IPC_HLE_Device_DI.cpp | 15 +-- Source/Core/Core/State.cpp | 2 +- 6 files changed, 74 insertions(+), 65 deletions(-) diff --git a/Source/Core/Core/HW/DVDInterface.cpp b/Source/Core/Core/HW/DVDInterface.cpp index 5d41e33d15..2276150d27 100644 --- a/Source/Core/Core/HW/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVDInterface.cpp @@ -25,6 +25,8 @@ #include "Core/HW/ProcessorInterface.h" #include "Core/HW/StreamADPCM.h" #include "Core/HW/SystemTimers.h" +#include "Core/IPC_HLE/WII_IPC_HLE.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_DI.h" #include "DiscIO/Volume.h" #include "DiscIO/VolumeCreator.h" @@ -244,7 +246,7 @@ static u32 s_error_code = 0; static bool s_disc_inside = false; static bool s_stream = false; static bool s_stop_at_track_end = false; -static int s_finish_execute_command = 0; +static int s_finish_executing_command = 0; static int s_dtk = 0; static u64 s_last_read_offset; @@ -258,15 +260,16 @@ static int s_insert_disc; static void EjectDiscCallback(u64 userdata, s64 cyclesLate); static void InsertDiscCallback(u64 userdata, s64 cyclesLate); +static void FinishExecutingCommandCallback(u64 userdata, s64 cycles_late); void SetLidOpen(bool _bOpen); void UpdateInterrupts(); void GenerateDIInterrupt(DIInterruptType _DVDInterrupt); -void WriteImmediate(u32 value, u32 output_address, bool write_to_DIIMMBUF); +void WriteImmediate(u32 value, u32 output_address, bool reply_to_ios); bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length, bool decrypt, - int callback_event_type, DIInterruptType* interrupt_type, u64* ticks_until_completion); + bool reply_to_ios, DIInterruptType* interrupt_type, u64* ticks_until_completion); u64 SimulateDiscReadTime(u64 offset, u32 length); s64 CalculateRawDiscReadTime(u64 offset, s64 length); @@ -301,16 +304,6 @@ void DoState(PointerWrap &p) DVDThread::DoState(p); } -static void FinishExecuteCommand(u64 userdata, s64 cyclesLate) -{ - if (s_DICR.TSTART) - { - s_DICR.TSTART = 0; - s_DILENGTH.Length = 0; - GenerateDIInterrupt((DIInterruptType)userdata); - } -} - static u32 ProcessDTKSamples(short *tempPCM, u32 num_samples) { // TODO: Read audio data using the DVD thread instead of blocking on it? @@ -408,7 +401,7 @@ void Init() s_eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback); s_insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback); - s_finish_execute_command = CoreTiming::RegisterEvent("FinishExecuteCommand", FinishExecuteCommand); + s_finish_executing_command = CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback); s_dtk = CoreTiming::RegisterEvent("StreamingTimer", DTKStreamingCallback); CoreTiming::ScheduleEvent(0, s_dtk); @@ -589,7 +582,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) if (s_DICR.TSTART) { ExecuteCommand(s_DICMDBUF[0].Hex, s_DICMDBUF[1].Hex, s_DICMDBUF[2].Hex, - s_DIMAR.Hex, s_DILENGTH.Hex, true, s_finish_execute_command); + s_DIMAR.Hex, s_DILENGTH.Hex, false); } }) ); @@ -637,17 +630,17 @@ void GenerateDIInterrupt(DIInterruptType dvd_interrupt) UpdateInterrupts(); } -void WriteImmediate(u32 value, u32 output_address, bool write_to_DIIMMBUF) +void WriteImmediate(u32 value, u32 output_address, bool reply_to_ios) { - if (write_to_DIIMMBUF) - s_DIIMMBUF.Hex = value; - else + if (reply_to_ios) Memory::Write_U32(value, output_address); + else + s_DIIMMBUF.Hex = value; } // Iff false is returned, ScheduleEvent must be used to finish executing the command bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length, bool decrypt, - int callback_event_type, DIInterruptType* interrupt_type, u64* ticks_until_completion) + bool reply_to_ios, DIInterruptType* interrupt_type, u64* ticks_until_completion) { if (!s_disc_inside) { @@ -675,15 +668,15 @@ bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 *ticks_until_completion = SimulateDiscReadTime(DVD_offset, DVD_length); DVDThread::StartRead(DVD_offset, output_address, DVD_length, decrypt, - callback_event_type, (int)*ticks_until_completion); + reply_to_ios, (int)*ticks_until_completion); return true; } // When the command has finished executing, callback_event_type // will be called using CoreTiming::ScheduleEvent, // with the userdata set to the interrupt type. -void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_address, u32 output_length, - bool write_to_DIIMMBUF, int callback_event_type) +void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_address, + u32 output_length, bool reply_to_ios) { DIInterruptType interrupt_type = INT_TCINT; u64 ticks_until_completion = SystemTimers::GetTicksPerSecond() / 15000; @@ -713,7 +706,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr { // 0x29484100... // was 21 i'm not entirely sure about this, but it works well. - WriteImmediate(0x21000000, output_address, write_to_DIIMMBUF); + WriteImmediate(0x21000000, output_address, reply_to_ios); } else { @@ -733,14 +726,14 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr case DVDLowReadDiskID: INFO_LOG(DVDINTERFACE, "DVDLowReadDiskID"); command_handled_by_thread = ExecuteReadCommand(0, output_address, 0x20, output_length, false, - callback_event_type, &interrupt_type, &ticks_until_completion); + reply_to_ios, &interrupt_type, &ticks_until_completion); break; // Only used from WII_IPC. This is the only read command that decrypts data case DVDLowRead: INFO_LOG(DVDINTERFACE, "DVDLowRead: DVDAddr: 0x%09" PRIx64 ", Size: 0x%x", (u64)command_2 << 2, command_1); command_handled_by_thread = ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, true, - callback_event_type, &interrupt_type, &ticks_until_completion); + reply_to_ios, &interrupt_type, &ticks_until_completion); break; // Probably only used by Wii @@ -756,7 +749,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr // Probably only used though WII_IPC case DVDLowGetCoverReg: - WriteImmediate(s_DICVR.Hex, output_address, write_to_DIIMMBUF); + WriteImmediate(s_DICVR.Hex, output_address, reply_to_ios); INFO_LOG(DVDINTERFACE, "DVDLowGetCoverReg 0x%08x", s_DICVR.Hex); break; @@ -789,7 +782,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr // Probably only used by Wii case DVDLowGetCoverStatus: - WriteImmediate(s_disc_inside ? 2 : 1, output_address, write_to_DIIMMBUF); + WriteImmediate(s_disc_inside ? 2 : 1, output_address, reply_to_ios); INFO_LOG(DVDINTERFACE, "DVDLowGetCoverStatus: Disc %sInserted", s_disc_inside ? "" : "Not "); break; @@ -820,7 +813,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr (((command_2 + command_1) > 0x7ed40000) && (command_2 + command_1) < 0x7ed40008))) { command_handled_by_thread = ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, false, - callback_event_type, &interrupt_type, &ticks_until_completion); + reply_to_ios, &interrupt_type, &ticks_until_completion); } else { @@ -917,14 +910,14 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr } command_handled_by_thread = ExecuteReadCommand(iDVDOffset, output_address, command_2, output_length, false, - callback_event_type, &interrupt_type, &ticks_until_completion); + reply_to_ios, &interrupt_type, &ticks_until_completion); } break; case 0x40: // Read DiscID INFO_LOG(DVDINTERFACE, "Read DiscID %08x", Memory::Read_U32(output_address)); command_handled_by_thread = ExecuteReadCommand(0, output_address, 0x20, output_length, false, - callback_event_type, &interrupt_type, &ticks_until_completion); + reply_to_ios, &interrupt_type, &ticks_until_completion); break; default: @@ -1060,7 +1053,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr break; } memset(s_media_buffer + 0x20, 0, 0x20); - WriteImmediate(0x66556677, output_address, write_to_DIIMMBUF); // just a random value that works. + WriteImmediate(0x66556677, output_address, reply_to_ios); // just a random value that works. } break; @@ -1105,7 +1098,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr // Used by both GC and Wii case DVDLowRequestError: INFO_LOG(DVDINTERFACE, "Requesting error... (0x%08x)", s_error_code); - WriteImmediate(s_error_code, output_address, write_to_DIIMMBUF); + WriteImmediate(s_error_code, output_address, reply_to_ios); s_error_code = 0; break; @@ -1162,19 +1155,19 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr case 0x00: // Returns streaming status INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:%08x/%08x CurrentStart:%08x CurrentLength:%08x", s_audio_position, s_current_start + s_current_length, s_current_start, s_current_length); - WriteImmediate(s_stream ? 1 : 0, output_address, write_to_DIIMMBUF); + WriteImmediate(s_stream ? 1 : 0, output_address, reply_to_ios); break; case 0x01: // Returns the current offset INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:%08x", s_audio_position); - WriteImmediate(s_audio_position >> 2, output_address, write_to_DIIMMBUF); + WriteImmediate(s_audio_position >> 2, output_address, reply_to_ios); break; case 0x02: // Returns the start offset INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentStart:%08x", s_current_start); - WriteImmediate(s_current_start >> 2, output_address, write_to_DIIMMBUF); + WriteImmediate(s_current_start >> 2, output_address, reply_to_ios); break; case 0x03: // Returns the total length INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentLength:%08x", s_current_length); - WriteImmediate(s_current_length >> 2, output_address, write_to_DIIMMBUF); + WriteImmediate(s_current_length >> 2, output_address, reply_to_ios); break; default: WARN_LOG(DVDINTERFACE, "(Audio): Subcommand: %02x Request Audio status %s", command_0 >> 16 & 0xFF, s_stream ? "on" : "off"); @@ -1263,7 +1256,35 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr // The command will finish executing after a delay // to simulate the speed of a real disc drive if (!command_handled_by_thread) - CoreTiming::ScheduleEvent((int)ticks_until_completion, callback_event_type, interrupt_type); + { + u64 userdata = (static_cast(reply_to_ios) << 32) + static_cast(interrupt_type); + CoreTiming::ScheduleEvent((int)ticks_until_completion, s_finish_executing_command, userdata); + } +} + +void FinishExecutingCommandCallback(u64 userdata, s64 cycles_late) +{ + bool reply_to_ios = userdata >> 32 != 0; + DIInterruptType interrupt_type = static_cast(userdata & 0xFFFFFFFF); + FinishExecutingCommand(reply_to_ios, interrupt_type); +} + +void FinishExecutingCommand(bool reply_to_ios, DIInterruptType interrupt_type) +{ + if (reply_to_ios) + { + std::shared_ptr di = WII_IPC_HLE_Interface::GetDeviceByName("/dev/di"); + if (di) + std::static_pointer_cast(di)->FinishIOCtl(interrupt_type); + + // If di == nullptr, IOS was probably shut down, so the command shouldn't be completed + } + else if (s_DICR.TSTART) + { + s_DICR.TSTART = 0; + s_DILENGTH.Length = 0; + GenerateDIInterrupt(interrupt_type); + } } // Simulates the timing aspects of reading data from a disc. diff --git a/Source/Core/Core/HW/DVDInterface.h b/Source/Core/Core/HW/DVDInterface.h index 5c711cdeba..8c26b3b7c8 100644 --- a/Source/Core/Core/HW/DVDInterface.h +++ b/Source/Core/Core/HW/DVDInterface.h @@ -106,7 +106,8 @@ void ChangeDisc(const std::string& fileName); // DVD Access Functions bool ChangePartition(u64 offset); -void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_address, u32 output_length, - bool write_to_DIIMMBUF, int callback_event_type); +void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_address, + u32 output_length, bool reply_to_ios); +void FinishExecutingCommand(bool reply_to_ios, DIInterruptType interrupt_type); } // end of namespace DVDInterface diff --git a/Source/Core/Core/HW/DVDThread.cpp b/Source/Core/Core/HW/DVDThread.cpp index dc3ceeaf02..1ef6642842 100644 --- a/Source/Core/Core/HW/DVDThread.cpp +++ b/Source/Core/Core/HW/DVDThread.cpp @@ -30,7 +30,7 @@ namespace DVDThread static void DVDThread(); -static void FinishRead(u64 userdata, s64 cyclesLate); +static void FinishRead(u64 userdata, s64 cycles_late); static int s_finish_read; static std::thread s_dvd_thread; @@ -47,9 +47,9 @@ static u32 s_output_address; static u32 s_length; static bool s_decrypt; -// Used to notify emulated software after executing command. -// Pointers don't work with savestates, so CoreTiming events are used instead -static int s_callback_event_type; +// This determines which function will be used as a callback. +// We can't have a function pointer here, because they can't be in savestates. +static bool s_reply_to_ios; // The following time variables are only used for logging static u64 s_realtime_started_us; @@ -89,7 +89,7 @@ void DoState(PointerWrap &p) p.Do(s_output_address); p.Do(s_length); p.Do(s_decrypt); - p.Do(s_callback_event_type); + p.Do(s_reply_to_ios); // s_realtime_started_us and s_realtime_done_us aren't savestated // because they rely on the current system's time. @@ -109,7 +109,7 @@ void WaitUntilIdle() } void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt, - int callback_event_type, int ticks_until_completion) + bool reply_to_ios, int ticks_until_completion) { _assert_(Core::IsCPUThread()); @@ -119,7 +119,7 @@ void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt, s_output_address = output_address; s_length = length; s_decrypt = decrypt; - s_callback_event_type = callback_event_type; + s_reply_to_ios = reply_to_ios; s_time_read_started = CoreTiming::GetTicks(); s_realtime_started_us = Common::Timer::GetTimeUs(); @@ -129,7 +129,7 @@ void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt, CoreTiming::ScheduleEvent(ticks_until_completion, s_finish_read); } -static void FinishRead(u64 userdata, s64 cyclesLate) +static void FinishRead(u64 userdata, s64 cycles_late) { WaitUntilIdle(); @@ -151,7 +151,7 @@ static void FinishRead(u64 userdata, s64 cyclesLate) s_dvd_buffer.resize(0); // Notify the emulated software that the command has been executed - CoreTiming::ScheduleEvent_Immediate(s_callback_event_type, DVDInterface::INT_TCINT); + DVDInterface::FinishExecutingCommand(s_reply_to_ios, DVDInterface::INT_TCINT); } static void DVDThread() diff --git a/Source/Core/Core/HW/DVDThread.h b/Source/Core/Core/HW/DVDThread.h index c2716ae7c8..795c7ad617 100644 --- a/Source/Core/Core/HW/DVDThread.h +++ b/Source/Core/Core/HW/DVDThread.h @@ -16,6 +16,6 @@ void DoState(PointerWrap &p); void WaitUntilIdle(); void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt, - int callback_event_type, int ticks_until_completion); + bool reply_to_ios, int ticks_until_completion); } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_DI.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_DI.cpp index f039164c31..36c1d046c3 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_DI.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_DI.cpp @@ -16,21 +16,9 @@ #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_DI.h" -static int ioctl_callback; - -static void IOCtlCallback(u64 userdata, s64 cycles_late) -{ - std::shared_ptr di = WII_IPC_HLE_Interface::GetDeviceByName("/dev/di"); - if (di) - std::static_pointer_cast(di)->FinishIOCtl((DVDInterface::DIInterruptType)userdata); - - // If di == nullptr, IOS was probably shut down, so the command shouldn't be completed -} - CWII_IPC_HLE_Device_di::CWII_IPC_HLE_Device_di(u32 _DeviceID, const std::string& _rDeviceName) : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) { - ioctl_callback = CoreTiming::RegisterEvent("IOCtlCallbackDI", IOCtlCallback); } CWII_IPC_HLE_Device_di::~CWII_IPC_HLE_Device_di() @@ -101,8 +89,7 @@ void CWII_IPC_HLE_Device_di::StartIOCtl(u32 command_address) // DVDInterface's ExecuteCommand handles most of the work. // The IOCtl callback is used to generate a reply afterwards. - DVDInterface::ExecuteCommand(command_0, command_1, command_2, BufferOut, BufferOutSize, - false, ioctl_callback); + DVDInterface::ExecuteCommand(command_0, command_1, command_2, BufferOut, BufferOutSize, true); } void CWII_IPC_HLE_Device_di::FinishIOCtl(DVDInterface::DIInterruptType interrupt_type) diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index a1aa0bc562..f9542d3ce4 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 52; // Last changed in PR 3667 +static const u32 STATE_VERSION = 53; // Last changed in PR 3759 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list,