From ab38be1ee23fe47c7ba7867e281288531ce04b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 28 Jan 2017 19:04:33 +0100 Subject: [PATCH 1/7] IOS: Clarify Init, Reinit, Reset, Shutdown Some minor changes to make things slightly less confusing: * Reinit doesn't actually init anything. It just adds static devices to the map, so let's give it an actually descriptive name. And let's not expose it in the header when it should not be. * Reset's parameter name was changed from "force" -- which totally does not describe what it does -- to "clear_devices". * Add a reload function which handles the reload process properly (reset all devices, set up memory values, re-add devices) and without publicly exposing implementation details. --- Source/Core/Core/Boot/Boot_BS2Emu.cpp | 2 +- Source/Core/Core/IOS/ES/ES.cpp | 4 +--- Source/Core/Core/IOS/IPC.cpp | 26 ++++++++++++++++++-------- Source/Core/Core/IOS/IPC.h | 17 ++++++----------- Source/Core/Core/State.cpp | 2 +- 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index e3ba2536da..61dd1dbb8c 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -275,7 +275,7 @@ bool CBoot::SetupWiiMemory(u64 ios_title_id) Memory::Write_U16(0x8201, 0x000030e6); // Dev console / debug capable Memory::Write_U32(0x00000000, 0x000030f0); // Apploader - if (!IOS::HLE::SetupMemory(ios_title_id)) + if (!IOS::HLE::Reload(ios_title_id)) { return false; } diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index abe00c215a..f956d0824a 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -1176,9 +1176,7 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request) wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected(); } - Reset(true); - Reinit(); - SetupMemory(ios_to_load); + Reload(ios_to_load); bReset = true; if (!SConfig::GetInstance().m_bt_passthrough_enabled) diff --git a/Source/Core/Core/IOS/IPC.cpp b/Source/Core/Core/IOS/IPC.cpp index 1580791a80..cb0876527e 100644 --- a/Source/Core/Core/IOS/IPC.cpp +++ b/Source/Core/Core/IOS/IPC.cpp @@ -421,7 +421,7 @@ u32 GetVersion() return static_cast(s_active_title_id); } -bool SetupMemory(u64 ios_title_id) +static bool SetupMemory(u64 ios_title_id) { auto target_imv = std::find_if( ios_memory_values.begin(), ios_memory_values.end(), @@ -433,8 +433,6 @@ bool SetupMemory(u64 ios_title_id) return false; } - s_active_title_id = ios_title_id; - Memory::Write_U32(target_imv->mem1_physical_size, ADDR_MEM1_SIZE); Memory::Write_U32(target_imv->mem1_simulated_size, ADDR_MEM1_SIM_SIZE); Memory::Write_U32(target_imv->mem1_end, ADDR_MEM1_END); @@ -477,7 +475,7 @@ std::shared_ptr AddDevice(const char* device_name) return device; } -void Reinit() +static void AddStaticDevices() { std::lock_guard lock(s_device_map_mutex); _assert_msg_(IOS, s_device_map.empty(), "Reinit called while already initialized"); @@ -519,13 +517,12 @@ void Reinit() void Init() { - Reinit(); - + AddStaticDevices(); s_event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent); s_event_sdio_notify = CoreTiming::RegisterEvent("SDIO_EventNotify", SDIO_EventNotify_CPUThread); } -void Reset(bool hard) +void Reset(const bool clear_devices) { CoreTiming::RemoveAllEvents(s_event_enqueue); @@ -538,7 +535,7 @@ void Reset(bool hard) device.reset(); } - if (hard) + if (clear_devices) { std::lock_guard lock(s_device_map_mutex); s_device_map.clear(); @@ -555,6 +552,18 @@ void Shutdown() Reset(true); } +bool Reload(const u64 ios_title_id) +{ + if (!SetupMemory(ios_title_id)) + return false; + + s_active_title_id = ios_title_id; + Reset(true); + + AddStaticDevices(); + return true; +} + void SetDefaultContentFile(const std::string& file_name) { std::lock_guard lock(s_device_map_mutex); @@ -618,6 +627,7 @@ void DoState(PointerWrap& p) p.Do(s_request_queue); p.Do(s_reply_queue); p.Do(s_last_reply_time); + p.Do(s_active_title_id); // We need to make sure all file handles are closed so IOS::HLE::Device::FS::DoState can // successfully save or re-create /tmp diff --git a/Source/Core/Core/IOS/IPC.h b/Source/Core/Core/IOS/IPC.h index 7508be12f9..09b3c1179c 100644 --- a/Source/Core/Core/IOS/IPC.h +++ b/Source/Core/Core/IOS/IPC.h @@ -45,21 +45,16 @@ enum IPCCommandType : u32 IPC_REPLY = 8, }; -// Init +// Init events and devices void Init(); - -// Needs to be called after Reset(true) to recreate the device tree -void Reinit(); - -u32 GetVersion(); - -bool SetupMemory(u64 ios_title_id); - +// Reset all events and devices (and optionally clear them) +void Reset(bool clear_devices = false); // Shutdown void Shutdown(); -// Reset -void Reset(bool hard = false); +// Reload IOS (to a possibly different version); set up memory and devices. +bool Reload(u64 ios_title_id); +u32 GetVersion(); // Do State void DoState(PointerWrap& p); diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 7714659954..0073b9ea4b 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 = 76; // Last changed in PR 4829 +static const u32 STATE_VERSION = 77; // Last changed in PR 4784 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list, From 9e6f5b203ed6ce999f23d96978bbbc3a72ffeb57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 28 Jan 2017 22:13:01 +0100 Subject: [PATCH 2/7] IOS/ES: Implement ioctlv 0x25 (ES_LaunchBC) This ioctlv is used to launch BC. Not sure if that's useful, since only the system menu is known to launch BC and it does that through a regular ES_LAUNCH; but let's implement it anyway. (Implementation based on IOS59.) --- Source/Core/Core/IOS/ES/ES.cpp | 76 ++++++++++++++++++++++------------ Source/Core/Core/IOS/ES/ES.h | 5 ++- 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index f956d0824a..2a7eb870b9 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -317,6 +317,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request) return Decrypt(request); case IOCTL_ES_LAUNCH: return Launch(request); + case IOCTL_ES_LAUNCHBC: + return LaunchBC(request); case IOCTL_ES_CHECKKOREAREGION: return CheckKoreaRegion(request); case IOCTL_ES_GETDEVICECERT: @@ -1168,34 +1170,8 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request) } else { - bool* wiiMoteConnected = new bool[MAX_BBMOTES]; - if (!SConfig::GetInstance().m_bt_passthrough_enabled) - { - BluetoothEmu* s_Usb = GetUsbPointer(); - for (unsigned int i = 0; i < MAX_BBMOTES; i++) - wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected(); - } - - Reload(ios_to_load); + ResetAfterLaunch(ios_to_load); bReset = true; - - if (!SConfig::GetInstance().m_bt_passthrough_enabled) - { - BluetoothEmu* s_Usb = GetUsbPointer(); - for (unsigned int i = 0; i < MAX_BBMOTES; i++) - { - if (wiiMoteConnected[i]) - { - s_Usb->m_WiiMotes[i].Activate(false); - s_Usb->m_WiiMotes[i].Activate(true); - } - else - { - s_Usb->m_WiiMotes[i].Activate(false); - } - } - } - delete[] wiiMoteConnected; SetDefaultContentFile(tContentFile); } @@ -1223,6 +1199,52 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request) return GetNoReply(); } +IPCCommandResult ES::LaunchBC(const IOCtlVRequest& request) +{ + if (request.in_vectors.size() != 0 || request.io_vectors.size() != 0) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + // Here, IOS checks the clock speed and prevents ioctlv 0x25 from being used in GC mode. + // An alternative way to do this is to check whether the current active IOS is MIOS. + if (GetVersion() == 0x101) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + ResetAfterLaunch(0x00000001'00000100); + EnqueueCommandAcknowledgement(request.address, 0); + return GetNoReply(); +} + +void ES::ResetAfterLaunch(const u64 ios_to_load) const +{ + bool* wiiMoteConnected = new bool[MAX_BBMOTES]; + if (!SConfig::GetInstance().m_bt_passthrough_enabled) + { + BluetoothEmu* s_Usb = GetUsbPointer(); + for (unsigned int i = 0; i < MAX_BBMOTES; i++) + wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected(); + } + + Reload(ios_to_load); + + if (!SConfig::GetInstance().m_bt_passthrough_enabled) + { + BluetoothEmu* s_Usb = GetUsbPointer(); + for (unsigned int i = 0; i < MAX_BBMOTES; i++) + { + if (wiiMoteConnected[i]) + { + s_Usb->m_WiiMotes[i].Activate(false); + s_Usb->m_WiiMotes[i].Activate(true); + } + else + { + s_Usb->m_WiiMotes[i].Activate(false); + } + } + } + delete[] wiiMoteConnected; +} + IPCCommandResult ES::CheckKoreaRegion(const IOCtlVRequest& request) { // note by DacoTaco : name is unknown, I just tried to name it SOMETHING. diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index 83acd77865..2fbce4d7f1 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -90,7 +90,7 @@ private: IOCTL_ES_DELETETITLECONTENT = 0x22, IOCTL_ES_SEEKCONTENT = 0x23, IOCTL_ES_OPENTITLECONTENT = 0x24, - // IOCTL_ES_LAUNCHBC = 0x25, + IOCTL_ES_LAUNCHBC = 0x25, // IOCTL_ES_EXPORTTITLEINIT = 0x26, // IOCTL_ES_EXPORTCONTENTBEGIN = 0x27, // IOCTL_ES_EXPORTCONTENTDATA = 0x28, @@ -182,6 +182,7 @@ private: IPCCommandResult Encrypt(const IOCtlVRequest& request); IPCCommandResult Decrypt(const IOCtlVRequest& request); IPCCommandResult Launch(const IOCtlVRequest& request); + IPCCommandResult LaunchBC(const IOCtlVRequest& request); IPCCommandResult CheckKoreaRegion(const IOCtlVRequest& request); IPCCommandResult GetDeviceCertificate(const IOCtlVRequest& request); IPCCommandResult Sign(const IOCtlVRequest& request); @@ -189,6 +190,8 @@ private: IPCCommandResult DIGetTicketView(const IOCtlVRequest& request); IPCCommandResult GetOwnedTitleCount(const IOCtlVRequest& request); + void ResetAfterLaunch(u64 ios_to_load) const; + const DiscIO::CNANDContentLoader& AccessContentDevice(u64 title_id); u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index); From 5fd5eeb82a478883e007518ce6ae0bcd5816626b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 28 Jan 2017 22:14:52 +0100 Subject: [PATCH 3/7] IOS/ES: Don't write anything to the request after ES_Launch Unless IOS failed at ES_Launch, it doesn't appear to write anything back to the request after a launch, because the request is never actually replied to in the normal way. So let's just drop the writes to make things less confusing. --- Source/Core/Core/IOS/ES/ES.cpp | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 2a7eb870b9..d99b05a055 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -1105,7 +1105,6 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request) { _dbg_assert_(IOS_ES, request.in_vectors.size() == 2); bool bSuccess = false; - bool bReset = false; u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); u32 view = Memory::Read_U32(request.in_vectors[1].address); @@ -1171,30 +1170,16 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request) else { ResetAfterLaunch(ios_to_load); - bReset = true; SetDefaultContentFile(tContentFile); } - // Note: If we just reset the PPC, don't write anything to the command buffer. This - // could clobber the DOL we just loaded. - ERROR_LOG(IOS_ES, "IOCTL_ES_LAUNCH %016" PRIx64 " %08x %016" PRIx64 " %08x %016" PRIx64 " %04x", TitleID, view, ticketid, devicetype, titleid, access); - // IOCTL_ES_LAUNCH 0001000248414341 00000001 0001c0fef3df2cfa 00000000 - // 0001000248414341 ffff - - // This is necessary because Reset(true) above deleted this object. Ew. - - if (!bReset) - { - // The command type is overwritten with the reply type. - Memory::Write_U32(IPC_REPLY, request.address); - // IOS also writes back the command that was responded to in the FD field. - Memory::Write_U32(IPC_CMD_IOCTLV, request.address + 8); - } // Generate a "reply" to the IPC command. ES_LAUNCH is unique because it // involves restarting IOS; IOS generates two acknowledgements in a row. + // Note: If we just reset the PPC, don't write anything to the command buffer. This + // could clobber the DOL we just loaded. EnqueueCommandAcknowledgement(request.address, 0); return GetNoReply(); } From fd49a1b2d5902e01176cf9066fe810ce62a750e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 28 Jan 2017 22:57:43 +0100 Subject: [PATCH 4/7] Get rid of GetUsbPointer for emulated Bluetooth It held a raw pointer to a IOS::HLE::Device::BluetoothEmu that is not guaranteed to exist (and of course, nothing checked that it wasn't nullptr), but what is more, it's totally unnecessary because we have IOS::HLE::GetDeviceByName(). Since we cannot always inform the host that Wii remotes are disconnected from ES, that is now done in BluetoothEmu's destructor. --- Source/Core/Core/Core.cpp | 6 ++- Source/Core/Core/IOS/ES/ES.cpp | 17 +++++---- Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp | 3 +- .../Core/IOS/USB/Bluetooth/WiimoteDevice.cpp | 17 ++------- .../Core/IOS/USB/Bluetooth/WiimoteDevice.h | 3 -- Source/Core/Core/Movie.cpp | 6 ++- Source/Core/DolphinWX/FrameTools.cpp | 37 +++++++++---------- Source/Core/DolphinWX/MainNoGUI.cpp | 5 ++- 8 files changed, 43 insertions(+), 51 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index e123989f7b..711e74a12f 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -528,9 +528,11 @@ void EmuThread() Wiimote::LoadConfig(); // Activate Wiimotes which don't have source set to "None" + const auto bt = std::static_pointer_cast( + IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305")); for (unsigned int i = 0; i != MAX_BBMOTES; ++i) - if (g_wiimote_sources[i]) - IOS::HLE::GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(true); + if (g_wiimote_sources[i] && bt) + bt->AccessWiiMote(i | 0x100)->Activate(true); } AudioCommon::InitSoundStream(); diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index d99b05a055..419f5844b9 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -1201,29 +1201,30 @@ IPCCommandResult ES::LaunchBC(const IOCtlVRequest& request) void ES::ResetAfterLaunch(const u64 ios_to_load) const { + auto bt = std::static_pointer_cast(GetDeviceByName("/dev/usb/oh1/57e/305")); bool* wiiMoteConnected = new bool[MAX_BBMOTES]; - if (!SConfig::GetInstance().m_bt_passthrough_enabled) + if (!SConfig::GetInstance().m_bt_passthrough_enabled && bt) { - BluetoothEmu* s_Usb = GetUsbPointer(); for (unsigned int i = 0; i < MAX_BBMOTES; i++) - wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected(); + wiiMoteConnected[i] = bt->m_WiiMotes[i].IsConnected(); } Reload(ios_to_load); - if (!SConfig::GetInstance().m_bt_passthrough_enabled) + // Get the new Bluetooth device. Note that it is not guaranteed to exist. + bt = std::static_pointer_cast(GetDeviceByName("/dev/usb/oh1/57e/305")); + if (!SConfig::GetInstance().m_bt_passthrough_enabled && bt) { - BluetoothEmu* s_Usb = GetUsbPointer(); for (unsigned int i = 0; i < MAX_BBMOTES; i++) { if (wiiMoteConnected[i]) { - s_Usb->m_WiiMotes[i].Activate(false); - s_Usb->m_WiiMotes[i].Activate(true); + bt->m_WiiMotes[i].Activate(false); + bt->m_WiiMotes[i].Activate(true); } else { - s_Usb->m_WiiMotes[i].Activate(false); + bt->m_WiiMotes[i].Activate(false); } } } diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp index 69a12cdd8d..f167d1ae23 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp @@ -50,7 +50,6 @@ BluetoothEmu::BluetoothEmu(u32 device_id, const std::string& device_name) // Activate only first Wii Remote by default _conf_pads BT_DINF; - SetUsbPointer(this); if (!sysconf.GetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads))) { PanicAlertT("Trying to read from invalid SYSCONF\nWii Remote Bluetooth IDs are not available"); @@ -103,8 +102,8 @@ BluetoothEmu::BluetoothEmu(u32 device_id, const std::string& device_name) BluetoothEmu::~BluetoothEmu() { + Host_SetWiiMoteConnectionState(0); m_WiiMotes.clear(); - SetUsbPointer(nullptr); } template diff --git a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp index dddd3feb64..d374ba7451 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp @@ -25,18 +25,6 @@ namespace IOS { namespace HLE { -static Device::BluetoothEmu* s_Usb = nullptr; - -Device::BluetoothEmu* GetUsbPointer() -{ - return s_Usb; -} - -void SetUsbPointer(Device::BluetoothEmu* ptr) -{ - s_Usb = ptr; -} - WiimoteDevice::WiimoteDevice(Device::BluetoothEmu* host, int number, bdaddr_t bd, bool ready) : m_BD(bd), m_Name(number == WIIMOTE_BALANCE_BOARD ? "Nintendo RVL-WBC-01" : "Nintendo RVL-CNT-01"), @@ -943,6 +931,9 @@ void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _ DEBUG_LOG(WIIMOTE, " Data: %s", ArrayToString(pData, _Size, 50).c_str()); DEBUG_LOG(WIIMOTE, " Channel: %x", _channelID); - IOS::HLE::s_Usb->m_WiiMotes[_number].ReceiveL2capData(_channelID, _pData, _Size); + const auto bt = std::static_pointer_cast( + IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305")); + if (bt) + bt->m_WiiMotes[_number].ReceiveL2capData(_channelID, _pData, _Size); } } diff --git a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.h b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.h index c7e1066d5f..3937a0c777 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.h +++ b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.h @@ -23,9 +23,6 @@ namespace Device class BluetoothEmu; } -Device::BluetoothEmu* GetUsbPointer(); -void SetUsbPointer(Device::BluetoothEmu* ptr); - class CBigEndianBuffer { public: diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index 2f5c071f00..d47d8b1ac9 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -521,11 +521,13 @@ void ChangeWiiPads(bool instantly) if (instantly && (s_controllers >> 4) == controllers) return; + const auto bt = std::static_pointer_cast( + IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305")); for (int i = 0; i < MAX_WIIMOTES; ++i) { g_wiimote_sources[i] = IsUsingWiimote(i) ? WIIMOTE_SRC_EMU : WIIMOTE_SRC_NONE; - if (!SConfig::GetInstance().m_bt_passthrough_enabled) - IOS::HLE::GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(IsUsingWiimote(i)); + if (!SConfig::GetInstance().m_bt_passthrough_enabled && bt) + bt->AccessWiiMote(i | 0x100)->Activate(IsUsingWiimote(i)); } } diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index c40e6d0916..94b91179c5 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -1245,7 +1245,10 @@ void CFrame::ConnectWiimote(int wm_idx, bool connect) !SConfig::GetInstance().m_bt_passthrough_enabled) { bool was_unpaused = Core::PauseAndLock(true); - IOS::HLE::GetUsbPointer()->AccessWiiMote(wm_idx | 0x100)->Activate(connect); + const auto bt = std::static_pointer_cast( + IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305")); + if (bt) + bt->AccessWiiMote(wm_idx | 0x100)->Activate(connect); const char* message = connect ? "Wii Remote %i connected" : "Wii Remote %i disconnected"; Core::DisplayMessage(StringFromFormat(message, wm_idx + 1), 3000); Host_UpdateMainFrame(); @@ -1258,10 +1261,11 @@ void CFrame::OnConnectWiimote(wxCommandEvent& event) if (SConfig::GetInstance().m_bt_passthrough_enabled) return; bool was_unpaused = Core::PauseAndLock(true); - ConnectWiimote(event.GetId() - IDM_CONNECT_WIIMOTE1, - !IOS::HLE::GetUsbPointer() - ->AccessWiiMote((event.GetId() - IDM_CONNECT_WIIMOTE1) | 0x100) - ->IsConnected()); + const auto bt = std::static_pointer_cast( + IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305")); + const bool is_connected = + bt && bt->AccessWiiMote((event.GetId() - IDM_CONNECT_WIIMOTE1) | 0x100)->IsConnected(); + ConnectWiimote(event.GetId() - IDM_CONNECT_WIIMOTE1, !is_connected); Core::PauseAndLock(false, was_unpaused); } @@ -1416,8 +1420,9 @@ void CFrame::UpdateGUI() // Tools GetMenuBar()->FindItem(IDM_CHEATS)->Enable(SConfig::GetInstance().bEnableCheats); - bool ShouldEnableWiimotes = - Running && SConfig::GetInstance().bWii && !SConfig::GetInstance().m_bt_passthrough_enabled; + const auto bt = std::static_pointer_cast( + IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305")); + bool ShouldEnableWiimotes = Running && bt && !SConfig::GetInstance().m_bt_passthrough_enabled; GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Enable(ShouldEnableWiimotes); GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)->Enable(ShouldEnableWiimotes); GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)->Enable(ShouldEnableWiimotes); @@ -1426,21 +1431,13 @@ void CFrame::UpdateGUI() if (ShouldEnableWiimotes) { bool was_unpaused = Core::PauseAndLock(true); - GetMenuBar() - ->FindItem(IDM_CONNECT_WIIMOTE1) - ->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0100)->IsConnected()); - GetMenuBar() - ->FindItem(IDM_CONNECT_WIIMOTE2) - ->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0101)->IsConnected()); - GetMenuBar() - ->FindItem(IDM_CONNECT_WIIMOTE3) - ->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0102)->IsConnected()); - GetMenuBar() - ->FindItem(IDM_CONNECT_WIIMOTE4) - ->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0103)->IsConnected()); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Check(bt->AccessWiiMote(0x0100)->IsConnected()); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)->Check(bt->AccessWiiMote(0x0101)->IsConnected()); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)->Check(bt->AccessWiiMote(0x0102)->IsConnected()); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE4)->Check(bt->AccessWiiMote(0x0103)->IsConnected()); GetMenuBar() ->FindItem(IDM_CONNECT_BALANCEBOARD) - ->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0104)->IsConnected()); + ->Check(bt->AccessWiiMote(0x0104)->IsConnected()); Core::PauseAndLock(false, was_unpaused); } diff --git a/Source/Core/DolphinWX/MainNoGUI.cpp b/Source/Core/DolphinWX/MainNoGUI.cpp index 1613fa62ac..7cc814d05b 100644 --- a/Source/Core/DolphinWX/MainNoGUI.cpp +++ b/Source/Core/DolphinWX/MainNoGUI.cpp @@ -143,7 +143,10 @@ void Host_ConnectWiimote(int wm_idx, bool connect) { Core::QueueHostJob([=] { bool was_unpaused = Core::PauseAndLock(true); - IOS::HLE::GetUsbPointer()->AccessWiiMote(wm_idx | 0x100)->Activate(connect); + const auto bt = std::static_pointer_cast( + IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305")); + if (bt) + bt->AccessWiiMote(wm_idx | 0x100)->Activate(connect); Host_UpdateMainFrame(); Core::PauseAndLock(false, was_unpaused); }); From 4662e25cbb15e00c3719814f291758e49356463c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 29 Jan 2017 15:25:27 +0100 Subject: [PATCH 5/7] DolphinWX: Fix overclock slider clock display --- Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp b/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp index 732b770ce6..4c001c6310 100644 --- a/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp @@ -16,6 +16,7 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" +#include "Core/HW/SystemTimers.h" #include "DolphinWX/DolphinSlider.h" #include "DolphinWX/WxEventUtils.h" @@ -181,12 +182,12 @@ void AdvancedConfigPane::OnCustomRTCTimeChanged(wxCommandEvent& event) void AdvancedConfigPane::UpdateCPUClock() { - bool wii = SConfig::GetInstance().bWii; - int percent = (int)(std::roundf(SConfig::GetInstance().m_OCFactor * 100.f)); - int clock = (int)(std::roundf(SConfig::GetInstance().m_OCFactor * (wii ? 729.f : 486.f))); + int core_clock = SystemTimers::GetTicksPerSecond() / pow(10, 6); + int percent = static_cast(std::round(SConfig::GetInstance().m_OCFactor * 100.f)); + int clock = static_cast(std::round(SConfig::GetInstance().m_OCFactor * core_clock)); m_clock_override_text->SetLabel( - SConfig::GetInstance().m_OCEnable ? wxString::Format("%d %% (%d mhz)", percent, clock) : ""); + SConfig::GetInstance().m_OCEnable ? wxString::Format("%d %% (%d MHz)", percent, clock) : ""); } void AdvancedConfigPane::LoadCustomRTC() From fdfe57a49b60b46aac2ad1caff135f7de1434097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 28 Jan 2017 18:12:05 +0100 Subject: [PATCH 6/7] IOS: Implement MIOS functionality This implements MIOS's PPC bootstrapping functionality, which enables users to start a GameCube game from the Wii System Menu. Because we aren't doing Starlet LLE (and don't have a boot1), we can just jump to MIOS when the emulated software does an ES_LAUNCH or uses ioctlv 0x25 to launch BC. Note that the process is more complex on a real Wii and goes through several more steps before getting to MIOS: * The System Menu detects a GameCube disc and launches BC (1-100) instead of the game. [Dolphin does this too.] * BC, which is reportedly very similar to boot1, lowers the Hollywood clock speed to the Flipper's and then launches boot2. * boot2 sees the lowered clock speed and launches MIOS (1-101) instead of the System Menu. MIOS runs instead of IOS in GC mode and has an embedded GC IPL (which is the code actually responsible for loading the disc game) and a PPC bootstrap code. To get things working properly, we simply need to load both to memory, then jump to the bootstrap code at 0x3400. Obviously, because of the way this works, a real MIOS is required. --- Source/Core/Core/Boot/Boot.h | 2 +- Source/Core/Core/Boot/ElfReader.cpp | 5 +- Source/Core/Core/Boot/ElfReader.h | 2 +- Source/Core/Core/CMakeLists.txt | 1 + Source/Core/Core/ConfigManager.h | 1 + Source/Core/Core/Core.cpp | 4 - Source/Core/Core/Core.vcxproj | 2 + Source/Core/Core/Core.vcxproj.filters | 6 + Source/Core/Core/HW/DSP.cpp | 10 +- Source/Core/Core/HW/DSP.h | 1 + Source/Core/Core/HW/DSPLLE/DSPLLE.cpp | 6 + Source/Core/Core/HW/DSPLLE/DSPLLE.h | 1 + Source/Core/Core/HW/DVDInterface.cpp | 28 ++-- Source/Core/Core/HW/DVDInterface.h | 1 + Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp | 5 +- Source/Core/Core/HW/HW.cpp | 7 +- Source/Core/Core/HW/SystemTimers.cpp | 7 +- Source/Core/Core/HW/SystemTimers.h | 7 + Source/Core/Core/IOS/ES/ES.cpp | 6 +- Source/Core/Core/IOS/IPC.cpp | 86 ++++++---- Source/Core/Core/IOS/MIOS.cpp | 195 ++++++++++++++++++++++ Source/Core/Core/IOS/MIOS.h | 16 ++ Source/Core/Core/PowerPC/PowerPC.cpp | 16 +- Source/Core/Core/PowerPC/PowerPC.h | 1 + Source/Core/Core/State.cpp | 13 ++ 25 files changed, 362 insertions(+), 67 deletions(-) create mode 100644 Source/Core/Core/IOS/MIOS.cpp create mode 100644 Source/Core/Core/IOS/MIOS.h diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index 6618036e3c..7f27014a4d 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -35,6 +35,7 @@ public: // Returns true if a map file exists, false if none could be found. static bool FindMapFile(std::string* existing_map_file, std::string* writable_map_file, std::string* title_id = nullptr); + static bool LoadMapFromFilename(); private: static bool DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt); @@ -42,7 +43,6 @@ private: static void UpdateDebugger_MapLoaded(); - static bool LoadMapFromFilename(); static bool Boot_ELF(const std::string& filename); static bool Boot_WiiWAD(const std::string& filename); diff --git a/Source/Core/Core/Boot/ElfReader.cpp b/Source/Core/Core/Boot/ElfReader.cpp index 77885649dd..b174ff4c92 100644 --- a/Source/Core/Core/Boot/ElfReader.cpp +++ b/Source/Core/Core/Boot/ElfReader.cpp @@ -102,7 +102,7 @@ const char* ElfReader::GetSectionName(int section) const } // This is just a simple elf loader, good enough to load elfs generated by devkitPPC -bool ElfReader::LoadIntoMemory() +bool ElfReader::LoadIntoMemory(bool only_in_mem1) { INFO_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx); @@ -132,6 +132,9 @@ bool ElfReader::LoadIntoMemory() u32 srcSize = p->p_filesz; u32 dstSize = p->p_memsz; + if (only_in_mem1 && p->p_vaddr >= Memory::REALRAM_SIZE) + continue; + Memory::CopyToEmu(writeAddr, src, srcSize); if (srcSize < dstSize) Memory::Memset(writeAddr + srcSize, 0, dstSize - srcSize); // zero out bss diff --git a/Source/Core/Core/Boot/ElfReader.h b/Source/Core/Core/Boot/ElfReader.h index 92392e2bc0..4580cf0715 100644 --- a/Source/Core/Core/Boot/ElfReader.h +++ b/Source/Core/Core/Boot/ElfReader.h @@ -39,7 +39,7 @@ public: ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } u32 GetEntryPoint() const { return entryPoint; } u32 GetFlags() const { return (u32)(header->e_flags); } - bool LoadIntoMemory(); + bool LoadIntoMemory(bool only_in_mem1 = false); bool LoadSymbols(); int GetNumSegments() const { return (int)(header->e_phnum); } diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 68eacfc3ed..4c31353f8b 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -140,6 +140,7 @@ set(SRCS ActionReplay.cpp IOS/Device.cpp IOS/DeviceStub.cpp IOS/IPC.cpp + IOS/MIOS.cpp IOS/DI/DI.cpp IOS/ES/ES.cpp IOS/ES/Formats.cpp diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 4221dc10d4..3974de3dfe 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -188,6 +188,7 @@ struct SConfig : NonCopyable BOOT_ELF, BOOT_DOL, BOOT_WII_NAND, + BOOT_MIOS, BOOT_BS2, BOOT_DFF }; diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 711e74a12f..5d7b1da8d3 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -634,10 +634,6 @@ void EmuThread() FileMon::Close(); - // Stop audio thread - Actually this does nothing when using HLE - // emulation, but stops the DSP Interpreter when using LLE emulation. - DSP::GetDSPEmulator()->DSP_StopSoundStream(); - // We must set up this flag before executing HW::Shutdown() s_hardware_initialized = false; INFO_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down HW").c_str()); diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index dc6bcd4a36..60a6de3fd5 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -172,6 +172,7 @@ + @@ -408,6 +409,7 @@ + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 109608d2bb..b96b206c0f 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -752,6 +752,9 @@ IOS + + IOS + IOS\Network @@ -1419,6 +1422,9 @@ IOS + + IOS + diff --git a/Source/Core/Core/HW/DSP.cpp b/Source/Core/Core/HW/DSP.cpp index 9210f73f6a..38fb513875 100644 --- a/Source/Core/Core/HW/DSP.cpp +++ b/Source/Core/Core/HW/DSP.cpp @@ -177,6 +177,13 @@ DSPEmulator* GetDSPEmulator() } void Init(bool hle) +{ + Reinit(hle); + s_et_GenerateDSPInterrupt = CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt); + s_et_CompleteARAM = CoreTiming::RegisterEvent("ARAMint", CompleteARAM); +} + +void Reinit(bool hle) { s_dsp_emulator = CreateDSPEmulator(hle); s_dsp_is_lle = s_dsp_emulator->IsLLE(); @@ -206,9 +213,6 @@ void Init(bool hle) s_ARAM_Info.Hex = 0; s_AR_MODE = 1; // ARAM Controller has init'd s_AR_REFRESH = 156; // 156MHz - - s_et_GenerateDSPInterrupt = CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt); - s_et_CompleteARAM = CoreTiming::RegisterEvent("ARAMint", CompleteARAM); } void Shutdown() diff --git a/Source/Core/Core/HW/DSP.h b/Source/Core/Core/HW/DSP.h index 502233fe43..f189b00b72 100644 --- a/Source/Core/Core/HW/DSP.h +++ b/Source/Core/Core/HW/DSP.h @@ -60,6 +60,7 @@ union UDSPControl }; void Init(bool hle); +void Reinit(bool hle); void Shutdown(); void RegisterMMIO(MMIO::Mapping* mmio, u32 base); diff --git a/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp b/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp index ca6e28acb8..fbb763c978 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp +++ b/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp @@ -37,6 +37,12 @@ static bool s_request_disable_thread; DSPLLE::DSPLLE() = default; +DSPLLE::~DSPLLE() +{ + DSPCore_Shutdown(); + DSP_StopSoundStream(); +} + void DSPLLE::DoState(PointerWrap& p) { bool is_hle = false; diff --git a/Source/Core/Core/HW/DSPLLE/DSPLLE.h b/Source/Core/Core/HW/DSPLLE/DSPLLE.h index dc951d52a7..be55b17a82 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPLLE.h +++ b/Source/Core/Core/HW/DSPLLE/DSPLLE.h @@ -22,6 +22,7 @@ class DSPLLE : public DSPEmulator { public: DSPLLE(); + ~DSPLLE(); bool Initialize(bool wii, bool dsp_thread) override; void Shutdown() override; diff --git a/Source/Core/Core/HW/DVDInterface.cpp b/Source/Core/Core/HW/DVDInterface.cpp index e338e76698..de9d2c726d 100644 --- a/Source/Core/Core/HW/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVDInterface.cpp @@ -419,8 +419,24 @@ void Init() { DVDThread::Start(); - s_DISR.Hex = 0; + Reset(); s_DICVR.Hex = 1; // Disc Channel relies on cover being open when no disc is inserted + s_disc_inside = false; + + s_eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback); + s_insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback); + + s_finish_executing_command = + CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback); + + u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::INT_TCINT); + CoreTiming::ScheduleEvent(0, s_finish_executing_command, userdata); +} + +// This doesn't reset any inserted disc or the cover state. +void Reset() +{ + s_DISR.Hex = 0; s_DICMDBUF[0].Hex = 0; s_DICMDBUF[1].Hex = 0; s_DICMDBUF[2].Hex = 0; @@ -441,7 +457,6 @@ void Init() s_pending_samples = 0; s_error_code = 0; - s_disc_inside = false; // The buffer is empty at start s_read_buffer_start_offset = 0; @@ -450,15 +465,6 @@ void Init() s_read_buffer_end_time = 0; s_disc_path_to_insert.clear(); - - s_eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback); - s_insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback); - - s_finish_executing_command = - CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback); - - u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::INT_TCINT); - CoreTiming::ScheduleEvent(0, s_finish_executing_command, userdata); } void Shutdown() diff --git a/Source/Core/Core/HW/DVDInterface.h b/Source/Core/Core/HW/DVDInterface.h index 90c534ea24..410aee8f3e 100644 --- a/Source/Core/Core/HW/DVDInterface.h +++ b/Source/Core/Core/HW/DVDInterface.h @@ -102,6 +102,7 @@ enum class ReplyType : u32 }; void Init(); +void Reset(); void Shutdown(); void DoState(PointerWrap& p); diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp index 71618d257f..69511aa946 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp @@ -232,7 +232,10 @@ void CEXIIPL::SetCS(int _iCS) void CEXIIPL::UpdateRTC() { - u32 epoch = SConfig::GetInstance().bWii ? WII_EPOCH : GC_EPOCH; + u32 epoch = + (SConfig::GetInstance().bWii || SConfig::GetInstance().m_BootType == SConfig::BOOT_MIOS) ? + WII_EPOCH : + GC_EPOCH; u32 rtc = Common::swap32(GetEmulatedTime(epoch)); std::memcpy(m_RTC, &rtc, sizeof(u32)); } diff --git a/Source/Core/Core/HW/HW.cpp b/Source/Core/Core/HW/HW.cpp index 63b0ddd2d2..3137a8ed85 100644 --- a/Source/Core/Core/HW/HW.cpp +++ b/Source/Core/Core/HW/HW.cpp @@ -61,12 +61,11 @@ void Init() void Shutdown() { + // IOS should always be shut down regardless of bWii because it can be running in GC mode (MIOS). + IOS::HLE::Shutdown(); // Depends on Memory + IOS::Shutdown(); if (SConfig::GetInstance().bWii) - { - IOS::HLE::Shutdown(); // Depends on Memory - IOS::Shutdown(); Core::ShutdownWiiRoot(); - } SystemTimers::Shutdown(); CPU::Shutdown(); diff --git a/Source/Core/Core/HW/SystemTimers.cpp b/Source/Core/Core/HW/SystemTimers.cpp index 0fa2ffe7fc..eb72f6de47 100644 --- a/Source/Core/Core/HW/SystemTimers.cpp +++ b/Source/Core/Core/HW/SystemTimers.cpp @@ -223,7 +223,12 @@ static void ThrottleCallback(u64 last_time, s64 cyclesLate) // SystemTimers::Init void PreInit() { - if (SConfig::GetInstance().bWii) + ChangePPCClock(SConfig::GetInstance().bWii ? Mode::Wii : Mode::GC); +} + +void ChangePPCClock(Mode mode) +{ + if (mode == Mode::Wii) s_cpu_core_clock = 729000000u; else s_cpu_core_clock = 486000000u; diff --git a/Source/Core/Core/HW/SystemTimers.h b/Source/Core/Core/HW/SystemTimers.h index ba060993d0..5ab65c809b 100644 --- a/Source/Core/Core/HW/SystemTimers.h +++ b/Source/Core/Core/HW/SystemTimers.h @@ -33,10 +33,17 @@ enum TIMER_RATIO = 12 }; +enum class Mode +{ + GC, + Wii, +}; + u32 GetTicksPerSecond(); void PreInit(); void Init(); void Shutdown(); +void ChangePPCClock(Mode mode); // Notify timing system that somebody wrote to the decrementer void DecrementerSet(); diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 419f5844b9..9274866b08 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -1113,6 +1113,9 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request) u64 titleid = Memory::Read_U64(request.in_vectors[1].address + 16); u16 access = Memory::Read_U16(request.in_vectors[1].address + 24); + NOTICE_LOG(IOS_ES, "IOCTL_ES_LAUNCH %016" PRIx64 " %08x %016" PRIx64 " %08x %016" PRIx64 " %04x", + TitleID, view, ticketid, devicetype, titleid, access); + // ES_LAUNCH should probably reset thw whole state, which at least means closing all open files. // leaving them open through ES_LAUNCH may cause hangs and other funky behavior // (supposedly when trying to re-open those files). @@ -1173,9 +1176,6 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request) SetDefaultContentFile(tContentFile); } - ERROR_LOG(IOS_ES, "IOCTL_ES_LAUNCH %016" PRIx64 " %08x %016" PRIx64 " %08x %016" PRIx64 " %04x", - TitleID, view, ticketid, devicetype, titleid, access); - // Generate a "reply" to the IPC command. ES_LAUNCH is unique because it // involves restarting IOS; IOS generates two acknowledgements in a row. // Note: If we just reset the PPC, don't write anything to the command buffer. This diff --git a/Source/Core/Core/IOS/IPC.cpp b/Source/Core/Core/IOS/IPC.cpp index cb0876527e..7abb1717ce 100644 --- a/Source/Core/Core/IOS/IPC.cpp +++ b/Source/Core/Core/IOS/IPC.cpp @@ -42,6 +42,7 @@ #include "Core/IOS/FS/FS.h" #include "Core/IOS/FS/FileIO.h" #include "Core/IOS/IPC.h" +#include "Core/IOS/MIOS.h" #include "Core/IOS/Network/Net.h" #include "Core/IOS/Network/SSL.h" #include "Core/IOS/Network/Socket.h" @@ -111,6 +112,7 @@ struct IosMemoryValues u32 ram_vendor; u32 unknown_begin; u32 unknown_end; + u32 sysmenu_sync; }; constexpr u32 ADDR_MEM1_SIZE = 0x3100; @@ -162,210 +164,210 @@ constexpr std::array ios_memory_values = { MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 12, 0xc020e, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 13, 0xd0408, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 14, 0xe0408, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 15, 0xf0408, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 17, 0x110408, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 21, 0x15040f, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 22, 0x16050e, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 28, 0x1c070f, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93800000, MEM2_ARENA_BEGIN, 0x937E0000, 0x937E0000, 0x93800000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93800000, 0x93820000, + RAM_VENDOR, 0x93800000, 0x93820000, 0, }, { 31, 0x1f0e18, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 33, 0x210e18, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 34, 0x220e18, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 35, 0x230e18, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 36, 0x240e18, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 37, 0x25161f, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 38, 0x26101c, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 41, 0x290e17, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 43, 0x2b0e17, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 45, 0x2d0e17, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 46, 0x2e0e17, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 48, 0x30101c, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 53, 0x35161f, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 55, 0x37161f, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 56, 0x38161e, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 57, 0x39171f, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 58, 0x3a1820, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 59, 0x3b1c21, 0x101811, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 61, 0x3d161e, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 62, 0x3e191e, 0x022712, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 80, 0x501b20, 0x030310, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 257, @@ -387,6 +389,7 @@ constexpr std::array ios_memory_values = { RAM_VENDOR_MIOS, PLACEHOLDER, PLACEHOLDER, + PLACEHOLDER, }}}; static void EnqueueEvent(u64 userdata, s64 cycles_late = 0) @@ -459,7 +462,7 @@ static bool SetupMemory(u64 ios_title_id) Memory::Write_U8(0xDE, ADDR_BOOT_FLAG); Memory::Write_U8(0xAD, ADDR_APPLOADER_FLAG); Memory::Write_U16(0xBEEF, ADDR_DEVKIT_BOOT_PROGRAM_VERSION); - Memory::Write_U32(0x00000000, ADDR_SYSMENU_SYNC); + Memory::Write_U32(target_imv->sysmenu_sync, ADDR_SYSMENU_SYNC); return true; } @@ -517,7 +520,6 @@ static void AddStaticDevices() void Init() { - AddStaticDevices(); s_event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent); s_event_sdio_notify = CoreTiming::RegisterEvent("SDIO_EventNotify", SDIO_EventNotify_CPUThread); } @@ -552,14 +554,31 @@ void Shutdown() Reset(true); } +constexpr u64 BC_TITLE_ID = 0x0000000100000100; +constexpr u64 MIOS_TITLE_ID = 0x0000000100000101; + bool Reload(const u64 ios_title_id) { + // A real Wii goes through several steps before getting to MIOS. + // + // * The System Menu detects a GameCube disc and launches BC (1-100) instead of the game. + // * BC (similar to boot1) lowers the clock speed to the Flipper's and then launches boot2. + // * boot2 sees the lowered clock speed and launches MIOS (1-101) instead of the System Menu. + // + // Because we currently don't have boot1 and boot2, and BC is only ever used to launch MIOS + // (indirectly via boot2), we can just launch MIOS when BC is launched. + if (ios_title_id == BC_TITLE_ID) + return Reload(MIOS_TITLE_ID); + if (!SetupMemory(ios_title_id)) return false; s_active_title_id = ios_title_id; Reset(true); + if (ios_title_id == MIOS_TITLE_ID) + return MIOS::Load(); + AddStaticDevices(); return true; } @@ -629,6 +648,9 @@ void DoState(PointerWrap& p) p.Do(s_last_reply_time); p.Do(s_active_title_id); + if (s_active_title_id == MIOS_TITLE_ID) + return; + // We need to make sure all file handles are closed so IOS::HLE::Device::FS::DoState can // successfully save or re-create /tmp for (auto& descriptor : s_fdmap) diff --git a/Source/Core/Core/IOS/MIOS.cpp b/Source/Core/Core/IOS/MIOS.cpp new file mode 100644 index 0000000000..6fa93f6d68 --- /dev/null +++ b/Source/Core/Core/IOS/MIOS.cpp @@ -0,0 +1,195 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include +#include + +#include "Common/CommonFuncs.h" +#include "Common/CommonTypes.h" +#include "Common/FileUtil.h" +#include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" +#include "Common/NandPaths.h" +#include "Core/Boot/Boot.h" +#include "Core/Boot/ElfReader.h" +#include "Core/ConfigManager.h" +#include "Core/Core.h" +#include "Core/DSPEmulator.h" +#include "Core/HLE/HLE.h" +#include "Core/HW/DSP.h" +#include "Core/HW/DVDInterface.h" +#include "Core/HW/DVDThread.h" +#include "Core/HW/Memmap.h" +#include "Core/HW/SystemTimers.h" +#include "Core/IOS/MIOS.h" +#include "Core/PowerPC/PPCSymbolDB.h" +#include "Core/PowerPC/PowerPC.h" +#include "DiscIO/NANDContentLoader.h" +#include "DiscIO/Volume.h" + +namespace IOS +{ +namespace HLE +{ +namespace MIOS +{ +constexpr u64 MIOS_TITLE_ID = 0x0000000100000101; + +// Source: https://wiibrew.org/wiki/ARM_Binaries +struct ARMBinary final +{ + explicit ARMBinary(const std::vector& bytes); + explicit ARMBinary(std::vector&& bytes); + + bool IsValid() const; + std::vector GetElf() const; + u32 GetHeaderSize() const; + u32 GetElfOffset() const; + u32 GetElfSize() const; + +private: + std::vector m_bytes; +}; + +ARMBinary::ARMBinary(const std::vector& bytes) : m_bytes(bytes) +{ +} + +ARMBinary::ARMBinary(std::vector&& bytes) : m_bytes(std::move(bytes)) +{ +} + +bool ARMBinary::IsValid() const +{ + // The header is at least 0x10. + if (m_bytes.size() < 0x10) + return false; + return m_bytes.size() >= (GetHeaderSize() + GetElfOffset() + GetElfSize()); +} + +std::vector ARMBinary::GetElf() const +{ + const auto iterator = m_bytes.cbegin() + GetHeaderSize() + GetElfOffset(); + return std::vector(iterator, iterator + GetElfSize()); +} + +u32 ARMBinary::GetHeaderSize() const +{ + return Common::swap32(m_bytes.data()); +} + +u32 ARMBinary::GetElfOffset() const +{ + return Common::swap32(m_bytes.data() + 0x4); +} + +u32 ARMBinary::GetElfSize() const +{ + return Common::swap32(m_bytes.data() + 0x8); +} + +static std::vector GetMIOSBinary() +{ + const auto& loader = + DiscIO::CNANDContentManager::Access().GetNANDLoader(MIOS_TITLE_ID, Common::FROM_SESSION_ROOT); + if (!loader.IsValid()) + return {}; + + const auto* content = loader.GetContentByIndex(loader.GetBootIndex()); + if (!content) + return {}; + + return content->m_Data->Get(); +} + +static void ReinitHardware() +{ + SConfig::GetInstance().bWii = false; + + // IOS clears mem2 and overwrites it with pseudo-random data (for security). + std::memset(Memory::m_pEXRAM, 0, Memory::EXRAM_SIZE); + // MIOS appears to only reset the DI and the PPC. + DVDInterface::Reset(); + PowerPC::Reset(); + // Note: this is specific to Dolphin and is required because we initialised it in Wii mode. + DSP::Reinit(SConfig::GetInstance().bDSPHLE); + DSP::GetDSPEmulator()->Initialize(SConfig::GetInstance().bWii, SConfig::GetInstance().bDSPThread); + + SystemTimers::ChangePPCClock(SystemTimers::Mode::GC); +} + +static void UpdateRunningGame() +{ + DVDThread::WaitUntilIdle(); + const DiscIO::IVolume& volume = DVDInterface::GetVolume(); + SConfig::GetInstance().m_BootType = SConfig::BOOT_MIOS; + SConfig::GetInstance().m_strName = volume.GetInternalName(); + SConfig::GetInstance().m_strGameID = volume.GetGameID(); + SConfig::GetInstance().m_revision = volume.GetRevision(); + + g_symbolDB.Clear(); + CBoot::LoadMapFromFilename(); + ::HLE::Clear(); + ::HLE::PatchFunctions(); + + NOTICE_LOG(IOS, "Running game: %s (%s)", SConfig::GetInstance().m_strName.c_str(), + SConfig::GetInstance().m_strGameID.c_str()); +} + +constexpr u32 ADDRESS_INIT_SEMAPHORE = 0x30f8; + +bool Load() +{ + Memory::Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE); + Memory::Write_U32(0x09142001, 0x3180); + + ARMBinary mios{GetMIOSBinary()}; + if (!mios.IsValid()) + { + PanicAlertT("Failed to load MIOS. It is required for launching GameCube titles from Wii mode."); + Core::QueueHostJob(Core::Stop); + return false; + } + + std::vector elf_bytes = mios.GetElf(); + ElfReader elf{elf_bytes.data()}; + if (!elf.LoadIntoMemory(true)) + { + PanicAlertT("Failed to load MIOS ELF into memory."); + Core::QueueHostJob(Core::Stop); + return false; + } + + ReinitHardware(); + NOTICE_LOG(IOS, "Reinitialised hardware."); + + // Load symbols for the IPL if they exist. + g_symbolDB.Clear(); + if (g_symbolDB.LoadMap(File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map")) + { + ::HLE::Clear(); + ::HLE::PatchFunctions(); + } + + const PowerPC::CoreMode core_mode = PowerPC::GetMode(); + PowerPC::SetMode(PowerPC::CoreMode::Interpreter); + MSR = 0; + PC = 0x3400; + NOTICE_LOG(IOS, "Loaded MIOS and bootstrapped PPC."); + + // IOS writes 0 to 0x30f8 before bootstrapping the PPC. Once started, the IPL eventually writes + // 0xdeadbeef there, then waits for it to be cleared by IOS before continuing. + while (Memory::Read_U32(ADDRESS_INIT_SEMAPHORE) != 0xdeadbeef) + PowerPC::SingleStep(); + PowerPC::SetMode(core_mode); + + Memory::Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE); + NOTICE_LOG(IOS, "IPL ready."); + UpdateRunningGame(); + return true; +} +} // namespace MIOS +} // namespace HLE +} // namespace IOS diff --git a/Source/Core/Core/IOS/MIOS.h b/Source/Core/Core/IOS/MIOS.h new file mode 100644 index 0000000000..f0be9d4ed3 --- /dev/null +++ b/Source/Core/Core/IOS/MIOS.h @@ -0,0 +1,16 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +namespace IOS +{ +namespace HLE +{ +namespace MIOS +{ +bool Load(); +} // namespace MIOS +} // namespace HLE +} // namespace IOS diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index 67ed02601b..2beeb37517 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -189,11 +189,7 @@ void Init(int cpu_core) s_invalidate_cache_thread_safe = CoreTiming::RegisterEvent("invalidateEmulatedCache", InvalidateCacheThreadSafe); - ppcState.pagetable_base = 0; - ppcState.pagetable_hashmask = 0; - ppcState.tlb = {}; - - ResetRegisters(); + Reset(); InitializeCPUCore(cpu_core); ppcState.iCache.Init(); @@ -202,6 +198,16 @@ void Init(int cpu_core) breakpoints.ClearAllTemporary(); } +void Reset() +{ + ppcState.pagetable_base = 0; + ppcState.pagetable_hashmask = 0; + ppcState.tlb = {}; + + ResetRegisters(); + ppcState.iCache.Reset(); +} + void ScheduleInvalidateCacheThreadSafe(u32 address) { if (CPU::GetState() == CPU::State::CPU_RUNNING) diff --git a/Source/Core/Core/PowerPC/PowerPC.h b/Source/Core/Core/PowerPC/PowerPC.h index 83647602dd..bdf883a4e0 100644 --- a/Source/Core/Core/PowerPC/PowerPC.h +++ b/Source/Core/Core/PowerPC/PowerPC.h @@ -136,6 +136,7 @@ extern MemChecks memchecks; extern PPCDebugInterface debug_interface; void Init(int cpu_core); +void Reset(); void Shutdown(); void DoState(PointerWrap& p); void ScheduleInvalidateCacheThreadSafe(u32 address); diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 0073b9ea4b..e2ce058903 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -156,6 +156,19 @@ static std::string DoState(PointerWrap& p) return version_created_by; } + bool is_wii = + SConfig::GetInstance().bWii || SConfig::GetInstance().m_BootType == SConfig::BOOT_MIOS; + const bool is_wii_currently = is_wii; + p.Do(is_wii); + if (is_wii != is_wii_currently) + { + OSD::AddMessage(StringFromFormat("Cannot load a savestate created under %s mode in %s mode", + is_wii ? "Wii" : "GC", is_wii_currently ? "Wii" : "GC"), + OSD::Duration::NORMAL, OSD::Color::RED); + p.SetMode(PointerWrap::MODE_MEASURE); + return version_created_by; + } + // Begin with video backend, so that it gets a chance to clear its caches and writeback modified // things to RAM g_video_backend->DoState(p); From a085cd431dbaed77349d1e1e2f41be1b94b84535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Wed, 8 Feb 2017 16:22:27 +0100 Subject: [PATCH 7/7] Adjust event times after a PPC clock change This likely doesn't change much, but it makes events trigger at the correct time after a clock change. --- Source/Core/Core/CoreTiming.cpp | 10 ++++++++++ Source/Core/Core/CoreTiming.h | 2 ++ Source/Core/Core/HW/SystemTimers.cpp | 2 ++ 3 files changed, 14 insertions(+) diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index 803cd76fec..0780d93ca4 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -364,6 +364,16 @@ void LogPendingEvents() } } +// Should only be called from the CPU thread after the PPC clock has changed +void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock) +{ + for (Event& ev : s_event_queue) + { + const s64 ticks = (ev.time - g_global_timer) * new_ppc_clock / old_ppc_clock; + ev.time = g_global_timer + ticks; + } +} + void Idle() { if (SConfig::GetInstance().bSyncGPUOnSkipIdleHack) diff --git a/Source/Core/Core/CoreTiming.h b/Source/Core/Core/CoreTiming.h index 28263be94c..2cdee0c6cf 100644 --- a/Source/Core/Core/CoreTiming.h +++ b/Source/Core/Core/CoreTiming.h @@ -91,6 +91,8 @@ void LogPendingEvents(); std::string GetScheduledEventsSummary(); +void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock); + u32 GetFakeDecStartValue(); void SetFakeDecStartValue(u32 val); u64 GetFakeDecStartTicks(); diff --git a/Source/Core/Core/HW/SystemTimers.cpp b/Source/Core/Core/HW/SystemTimers.cpp index eb72f6de47..4b3a9fda8a 100644 --- a/Source/Core/Core/HW/SystemTimers.cpp +++ b/Source/Core/Core/HW/SystemTimers.cpp @@ -228,10 +228,12 @@ void PreInit() void ChangePPCClock(Mode mode) { + const u32 previous_clock = s_cpu_core_clock; if (mode == Mode::Wii) s_cpu_core_clock = 729000000u; else s_cpu_core_clock = 486000000u; + CoreTiming::AdjustEventQueueTimes(s_cpu_core_clock, previous_clock); } void Init()